From 57f5932f010799a2858098374793f52f00dc1fd9 Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthm@freeswitch.org>
Date: Fri, 30 Dec 2016 17:36:29 -0600
Subject: [PATCH] FS-9206: [mod_sofia] proxy media with enable-3pcc=proxy does
 not properly pass audio after 3pcc re-invite #resolve

---
 src/mod/endpoints/mod_sofia/mod_sofia.c | 41 ++++++++----
 src/mod/endpoints/mod_sofia/sofia.c     | 72 +++++++++++++++------
 src/switch_core_media.c                 | 84 ++++++++++++++++---------
 3 files changed, 138 insertions(+), 59 deletions(-)

diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 82d1ecc3b4..12f086e709 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -668,17 +668,36 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
 		b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
 		switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
 
-		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY nomedia - sending ack, SDP:\n%s\n", tech_pvt->mparams.local_sdp_str);
+		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, 
+						  "3PCC-PROXY nomedia - sending ack, SDP:\n%s\n", tech_pvt->mparams.local_sdp_str);
+
+		if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+			switch_core_media_patch_sdp(tech_pvt->session);
+			switch_core_media_proxy_remote_addr(tech_pvt->session, NULL);
+		}
+
+		if (sofia_use_soa(tech_pvt)) {
+			nua_ack(tech_pvt->nh,
+					TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+					SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+					SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
+					SOATAG_REUSE_REJECTED(1),
+					SOATAG_RTP_SELECT(1), 
+					SOATAG_AUDIO_AUX("cn telephone-event"),
+					TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
+					TAG_END());
+		} else {
+			nua_ack(tech_pvt->nh,
+					NUTAG_MEDIA_ENABLE(0),
+					TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+					SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+					TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
+					TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str)),
+					SOATAG_AUDIO_AUX("cn telephone-event"),
+					TAG_END());			
+		}
+
 
-		nua_ack(tech_pvt->nh,
-				TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
-				SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
-				SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
-				SOATAG_REUSE_REJECTED(1),
-				SOATAG_RTP_SELECT(1), 
-				SOATAG_AUDIO_AUX("cn telephone-event"),
-				TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
-				TAG_END());
 		sofia_clear_flag(tech_pvt, TFLAG_3PCC_INVITE); // all done
 		sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
 		sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
@@ -2220,7 +2239,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 
 								while (switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) {
 									switch_ivr_parse_all_events(session);
-									switch_cond_next();
+									switch_yield(10000);
 								}
 
 								/*  Regain lock on sofia */
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index ce76e54bcb..33f4036053 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -1689,6 +1689,16 @@ static void our_sofia_event_callback(nua_event_t event,
 				switch_core_recovery_track(session);
 				sofia_set_flag(tech_pvt, TFLAG_GOT_ACK);
 
+				if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) && r_sdp) {
+					if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY)) {
+						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
+						sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
+						sofia_clear_flag(tech_pvt, TFLAG_PASS_ACK);
+					}
+					
+				}
+				
+				
 				if (sofia_test_flag(tech_pvt, TFLAG_PASS_ACK)) {
 					switch_core_session_t *other_session;
 
@@ -7431,15 +7441,27 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 							private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
 
 							sofia_glue_clear_soa(other_session, SWITCH_TRUE);
-
-							nua_ack(other_tech_pvt->nh,
-									NUTAG_MEDIA_ENABLE(0),
-									TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)),
-									SIPTAG_CONTACT_STR(other_tech_pvt->reply_contact),
-									SIPTAG_CONTENT_TYPE_STR("application/sdp"),
-									SIPTAG_PAYLOAD_STR(r_sdp),
-									TAG_END());
-
+							
+							if (sofia_use_soa(other_tech_pvt)) {
+								nua_ack(other_tech_pvt->nh,
+										TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)),
+										SIPTAG_CONTACT_STR(other_tech_pvt->reply_contact),
+										SOATAG_USER_SDP_STR(r_sdp),
+										SOATAG_REUSE_REJECTED(1),
+										SOATAG_RTP_SELECT(1), 
+										SOATAG_AUDIO_AUX("cn telephone-event"),
+										TAG_IF(sofia_test_pflag(other_tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
+										TAG_END());
+							} else {
+								nua_ack(other_tech_pvt->nh,
+										NUTAG_MEDIA_ENABLE(0),
+										TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)),
+										SIPTAG_CONTACT_STR(other_tech_pvt->reply_contact),
+										TAG_IF(r_sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
+										TAG_IF(r_sdp, SIPTAG_PAYLOAD_STR(r_sdp)),
+										SOATAG_AUDIO_AUX("cn telephone-event"),
+										TAG_END());
+							}
 
 							nua_ack(tech_pvt->nh,
 									TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
@@ -7486,17 +7508,27 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 
 					switch_core_media_activate_rtp(session);
 
-					nua_ack(tech_pvt->nh,
-							TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
-							SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
-							//SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
-							TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
-							TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str)),
-							//SOATAG_REUSE_REJECTED(1),
-							//SOATAG_RTP_SELECT(1), 
-							SOATAG_AUDIO_AUX("cn telephone-event"),
-							//TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
-							TAG_END());
+
+					if (sofia_use_soa(tech_pvt)) {
+						nua_ack(tech_pvt->nh,
+								TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+								SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
+								SOATAG_REUSE_REJECTED(1),
+								SOATAG_RTP_SELECT(1), 
+								SOATAG_AUDIO_AUX("cn telephone-event"),
+								TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
+								TAG_END());
+					} else {
+						nua_ack(tech_pvt->nh,
+								NUTAG_MEDIA_ENABLE(0),
+								TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+								TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
+								TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str)),
+								SOATAG_AUDIO_AUX("cn telephone-event"),
+								TAG_END());
+					}
 					
 					switch_channel_clear_flag(channel, CF_3P_MEDIA_REQUESTED);
 					goto done;
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 413ec7d215..df179c8dd2 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -472,7 +472,7 @@ static void switch_core_media_find_zrtp_hash(switch_core_session_t *session, sdp
 
 	audio_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO];
 	video_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
-	text_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
+	text_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT];
 
 
 	switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Looking for zrtp-hash\n");
@@ -1836,7 +1836,7 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t
 
 
 		session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t));
-		session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].payload_map;
+		session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].payload_map;
 		session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].cur_payload_map->current = 1;
 
 		switch_channel_set_flag(session->channel, CF_DTLS_OK);
@@ -6862,33 +6862,39 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_
 		}
 	}
 
-	p = port_ptr;
-	x = 0;
-	while (x < sizeof(rp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
-		rp[x++] = *p;
-		p++;
-		if (p >= pe) {
-			goto end;
+	if (port_ptr) {
+		p = port_ptr;
+		x = 0;
+		while (x < sizeof(rp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
+			rp[x++] = *p;
+			p++;
+			if (p >= pe) {
+				goto end;
+			}
 		}
 	}
 
-	p = vid_port_ptr;
-	x = 0;
-	while (x < sizeof(rvp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
-		rvp[x++] = *p;
-		p++;
-		if (p >= pe) {
-			goto end;
+	if (vid_port_ptr) {
+		p = vid_port_ptr;
+		x = 0;
+		while (x < sizeof(rvp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
+			rvp[x++] = *p;
+			p++;
+			if (p >= pe) {
+				goto end;
+			}
 		}
 	}
 
-	p = text_port_ptr;
-	x = 0;
-	while (x < sizeof(rtp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
-		rtp[x++] = *p;
-		p++;
-		if (p >= pe) {
-			goto end;
+	if (text_port_ptr) {
+		p = text_port_ptr;
+		x = 0;
+		while (x < sizeof(rtp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
+			rtp[x++] = *p;
+			p++;
+			if (p >= pe) {
+				goto end;
+			}
 		}
 	}
 
@@ -6914,7 +6920,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_
 		switch_channel_set_flag(session->channel, CF_TEXT_POSSIBLE);
 	}
 
-	if (v_engine->cur_payload_map->remote_sdp_ip && v_engine->cur_payload_map->remote_sdp_port) {
+	if (v_engine->cur_payload_map && v_engine->cur_payload_map->remote_sdp_ip && v_engine->cur_payload_map->remote_sdp_port) {
 		if (!strcmp(v_engine->cur_payload_map->remote_sdp_ip, rip) && atoi(rvp) == v_engine->cur_payload_map->remote_sdp_port) {
 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote video address:port [%s:%d] has not changed.\n",
 							  v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port);
@@ -6952,7 +6958,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_
 		}
 	}
 
-	if (t_engine->cur_payload_map->remote_sdp_ip && t_engine->cur_payload_map->remote_sdp_port) {
+	if (t_engine->cur_payload_map && t_engine->cur_payload_map->remote_sdp_ip && t_engine->cur_payload_map->remote_sdp_port) {
 		if (!strcmp(t_engine->cur_payload_map->remote_sdp_ip, rip) && atoi(rvp) == t_engine->cur_payload_map->remote_sdp_port) {
 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote text address:port [%s:%d] has not changed.\n",
 							  t_engine->cur_payload_map->remote_sdp_ip, t_engine->cur_payload_map->remote_sdp_port);
@@ -11082,13 +11088,13 @@ SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session)
 			}
 
 			has_video++;
-				} else if (!strncmp("m=text ", p, 8) && *(p + 8) != '0') {
+		} else if (!strncmp("m=text ", p, 8) && *(p + 8) != '0') {
 			if (!has_text) {
 				switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_TEXT, 1);
 				clear_pmaps(t_engine);
 				pmap = switch_core_media_add_payload_map(session,
 														 SWITCH_MEDIA_TYPE_TEXT,
-														 "PROXY-VID",
+														 "PROXY-TXT",
 														 NULL,
 														 NULL,
 														 SDP_TYPE_RESPONSE,
@@ -12552,7 +12558,7 @@ SWITCH_DECLARE(void) switch_core_session_stop_media(switch_core_session_t *sessi
 //?
 SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_t *session, switch_core_session_t *o_session)
 {
-	switch_rtp_engine_t *a_engine, *v_engine;
+	switch_rtp_engine_t *a_engine, *v_engine, *t_engine;
 	switch_media_handle_t *smh;
 	const char *r_sdp = NULL;
 	payload_map_t *pmap;
@@ -12571,6 +12577,7 @@ SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_
 	
 	a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
 	v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+	t_engine = &smh->engines[SWITCH_MEDIA_TYPE_TEXT];
 
 	switch_channel_set_flag(session->channel, CF_PROXY_MEDIA);
 
@@ -12610,6 +12617,27 @@ SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_
 		switch_channel_set_flag(session->channel, CF_VIDEO);
 		switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
 	}
+
+
+	if (switch_stristr("m=text", r_sdp)) {
+		switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1);
+		pmap = switch_core_media_add_payload_map(session,
+												 SWITCH_MEDIA_TYPE_AUDIO,
+												 "PROXY-TXT",
+												 NULL,
+												 NULL,
+												 SDP_TYPE_RESPONSE,
+												 0,
+												 1000,
+												 1000,
+												 1,
+												 SWITCH_TRUE);
+		
+		t_engine->cur_payload_map = pmap;
+
+		switch_channel_set_flag(session->channel, CF_HAS_TEXT);
+		switch_channel_set_flag(session->channel, CF_TEXT_POSSIBLE);
+	}
 }