diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 42af2ffe4b..5c7c7bea09 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Fri Mar 14 12:27:15 CDT 2014 +Mon Mar 17 12:22:51 EDT 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index f0b4d35d58..c9736387be 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -2952,7 +2952,7 @@ int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags) nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL); int status = sr->sr_status; char const *phrase = sr->sr_phrase; - int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent; + int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent || sr->sr_offer_sent || sr->sr_answer_recv; int retval; retval = nua_base_server_report(sr, tags), sr = NULL; /* destroys sr */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index c373804c08..1be1a96a00 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1399,6 +1399,7 @@ typedef enum { CF_DTLS, CF_VERBOSE_SDP, CF_DTLS_OK, + CF_3PCC, CF_VIDEO_PASSIVE, CF_NOVIDEO, CF_VIDEO_ECHO, diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 06925863f0..d9a3df256c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -663,11 +663,14 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) /* This if statement check and handles the 3pcc proxy mode */ if (is_3pcc) { + switch_channel_set_flag(channel, CF_3PCC); + if(!is_proxy) { switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE); tech_pvt->mparams.local_sdp_str = NULL; switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0); + switch_core_session_set_ice(session); switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); } else { switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE); @@ -2035,7 +2038,99 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *sticky = NULL; const char *val = NULL; const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); + const char *b_sdp = NULL; + int is_proxy = 0, is_3pcc = 0; + b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE); + is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)); + is_3pcc = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)); + + if (b_sdp && is_proxy && !is_3pcc) { + switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE); + + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + switch_core_media_patch_sdp(tech_pvt->session); + if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + } + } else { + if (is_3pcc) { + switch_channel_set_flag(channel, CF_3PCC); + + if(!is_proxy) { + switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE); + tech_pvt->mparams.local_sdp_str = NULL; + + switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0); + switch_core_session_set_ice(session); + switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL , 0, NULL, 0); + } else { + switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE); + + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + switch_core_media_patch_sdp(tech_pvt->session); + if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "failed to activate rtp\n"); + return SWITCH_STATUS_FALSE; + } + } + } + /* Send the 183 */ + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); + if (sofia_use_soa(tech_pvt)) { + + nua_respond(tech_pvt->nh, SIP_183_SESSION_PROGRESS, + TAG_IF(is_proxy, NUTAG_AUTOANSWER(0)), + SIPTAG_CONTACT_STR(tech_pvt->profile->url), + SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), + SOATAG_REUSE_REJECTED(1), + SOATAG_RTP_SELECT(1), + SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + } else { + nua_respond(tech_pvt->nh, SIP_183_SESSION_PROGRESS, + NUTAG_MEDIA_ENABLE(0), + SIPTAG_CONTACT_STR(tech_pvt->profile->url), + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), + SIPTAG_CONTENT_TYPE_STR("application/sdp"), + SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Sent a 183 SESSION PROGRESS, waiting for PRACK\n"); + switch_safe_free(extra_headers); + } + + /* Unlock the session signal to allow the ack to make it in */ + // Maybe we should timeout? + switch_mutex_unlock(tech_pvt->sofia_mutex); + + while (switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) { + switch_cond_next(); + } + + /* Regain lock on sofia */ + switch_mutex_lock(tech_pvt->sofia_mutex); + + if(is_proxy || !switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE)) { + sofia_clear_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); + sofia_clear_flag(tech_pvt, TFLAG_3PCC); + // This sends the message to the other leg that causes it to call the TFLAG_3PCC_INVITE code at the start of this function. + // Is there another message it would be better to hang this on though? + switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_ANSWER); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for PRACK\n"); + return SWITCH_STATUS_SUCCESS; + } + } if (!sofia_test_flag(tech_pvt, TFLAG_ANS) && !sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index feb42dd4d3..430f0311af 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6578,6 +6578,38 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, break; case nua_callstate_early: + if (answer_recv) { + uint8_t match = 0; + int is_ok = 0; + sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); + switch_channel_mark_pre_answered(channel); + sofia_set_flag(tech_pvt, TFLAG_SDP); + + if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my PRACK\n"); + sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); + } + + match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_RESPONSE); + if (match) { + if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) { + goto done; + } + + switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); + + if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Early Media RTP Error!\n"); + is_ok = 0; + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n"); + } else { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Early Media Codec Error!\n"); + is_ok = 0; + } + } break; case nua_callstate_completed: if (r_sdp) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 778bd2ff8a..f296a51055 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -2455,6 +2455,10 @@ SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session { switch_call_direction_t r = switch_channel_direction(session->channel); + if (switch_channel_test_flag(session->channel, CF_3PCC)) { + r = (r == SWITCH_CALL_DIRECTION_INBOUND) ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND; + } + if ((switch_channel_test_flag(session->channel, CF_REINVITE) || switch_channel_test_flag(session->channel, CF_RECOVERING)) && switch_channel_test_flag(session->channel, CF_WEBRTC)) { r = SWITCH_CALL_DIRECTION_OUTBOUND; @@ -5087,6 +5091,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if (!zstr(a_engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(smh->session)) { dtls_type_t xtype, dtype = switch_channel_direction(smh->session->channel) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER; + if (switch_channel_test_flag(smh->session->channel, CF_3PCC)) { + dtype = (dtype == DTLS_TYPE_CLIENT) ? DTLS_TYPE_SERVER : DTLS_TYPE_CLIENT; + } xtype = DTLS_TYPE_RTP; if (a_engine->rtcp_mux > 0 && smh->mparams->rtcp_audio_interval_msec) xtype |= DTLS_TYPE_RTCP; @@ -6048,7 +6055,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess switch_channel_clear_flag(smh->session->channel, CF_DTLS); } - if (is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING)) { + if (is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING) || + switch_channel_test_flag(session->channel, CF_3PCC)) { if (!switch_channel_test_flag(session->channel, CF_WEBRTC) && switch_true(switch_channel_get_variable(session->channel, "media_webrtc"))) { switch_channel_set_flag(session->channel, CF_WEBRTC);