From f6b56c3983bc77510bfece483f4af6392e7bece7 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 19 Dec 2012 14:47:04 -0600 Subject: [PATCH] wip --- src/mod/endpoints/mod_sofia/sofia_glue.c | 1648 -------------------- src/mod/endpoints/mod_sofia/sofia_media.c | 1656 +++++++++++++++++++++ 2 files changed, 1656 insertions(+), 1648 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index b15a4ce15c..c3707f5ae3 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -178,187 +178,6 @@ void sofia_glue_set_udptl_image_sdp(private_object_t *tech_pvt, switch_t38_optio } -static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, - switch_port_t port, - int cur_ptime, const char *append_audio, const char *sr, int use_cng, int cng_type, switch_event_t *map, int verbose_sdp, int secure) -{ - int i = 0; - int rate; - int already_did[128] = { 0 }; - int ptime = 0, noptime = 0; - const char *local_audio_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); - - - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d RTP/%sAVP", - port, secure ? "S" : ""); - - - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - int this_ptime = (imp->microseconds_per_packet / 1000); - - if (!strcasecmp(imp->iananame, "ilbc")) { - this_ptime = 20; - } - - if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { - continue; - } - - if (!noptime) { - if (!cur_ptime) { -#if 0 - if (ptime) { - if (ptime != this_ptime) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Codec %s payload %d added to sdp wanting ptime %d but it's already %d (%s:%d:%d), disabling ptime.\n", - imp->iananame, - tech_pvt->ianacodes[i], - this_ptime, - ptime, - tech_pvt->codecs[0]->iananame, - tech_pvt->codecs[0]->ianacode, - ptime); - ptime = 0; - noptime = 1; - } - } else { - ptime = this_ptime; - } -#else - if (!ptime) { - ptime = this_ptime; - } -#endif - } else { - if (this_ptime != cur_ptime) { - continue; - } - } - } - - if (tech_pvt->ianacodes[i] < 128) { - if (already_did[tech_pvt->ianacodes[i]]) { - continue; - } - - already_did[tech_pvt->ianacodes[i]] = 1; - } - - - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", tech_pvt->ianacodes[i]); - } - - if (tech_pvt->dtmf_type == DTMF_2833 && tech_pvt->te > 95) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", tech_pvt->te); - } - - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && cng_type && use_cng) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", cng_type); - } - - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "\n"); - - - memset(already_did, 0, sizeof(already_did)); - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - char *fmtp = imp->fmtp; - int this_ptime = imp->microseconds_per_packet / 1000; - - if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { - continue; - } - - if (!strcasecmp(imp->iananame, "ilbc")) { - this_ptime = 20; - } - - if (!noptime) { - if (!cur_ptime) { - if (!ptime) { - ptime = this_ptime; - } - } else { - if (this_ptime != cur_ptime) { - continue; - } - } - } - - if (tech_pvt->ianacodes[i] < 128) { - if (already_did[tech_pvt->ianacodes[i]]) { - continue; - } - - already_did[tech_pvt->ianacodes[i]] = 1; - } - - - rate = imp->samples_per_second; - - if (map) { - char key[128] = ""; - char *check = NULL; - switch_snprintf(key, sizeof(key), "%s:%u", imp->iananame, imp->bits_per_second); - - if ((check = switch_event_get_header(map, key)) || (check = switch_event_get_header(map, imp->iananame))) { - fmtp = check; - } - } - - if (tech_pvt->ianacodes[i] > 95 || verbose_sdp) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->ianacodes[i], imp->iananame, rate); - } - - if (fmtp) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->ianacodes[i], fmtp); - } - } - - - if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) - && tech_pvt->te > 95) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); - } - - if (secure) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); - //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); - } - - if (!cng_type) { - //switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d CN/8000\n", cng_type); - //} else { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=silenceSupp:off - - - -\n"); - } - - if (append_audio) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "%s%s", append_audio, end_of(append_audio) == '\n' ? "" : "\n"); - } - - if (!cur_ptime) { - cur_ptime = ptime; - } - - if (!noptime && cur_ptime) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ptime:%d\n", cur_ptime); - } - - if (tech_pvt->local_sdp_audio_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); - } - - if (!zstr(sr)) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=%s\n", sr); - } -} - void sofia_glue_check_dtmf_type(private_object_t *tech_pvt) { const char *val; @@ -376,533 +195,6 @@ void sofia_glue_check_dtmf_type(private_object_t *tech_pvt) } } -#define SDPBUFLEN 65536 -void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch_port_t port, const char *sr, int force) -{ - char *buf; - int ptime = 0; - uint32_t rate = 0; - uint32_t v_port; - int use_cng = 1; - const char *val; - const char *family; - const char *pass_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_video_fmtp"); - const char *ov_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_force_video_fmtp"); - const char *append_audio = switch_channel_get_variable(tech_pvt->channel, "sip_append_audio_sdp"); - char srbuf[128] = ""; - const char *var_val; - const char *username = tech_pvt->profile->username; - const char *fmtp_out = tech_pvt->fmtp_out; - const char *fmtp_out_var = switch_channel_get_variable(tech_pvt->channel, "sip_force_audio_fmtp"); - switch_event_t *map = NULL, *ptmap = NULL; - const char *b_sdp = NULL; - int verbose_sdp = 0; - const char *local_audio_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); - - switch_zmalloc(buf, SDPBUFLEN); - - sofia_glue_check_dtmf_type(tech_pvt); - - if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) || - ((val = switch_channel_get_variable(tech_pvt->channel, "supress_cng")) && switch_true(val)) || - ((val = switch_channel_get_variable(tech_pvt->channel, "suppress_cng")) && switch_true(val))) { - use_cng = 0; - tech_pvt->cng_pt = 0; - } - - if (!tech_pvt->payload_space) { - int i; - - tech_pvt->payload_space = 98; - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - - tech_pvt->ianacodes[i] = imp->ianacode; - - if (tech_pvt->ianacodes[i] > 64) { - if (tech_pvt->dtmf_type == DTMF_2833 && tech_pvt->te > 95 && tech_pvt->te == tech_pvt->payload_space) { - tech_pvt->payload_space++; - } - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && - tech_pvt->cng_pt && use_cng && tech_pvt->cng_pt == tech_pvt->payload_space) { - tech_pvt->payload_space++; - } - tech_pvt->ianacodes[i] = tech_pvt->payload_space++; - } - } - } - - if (fmtp_out_var) { - fmtp_out = fmtp_out_var; - } - - if ((val = switch_channel_get_variable(tech_pvt->channel, "verbose_sdp")) && switch_true(val)) { - verbose_sdp = 1; - } - - if (!force && !ip && zstr(sr) - && (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA))) { - switch_safe_free(buf); - return; - } - - if (!ip) { - if (!(ip = tech_pvt->adv_sdp_audio_ip)) { - ip = tech_pvt->proxy_sdp_audio_ip; - } - } - - if (!ip) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO IP!\n", switch_channel_get_name(tech_pvt->channel)); - switch_safe_free(buf); - return; - } - - if (!port) { - if (!(port = tech_pvt->adv_sdp_audio_port)) { - port = tech_pvt->proxy_sdp_audio_port; - } - } - - if (!port) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO PORT!\n", switch_channel_get_name(tech_pvt->channel)); - switch_safe_free(buf); - return; - } - - if (!tech_pvt->rm_encoding && (b_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) { - sofia_glue_sdp_map(b_sdp, &map, &ptmap); - } - - if (zstr(sr)) { - if ((var_val = switch_channel_get_variable(tech_pvt->channel, "media_audio_mode"))) { - sr = var_val; - } else { - sr = "sendrecv"; - } - } - - if (!tech_pvt->owner_id) { - tech_pvt->owner_id = (uint32_t) switch_epoch_time_now(NULL) - port; - } - - if (!tech_pvt->session_id) { - tech_pvt->session_id = tech_pvt->owner_id; - } - - if (switch_true(switch_channel_get_variable_dup(tech_pvt->channel, "drop_dtmf", SWITCH_FALSE, -1))) { - sofia_set_flag(tech_pvt, TFLAG_DROP_DTMF); - } - - tech_pvt->session_id++; - - if ((tech_pvt->profile->ndlb & PFLAG_NDLB_SENDRECV_IN_SESSION) || - ((var_val = switch_channel_get_variable(tech_pvt->channel, "ndlb_sendrecv_in_session")) && switch_true(var_val))) { - if (!zstr(sr)) { - switch_snprintf(srbuf, sizeof(srbuf), "a=%s\n", sr); - } - sr = NULL; - } - - family = strchr(ip, ':') ? "IP6" : "IP4"; - switch_snprintf(buf, SDPBUFLEN, - "v=0\n" - "o=%s %010u %010u IN %s %s\n" - "s=%s\n" - "c=IN %s %s\n" "t=0 0\n" - "%s", - username, tech_pvt->owner_id, tech_pvt->session_id, family, ip, username, family, ip, srbuf); - - if (tech_pvt->rm_encoding) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=audio %d RTP/%sAVP", - port, (!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) ? "S" : ""); - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->pt); - - if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) && tech_pvt->te > 95) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->te); - } - - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->cng_pt); - } - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n"); - - rate = tech_pvt->rm_rate; - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate); - if (fmtp_out) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->agreed_pt, fmtp_out); - } - - if (tech_pvt->read_codec.implementation && !ptime) { - ptime = tech_pvt->read_codec.implementation->microseconds_per_packet / 1000; - } - - - if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) - && tech_pvt->te > 95) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); - } - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d CN/8000\n", tech_pvt->cng_pt); - if (!tech_pvt->rm_encoding) { - tech_pvt->cng_pt = 0; - } - } else { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=silenceSupp:off - - - -\n"); - } - - if (append_audio) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s%s", append_audio, end_of(append_audio) == '\n' ? "" : "\n"); - } - - if (ptime) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ptime:%d\n", ptime); - } - - - if (tech_pvt->local_sdp_audio_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); - } - - if (!zstr(sr)) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=%s\n", sr); - } - - if (!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); - //switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=encryption:optional\n"); - } - - } else if (tech_pvt->num_codecs) { - int i; - int cur_ptime = 0, this_ptime = 0, cng_type = 0; - const char *mult; - - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) { - cng_type = tech_pvt->cng_pt; - - if (!tech_pvt->rm_encoding) { - tech_pvt->cng_pt = 0; - } - } - - mult = switch_channel_get_variable(tech_pvt->channel, "sdp_m_per_ptime"); - - if (mult && switch_false(mult)) { - char *bp = buf; - int both = 1; - - if ((!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE))) { - generate_m(tech_pvt, buf, SDPBUFLEN, port, 0, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 1); - bp = (buf + strlen(buf)); - - /* asterisk can't handle AVP and SAVP in sep streams, way to blow off the spec....*/ - if (switch_true(switch_channel_get_variable(tech_pvt->channel, "sdp_secure_savp_only"))) { - both = 0; - } - - } - - if (both) { - generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, 0, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 0); - } - - } else { - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - - if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { - continue; - } - - this_ptime = imp->microseconds_per_packet / 1000; - - if (!strcasecmp(imp->iananame, "ilbc")) { - this_ptime = 20; - } - - if (cur_ptime != this_ptime) { - char *bp = buf; - int both = 1; - - cur_ptime = this_ptime; - - if ((!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE))) { - generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, cur_ptime, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 1); - bp = (buf + strlen(buf)); - - /* asterisk can't handle AVP and SAVP in sep streams, way to blow off the spec....*/ - if (switch_true(switch_channel_get_variable(tech_pvt->channel, "sdp_secure_savp_only"))) { - both = 0; - } - } - - if (both) { - generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, cur_ptime, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 0); - } - } - - } - } - - } - - if (sofia_test_flag(tech_pvt, TFLAG_VIDEO)) { - const char *local_video_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO); - - if (!tech_pvt->local_sdp_video_port) { - sofia_glue_tech_choose_video_port(tech_pvt, 0); - } - - if ((v_port = tech_pvt->adv_sdp_video_port)) { - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=video %d RTP/%sAVP", - v_port, (!zstr(local_video_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) ? "S" : ""); - - - /*****************************/ - if (tech_pvt->video_rm_encoding) { - sofia_glue_tech_set_video_codec(tech_pvt, 0); - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->video_agreed_pt); - } else if (tech_pvt->num_codecs) { - int i; - int already_did[128] = { 0 }; - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - - if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { - continue; - } - - if (tech_pvt->ianacodes[i] < 128) { - if (already_did[tech_pvt->ianacodes[i]]) { - continue; - } - already_did[tech_pvt->ianacodes[i]] = 1; - } - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->ianacodes[i]); - if (!ptime) { - ptime = imp->microseconds_per_packet / 1000; - } - } - } - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n"); - - if (tech_pvt->video_rm_encoding) { - const char *of; - rate = tech_pvt->video_rm_rate; - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->video_pt, tech_pvt->video_rm_encoding, - tech_pvt->video_rm_rate); - - if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { - pass_fmtp = tech_pvt->video_rm_fmtp; - } else { - - pass_fmtp = NULL; - - if (switch_channel_get_partner_uuid(tech_pvt->channel)) { - if ((of = switch_channel_get_variable_partner(tech_pvt->channel, "sip_video_fmtp"))) { - pass_fmtp = of; - } - } - - if (ov_fmtp) { - pass_fmtp = ov_fmtp; - }// else { // seems to break eyebeam at least... - //pass_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_video_fmtp"); - //} - } - - if (pass_fmtp) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->video_pt, pass_fmtp); - } - - } else if (tech_pvt->num_codecs) { - int i; - int already_did[128] = { 0 }; - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - char *fmtp = NULL; - uint32_t ianacode = tech_pvt->ianacodes[i]; - - if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { - continue; - } - - if (ianacode < 128) { - if (already_did[ianacode]) { - continue; - } - already_did[ianacode] = 1; - } - - if (!rate) { - rate = imp->samples_per_second; - } - - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", ianacode, imp->iananame, - imp->samples_per_second); - - if (!zstr(ov_fmtp)) { - fmtp = (char *) ov_fmtp; - } else { - - if (map) { - fmtp = switch_event_get_header(map, imp->iananame); - } - - if (zstr(fmtp)) fmtp = imp->fmtp; - - if (zstr(fmtp)) fmtp = (char *) pass_fmtp; - } - - if (!zstr(fmtp) && strcasecmp(fmtp, "_blank_")) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", ianacode, fmtp); - } - } - - } - - if (switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_video_crypto_key); - //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); - } - - - if (tech_pvt->local_sdp_video_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding video a=zrtp-hash:%s\n", - tech_pvt->local_sdp_video_zrtp_hash); - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", - tech_pvt->local_sdp_video_zrtp_hash); - } - } - } - - - if (map) { - switch_event_destroy(&map); - } - - if (ptmap) { - switch_event_destroy(&ptmap); - } - - sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE); - - switch_safe_free(buf); -} - -const char *sofia_glue_get_codec_string(private_object_t *tech_pvt) -{ - const char *preferred = NULL, *fallback = NULL; - - if (!(preferred = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) { - preferred = switch_channel_get_variable(tech_pvt->channel, "codec_string"); - } - - if (!preferred) { - if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { - preferred = tech_pvt->profile->outbound_codec_string; - fallback = tech_pvt->profile->inbound_codec_string; - } else { - preferred = tech_pvt->profile->inbound_codec_string; - fallback = tech_pvt->profile->outbound_codec_string; - } - } - - return !zstr(preferred) ? preferred : fallback; -} - -void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt) -{ - const char *abs, *codec_string = NULL; - const char *ocodec = NULL; - - if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) { - return; - } - - if (tech_pvt->num_codecs) { - return; - } - - tech_pvt->payload_space = 0; - - switch_assert(tech_pvt->session != NULL); - - if ((abs = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) { - /* inherit_codec == true will implicitly clear the absolute_codec_string - variable if used since it was the reason it was set in the first place and is no longer needed */ - if (switch_true(switch_channel_get_variable(tech_pvt->channel, "inherit_codec"))) { - switch_channel_set_variable(tech_pvt->channel, "absolute_codec_string", NULL); - } - codec_string = abs; - goto ready; - } - - if (!(codec_string = switch_channel_get_variable(tech_pvt->channel, "codec_string"))) { - codec_string = sofia_glue_get_codec_string(tech_pvt); - } - - if (codec_string && *codec_string == '=') { - codec_string++; - goto ready; - } - - - if ((ocodec = switch_channel_get_variable(tech_pvt->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { - if (!codec_string || sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_TRANSCODING)) { - codec_string = ocodec; - } else { - if (!(codec_string = switch_core_session_sprintf(tech_pvt->session, "%s,%s", ocodec, codec_string))) { - codec_string = ocodec; - } - } - } - - ready: - - if (codec_string) { - char *tmp_codec_string; - if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) { - tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS); - tech_pvt->num_codecs = - switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last); - } - } else { - tech_pvt->num_codecs = switch_loadable_module_get_codecs(tech_pvt->codecs, sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0])); - } - - -} - -void sofia_glue_check_video_codecs(private_object_t *tech_pvt) -{ - if (tech_pvt->num_codecs && !sofia_test_flag(tech_pvt, TFLAG_VIDEO)) { - int i; - tech_pvt->video_count = 0; - for (i = 0; i < tech_pvt->num_codecs; i++) { - - if (tech_pvt->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) { - tech_pvt->video_count++; - } - } - if (tech_pvt->video_count) { - sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO); - } - } -} private_object_t *sofia_glue_new_pvt(switch_core_session_t *session) { @@ -1693,336 +985,6 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt, co } -void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) -{ - switch_size_t len; - char *p, *q, *pe, *qe; - int has_video = 0, has_audio = 0, has_ip = 0; - char port_buf[25] = ""; - char vport_buf[25] = ""; - char *new_sdp; - int bad = 0; - - if (zstr(tech_pvt->local_sdp_str)) { - return; - } - - len = strlen(tech_pvt->local_sdp_str) * 2; - - if (switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) && - (switch_stristr("sendonly", tech_pvt->local_sdp_str) || switch_stristr("0.0.0.0", tech_pvt->local_sdp_str))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Skip patch on hold SDP\n"); - return; - } - - if (zstr(tech_pvt->adv_sdp_audio_ip) || !tech_pvt->adv_sdp_audio_port) { - if (sofia_glue_tech_choose_port(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s I/O Error\n", - switch_channel_get_name(tech_pvt->channel)); - return; - } - tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, "PROXY"); - tech_pvt->rm_rate = 8000; - tech_pvt->codec_ms = 20; - } - - new_sdp = switch_core_session_alloc(tech_pvt->session, len); - switch_snprintf(port_buf, sizeof(port_buf), "%u", tech_pvt->adv_sdp_audio_port); - - - p = tech_pvt->local_sdp_str; - q = new_sdp; - pe = p + strlen(p); - qe = q + len - 1; - - - while (p && *p) { - if (p >= pe) { - bad = 1; - goto end; - } - - if (q >= qe) { - bad = 2; - goto end; - } - - if (tech_pvt->adv_sdp_audio_ip && !strncmp("c=IN IP", p, 7)) { - strncpy(q, p, 7); - p += 7; - q += 7; - strncpy(q, strchr(tech_pvt->adv_sdp_audio_ip, ':') ? "6 " : "4 ", 2); - p +=2; - q +=2; - strncpy(q, tech_pvt->adv_sdp_audio_ip, strlen(tech_pvt->adv_sdp_audio_ip)); - q += strlen(tech_pvt->adv_sdp_audio_ip); - - while (p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f'))) { - if (p >= pe) { - bad = 3; - goto end; - } - p++; - } - - has_ip++; - - } else if (!strncmp("o=", p, 2)) { - char *oe = strchr(p, '\n'); - switch_size_t len; - - if (oe) { - const char *family = "IP4"; - char o_line[1024] = ""; - - if (oe >= pe) { - bad = 5; - goto end; - } - - len = (oe - p); - p += len; - - - family = strchr(tech_pvt->profile->sipip, ':') ? "IP6" : "IP4"; - - if (!tech_pvt->owner_id) { - tech_pvt->owner_id = (uint32_t) switch_epoch_time_now(NULL) * 31821U + 13849U; - } - - if (!tech_pvt->session_id) { - tech_pvt->session_id = tech_pvt->owner_id; - } - - tech_pvt->session_id++; - - - snprintf(o_line, sizeof(o_line), "o=%s %010u %010u IN %s %s\n", - tech_pvt->profile->username, tech_pvt->owner_id, tech_pvt->session_id, family, tech_pvt->profile->sipip); - - strncpy(q, o_line, strlen(o_line)); - q += strlen(o_line) - 1; - - } - - } else if (!strncmp("s=", p, 2)) { - char *se = strchr(p, '\n'); - switch_size_t len; - - if (se) { - char s_line[1024] = ""; - - if (se >= pe) { - bad = 5; - goto end; - } - - len = (se - p); - p += len; - - snprintf(s_line, sizeof(s_line), "s=%s\n", tech_pvt->profile->username); - - strncpy(q, s_line, strlen(s_line)); - q += strlen(s_line) - 1; - - } - - } else if ((!strncmp("m=audio ", p, 8) && *(p + 8) != '0') || (!strncmp("m=image ", p, 8) && *(p + 8) != '0')) { - strncpy(q, p, 8); - p += 8; - - if (p >= pe) { - bad = 4; - goto end; - } - - - q += 8; - - if (q >= qe) { - bad = 5; - goto end; - } - - - strncpy(q, port_buf, strlen(port_buf)); - q += strlen(port_buf); - - if (q >= qe) { - bad = 6; - goto end; - } - - while (p && *p && (*p >= '0' && *p <= '9')) { - if (p >= pe) { - bad = 7; - goto end; - } - p++; - } - - has_audio++; - - } else if (!strncmp("m=video ", p, 8) && *(p + 8) != '0') { - if (!has_video) { - sofia_glue_tech_choose_video_port(tech_pvt, 1); - tech_pvt->video_rm_encoding = "PROXY-VID"; - tech_pvt->video_rm_rate = 90000; - tech_pvt->video_codec_ms = 0; - switch_snprintf(vport_buf, sizeof(vport_buf), "%u", tech_pvt->adv_sdp_video_port); - if (switch_channel_media_ready(tech_pvt->channel) && !switch_rtp_ready(tech_pvt->video_rtp_session)) { - sofia_set_flag(tech_pvt, TFLAG_VIDEO); - sofia_set_flag(tech_pvt, TFLAG_REINVITE); - sofia_media_activate_rtp(tech_pvt); - } - } - - strncpy(q, p, 8); - p += 8; - - if (p >= pe) { - bad = 8; - goto end; - } - - q += 8; - - if (q >= qe) { - bad = 9; - goto end; - } - - strncpy(q, vport_buf, strlen(vport_buf)); - q += strlen(vport_buf); - - if (q >= qe) { - bad = 10; - goto end; - } - - while (p && *p && (*p >= '0' && *p <= '9')) { - - if (p >= pe) { - bad = 11; - goto end; - } - - p++; - } - - has_video++; - } - - while (p && *p && *p != '\n') { - - if (p >= pe) { - bad = 12; - goto end; - } - - if (q >= qe) { - bad = 13; - goto end; - } - - *q++ = *p++; - } - - if (p >= pe) { - bad = 14; - goto end; - } - - if (q >= qe) { - bad = 15; - goto end; - } - - *q++ = *p++; - - } - - end: - - if (bad) { - return; - } - - - if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s too late.\n", switch_channel_get_name(tech_pvt->channel)); - return; - } - - - if (!has_ip && !has_audio) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s SDP has no audio in it.\n%s\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str); - return; - } - - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s Patched SDP\n---\n%s\n+++\n%s\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str, new_sdp); - - sofia_glue_tech_set_local_sdp(tech_pvt, new_sdp, SWITCH_FALSE); - -} - - -void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup) -{ - switch_mutex_lock(tech_pvt->sofia_mutex); - tech_pvt->local_sdp_str = dup ? switch_core_session_strdup(tech_pvt->session, sdp_str) : (char *) sdp_str; - switch_channel_set_variable(tech_pvt->channel, "sip_local_sdp_str", tech_pvt->local_sdp_str); - switch_mutex_unlock(tech_pvt->sofia_mutex); -} - -char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type) -{ - char *extra_headers = NULL; - switch_stream_handle_t stream = { 0 }; - switch_event_header_t *hi = NULL; - int x = 0; - switch_channel_t *channel = switch_core_session_get_channel(session); - const char *boundary = switch_core_session_get_uuid(session); - - SWITCH_STANDARD_STREAM(stream); - if ((hi = switch_channel_variable_first(channel))) { - for (; hi; hi = hi->next) { - const char *name = (char *) hi->name; - char *value = (char *) hi->value; - - if (!strncasecmp(name, prefix, strlen(prefix))) { - const char *hname = name + strlen(prefix); - if (*value == '~') { - stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n%s\n", boundary, hname, strlen(value), value + 1); - } else { - stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n\n%s\n", boundary, hname, strlen(value) + 1, value); - } - x++; - } - } - switch_channel_variable_last(channel); - } - - if (x) { - *mp_type = switch_core_session_sprintf(session, "multipart/mixed; boundary=%s", boundary); - if (sdp) { - stream.write_function(&stream, "--%s\nContent-Type: application/sdp\nContent-Length: %d\n\n%s\n", boundary, strlen(sdp) + 1, sdp); - } - stream.write_function(&stream, "--%s--\n", boundary); - } - - if (!zstr((char *) stream.data)) { - extra_headers = stream.data; - } else { - switch_safe_free(stream.data); - } - - return extra_headers; -} - char *sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix) { @@ -2892,288 +1854,6 @@ void sofia_glue_deactivate_rtp(private_object_t *tech_pvt) } -switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force) -{ - - if (!tech_pvt->video_rm_encoding) { - return SWITCH_STATUS_FALSE; - } - - if (tech_pvt->video_read_codec.implementation && switch_core_codec_ready(&tech_pvt->video_read_codec)) { - if (!force) { - return SWITCH_STATUS_SUCCESS; - } - if (strcasecmp(tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding) || - tech_pvt->video_read_codec.implementation->samples_per_second != tech_pvt->video_rm_rate) { - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n", - tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding); - switch_core_codec_destroy(&tech_pvt->video_read_codec); - switch_core_codec_destroy(&tech_pvt->video_write_codec); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", - tech_pvt->video_read_codec.implementation->iananame); - return SWITCH_STATUS_SUCCESS; - } - } - - - - if (switch_core_codec_init(&tech_pvt->video_read_codec, - tech_pvt->video_rm_encoding, - tech_pvt->video_rm_fmtp, - tech_pvt->video_rm_rate, - 0, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - return SWITCH_STATUS_FALSE; - } else { - if (switch_core_codec_init(&tech_pvt->video_write_codec, - tech_pvt->video_rm_encoding, - tech_pvt->video_rm_fmtp, - tech_pvt->video_rm_rate, - 0, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - return SWITCH_STATUS_FALSE; - } else { - tech_pvt->video_read_frame.rate = tech_pvt->video_rm_rate; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->video_rm_encoding, tech_pvt->video_rm_rate, tech_pvt->video_codec_ms); - tech_pvt->video_read_frame.codec = &tech_pvt->video_read_codec; - - tech_pvt->video_fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->video_write_codec.fmtp_out); - - tech_pvt->video_write_codec.agreed_pt = tech_pvt->video_agreed_pt; - tech_pvt->video_read_codec.agreed_pt = tech_pvt->video_agreed_pt; - switch_core_session_set_video_read_codec(tech_pvt->session, &tech_pvt->video_read_codec); - switch_core_session_set_video_write_codec(tech_pvt->session, &tech_pvt->video_write_codec); - - - if (switch_rtp_ready(tech_pvt->video_rtp_session)) { - switch_core_session_message_t msg = { 0 }; - - msg.from = __FILE__; - msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ; - - switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); - - if (tech_pvt->video_recv_pt != tech_pvt->video_agreed_pt) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, - "%s Set video receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->video_recv_pt); - - switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_recv_pt); - } else { - switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); - } - - switch_core_session_receive_message(tech_pvt->session, &msg); - - - } - - switch_channel_set_variable(tech_pvt->channel, "sip_use_video_codec_name", tech_pvt->video_rm_encoding); - switch_channel_set_variable(tech_pvt->channel, "sip_use_video_codec_fmtp", tech_pvt->video_rm_fmtp); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_codec_rate", "%d", tech_pvt->video_rm_rate); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_codec_ptime", "%d", 0); - - } - } - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) -{ - switch_status_t status = SWITCH_STATUS_SUCCESS; - int resetting = 0; - - if (!tech_pvt->iananame) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "No audio codec available\n"); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - if (switch_core_codec_ready(&tech_pvt->read_codec)) { - if (!force) { - switch_goto_status(SWITCH_STATUS_SUCCESS, end); - } - if (strcasecmp(tech_pvt->read_impl.iananame, tech_pvt->iananame) || - tech_pvt->read_impl.samples_per_second != tech_pvt->rm_rate || - tech_pvt->codec_ms != (uint32_t) tech_pvt->read_impl.microseconds_per_packet / 1000) { - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, - "Changing Codec from %s@%dms@%dhz to %s@%dms@%luhz\n", - tech_pvt->read_impl.iananame, tech_pvt->read_impl.microseconds_per_packet / 1000, - tech_pvt->read_impl.samples_per_second, - tech_pvt->rm_encoding, - tech_pvt->codec_ms, - tech_pvt->rm_rate); - - switch_yield(tech_pvt->read_impl.microseconds_per_packet); - switch_core_session_lock_codec_write(tech_pvt->session); - switch_core_session_lock_codec_read(tech_pvt->session); - resetting = 1; - switch_yield(tech_pvt->read_impl.microseconds_per_packet); - switch_core_codec_destroy(&tech_pvt->read_codec); - switch_core_codec_destroy(&tech_pvt->write_codec); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_impl.iananame); - switch_goto_status(SWITCH_STATUS_SUCCESS, end); - } - } - - if (switch_core_codec_init_with_bitrate(&tech_pvt->read_codec, - tech_pvt->iananame, - tech_pvt->rm_fmtp, - tech_pvt->rm_rate, - tech_pvt->codec_ms, - 1, - tech_pvt->bitrate, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - tech_pvt->read_codec.session = tech_pvt->session; - - - if (switch_core_codec_init_with_bitrate(&tech_pvt->write_codec, - tech_pvt->iananame, - tech_pvt->rm_fmtp, - tech_pvt->rm_rate, - tech_pvt->codec_ms, - 1, - tech_pvt->bitrate, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - tech_pvt->write_codec.session = tech_pvt->session; - - switch_channel_set_variable(tech_pvt->channel, "sip_use_codec_name", tech_pvt->iananame); - switch_channel_set_variable(tech_pvt->channel, "sip_use_codec_fmtp", tech_pvt->rm_fmtp); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_codec_rate", "%d", tech_pvt->rm_rate); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_codec_ptime", "%d", tech_pvt->codec_ms); - - - switch_assert(tech_pvt->read_codec.implementation); - switch_assert(tech_pvt->write_codec.implementation); - - tech_pvt->read_impl = *tech_pvt->read_codec.implementation; - tech_pvt->write_impl = *tech_pvt->write_codec.implementation; - - switch_core_session_set_read_impl(tech_pvt->session, tech_pvt->read_codec.implementation); - switch_core_session_set_write_impl(tech_pvt->session, tech_pvt->write_codec.implementation); - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_assert(tech_pvt->read_codec.implementation); - - if (switch_rtp_change_interval(tech_pvt->rtp_session, - tech_pvt->read_impl.microseconds_per_packet, - tech_pvt->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) { - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - } - - tech_pvt->read_frame.rate = tech_pvt->rm_rate; - - if (!switch_core_codec_ready(&tech_pvt->read_codec)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms, - tech_pvt->read_impl.samples_per_packet, tech_pvt->read_impl.bits_per_second); - tech_pvt->read_frame.codec = &tech_pvt->read_codec; - - tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt; - tech_pvt->read_codec.agreed_pt = tech_pvt->agreed_pt; - - if (force != 2) { - switch_core_session_set_real_read_codec(tech_pvt->session, &tech_pvt->read_codec); - switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); - } - - tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out); - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->pt); - switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt); - } - - end: - if (resetting) { - switch_core_session_unlock_codec_write(tech_pvt->session); - switch_core_session_unlock_codec_read(tech_pvt->session); - } - - sofia_glue_tech_set_video_codec(tech_pvt, force); - - return status; -} - - -static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen) -{ - int codec_ms = ptime; - uint32_t map_bit_rate = 0; - char ptstr[20] = ""; - char ratestr[20] = ""; - char bitstr[20] = ""; - switch_codec_fmtp_t codec_fmtp = { 0 }; - - if (!codec_ms) { - codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt); - } - - map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); - - if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { - ptime = codec_ms = 30; - } - - if (zstr(map->rm_fmtp)) { - if (!strcasecmp(map->rm_encoding, "ilbc")) { - ptime = codec_ms = 30; - map_bit_rate = 13330; - } - } else { - if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) { - if (codec_fmtp.bits_per_second) { - map_bit_rate = codec_fmtp.bits_per_second; - } - if (codec_fmtp.microseconds_per_packet) { - codec_ms = (codec_fmtp.microseconds_per_packet / 1000); - } - } - } - - if (map->rm_rate) { - switch_snprintf(ratestr, sizeof(ratestr), "@%uh", (unsigned int) map->rm_rate); - } - - if (codec_ms) { - switch_snprintf(ptstr, sizeof(ptstr), "@%di", codec_ms); - } - - if (map_bit_rate) { - switch_snprintf(bitstr, sizeof(bitstr), "@%db", map_bit_rate); - } - - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s%s%s%s", map->rm_encoding, ratestr, ptstr, bitstr); - -} - void sofia_glue_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session) { switch_channel_t *aleg_channel; @@ -3273,334 +1953,6 @@ void find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp) } } -void sofia_glue_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp) -{ - char buf[1024] = { 0 }; - sdp_media_t *m; - sdp_attribute_t *attr; - int ptime = 0, dptime = 0; - sdp_connection_t *connection; - sdp_rtpmap_t *map; - short int match = 0; - int i; - int already_did[128] = { 0 }; - int num_codecs = 0; - char *codec_order[SWITCH_MAX_CODECS]; - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; - switch_channel_t *channel = switch_core_session_get_channel(session); - private_object_t *tech_pvt = switch_core_session_get_private(session); - int prefer_sdp = 0; - const char *var; - - if ((var = switch_channel_get_variable(channel, "ep_codec_prefer_sdp")) && switch_true(var)) { - prefer_sdp = 1; - } - - if (!zstr(codec_string)) { - char *tmp_codec_string; - if ((tmp_codec_string = strdup(codec_string))) { - num_codecs = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS); - num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, num_codecs); - switch_safe_free(tmp_codec_string); - } - } else { - num_codecs = switch_loadable_module_get_codecs(codecs, SWITCH_MAX_CODECS); - } - - if (!channel || !num_codecs) { - return; - } - - for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) { - if (zstr(attr->a_name)) { - continue; - } - if (!strcasecmp(attr->a_name, "ptime")) { - dptime = atoi(attr->a_value); - break; - } - } - - find_zrtp_hash(session, sdp); - sofia_glue_pass_zrtp_hash(session); - - for (m = sdp->sdp_media; m; m = m->m_next) { - ptime = dptime; - if (m->m_type == sdp_media_image && m->m_port) { - switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",t38"); - } else if (m->m_type == sdp_media_audio && m->m_port) { - for (attr = m->m_attributes; attr; attr = attr->a_next) { - if (zstr(attr->a_name)) { - continue; - } - if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { - ptime = atoi(attr->a_value); - break; - } - } - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - if (!connection) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); - break; - } - - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) { - for (map = m->m_rtpmaps; map; map = map->rm_next) { - if (map->rm_pt > 127 || already_did[map->rm_pt]) { - continue; - } - - for (i = 0; i < num_codecs; i++) { - const switch_codec_implementation_t *imp = codecs[i]; - - if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { - match = (map->rm_pt == imp->ianacode) ? 1 : 0; - } else { - if (map->rm_encoding) { - match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; - } else { - match = 0; - } - } - - if (match) { - add_audio_codec(map, ptime, buf, sizeof(buf)); - break; - } - - } - } - - } else { - for (i = 0; i < num_codecs; i++) { - const switch_codec_implementation_t *imp = codecs[i]; - if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO || imp->ianacode > 127 || already_did[imp->ianacode]) { - continue; - } - for (map = m->m_rtpmaps; map; map = map->rm_next) { - if (map->rm_pt > 127 || already_did[map->rm_pt]) { - continue; - } - - if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { - match = (map->rm_pt == imp->ianacode) ? 1 : 0; - } else { - if (map->rm_encoding) { - match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; - } else { - match = 0; - } - } - - if (match) { - add_audio_codec(map, ptime, buf, sizeof(buf)); - break; - } - } - } - } - - } else if (m->m_type == sdp_media_video && m->m_port) { - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - if (!connection) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); - break; - } - for (i = 0; i < num_codecs; i++) { - const switch_codec_implementation_t *imp = codecs[i]; - if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) { - continue; - } - for (map = m->m_rtpmaps; map; map = map->rm_next) { - if (map->rm_pt > 127 || already_did[map->rm_pt]) { - continue; - } - - if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { - match = (map->rm_pt == imp->ianacode) ? 1 : 0; - } else { - if (map->rm_encoding) { - match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; - } else { - match = 0; - } - } - - if (match) { - if (ptime > 0) { - switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate, - ptime); - } else { - switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate); - } - already_did[imp->ianacode] = 1; - break; - } - } - } - } - } - if (buf[0] == ',') { - switch_channel_set_variable(channel, "ep_codec_string", buf + 1); - } -} - -switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp) -{ - uint8_t match = 0; - - switch_assert(tech_pvt != NULL); - switch_assert(r_sdp != NULL); - - if (zstr(r_sdp)) { - return SWITCH_STATUS_FALSE; - } - - if ((match = sofia_glue_negotiate_sdp(tech_pvt->session, r_sdp))) { - if (sofia_glue_tech_choose_port(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA"); - sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); - switch_channel_mark_pre_answered(tech_pvt->channel); - return SWITCH_STATUS_SUCCESS; - } - - - return SWITCH_STATUS_FALSE; -} - -int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) -{ - int changed = 0; - - if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE) || sofia_test_flag(tech_pvt, TFLAG_SLA_BARGING)) { - switch_channel_mark_hold(tech_pvt->channel, sendonly); - return 0; - } - - if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) { - if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - const char *stream; - const char *msg = "hold"; - - if (sofia_test_pflag(tech_pvt->profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - const char *info = switch_channel_get_variable(tech_pvt->channel, "presence_call_info"); - if (info) { - if (switch_stristr("private", info)) { - msg = "hold-private"; - } - } - } - - sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); - switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL); - changed = 1; - - if (tech_pvt->max_missed_hold_packets) { - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets); - } - - if (!(stream = switch_channel_get_hold_music(tech_pvt->channel))) { - stream = tech_pvt->profile->hold_music; - } - - if (stream && strcasecmp(stream, "silence")) { - if (!strcasecmp(stream, "indicate_hold")) { - switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND); - switch_channel_set_flag(tech_pvt->channel, CF_HOLD); - switch_ivr_hold_uuid(switch_channel_get_partner_uuid(tech_pvt->channel), NULL, 0); - } else { - switch_ivr_broadcast(switch_channel_get_partner_uuid(tech_pvt->channel), stream, - SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY); - switch_yield(250000); - } - } - } - } else { - if (sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { - sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); - changed = 1; - } - - sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); - - if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - const char *uuid; - switch_core_session_t *b_session; - - switch_yield(250000); - - if (tech_pvt->max_missed_packets) { - switch_rtp_reset_media_timer(tech_pvt->rtp_session); - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); - } - - if ((uuid = switch_channel_get_partner_uuid(tech_pvt->channel)) && (b_session = switch_core_session_locate(uuid))) { - switch_channel_t *b_channel = switch_core_session_get_channel(b_session); - - if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) { - switch_ivr_unhold(b_session); - switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND); - switch_channel_clear_flag(tech_pvt->channel, CF_HOLD); - } else { - switch_channel_stop_broadcast(b_channel); - switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL); - } - switch_core_session_rwunlock(b_session); - } - - sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE); - switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); - changed = 1; - } - } - - return changed; -} - -void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session) -{ - switch_channel_t *channel = switch_core_session_get_channel(session); - switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options"); - - switch_assert(t38_options); - - if (!local_t38_options) { - local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t)); - } - - local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate; - local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval; - local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR; - local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG; - local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement); - local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer; - local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram; - local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC); - local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo); - local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip); - local_t38_options->remote_port = t38_options->remote_port; - - - switch_channel_set_private(channel, "t38_options", local_t38_options); - -} - /* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */ switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status) { diff --git a/src/mod/endpoints/mod_sofia/sofia_media.c b/src/mod/endpoints/mod_sofia/sofia_media.c index 738f27cb12..9d0ff64d0d 100644 --- a/src/mod/endpoints/mod_sofia/sofia_media.c +++ b/src/mod/endpoints/mod_sofia/sofia_media.c @@ -1776,6 +1776,1662 @@ void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char } +switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force) +{ + + if (!tech_pvt->video_rm_encoding) { + return SWITCH_STATUS_FALSE; + } + + if (tech_pvt->video_read_codec.implementation && switch_core_codec_ready(&tech_pvt->video_read_codec)) { + if (!force) { + return SWITCH_STATUS_SUCCESS; + } + if (strcasecmp(tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding) || + tech_pvt->video_read_codec.implementation->samples_per_second != tech_pvt->video_rm_rate) { + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n", + tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding); + switch_core_codec_destroy(&tech_pvt->video_read_codec); + switch_core_codec_destroy(&tech_pvt->video_write_codec); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", + tech_pvt->video_read_codec.implementation->iananame); + return SWITCH_STATUS_SUCCESS; + } + } + + + + if (switch_core_codec_init(&tech_pvt->video_read_codec, + tech_pvt->video_rm_encoding, + tech_pvt->video_rm_fmtp, + tech_pvt->video_rm_rate, + 0, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + return SWITCH_STATUS_FALSE; + } else { + if (switch_core_codec_init(&tech_pvt->video_write_codec, + tech_pvt->video_rm_encoding, + tech_pvt->video_rm_fmtp, + tech_pvt->video_rm_rate, + 0, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + return SWITCH_STATUS_FALSE; + } else { + tech_pvt->video_read_frame.rate = tech_pvt->video_rm_rate; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n", + switch_channel_get_name(tech_pvt->channel), tech_pvt->video_rm_encoding, tech_pvt->video_rm_rate, tech_pvt->video_codec_ms); + tech_pvt->video_read_frame.codec = &tech_pvt->video_read_codec; + + tech_pvt->video_fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->video_write_codec.fmtp_out); + + tech_pvt->video_write_codec.agreed_pt = tech_pvt->video_agreed_pt; + tech_pvt->video_read_codec.agreed_pt = tech_pvt->video_agreed_pt; + switch_core_session_set_video_read_codec(tech_pvt->session, &tech_pvt->video_read_codec); + switch_core_session_set_video_write_codec(tech_pvt->session, &tech_pvt->video_write_codec); + + + if (switch_rtp_ready(tech_pvt->video_rtp_session)) { + switch_core_session_message_t msg = { 0 }; + + msg.from = __FILE__; + msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ; + + switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); + + if (tech_pvt->video_recv_pt != tech_pvt->video_agreed_pt) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, + "%s Set video receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->video_recv_pt); + + switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_recv_pt); + } else { + switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); + } + + switch_core_session_receive_message(tech_pvt->session, &msg); + + + } + + switch_channel_set_variable(tech_pvt->channel, "sip_use_video_codec_name", tech_pvt->video_rm_encoding); + switch_channel_set_variable(tech_pvt->channel, "sip_use_video_codec_fmtp", tech_pvt->video_rm_fmtp); + switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_codec_rate", "%d", tech_pvt->video_rm_rate); + switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_codec_ptime", "%d", 0); + + } + } + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + int resetting = 0; + + if (!tech_pvt->iananame) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "No audio codec available\n"); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + if (switch_core_codec_ready(&tech_pvt->read_codec)) { + if (!force) { + switch_goto_status(SWITCH_STATUS_SUCCESS, end); + } + if (strcasecmp(tech_pvt->read_impl.iananame, tech_pvt->iananame) || + tech_pvt->read_impl.samples_per_second != tech_pvt->rm_rate || + tech_pvt->codec_ms != (uint32_t) tech_pvt->read_impl.microseconds_per_packet / 1000) { + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, + "Changing Codec from %s@%dms@%dhz to %s@%dms@%luhz\n", + tech_pvt->read_impl.iananame, tech_pvt->read_impl.microseconds_per_packet / 1000, + tech_pvt->read_impl.samples_per_second, + tech_pvt->rm_encoding, + tech_pvt->codec_ms, + tech_pvt->rm_rate); + + switch_yield(tech_pvt->read_impl.microseconds_per_packet); + switch_core_session_lock_codec_write(tech_pvt->session); + switch_core_session_lock_codec_read(tech_pvt->session); + resetting = 1; + switch_yield(tech_pvt->read_impl.microseconds_per_packet); + switch_core_codec_destroy(&tech_pvt->read_codec); + switch_core_codec_destroy(&tech_pvt->write_codec); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_impl.iananame); + switch_goto_status(SWITCH_STATUS_SUCCESS, end); + } + } + + if (switch_core_codec_init_with_bitrate(&tech_pvt->read_codec, + tech_pvt->iananame, + tech_pvt->rm_fmtp, + tech_pvt->rm_rate, + tech_pvt->codec_ms, + 1, + tech_pvt->bitrate, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + tech_pvt->read_codec.session = tech_pvt->session; + + + if (switch_core_codec_init_with_bitrate(&tech_pvt->write_codec, + tech_pvt->iananame, + tech_pvt->rm_fmtp, + tech_pvt->rm_rate, + tech_pvt->codec_ms, + 1, + tech_pvt->bitrate, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + tech_pvt->write_codec.session = tech_pvt->session; + + switch_channel_set_variable(tech_pvt->channel, "sip_use_codec_name", tech_pvt->iananame); + switch_channel_set_variable(tech_pvt->channel, "sip_use_codec_fmtp", tech_pvt->rm_fmtp); + switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_codec_rate", "%d", tech_pvt->rm_rate); + switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_codec_ptime", "%d", tech_pvt->codec_ms); + + + switch_assert(tech_pvt->read_codec.implementation); + switch_assert(tech_pvt->write_codec.implementation); + + tech_pvt->read_impl = *tech_pvt->read_codec.implementation; + tech_pvt->write_impl = *tech_pvt->write_codec.implementation; + + switch_core_session_set_read_impl(tech_pvt->session, tech_pvt->read_codec.implementation); + switch_core_session_set_write_impl(tech_pvt->session, tech_pvt->write_codec.implementation); + + if (switch_rtp_ready(tech_pvt->rtp_session)) { + switch_assert(tech_pvt->read_codec.implementation); + + if (switch_rtp_change_interval(tech_pvt->rtp_session, + tech_pvt->read_impl.microseconds_per_packet, + tech_pvt->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + } + + tech_pvt->read_frame.rate = tech_pvt->rm_rate; + + if (!switch_core_codec_ready(&tech_pvt->read_codec)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits\n", + switch_channel_get_name(tech_pvt->channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms, + tech_pvt->read_impl.samples_per_packet, tech_pvt->read_impl.bits_per_second); + tech_pvt->read_frame.codec = &tech_pvt->read_codec; + + tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt; + tech_pvt->read_codec.agreed_pt = tech_pvt->agreed_pt; + + if (force != 2) { + switch_core_session_set_real_read_codec(tech_pvt->session, &tech_pvt->read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); + } + + tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out); + + if (switch_rtp_ready(tech_pvt->rtp_session)) { + switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->pt); + } + + end: + if (resetting) { + switch_core_session_unlock_codec_write(tech_pvt->session); + switch_core_session_unlock_codec_read(tech_pvt->session); + } + + sofia_glue_tech_set_video_codec(tech_pvt, force); + + return status; +} + + + +static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen) +{ + int codec_ms = ptime; + uint32_t map_bit_rate = 0; + char ptstr[20] = ""; + char ratestr[20] = ""; + char bitstr[20] = ""; + switch_codec_fmtp_t codec_fmtp = { 0 }; + + if (!codec_ms) { + codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt); + } + + map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); + + if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { + ptime = codec_ms = 30; + } + + if (zstr(map->rm_fmtp)) { + if (!strcasecmp(map->rm_encoding, "ilbc")) { + ptime = codec_ms = 30; + map_bit_rate = 13330; + } + } else { + if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) { + if (codec_fmtp.bits_per_second) { + map_bit_rate = codec_fmtp.bits_per_second; + } + if (codec_fmtp.microseconds_per_packet) { + codec_ms = (codec_fmtp.microseconds_per_packet / 1000); + } + } + } + + if (map->rm_rate) { + switch_snprintf(ratestr, sizeof(ratestr), "@%uh", (unsigned int) map->rm_rate); + } + + if (codec_ms) { + switch_snprintf(ptstr, sizeof(ptstr), "@%di", codec_ms); + } + + if (map_bit_rate) { + switch_snprintf(bitstr, sizeof(bitstr), "@%db", map_bit_rate); + } + + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s%s%s%s", map->rm_encoding, ratestr, ptstr, bitstr); + +} + + +void sofia_glue_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp) +{ + char buf[1024] = { 0 }; + sdp_media_t *m; + sdp_attribute_t *attr; + int ptime = 0, dptime = 0; + sdp_connection_t *connection; + sdp_rtpmap_t *map; + short int match = 0; + int i; + int already_did[128] = { 0 }; + int num_codecs = 0; + char *codec_order[SWITCH_MAX_CODECS]; + const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; + switch_channel_t *channel = switch_core_session_get_channel(session); + private_object_t *tech_pvt = switch_core_session_get_private(session); + int prefer_sdp = 0; + const char *var; + + if ((var = switch_channel_get_variable(channel, "ep_codec_prefer_sdp")) && switch_true(var)) { + prefer_sdp = 1; + } + + if (!zstr(codec_string)) { + char *tmp_codec_string; + if ((tmp_codec_string = strdup(codec_string))) { + num_codecs = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS); + num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, num_codecs); + switch_safe_free(tmp_codec_string); + } + } else { + num_codecs = switch_loadable_module_get_codecs(codecs, SWITCH_MAX_CODECS); + } + + if (!channel || !num_codecs) { + return; + } + + for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) { + if (zstr(attr->a_name)) { + continue; + } + if (!strcasecmp(attr->a_name, "ptime")) { + dptime = atoi(attr->a_value); + break; + } + } + + find_zrtp_hash(session, sdp); + sofia_glue_pass_zrtp_hash(session); + + for (m = sdp->sdp_media; m; m = m->m_next) { + ptime = dptime; + if (m->m_type == sdp_media_image && m->m_port) { + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",t38"); + } else if (m->m_type == sdp_media_audio && m->m_port) { + for (attr = m->m_attributes; attr; attr = attr->a_next) { + if (zstr(attr->a_name)) { + continue; + } + if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { + ptime = atoi(attr->a_value); + break; + } + } + connection = sdp->sdp_connection; + if (m->m_connections) { + connection = m->m_connections; + } + + if (!connection) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); + break; + } + + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) { + for (map = m->m_rtpmaps; map; map = map->rm_next) { + if (map->rm_pt > 127 || already_did[map->rm_pt]) { + continue; + } + + for (i = 0; i < num_codecs; i++) { + const switch_codec_implementation_t *imp = codecs[i]; + + if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + match = (map->rm_pt == imp->ianacode) ? 1 : 0; + } else { + if (map->rm_encoding) { + match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; + } else { + match = 0; + } + } + + if (match) { + add_audio_codec(map, ptime, buf, sizeof(buf)); + break; + } + + } + } + + } else { + for (i = 0; i < num_codecs; i++) { + const switch_codec_implementation_t *imp = codecs[i]; + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO || imp->ianacode > 127 || already_did[imp->ianacode]) { + continue; + } + for (map = m->m_rtpmaps; map; map = map->rm_next) { + if (map->rm_pt > 127 || already_did[map->rm_pt]) { + continue; + } + + if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + match = (map->rm_pt == imp->ianacode) ? 1 : 0; + } else { + if (map->rm_encoding) { + match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; + } else { + match = 0; + } + } + + if (match) { + add_audio_codec(map, ptime, buf, sizeof(buf)); + break; + } + } + } + } + + } else if (m->m_type == sdp_media_video && m->m_port) { + connection = sdp->sdp_connection; + if (m->m_connections) { + connection = m->m_connections; + } + + if (!connection) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); + break; + } + for (i = 0; i < num_codecs; i++) { + const switch_codec_implementation_t *imp = codecs[i]; + if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) { + continue; + } + for (map = m->m_rtpmaps; map; map = map->rm_next) { + if (map->rm_pt > 127 || already_did[map->rm_pt]) { + continue; + } + + if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + match = (map->rm_pt == imp->ianacode) ? 1 : 0; + } else { + if (map->rm_encoding) { + match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1; + } else { + match = 0; + } + } + + if (match) { + if (ptime > 0) { + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate, + ptime); + } else { + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate); + } + already_did[imp->ianacode] = 1; + break; + } + } + } + } + } + if (buf[0] == ',') { + switch_channel_set_variable(channel, "ep_codec_string", buf + 1); + } +} + +switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp) +{ + uint8_t match = 0; + + switch_assert(tech_pvt != NULL); + switch_assert(r_sdp != NULL); + + if (zstr(r_sdp)) { + return SWITCH_STATUS_FALSE; + } + + if ((match = sofia_glue_negotiate_sdp(tech_pvt->session, r_sdp))) { + if (sofia_glue_tech_choose_port(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA"); + sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); + switch_channel_mark_pre_answered(tech_pvt->channel); + return SWITCH_STATUS_SUCCESS; + } + + + return SWITCH_STATUS_FALSE; +} + +int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) +{ + int changed = 0; + + if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE) || sofia_test_flag(tech_pvt, TFLAG_SLA_BARGING)) { + switch_channel_mark_hold(tech_pvt->channel, sendonly); + return 0; + } + + if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) { + if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { + const char *stream; + const char *msg = "hold"; + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { + const char *info = switch_channel_get_variable(tech_pvt->channel, "presence_call_info"); + if (info) { + if (switch_stristr("private", info)) { + msg = "hold-private"; + } + } + } + + sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); + switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL); + changed = 1; + + if (tech_pvt->max_missed_hold_packets) { + switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets); + } + + if (!(stream = switch_channel_get_hold_music(tech_pvt->channel))) { + stream = tech_pvt->profile->hold_music; + } + + if (stream && strcasecmp(stream, "silence")) { + if (!strcasecmp(stream, "indicate_hold")) { + switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND); + switch_channel_set_flag(tech_pvt->channel, CF_HOLD); + switch_ivr_hold_uuid(switch_channel_get_partner_uuid(tech_pvt->channel), NULL, 0); + } else { + switch_ivr_broadcast(switch_channel_get_partner_uuid(tech_pvt->channel), stream, + SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY); + switch_yield(250000); + } + } + } + } else { + if (sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { + sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); + changed = 1; + } + + sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); + + if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { + const char *uuid; + switch_core_session_t *b_session; + + switch_yield(250000); + + if (tech_pvt->max_missed_packets) { + switch_rtp_reset_media_timer(tech_pvt->rtp_session); + switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); + } + + if ((uuid = switch_channel_get_partner_uuid(tech_pvt->channel)) && (b_session = switch_core_session_locate(uuid))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + + if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) { + switch_ivr_unhold(b_session); + switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND); + switch_channel_clear_flag(tech_pvt->channel, CF_HOLD); + } else { + switch_channel_stop_broadcast(b_channel); + switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL); + } + switch_core_session_rwunlock(b_session); + } + + sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE); + switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); + changed = 1; + } + } + + return changed; +} + +void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options"); + + switch_assert(t38_options); + + if (!local_t38_options) { + local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t)); + } + + local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate; + local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval; + local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR; + local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG; + local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement); + local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer; + local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram; + local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC); + local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo); + local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip); + local_t38_options->remote_port = t38_options->remote_port; + + + switch_channel_set_private(channel, "t38_options", local_t38_options); + +} + +static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, + switch_port_t port, + int cur_ptime, const char *append_audio, const char *sr, int use_cng, int cng_type, switch_event_t *map, int verbose_sdp, int secure) +{ + int i = 0; + int rate; + int already_did[128] = { 0 }; + int ptime = 0, noptime = 0; + const char *local_audio_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); + + + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d RTP/%sAVP", + port, secure ? "S" : ""); + + + + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + int this_ptime = (imp->microseconds_per_packet / 1000); + + if (!strcasecmp(imp->iananame, "ilbc")) { + this_ptime = 20; + } + + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { + continue; + } + + if (!noptime) { + if (!cur_ptime) { +#if 0 + if (ptime) { + if (ptime != this_ptime) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Codec %s payload %d added to sdp wanting ptime %d but it's already %d (%s:%d:%d), disabling ptime.\n", + imp->iananame, + tech_pvt->ianacodes[i], + this_ptime, + ptime, + tech_pvt->codecs[0]->iananame, + tech_pvt->codecs[0]->ianacode, + ptime); + ptime = 0; + noptime = 1; + } + } else { + ptime = this_ptime; + } +#else + if (!ptime) { + ptime = this_ptime; + } +#endif + } else { + if (this_ptime != cur_ptime) { + continue; + } + } + } + + if (tech_pvt->ianacodes[i] < 128) { + if (already_did[tech_pvt->ianacodes[i]]) { + continue; + } + + already_did[tech_pvt->ianacodes[i]] = 1; + } + + + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", tech_pvt->ianacodes[i]); + } + + if (tech_pvt->dtmf_type == DTMF_2833 && tech_pvt->te > 95) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", tech_pvt->te); + } + + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && cng_type && use_cng) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", cng_type); + } + + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "\n"); + + + memset(already_did, 0, sizeof(already_did)); + + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + char *fmtp = imp->fmtp; + int this_ptime = imp->microseconds_per_packet / 1000; + + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { + continue; + } + + if (!strcasecmp(imp->iananame, "ilbc")) { + this_ptime = 20; + } + + if (!noptime) { + if (!cur_ptime) { + if (!ptime) { + ptime = this_ptime; + } + } else { + if (this_ptime != cur_ptime) { + continue; + } + } + } + + if (tech_pvt->ianacodes[i] < 128) { + if (already_did[tech_pvt->ianacodes[i]]) { + continue; + } + + already_did[tech_pvt->ianacodes[i]] = 1; + } + + + rate = imp->samples_per_second; + + if (map) { + char key[128] = ""; + char *check = NULL; + switch_snprintf(key, sizeof(key), "%s:%u", imp->iananame, imp->bits_per_second); + + if ((check = switch_event_get_header(map, key)) || (check = switch_event_get_header(map, imp->iananame))) { + fmtp = check; + } + } + + if (tech_pvt->ianacodes[i] > 95 || verbose_sdp) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->ianacodes[i], imp->iananame, rate); + } + + if (fmtp) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->ianacodes[i], fmtp); + } + } + + + if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) + && tech_pvt->te > 95) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); + } + + if (secure) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); + //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); + } + + if (!cng_type) { + //switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d CN/8000\n", cng_type); + //} else { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=silenceSupp:off - - - -\n"); + } + + if (append_audio) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "%s%s", append_audio, end_of(append_audio) == '\n' ? "" : "\n"); + } + + if (!cur_ptime) { + cur_ptime = ptime; + } + + if (!noptime && cur_ptime) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ptime:%d\n", cur_ptime); + } + + if (tech_pvt->local_sdp_audio_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", + tech_pvt->local_sdp_audio_zrtp_hash); + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=zrtp-hash:%s\n", + tech_pvt->local_sdp_audio_zrtp_hash); + } + + if (!zstr(sr)) { + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=%s\n", sr); + } +} + + +#define SDPBUFLEN 65536 +void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch_port_t port, const char *sr, int force) +{ + char *buf; + int ptime = 0; + uint32_t rate = 0; + uint32_t v_port; + int use_cng = 1; + const char *val; + const char *family; + const char *pass_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_video_fmtp"); + const char *ov_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_force_video_fmtp"); + const char *append_audio = switch_channel_get_variable(tech_pvt->channel, "sip_append_audio_sdp"); + char srbuf[128] = ""; + const char *var_val; + const char *username = tech_pvt->profile->username; + const char *fmtp_out = tech_pvt->fmtp_out; + const char *fmtp_out_var = switch_channel_get_variable(tech_pvt->channel, "sip_force_audio_fmtp"); + switch_event_t *map = NULL, *ptmap = NULL; + const char *b_sdp = NULL; + int verbose_sdp = 0; + const char *local_audio_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); + + switch_zmalloc(buf, SDPBUFLEN); + + sofia_glue_check_dtmf_type(tech_pvt); + + if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) || + ((val = switch_channel_get_variable(tech_pvt->channel, "supress_cng")) && switch_true(val)) || + ((val = switch_channel_get_variable(tech_pvt->channel, "suppress_cng")) && switch_true(val))) { + use_cng = 0; + tech_pvt->cng_pt = 0; + } + + if (!tech_pvt->payload_space) { + int i; + + tech_pvt->payload_space = 98; + + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + + tech_pvt->ianacodes[i] = imp->ianacode; + + if (tech_pvt->ianacodes[i] > 64) { + if (tech_pvt->dtmf_type == DTMF_2833 && tech_pvt->te > 95 && tech_pvt->te == tech_pvt->payload_space) { + tech_pvt->payload_space++; + } + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && + tech_pvt->cng_pt && use_cng && tech_pvt->cng_pt == tech_pvt->payload_space) { + tech_pvt->payload_space++; + } + tech_pvt->ianacodes[i] = tech_pvt->payload_space++; + } + } + } + + if (fmtp_out_var) { + fmtp_out = fmtp_out_var; + } + + if ((val = switch_channel_get_variable(tech_pvt->channel, "verbose_sdp")) && switch_true(val)) { + verbose_sdp = 1; + } + + if (!force && !ip && zstr(sr) + && (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA))) { + switch_safe_free(buf); + return; + } + + if (!ip) { + if (!(ip = tech_pvt->adv_sdp_audio_ip)) { + ip = tech_pvt->proxy_sdp_audio_ip; + } + } + + if (!ip) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO IP!\n", switch_channel_get_name(tech_pvt->channel)); + switch_safe_free(buf); + return; + } + + if (!port) { + if (!(port = tech_pvt->adv_sdp_audio_port)) { + port = tech_pvt->proxy_sdp_audio_port; + } + } + + if (!port) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO PORT!\n", switch_channel_get_name(tech_pvt->channel)); + switch_safe_free(buf); + return; + } + + if (!tech_pvt->rm_encoding && (b_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) { + sofia_glue_sdp_map(b_sdp, &map, &ptmap); + } + + if (zstr(sr)) { + if ((var_val = switch_channel_get_variable(tech_pvt->channel, "media_audio_mode"))) { + sr = var_val; + } else { + sr = "sendrecv"; + } + } + + if (!tech_pvt->owner_id) { + tech_pvt->owner_id = (uint32_t) switch_epoch_time_now(NULL) - port; + } + + if (!tech_pvt->session_id) { + tech_pvt->session_id = tech_pvt->owner_id; + } + + if (switch_true(switch_channel_get_variable_dup(tech_pvt->channel, "drop_dtmf", SWITCH_FALSE, -1))) { + sofia_set_flag(tech_pvt, TFLAG_DROP_DTMF); + } + + tech_pvt->session_id++; + + if ((tech_pvt->profile->ndlb & PFLAG_NDLB_SENDRECV_IN_SESSION) || + ((var_val = switch_channel_get_variable(tech_pvt->channel, "ndlb_sendrecv_in_session")) && switch_true(var_val))) { + if (!zstr(sr)) { + switch_snprintf(srbuf, sizeof(srbuf), "a=%s\n", sr); + } + sr = NULL; + } + + family = strchr(ip, ':') ? "IP6" : "IP4"; + switch_snprintf(buf, SDPBUFLEN, + "v=0\n" + "o=%s %010u %010u IN %s %s\n" + "s=%s\n" + "c=IN %s %s\n" "t=0 0\n" + "%s", + username, tech_pvt->owner_id, tech_pvt->session_id, family, ip, username, family, ip, srbuf); + + if (tech_pvt->rm_encoding) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=audio %d RTP/%sAVP", + port, (!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) ? "S" : ""); + + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->pt); + + if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) && tech_pvt->te > 95) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->te); + } + + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->cng_pt); + } + + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n"); + + rate = tech_pvt->rm_rate; + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate); + if (fmtp_out) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->agreed_pt, fmtp_out); + } + + if (tech_pvt->read_codec.implementation && !ptime) { + ptime = tech_pvt->read_codec.implementation->microseconds_per_packet / 1000; + } + + + if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) + && tech_pvt->te > 95) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); + } + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d CN/8000\n", tech_pvt->cng_pt); + if (!tech_pvt->rm_encoding) { + tech_pvt->cng_pt = 0; + } + } else { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=silenceSupp:off - - - -\n"); + } + + if (append_audio) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s%s", append_audio, end_of(append_audio) == '\n' ? "" : "\n"); + } + + if (ptime) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ptime:%d\n", ptime); + } + + + if (tech_pvt->local_sdp_audio_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", + tech_pvt->local_sdp_audio_zrtp_hash); + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", + tech_pvt->local_sdp_audio_zrtp_hash); + } + + if (!zstr(sr)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=%s\n", sr); + } + + if (!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); + //switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=encryption:optional\n"); + } + + } else if (tech_pvt->num_codecs) { + int i; + int cur_ptime = 0, this_ptime = 0, cng_type = 0; + const char *mult; + + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) { + cng_type = tech_pvt->cng_pt; + + if (!tech_pvt->rm_encoding) { + tech_pvt->cng_pt = 0; + } + } + + mult = switch_channel_get_variable(tech_pvt->channel, "sdp_m_per_ptime"); + + if (mult && switch_false(mult)) { + char *bp = buf; + int both = 1; + + if ((!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE))) { + generate_m(tech_pvt, buf, SDPBUFLEN, port, 0, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 1); + bp = (buf + strlen(buf)); + + /* asterisk can't handle AVP and SAVP in sep streams, way to blow off the spec....*/ + if (switch_true(switch_channel_get_variable(tech_pvt->channel, "sdp_secure_savp_only"))) { + both = 0; + } + + } + + if (both) { + generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, 0, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 0); + } + + } else { + + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { + continue; + } + + this_ptime = imp->microseconds_per_packet / 1000; + + if (!strcasecmp(imp->iananame, "ilbc")) { + this_ptime = 20; + } + + if (cur_ptime != this_ptime) { + char *bp = buf; + int both = 1; + + cur_ptime = this_ptime; + + if ((!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE))) { + generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, cur_ptime, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 1); + bp = (buf + strlen(buf)); + + /* asterisk can't handle AVP and SAVP in sep streams, way to blow off the spec....*/ + if (switch_true(switch_channel_get_variable(tech_pvt->channel, "sdp_secure_savp_only"))) { + both = 0; + } + } + + if (both) { + generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, cur_ptime, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 0); + } + } + + } + } + + } + + if (sofia_test_flag(tech_pvt, TFLAG_VIDEO)) { + const char *local_video_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO); + + if (!tech_pvt->local_sdp_video_port) { + sofia_glue_tech_choose_video_port(tech_pvt, 0); + } + + if ((v_port = tech_pvt->adv_sdp_video_port)) { + + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=video %d RTP/%sAVP", + v_port, (!zstr(local_video_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) ? "S" : ""); + + + /*****************************/ + if (tech_pvt->video_rm_encoding) { + sofia_glue_tech_set_video_codec(tech_pvt, 0); + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->video_agreed_pt); + } else if (tech_pvt->num_codecs) { + int i; + int already_did[128] = { 0 }; + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + + if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { + continue; + } + + if (tech_pvt->ianacodes[i] < 128) { + if (already_did[tech_pvt->ianacodes[i]]) { + continue; + } + already_did[tech_pvt->ianacodes[i]] = 1; + } + + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->ianacodes[i]); + if (!ptime) { + ptime = imp->microseconds_per_packet / 1000; + } + } + } + + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n"); + + if (tech_pvt->video_rm_encoding) { + const char *of; + rate = tech_pvt->video_rm_rate; + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->video_pt, tech_pvt->video_rm_encoding, + tech_pvt->video_rm_rate); + + if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { + pass_fmtp = tech_pvt->video_rm_fmtp; + } else { + + pass_fmtp = NULL; + + if (switch_channel_get_partner_uuid(tech_pvt->channel)) { + if ((of = switch_channel_get_variable_partner(tech_pvt->channel, "sip_video_fmtp"))) { + pass_fmtp = of; + } + } + + if (ov_fmtp) { + pass_fmtp = ov_fmtp; + }// else { // seems to break eyebeam at least... + //pass_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_video_fmtp"); + //} + } + + if (pass_fmtp) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->video_pt, pass_fmtp); + } + + } else if (tech_pvt->num_codecs) { + int i; + int already_did[128] = { 0 }; + + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + char *fmtp = NULL; + uint32_t ianacode = tech_pvt->ianacodes[i]; + + if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { + continue; + } + + if (ianacode < 128) { + if (already_did[ianacode]) { + continue; + } + already_did[ianacode] = 1; + } + + if (!rate) { + rate = imp->samples_per_second; + } + + + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", ianacode, imp->iananame, + imp->samples_per_second); + + if (!zstr(ov_fmtp)) { + fmtp = (char *) ov_fmtp; + } else { + + if (map) { + fmtp = switch_event_get_header(map, imp->iananame); + } + + if (zstr(fmtp)) fmtp = imp->fmtp; + + if (zstr(fmtp)) fmtp = (char *) pass_fmtp; + } + + if (!zstr(fmtp) && strcasecmp(fmtp, "_blank_")) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", ianacode, fmtp); + } + } + + } + + if (switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_video_crypto_key); + //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); + } + + + if (tech_pvt->local_sdp_video_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding video a=zrtp-hash:%s\n", + tech_pvt->local_sdp_video_zrtp_hash); + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", + tech_pvt->local_sdp_video_zrtp_hash); + } + } + } + + + if (map) { + switch_event_destroy(&map); + } + + if (ptmap) { + switch_event_destroy(&ptmap); + } + + sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE); + + switch_safe_free(buf); +} + +const char *sofia_glue_get_codec_string(private_object_t *tech_pvt) +{ + const char *preferred = NULL, *fallback = NULL; + + if (!(preferred = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) { + preferred = switch_channel_get_variable(tech_pvt->channel, "codec_string"); + } + + if (!preferred) { + if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + preferred = tech_pvt->profile->outbound_codec_string; + fallback = tech_pvt->profile->inbound_codec_string; + } else { + preferred = tech_pvt->profile->inbound_codec_string; + fallback = tech_pvt->profile->outbound_codec_string; + } + } + + return !zstr(preferred) ? preferred : fallback; +} + +void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt) +{ + const char *abs, *codec_string = NULL; + const char *ocodec = NULL; + + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) { + return; + } + + if (tech_pvt->num_codecs) { + return; + } + + tech_pvt->payload_space = 0; + + switch_assert(tech_pvt->session != NULL); + + if ((abs = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) { + /* inherit_codec == true will implicitly clear the absolute_codec_string + variable if used since it was the reason it was set in the first place and is no longer needed */ + if (switch_true(switch_channel_get_variable(tech_pvt->channel, "inherit_codec"))) { + switch_channel_set_variable(tech_pvt->channel, "absolute_codec_string", NULL); + } + codec_string = abs; + goto ready; + } + + if (!(codec_string = switch_channel_get_variable(tech_pvt->channel, "codec_string"))) { + codec_string = sofia_glue_get_codec_string(tech_pvt); + } + + if (codec_string && *codec_string == '=') { + codec_string++; + goto ready; + } + + + if ((ocodec = switch_channel_get_variable(tech_pvt->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { + if (!codec_string || sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_TRANSCODING)) { + codec_string = ocodec; + } else { + if (!(codec_string = switch_core_session_sprintf(tech_pvt->session, "%s,%s", ocodec, codec_string))) { + codec_string = ocodec; + } + } + } + + ready: + + if (codec_string) { + char *tmp_codec_string; + if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) { + tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS); + tech_pvt->num_codecs = + switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last); + } + } else { + tech_pvt->num_codecs = switch_loadable_module_get_codecs(tech_pvt->codecs, sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0])); + } + + +} + +void sofia_glue_check_video_codecs(private_object_t *tech_pvt) +{ + if (tech_pvt->num_codecs && !sofia_test_flag(tech_pvt, TFLAG_VIDEO)) { + int i; + tech_pvt->video_count = 0; + for (i = 0; i < tech_pvt->num_codecs; i++) { + + if (tech_pvt->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) { + tech_pvt->video_count++; + } + } + if (tech_pvt->video_count) { + sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO); + } + } +} + + +void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) +{ + switch_size_t len; + char *p, *q, *pe, *qe; + int has_video = 0, has_audio = 0, has_ip = 0; + char port_buf[25] = ""; + char vport_buf[25] = ""; + char *new_sdp; + int bad = 0; + + if (zstr(tech_pvt->local_sdp_str)) { + return; + } + + len = strlen(tech_pvt->local_sdp_str) * 2; + + if (switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) && + (switch_stristr("sendonly", tech_pvt->local_sdp_str) || switch_stristr("0.0.0.0", tech_pvt->local_sdp_str))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Skip patch on hold SDP\n"); + return; + } + + if (zstr(tech_pvt->adv_sdp_audio_ip) || !tech_pvt->adv_sdp_audio_port) { + if (sofia_glue_tech_choose_port(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s I/O Error\n", + switch_channel_get_name(tech_pvt->channel)); + return; + } + tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, "PROXY"); + tech_pvt->rm_rate = 8000; + tech_pvt->codec_ms = 20; + } + + new_sdp = switch_core_session_alloc(tech_pvt->session, len); + switch_snprintf(port_buf, sizeof(port_buf), "%u", tech_pvt->adv_sdp_audio_port); + + + p = tech_pvt->local_sdp_str; + q = new_sdp; + pe = p + strlen(p); + qe = q + len - 1; + + + while (p && *p) { + if (p >= pe) { + bad = 1; + goto end; + } + + if (q >= qe) { + bad = 2; + goto end; + } + + if (tech_pvt->adv_sdp_audio_ip && !strncmp("c=IN IP", p, 7)) { + strncpy(q, p, 7); + p += 7; + q += 7; + strncpy(q, strchr(tech_pvt->adv_sdp_audio_ip, ':') ? "6 " : "4 ", 2); + p +=2; + q +=2; + strncpy(q, tech_pvt->adv_sdp_audio_ip, strlen(tech_pvt->adv_sdp_audio_ip)); + q += strlen(tech_pvt->adv_sdp_audio_ip); + + while (p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f'))) { + if (p >= pe) { + bad = 3; + goto end; + } + p++; + } + + has_ip++; + + } else if (!strncmp("o=", p, 2)) { + char *oe = strchr(p, '\n'); + switch_size_t len; + + if (oe) { + const char *family = "IP4"; + char o_line[1024] = ""; + + if (oe >= pe) { + bad = 5; + goto end; + } + + len = (oe - p); + p += len; + + + family = strchr(tech_pvt->profile->sipip, ':') ? "IP6" : "IP4"; + + if (!tech_pvt->owner_id) { + tech_pvt->owner_id = (uint32_t) switch_epoch_time_now(NULL) * 31821U + 13849U; + } + + if (!tech_pvt->session_id) { + tech_pvt->session_id = tech_pvt->owner_id; + } + + tech_pvt->session_id++; + + + snprintf(o_line, sizeof(o_line), "o=%s %010u %010u IN %s %s\n", + tech_pvt->profile->username, tech_pvt->owner_id, tech_pvt->session_id, family, tech_pvt->profile->sipip); + + strncpy(q, o_line, strlen(o_line)); + q += strlen(o_line) - 1; + + } + + } else if (!strncmp("s=", p, 2)) { + char *se = strchr(p, '\n'); + switch_size_t len; + + if (se) { + char s_line[1024] = ""; + + if (se >= pe) { + bad = 5; + goto end; + } + + len = (se - p); + p += len; + + snprintf(s_line, sizeof(s_line), "s=%s\n", tech_pvt->profile->username); + + strncpy(q, s_line, strlen(s_line)); + q += strlen(s_line) - 1; + + } + + } else if ((!strncmp("m=audio ", p, 8) && *(p + 8) != '0') || (!strncmp("m=image ", p, 8) && *(p + 8) != '0')) { + strncpy(q, p, 8); + p += 8; + + if (p >= pe) { + bad = 4; + goto end; + } + + + q += 8; + + if (q >= qe) { + bad = 5; + goto end; + } + + + strncpy(q, port_buf, strlen(port_buf)); + q += strlen(port_buf); + + if (q >= qe) { + bad = 6; + goto end; + } + + while (p && *p && (*p >= '0' && *p <= '9')) { + if (p >= pe) { + bad = 7; + goto end; + } + p++; + } + + has_audio++; + + } else if (!strncmp("m=video ", p, 8) && *(p + 8) != '0') { + if (!has_video) { + sofia_glue_tech_choose_video_port(tech_pvt, 1); + tech_pvt->video_rm_encoding = "PROXY-VID"; + tech_pvt->video_rm_rate = 90000; + tech_pvt->video_codec_ms = 0; + switch_snprintf(vport_buf, sizeof(vport_buf), "%u", tech_pvt->adv_sdp_video_port); + if (switch_channel_media_ready(tech_pvt->channel) && !switch_rtp_ready(tech_pvt->video_rtp_session)) { + sofia_set_flag(tech_pvt, TFLAG_VIDEO); + sofia_set_flag(tech_pvt, TFLAG_REINVITE); + sofia_media_activate_rtp(tech_pvt); + } + } + + strncpy(q, p, 8); + p += 8; + + if (p >= pe) { + bad = 8; + goto end; + } + + q += 8; + + if (q >= qe) { + bad = 9; + goto end; + } + + strncpy(q, vport_buf, strlen(vport_buf)); + q += strlen(vport_buf); + + if (q >= qe) { + bad = 10; + goto end; + } + + while (p && *p && (*p >= '0' && *p <= '9')) { + + if (p >= pe) { + bad = 11; + goto end; + } + + p++; + } + + has_video++; + } + + while (p && *p && *p != '\n') { + + if (p >= pe) { + bad = 12; + goto end; + } + + if (q >= qe) { + bad = 13; + goto end; + } + + *q++ = *p++; + } + + if (p >= pe) { + bad = 14; + goto end; + } + + if (q >= qe) { + bad = 15; + goto end; + } + + *q++ = *p++; + + } + + end: + + if (bad) { + return; + } + + + if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s too late.\n", switch_channel_get_name(tech_pvt->channel)); + return; + } + + + if (!has_ip && !has_audio) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s SDP has no audio in it.\n%s\n", + switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str); + return; + } + + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s Patched SDP\n---\n%s\n+++\n%s\n", + switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str, new_sdp); + + sofia_glue_tech_set_local_sdp(tech_pvt, new_sdp, SWITCH_FALSE); + +} + + +void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup) +{ + switch_mutex_lock(tech_pvt->sofia_mutex); + tech_pvt->local_sdp_str = dup ? switch_core_session_strdup(tech_pvt->session, sdp_str) : (char *) sdp_str; + switch_channel_set_variable(tech_pvt->channel, "sip_local_sdp_str", tech_pvt->local_sdp_str); + switch_mutex_unlock(tech_pvt->sofia_mutex); +} + + +char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type) +{ + char *extra_headers = NULL; + switch_stream_handle_t stream = { 0 }; + switch_event_header_t *hi = NULL; + int x = 0; + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *boundary = switch_core_session_get_uuid(session); + + SWITCH_STANDARD_STREAM(stream); + if ((hi = switch_channel_variable_first(channel))) { + for (; hi; hi = hi->next) { + const char *name = (char *) hi->name; + char *value = (char *) hi->value; + + if (!strncasecmp(name, prefix, strlen(prefix))) { + const char *hname = name + strlen(prefix); + if (*value == '~') { + stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n%s\n", boundary, hname, strlen(value), value + 1); + } else { + stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n\n%s\n", boundary, hname, strlen(value) + 1, value); + } + x++; + } + } + switch_channel_variable_last(channel); + } + + if (x) { + *mp_type = switch_core_session_sprintf(session, "multipart/mixed; boundary=%s", boundary); + if (sdp) { + stream.write_function(&stream, "--%s\nContent-Type: application/sdp\nContent-Length: %d\n\n%s\n", boundary, strlen(sdp) + 1, sdp); + } + stream.write_function(&stream, "--%s--\n", boundary); + } + + if (!zstr((char *) stream.data)) { + extra_headers = stream.data; + } else { + switch_safe_free(stream.data); + } + + return extra_headers; +} + + + + /* For Emacs: * Local Variables: