From 7296b670d4ca4fdaba41b82a0236f0cb6dd1da02 Mon Sep 17 00:00:00 2001
From: Joshua Colp <jcolp@digium.com>
Date: Tue, 10 Jul 2012 11:49:18 +0000
Subject: [PATCH] Add required items for Google video support.

This adds legacy STUN support for RTCP sockets, adds RTCP candidates to the Google transport information, and adds required codec parameters.

(closes issue ASTERISK-20106)
Reported by: Malcolm Davenport


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@369864 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_motif.c  | 35 ++++++++++++++++++++++++++++++++---
 res/res_rtp_asterisk.c | 26 ++++++++++++++++++++++++--
 2 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/channels/chan_motif.c b/channels/chan_motif.c
index d7238cec5e..d8e3320497 100644
--- a/channels/chan_motif.c
+++ b/channels/chan_motif.c
@@ -820,12 +820,15 @@ static int jingle_add_google_candidates_to_transport(struct ast_rtp_instance *rt
 			break;
 		}
 
-		/* We only support RTP candidates */
-		if (candidate->id != 1) {
+		if (candidate->id == 1) {
+			iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
+		} else if (candidate->id == 2) {
+			iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
+		} else {
+			iks_delete(local_candidate);
 			continue;
 		}
 
-		iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
 		iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
 		iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
 
@@ -1150,6 +1153,27 @@ static int jingle_add_payloads_to_description(struct jingle_session *session, st
 			iks_insert_attrib(payload, "clockrate", tmp);
 		}
 
+		if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
+			iks *parameter;
+
+			/* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
+			if ((parameter = iks_new("parameter"))) {
+				iks_insert_attrib(parameter, "name", "width");
+				iks_insert_attrib(parameter, "value", "640");
+				iks_insert_node(payload, parameter);
+			}
+			if ((parameter = iks_new("parameter"))) {
+				iks_insert_attrib(parameter, "name", "height");
+				iks_insert_attrib(parameter, "value", "480");
+				iks_insert_node(payload, parameter);
+			}
+			if ((parameter = iks_new("parameter"))) {
+				iks_insert_attrib(parameter, "name", "framerate");
+				iks_insert_attrib(parameter, "value", "30");
+				iks_insert_node(payload, parameter);
+			}
+		}
+
 		iks_insert_node(description, payload);
 		payloads[i++] = payload;
 	}
@@ -2010,6 +2034,11 @@ static int jingle_interpret_google_transport(struct jingle_session *session, iks
 			continue;
 		}
 
+		/* We only permit audio and video, not RTCP */
+		if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
+			continue;
+		}
+
 		/* Parse the target information so we can send a STUN request to the candidate */
 		if (sscanf(port, "%30d", &real_port) != 1) {
 			jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index eb639d38e7..347f29c892 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -2421,14 +2421,14 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct ast_sockaddr addr;
-	unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
+	unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
 	unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
 	int res, packetwords, position = 0;
 	struct ast_frame *f = &ast_null_frame;
 
 	/* Read in RTCP data from the socket */
 	if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET,
-				sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET,
+				sizeof(rtcpdata) - AST_FRIENDLY_OFFSET,
 				0, &addr)) < 0) {
 		ast_assert(errno != EBADF);
 		if (errno != EAGAIN) {
@@ -2443,6 +2443,28 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 		return &ast_null_frame;
 	}
 
+	if (!*(rtcpdata + AST_FRIENDLY_OFFSET)) {
+		struct sockaddr_in addr_tmp;
+		struct ast_sockaddr addr_v4;
+
+		if (ast_sockaddr_is_ipv4(&addr)) {
+			ast_sockaddr_to_sin(&addr, &addr_tmp);
+		} else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) {
+			ast_debug(1, "Using IPv6 mapped address %s for STUN\n",
+				  ast_sockaddr_stringify(&addr));
+			ast_sockaddr_to_sin(&addr_v4, &addr_tmp);
+		} else {
+			ast_debug(1, "Cannot do STUN for non IPv4 address %s\n",
+				  ast_sockaddr_stringify(&addr));
+			return &ast_null_frame;
+		}
+		if ((ast_stun_handle_packet(rtp->rtcp->s, &addr_tmp, rtcpdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT)) {
+			ast_sockaddr_from_sin(&addr, &addr_tmp);
+			ast_sockaddr_copy(&rtp->rtcp->them, &addr);
+		}
+		return &ast_null_frame;
+	}
+
 	packetwords = res / 4;
 
 	if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
-- 
GitLab