From 5d4d2fdfd41a804fc2696b737ef3fca5d64daaca Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Tue, 30 Aug 2005 02:12:09 +0000
Subject: [PATCH] Add SIP video fixes

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6448 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 app.c                    |  2 ++
 apps/app_dial.c          | 10 +++++++++
 apps/app_record.c        |  3 +++
 channel.c                |  5 ++++-
 channels/chan_sip.c      | 45 +++++++++++++++++++++++++++++++++++++++-
 file.c                   |  1 +
 include/asterisk/frame.h |  2 ++
 rtp.c                    | 13 +++++++++++-
 8 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/app.c b/app.c
index f3a84c3a59..4db43846b3 100755
--- a/app.c
+++ b/app.c
@@ -615,6 +615,8 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
 			return -1;
 		}
 	}
+	/* Request a video update */
+	ast_indicate(chan, AST_CONTROL_VIDUPDATE);
 
 	if (x == fmtcnt) {
 	/* Loop forever, writing the packets we read to the writer(s), until
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 8fe9fc43ad..ca72060b9e 100755
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -493,6 +493,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
 							if (!ast_test_flag(outgoing, DIAL_RINGBACKONLY))
 								ast_indicate(in, AST_CONTROL_PROGRESS);
 							break;
+						case AST_CONTROL_VIDUPDATE:
+							if (option_verbose > 2)
+								ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", o->chan->name,in->name);
+							ast_indicate(in, AST_CONTROL_VIDUPDATE);
+							break;
 						case AST_CONTROL_PROCEEDING:
 							if (option_verbose > 2)
 								ast_verbose ( VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", o->chan->name,in->name);
@@ -600,6 +605,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
 				if (ast_write(outgoing->chan, f))
 					ast_log(LOG_WARNING, "Unable to forward voice\n");
 			}
+			if (single && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_VIDUPDATE)) {
+				if (option_verbose > 2)
+					ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", in->name,outgoing->chan->name);
+				ast_indicate(outgoing->chan, AST_CONTROL_VIDUPDATE);
+			}
 			ast_frfree(f);
 		}
 		if (!*to && (option_verbose > 2))
diff --git a/apps/app_record.c b/apps/app_record.c
index c5da8f9102..bb0e1ed000 100755
--- a/apps/app_record.c
+++ b/apps/app_record.c
@@ -218,6 +218,9 @@ static int record_exec(struct ast_channel *chan, void *data)
 		
 		
 		if (s) {
+			/* Request a video update */
+			ast_indicate(chan, AST_CONTROL_VIDUPDATE);
+
 			if (maxduration > 0)
 				timeout = time(NULL) + (time_t)maxduration;
 			
diff --git a/channel.c b/channel.c
index 6fd536b7f0..282a7967e9 100755
--- a/channel.c
+++ b/channel.c
@@ -1721,6 +1721,8 @@ int ast_indicate(struct ast_channel *chan, int condition)
 				/* Do nothing.... */
 			} else if (condition == AST_CONTROL_UNHOLD) {
 				/* Do nothing.... */
+			} else if (condition == AST_CONTROL_VIDUPDATE) {
+				/* Do nothing.... */
 			} else {
 				/* not handled */
 				ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
@@ -2966,7 +2968,8 @@ static enum ast_bridge_result ast_generic_bridge(int *playitagain, int *playit,
 		}
 
 		if ((f->frametype == AST_FRAME_CONTROL) && !(config->flags & AST_BRIDGE_IGNORE_SIGS)) {
-			if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD)) {
+			if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) ||
+			    (f->subclass == AST_CONTROL_VIDUPDATE)) {
 				ast_indicate(who == c0 ? c1 : c0, f->subclass);
 			} else {
 				*fo = f;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 0b77fabc4a..bdd2c36e88 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -832,6 +832,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int inc,
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sendsdp, struct sip_invite_param *options, int init);
 static int transmit_reinvite_with_sdp(struct sip_pvt *p);
 static int transmit_info_with_digit(struct sip_pvt *p, char digit);
+static int transmit_info_with_vidupdate(struct sip_pvt *p);
 static int transmit_message_with_text(struct sip_pvt *p, const char *text);
 static int transmit_refer(struct sip_pvt *p, const char *dest);
 static int sip_sipredirect(struct sip_pvt *p, const char *dest);
@@ -2609,6 +2610,13 @@ static int sip_indicate(struct ast_channel *ast, int condition)
 			ast_log(LOG_DEBUG, "Bridged channel is back from hold, let's talk! : %s\n", p->callid);
 		res = -1;
 		break;
+	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
+		if (p->vrtp && !ast_test_flag(p, SIP_NOVIDEO)) {
+			transmit_info_with_vidupdate(p);
+			res = 0;
+		} else
+			res = -1;
+		break;
 	case -1:
 		res = -1;
 		break;
@@ -3949,7 +3957,7 @@ static int __transmit_response(struct sip_pvt *p, char *msg, struct sip_request
 	/* If we are cancelling an incoming invite for some reason, add information
 		about the reason why we are doing this in clear text */
 	if (p->owner && p->owner->hangupcause) {
-		add_header(&resp, "X-Asterisk-HangupCause:", ast_cause2str(p->owner->hangupcause));
+		add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
 	}
 	add_blank_header(&resp);
 	return send_response(p, &resp, reliable, seqno);
@@ -4056,6 +4064,26 @@ static int add_digit(struct sip_request *req, char digit)
 	return 0;
 }
 
+/*--- add_vidupdate: add XML encoded media control with update ---*/
+/* XML: The only way to turn 0 bits of information into a few hundred. */
+static int add_vidupdate(struct sip_request *req)
+{
+	const char *xml_is_a_huge_waste_of_space =
+		"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
+		" <media_control>\r\n"
+		"  <vc_primitive>\r\n"
+		"   <to_encoder>\r\n"
+		"    <picture_fast_update\r\n"
+		"    </picture_fast_update>\r\n"
+		"   </to_encoder>\r\n"
+		"  </vc_primitive>\r\n"
+		" </media_control>\r\n";
+	add_header(req, "Content-Type", "application/media_control+xml");
+	add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space));
+	add_line(req, xml_is_a_huge_waste_of_space);
+	return 0;
+}
+
 /*--- add_sdp: Add Session Description Protocol message ---*/
 static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
 {
@@ -5209,6 +5237,15 @@ static int transmit_info_with_digit(struct sip_pvt *p, char digit)
 	return send_request(p, &req, 1, p->ocseq);
 }
 
+/*--- transmit_info_with_vidupdate: Send SIP INFO with video update request ---*/
+static int transmit_info_with_vidupdate(struct sip_pvt *p)
+{
+	struct sip_request req;
+	reqprep(&req, p, SIP_INFO, 0, 1);
+	add_vidupdate(&req);
+	return send_request(p, &req, 1, p->ocseq);
+}
+
 /*--- transmit_request: transmit generic SIP request ---*/
 static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, int reliable, int newbranch)
 {
@@ -8125,6 +8162,12 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
 			ast_set_flag(p, SIP_NEEDDESTROY);
 		}
 		return;
+	} else if (!strcasecmp(get_header(req, "Content-Type"), "application/media_control+xml")) {
+		/* Eh, we'll just assume it's a fast picture update for now */
+		if (p->owner)
+			ast_queue_control(p->owner, AST_CONTROL_VIDUPDATE);
+		transmit_response(p, "200 OK", req);
+		return;
 	} else if ((c = get_header(req, "X-ClientCode"))) {
 		/* Client code (from SNOM phone) */
 		if (ast_test_flag(p, SIP_USECLIENTCODE)) {
diff --git a/file.c b/file.c
index 6fcd31173f..ab24719cbb 100755
--- a/file.c
+++ b/file.c
@@ -987,6 +987,7 @@ int ast_waitstream(struct ast_channel *c, const char *breakon)
 					return -1;
 				case AST_CONTROL_RINGING:
 				case AST_CONTROL_ANSWER:
+				case AST_CONTROL_VIDUPDATE:
 					/* Unimportant */
 					break;
 				default:
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 41a4e7cb5f..364aaa4cc5 100755
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -194,6 +194,8 @@ struct ast_frame_chain {
 #define AST_CONTROL_HOLD			16
 /*! Indicate call is left from hold */
 #define AST_CONTROL_UNHOLD			17
+/*! Indicate video frame update */
+#define AST_CONTROL_VIDUPDATE		18
 
 #define AST_SMOOTHER_FLAG_G729		(1 << 0)
 
diff --git a/rtp.c b/rtp.c
index 71a24360f7..e71b2e0223 100755
--- a/rtp.c
+++ b/rtp.c
@@ -672,7 +672,7 @@ void ast_rtp_pt_default(struct ast_rtp* rtp)
 	rtp->rtp_lookup_code_cache_result = 0;
 }
 
-/* Make a note of a RTP payload type that was seen in a SDP "m=" line. */
+/* Make a note of a RTP paymoad type that was seen in a SDP "m=" line. */
 /* By default, use the well-known value for this type (although it may */
 /* still be set to a different value by a subsequent "a=rtpmap:" line): */
 void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt) {
@@ -1628,6 +1628,17 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
 					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
 			}
 			return AST_BRIDGE_COMPLETE;
+		} else if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
+			if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) ||
+			    (f->subclass == AST_CONTROL_VIDUPDATE)) {
+				ast_indicate(who == c0 ? c1 : c0, f->subclass);
+				ast_frfree(f);
+			} else {
+				*fo = f;
+				*rc = who;
+				ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
+				return AST_BRIDGE_COMPLETE;
+			}
 		} else {
 			if ((f->frametype == AST_FRAME_DTMF) || 
 				(f->frametype == AST_FRAME_VOICE) || 
-- 
GitLab