2964 lines
99 KiB
C
Raw Normal View History

2012-12-18 10:50:43 -06:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
*
* sofia_media.c -- SOFIA SIP Endpoint (sofia media code)
*
*/
#include "mod_sofia.h"
2012-12-19 14:51:28 -06:00
void sofia_media_tech_absorb_sdp(private_object_t *tech_pvt)
2012-12-18 10:50:43 -06:00
{
const char *sdp_str;
if ((sdp_str = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) {
sdp_parser_t *parser;
sdp_session_t *sdp;
sdp_media_t *m;
sdp_connection_t *connection;
if ((parser = sdp_parse(NULL, sdp_str, (int) strlen(sdp_str), 0))) {
if ((sdp = sdp_session(parser))) {
for (m = sdp->sdp_media; m; m = m->m_next) {
if (m->m_type != sdp_media_audio || !m->m_port) {
continue;
}
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
}
if (connection) {
tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
}
tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port;
if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
break;
}
}
}
sdp_parser_free(parser);
}
2012-12-19 14:51:28 -06:00
sofia_media_tech_set_local_sdp(tech_pvt, sdp_str, SWITCH_TRUE);
2012-12-18 10:50:43 -06:00
}
}
2012-12-19 14:51:28 -06:00
switch_status_t sofia_media_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt)
2012-12-18 10:50:43 -06:00
{
sdp_media_t *m;
sdp_parser_t *parser = NULL;
sdp_session_t *sdp;
if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
return SWITCH_STATUS_FALSE;
}
if (!(sdp = sdp_session(parser))) {
sdp_parser_free(parser);
return SWITCH_STATUS_FALSE;
}
switch_event_create(&(*fmtp), SWITCH_EVENT_REQUEST_PARAMS);
switch_event_create(&(*pt), SWITCH_EVENT_REQUEST_PARAMS);
for (m = sdp->sdp_media; m; m = m->m_next) {
if (m->m_proto == sdp_proto_rtp) {
sdp_rtpmap_t *map;
for (map = m->m_rtpmaps; map; map = map->rm_next) {
if (map->rm_encoding) {
char buf[25] = "";
char key[128] = "";
char *br = NULL;
if (map->rm_fmtp) {
if ((br = strstr(map->rm_fmtp, "bitrate="))) {
br += 8;
}
}
switch_snprintf(buf, sizeof(buf), "%d", map->rm_pt);
if (br) {
switch_snprintf(key, sizeof(key), "%s:%s", map->rm_encoding, br);
} else {
switch_snprintf(key, sizeof(key), "%s", map->rm_encoding);
}
switch_event_add_header_string(*pt, SWITCH_STACK_BOTTOM, key, buf);
if (map->rm_fmtp) {
switch_event_add_header_string(*fmtp, SWITCH_STACK_BOTTOM, key, map->rm_fmtp);
}
}
}
}
}
sdp_parser_free(parser);
return SWITCH_STATUS_SUCCESS;
}
2012-12-19 14:51:28 -06:00
void sofia_media_proxy_codec(switch_core_session_t *session, const char *r_sdp)
2012-12-18 10:50:43 -06:00
{
sdp_media_t *m;
sdp_parser_t *parser = NULL;
sdp_session_t *sdp;
private_object_t *tech_pvt = switch_core_session_get_private(session);
sdp_attribute_t *attr;
int ptime = 0, dptime = 0;
if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
return;
}
if (!(sdp = sdp_session(parser))) {
sdp_parser_free(parser);
return;
}
switch_assert(tech_pvt != NULL);
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);
}
}
for (m = sdp->sdp_media; m; m = m->m_next) {
ptime = dptime;
//maxptime = dmaxptime;
if (m->m_proto == sdp_proto_rtp) {
sdp_rtpmap_t *map;
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
ptime = atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
//maxptime = atoi(attr->a_value);
}
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, map->rm_encoding);
tech_pvt->rm_rate = map->rm_rate;
tech_pvt->codec_ms = ptime;
2012-12-19 14:51:28 -06:00
sofia_media_tech_set_codec(tech_pvt, 0);
2012-12-18 10:50:43 -06:00
break;
}
break;
}
}
sdp_parser_free(parser);
}
2012-12-20 22:57:47 -06:00
uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp)
2012-12-18 10:50:43 -06:00
{
2012-12-20 22:57:47 -06:00
uint8_t t, p = 0;
2012-12-18 10:50:43 -06:00
private_object_t *tech_pvt = switch_core_session_get_private(session);
2012-12-20 22:57:47 -06:00
if ((t = switch_core_media_negotiate_sdp(session, r_sdp, &p, sofia_test_flag(tech_pvt, TFLAG_REINVITE),
tech_pvt->profile->codec_flags, tech_pvt->profile->te))) {
sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
2012-12-18 10:50:43 -06:00
}
2012-12-20 22:57:47 -06:00
if (!p) {
sofia_set_flag(tech_pvt, TFLAG_NOREPLY);
2012-12-18 10:50:43 -06:00
}
2012-12-20 22:57:47 -06:00
return t;
2012-12-18 10:50:43 -06:00
}
2012-12-20 22:57:47 -06:00
#if 0
2012-12-19 14:51:28 -06:00
uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp)
2012-12-18 10:50:43 -06:00
{
uint8_t match = 0;
switch_payload_t best_te = 0, te = 0, cng_pt = 0;
private_object_t *tech_pvt = switch_core_session_get_private(session);
sdp_media_t *m;
sdp_attribute_t *attr;
int first = 0, last = 0;
int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
int sendonly = 0, recvonly = 0;
int greedy = 0, x = 0, skip = 0, mine = 0;
switch_channel_t *channel = switch_core_session_get_channel(session);
const char *val;
const char *crypto = NULL;
2012-12-18 22:02:19 -06:00
int got_crypto = 0, got_video_crypto = 0, got_audio = 0, got_avp = 0, got_video_avp = 0, got_video_savp = 0, got_savp = 0, got_udptl = 0;
2012-12-18 10:50:43 -06:00
int scrooge = 0;
sdp_parser_t *parser = NULL;
sdp_session_t *sdp;
int reneg = 1;
const switch_codec_implementation_t **codec_array;
int total_codecs;
codec_array = tech_pvt->codecs;
total_codecs = tech_pvt->num_codecs;
if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
return 0;
}
if (!(sdp = sdp_session(parser))) {
sdp_parser_free(parser);
return 0;
}
switch_assert(tech_pvt != NULL);
2012-12-20 22:57:47 -06:00
greedy = !!sofia_test_media_flag(tech_pvt->profile, SCMF_CODEC_GREEDY);
scrooge = !!sofia_test_media_flag(tech_pvt->profile, SCMF_CODEC_SCROOGE);
2012-12-18 10:50:43 -06:00
if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) {
if (!strcasecmp(val, "generous")) {
greedy = 0;
scrooge = 0;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : generous\n" );
} else if (!strcasecmp(val, "greedy")) {
greedy = 1;
scrooge = 0;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : greedy\n" );
} else if (!strcasecmp(val, "scrooge")) {
scrooge = 1;
greedy = 1;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : scrooge\n" );
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation ignored invalid value : '%s' \n", val );
}
}
if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833) {
if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
tech_pvt->rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
}
}
if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833) {
if (strstr(tech_pvt->origin, "Sonus_UAC")) {
tech_pvt->rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Hello,\nI see you have a Sonus!\n"
"FYI, Sonus cannot follow the RFC on the proper way to send DTMF.\n"
"Sadly, my creator had to spend several hours figuring this out so I thought you'd like to know that!\n"
"Don't worry, DTMF will work but you may want to ask them to fix it......\n");
}
}
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_liberal_dtmf")) && switch_true(val)) {
sofia_set_flag_locked(tech_pvt, TFLAG_LIBERAL_DTMF);
}
if ((m = sdp->sdp_media) &&
(m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive ||
(m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")))) {
sendonly = 2; /* global sendonly always wins */
}
for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
if (zstr(attr->a_name)) {
continue;
}
if (!strcasecmp(attr->a_name, "sendonly")) {
sendonly = 1;
switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "recvonly");
} else if (!strcasecmp(attr->a_name, "inactive")) {
sendonly = 1;
switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "inactive");
} else if (!strcasecmp(attr->a_name, "recvonly")) {
switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", "sendonly");
recvonly = 1;
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, 0);
tech_pvt->max_missed_hold_packets = 0;
tech_pvt->max_missed_packets = 0;
} else {
switch_channel_set_variable(tech_pvt->channel, "rtp_timeout_sec", "0");
switch_channel_set_variable(tech_pvt->channel, "rtp_hold_timeout_sec", "0");
}
} else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) {
sendonly = 0;
} else if (!strcasecmp(attr->a_name, "ptime")) {
dptime = atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "maxptime")) {
dmaxptime = atoi(attr->a_value);
}
}
if (sendonly != 1 && recvonly != 1) {
switch_channel_set_variable(tech_pvt->channel, "media_audio_mode", NULL);
}
2012-12-20 22:57:47 -06:00
if (sofia_test_media_flag(tech_pvt->profile, SCMF_DISABLE_HOLD) ||
2012-12-18 10:50:43 -06:00
((val = switch_channel_get_variable(tech_pvt->channel, "sip_disable_hold")) && switch_true(val))) {
sendonly = 0;
} else {
if (!tech_pvt->hold_laps) {
tech_pvt->hold_laps++;
2012-12-19 14:51:28 -06:00
if (sofia_media_toggle_hold(tech_pvt, sendonly)) {
2012-12-18 10:50:43 -06:00
reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD);
if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_hold"))) {
reneg = switch_true(val);
}
}
}
}
if (reneg) {
reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE);
if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_reinvite"))) {
reneg = switch_true(val);
}
}
if (!reneg && tech_pvt->num_negotiated_codecs) {
codec_array = tech_pvt->negotiated_codecs;
total_codecs = tech_pvt->num_negotiated_codecs;
} else if (reneg) {
tech_pvt->num_codecs = 0;
2012-12-19 14:51:28 -06:00
sofia_media_tech_prepare_codecs(tech_pvt);
2012-12-18 10:50:43 -06:00
codec_array = tech_pvt->codecs;
total_codecs = tech_pvt->num_codecs;
}
if (switch_stristr("T38FaxFillBitRemoval:", r_sdp) || switch_stristr("T38FaxTranscodingMMR:", r_sdp) ||
switch_stristr("T38FaxTranscodingJBIG:", r_sdp)) {
switch_channel_set_variable(tech_pvt->channel, "t38_broken_boolean", "true");
}
2012-12-20 22:57:47 -06:00
switch_core_media_find_zrtp_hash(session, sdp);
switch_core_media_pass_zrtp_hash(session);
2012-12-18 10:50:43 -06:00
for (m = sdp->sdp_media; m; m = m->m_next) {
sdp_connection_t *connection;
switch_core_session_t *other_session;
ptime = dptime;
maxptime = dmaxptime;
if (m->m_proto == sdp_proto_srtp) {
2012-12-18 22:02:19 -06:00
if (m->m_type == sdp_media_audio) {
got_savp++;
} else {
got_video_savp++;
}
2012-12-18 10:50:43 -06:00
} else if (m->m_proto == sdp_proto_rtp) {
2012-12-18 22:02:19 -06:00
if (m->m_type == sdp_media_audio) {
got_avp++;
} else {
got_video_avp++;
}
2012-12-18 10:50:43 -06:00
} else if (m->m_proto == sdp_proto_udptl) {
got_udptl++;
}
if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
2012-12-20 22:57:47 -06:00
switch_t38_options_t *t38_options = switch_core_media_process_udptl(tech_pvt->session, sdp, m);
2012-12-18 10:50:43 -06:00
if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_NEGOTIATED)) {
match = 1;
goto done;
}
if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) {
switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
match = 0;
goto done;
} else {
const char *var = switch_channel_get_variable(channel, "t38_passthru");
int pass = sofia_test_pflag(tech_pvt->profile, PFLAG_T38_PASSTHRU);
if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38)) {
sofia_set_flag(tech_pvt, TFLAG_NOREPLY);
}
if (var) {
if (!(pass = switch_true(var))) {
if (!strcasecmp(var, "once")) {
pass = 2;
}
}
}
if ((pass == 2 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU)) ||
!sofia_test_flag(tech_pvt, TFLAG_REINVITE) ||
switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) ||
switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) ||
!switch_rtp_ready(tech_pvt->rtp_session)) {
pass = 0;
}
if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
switch_core_session_message_t *msg;
char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
char tmp[32] = "";
if (switch_true(switch_channel_get_variable(tech_pvt->channel, "t38_broken_boolean")) &&
switch_true(switch_channel_get_variable(tech_pvt->channel, "t38_pass_broken_boolean"))) {
switch_channel_set_variable(other_channel, "t38_broken_boolean", "true");
}
tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, t38_options->remote_ip);
tech_pvt->remote_sdp_audio_port = t38_options->remote_port;
if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
switch_channel_get_name(tech_pvt->channel));
} else {
const char *err = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(tech_pvt->channel),
remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip,
tech_pvt->remote_sdp_audio_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
}
2012-12-19 14:51:28 -06:00
sofia_media_copy_t38_options(t38_options, other_session);
2012-12-18 10:50:43 -06:00
sofia_set_flag(tech_pvt, TFLAG_T38_PASSTHRU);
sofia_set_flag(other_tech_pvt, TFLAG_T38_PASSTHRU);
msg = switch_core_session_alloc(other_session, sizeof(*msg));
msg->message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA;
msg->from = __FILE__;
msg->string_arg = switch_core_session_strdup(other_session, r_sdp);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing T38 req to other leg.\n%s\n", r_sdp);
switch_core_session_queue_message(other_session, msg);
switch_core_session_rwunlock(other_session);
}
}
/* do nothing here, mod_fax will trigger a response (if it's listening =/) */
match = 1;
goto done;
} else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
sdp_rtpmap_t *map;
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
switch_channel_set_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port", attr->a_value);
} else if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
ptime = atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
maxptime = atoi(attr->a_value);
} else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) {
int crypto_tag;
2012-12-18 16:06:29 -06:00
if (!(tech_pvt->profile->ndlb & SM_NDLB_ALLOW_CRYPTO_IN_AVP) &&
2012-12-18 10:50:43 -06:00
!switch_true(switch_channel_get_variable(tech_pvt->channel, "sip_allow_crypto_in_avp"))) {
if (m->m_proto != sdp_proto_srtp) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n");
match = 0;
goto done;
}
}
crypto = attr->a_value;
crypto_tag = atoi(crypto);
got_crypto = switch_core_session_check_incoming_crypto(tech_pvt->session,
SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_MEDIA_TYPE_AUDIO, crypto, crypto_tag);
2012-12-18 10:50:43 -06:00
}
}
if (got_crypto && !got_avp) {
switch_channel_set_variable(tech_pvt->channel, SOFIA_CRYPTO_MANDATORY_VARIABLE, "true");
switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE, "true");
}
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
}
if (!connection) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
match = 0;
break;
}
greed:
x = 0;
if (tech_pvt->rm_encoding && !(sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) { // && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
char *remote_host = tech_pvt->remote_sdp_audio_ip;
switch_port_t remote_port = tech_pvt->remote_sdp_audio_port;
int same = 0;
if (switch_rtp_ready(tech_pvt->rtp_session)) {
remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
2012-12-18 16:06:29 -06:00
if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
2012-12-18 10:50:43 -06:00
match = (map->rm_pt == tech_pvt->pt) ? 1 : 0;
} else {
match = strcasecmp(switch_str_nil(map->rm_encoding), tech_pvt->iananame) ? 0 : 1;
}
if (match && connection->c_address && remote_host && !strcmp(connection->c_address, remote_host) && m->m_port == remote_port) {
same = 1;
} else {
same = 0;
break;
}
}
if (same) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Our existing sdp is still good [%s %s:%d], let's keep it.\n",
tech_pvt->rm_encoding, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
got_audio = 1;
} else {
match = 0;
got_audio = 0;
}
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
int32_t i;
uint32_t near_rate = 0;
const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
const char *rm_encoding;
uint32_t map_bit_rate = 0;
int codec_ms = 0;
switch_codec_fmtp_t codec_fmtp = { 0 };
if (x++ < skip) {
continue;
}
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
if (!strcasecmp(rm_encoding, "telephone-event")) {
if (!best_te || map->rm_rate == tech_pvt->rm_rate) {
best_te = (switch_payload_t) map->rm_pt;
}
}
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && !cng_pt && !strcasecmp(rm_encoding, "CN")) {
cng_pt = (switch_payload_t) map->rm_pt;
if (tech_pvt->rtp_session) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
}
}
if (match) {
continue;
}
if (greedy) {
first = mine;
last = first + 1;
} else {
first = 0;
last = tech_pvt->num_codecs;
}
codec_ms = ptime;
if (maxptime && (!codec_ms || codec_ms > maxptime)) {
codec_ms = maxptime;
}
if (!codec_ms) {
codec_ms = switch_default_ptime(rm_encoding, map->rm_pt);
}
map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
codec_ms = 30;
}
if (zstr(map->rm_fmtp)) {
if (!strcasecmp(map->rm_encoding, "ilbc")) {
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);
}
}
}
for (i = first; i < last && i < total_codecs; i++) {
const switch_codec_implementation_t *imp = codec_array[i];
uint32_t bit_rate = imp->bits_per_second;
uint32_t codec_rate = imp->samples_per_second;
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n",
rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate,
imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate);
2012-12-18 16:06:29 -06:00
if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
2012-12-18 10:50:43 -06:00
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
}
if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) {
/* if a bit rate is specified and doesn't match, this is not a codec match, except for ILBC */
match = 0;
}
if (match && map->rm_rate && codec_rate && map->rm_rate != codec_rate && (!strcasecmp(map->rm_encoding, "pcma") || !strcasecmp(map->rm_encoding, "pcmu"))) {
/* if the sampling rate is specified and doesn't match, this is not a codec match for G.711 */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sampling rates have to match for G.711\n");
match = 0;
}
if (match) {
if (scrooge) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Bah HUMBUG! Sticking with %s@%uh@%ui\n",
imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000);
} else {
if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) {
near_rate = map->rm_rate;
near_match = imp;
match = 0;
continue;
}
}
mimp = imp;
break;
}
}
if (!match && near_match) {
const switch_codec_implementation_t *search[1];
char *prefs[1];
char tmp[80];
int num;
switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui", near_match->iananame, near_rate ? near_rate : near_match->samples_per_second,
codec_ms);
prefs[0] = tmp;
num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
if (num) {
mimp = search[0];
} else {
mimp = near_match;
}
if (!maxptime || mimp->microseconds_per_packet / 1000 <= maxptime) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Substituting codec %s@%ui@%uh\n",
mimp->iananame, mimp->microseconds_per_packet / 1000, mimp->samples_per_second);
match = 1;
} else {
mimp = NULL;
match = 0;
}
}
if (!match && greedy) {
skip++;
continue;
}
if (mimp) {
char tmp[50];
2012-12-19 22:42:03 -06:00
const char *mirror = switch_channel_get_variable(tech_pvt->channel, "rtp_mirror_remote_audio_codec_payload");
2012-12-18 10:50:43 -06:00
tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding);
tech_pvt->iananame = switch_core_session_strdup(session, (char *) mimp->iananame);
tech_pvt->pt = (switch_payload_t) map->rm_pt;
tech_pvt->rm_rate = mimp->samples_per_second;
tech_pvt->codec_ms = mimp->microseconds_per_packet / 1000;
tech_pvt->bitrate = mimp->bits_per_second;
tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
tech_pvt->num_negotiated_codecs = 0;
tech_pvt->negotiated_codecs[tech_pvt->num_negotiated_codecs++] = mimp;
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
tech_pvt->audio_recv_pt = (switch_payload_t)map->rm_pt;
if (!switch_true(mirror) &&
switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND &&
(!sofia_test_flag(tech_pvt, TFLAG_REINVITE) || sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE))) {
2012-12-19 14:51:28 -06:00
sofia_media_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt);
2012-12-18 10:50:43 -06:00
}
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->audio_recv_pt);
2012-12-19 22:42:03 -06:00
switch_channel_set_variable(tech_pvt->channel, "rtp_audio_recv_pt", tmp);
2012-12-18 10:50:43 -06:00
}
if (match) {
2012-12-19 14:51:28 -06:00
if (sofia_media_tech_set_codec(tech_pvt, 1) == SWITCH_STATUS_SUCCESS) {
2012-12-18 10:50:43 -06:00
got_audio = 1;
} else {
match = 0;
}
}
}
if (!best_te && (sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"No 2833 in SDP. Liberal DTMF mode adding %d as telephone-event.\n", tech_pvt->profile->te);
best_te = tech_pvt->profile->te;
}
if (best_te) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
te = tech_pvt->te = (switch_payload_t) best_te;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", best_te);
if (tech_pvt->rtp_session) {
switch_rtp_set_telephony_event(tech_pvt->rtp_session, (switch_payload_t) best_te);
switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", best_te);
}
} else {
te = tech_pvt->recv_te = tech_pvt->te = (switch_payload_t) best_te;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send/recv payload to %u\n", te);
if (tech_pvt->rtp_session) {
switch_rtp_set_telephony_event(tech_pvt->rtp_session, te);
switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", te);
switch_rtp_set_telephony_recv_event(tech_pvt->rtp_session, te);
switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_recv_payload", "%d", te);
}
}
} else {
/* by default, use SIP INFO if 2833 is not in the SDP */
if (!switch_false(switch_channel_get_variable(channel, "sip_info_when_no_2833"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No 2833 in SDP. Disable 2833 dtmf and switch to INFO\n");
switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "info");
tech_pvt->dtmf_type = DTMF_INFO;
te = tech_pvt->recv_te = tech_pvt->te = 0;
} else {
switch_channel_set_variable(tech_pvt->channel, "dtmf_type", "none");
tech_pvt->dtmf_type = DTMF_NONE;
te = tech_pvt->recv_te = tech_pvt->te = 0;
}
}
if (!match && greedy && mine < total_codecs) {
mine++;
skip = 0;
goto greed;
}
} else if (m->m_type == sdp_media_video && m->m_port) {
sdp_rtpmap_t *map;
const char *rm_encoding;
const switch_codec_implementation_t *mimp = NULL;
int vmatch = 0, i;
switch_channel_set_variable(tech_pvt->channel, "video_possible", "true");
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
}
if (!connection) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
match = 0;
break;
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) {
//framerate = atoi(attr->a_value);
}
if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
switch_channel_set_variable(tech_pvt->channel, "sip_remote_video_rtcp_port", attr->a_value);
2012-12-18 22:02:19 -06:00
} else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) {
int crypto_tag;
if (!(tech_pvt->profile->ndlb & SM_NDLB_ALLOW_CRYPTO_IN_AVP) &&
!switch_true(switch_channel_get_variable(tech_pvt->channel, "sip_allow_crypto_in_avp"))) {
if (m->m_proto != sdp_proto_srtp) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n");
match = 0;
goto done;
}
}
crypto = attr->a_value;
crypto_tag = atoi(crypto);
got_video_crypto = switch_core_session_check_incoming_crypto(tech_pvt->session,
SOFIA_HAS_VIDEO_CRYPTO_VARIABLE,
SWITCH_MEDIA_TYPE_VIDEO, crypto, crypto_tag);
2012-12-18 10:50:43 -06:00
}
}
2012-12-18 22:02:19 -06:00
if (got_video_crypto && !got_video_avp) {
switch_channel_set_variable(tech_pvt->channel, SOFIA_CRYPTO_MANDATORY_VARIABLE, "true");
switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE, "true");
}
2012-12-18 10:50:43 -06:00
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
for (i = 0; i < total_codecs; i++) {
const switch_codec_implementation_t *imp = codec_array[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n",
rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
2012-12-18 16:06:29 -06:00
if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
2012-12-18 10:50:43 -06:00
vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
}
if (vmatch && (map->rm_rate == imp->samples_per_second)) {
mimp = imp;
break;
} else {
vmatch = 0;
}
}
if (mimp) {
if ((tech_pvt->video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
char tmp[50];
const char *mirror = switch_channel_get_variable(tech_pvt->channel, "sip_mirror_remote_video_codec_payload");
tech_pvt->video_pt = (switch_payload_t) map->rm_pt;
tech_pvt->video_rm_rate = map->rm_rate;
tech_pvt->video_codec_ms = mimp->microseconds_per_packet / 1000;
tech_pvt->remote_sdp_video_ip = switch_core_session_strdup(session, (char *) connection->c_address);
tech_pvt->video_rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
tech_pvt->remote_sdp_video_port = (switch_port_t) m->m_port;
tech_pvt->video_agreed_pt = (switch_payload_t) map->rm_pt;
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_video_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
switch_channel_set_variable(tech_pvt->channel, "sip_video_fmtp", tech_pvt->video_rm_fmtp);
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_agreed_pt);
switch_channel_set_variable(tech_pvt->channel, "sip_video_pt", tmp);
2012-12-19 14:51:28 -06:00
sofia_media_check_video_codecs(tech_pvt);
2012-12-18 10:50:43 -06:00
tech_pvt->video_recv_pt = (switch_payload_t)map->rm_pt;
if (!switch_true(mirror) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
2012-12-19 14:51:28 -06:00
sofia_media_get_offered_pt(tech_pvt, mimp, &tech_pvt->video_recv_pt);
2012-12-18 10:50:43 -06:00
}
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_recv_pt);
switch_channel_set_variable(tech_pvt->channel, "sip_video_recv_pt", tmp);
if (!match && vmatch) match = 1;
break;
} else {
vmatch = 0;
}
}
}
}
}
done:
if (parser) {
sdp_parser_free(parser);
}
tech_pvt->cng_pt = cng_pt;
sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
return match;
}
2012-12-20 22:57:47 -06:00
#endif
2012-12-18 10:50:43 -06:00
2012-12-18 16:06:29 -06:00
switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt)
2012-12-18 10:50:43 -06:00
{
const char *err = NULL;
const char *val = NULL;
2012-12-18 16:06:29 -06:00
switch_rtp_flag_t flags[SWITCH_RTP_FLAG_INVALID] = {0};
2012-12-18 10:50:43 -06:00
switch_status_t status = SWITCH_STATUS_SUCCESS;
char tmp[50];
uint32_t rtp_timeout_sec = tech_pvt->profile->rtp_timeout_sec;
uint32_t rtp_hold_timeout_sec = tech_pvt->profile->rtp_hold_timeout_sec;
char *timer_name = NULL;
const char *var;
uint32_t delay = tech_pvt->profile->rtp_digit_delay;
switch_assert(tech_pvt != NULL);
if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
return SWITCH_STATUS_FALSE;
}
switch_mutex_lock(tech_pvt->sofia_mutex);
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_reset_media_timer(tech_pvt->rtp_session);
}
if ((var = switch_channel_get_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
switch_channel_set_flag(tech_pvt->channel, CF_SECURE);
2012-12-18 10:50:43 -06:00
}
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
status = SWITCH_STATUS_SUCCESS;
goto end;
}
if (!sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
if (switch_rtp_ready(tech_pvt->rtp_session)) {
2012-12-20 22:57:47 -06:00
if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE) && !switch_rtp_ready(tech_pvt->video_rtp_session)) {
2012-12-18 10:50:43 -06:00
goto video;
}
status = SWITCH_STATUS_SUCCESS;
goto end;
}
}
2012-12-19 14:51:28 -06:00
if ((status = sofia_media_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
2012-12-18 10:50:43 -06:00
goto end;
}
2012-12-18 16:06:29 -06:00
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
2012-12-18 10:50:43 -06:00
2012-12-18 16:06:29 -06:00
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
2012-12-18 10:50:43 -06:00
}
2012-12-18 16:06:29 -06:00
2012-12-18 10:50:43 -06:00
if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_RFC2833)
|| ((val = switch_channel_get_variable(tech_pvt->channel, "pass_rfc2833")) && switch_true(val))) {
sofia_set_flag(tech_pvt, TFLAG_PASS_RFC2833);
}
if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFLUSH)
|| ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_autoflush")) && switch_true(val))) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_AUTOFLUSH]++;
2012-12-18 10:50:43 -06:00
}
if (!(sofia_test_pflag(tech_pvt->profile, PFLAG_REWRITE_TIMESTAMPS) ||
((val = switch_channel_get_variable(tech_pvt->channel, "rtp_rewrite_timestamps")) && switch_true(val)))) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_RAW_WRITE]++;
2012-12-18 10:50:43 -06:00
}
if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
tech_pvt->cng_pt = 0;
} else if (tech_pvt->cng_pt) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_AUTO_CNG]++;
2012-12-18 10:50:43 -06:00
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
if (!strcasecmp(tech_pvt->read_impl.iananame, "L16")) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_BYTESWAP]++;
2012-12-18 10:50:43 -06:00
}
#endif
2012-12-18 16:06:29 -06:00
if ((flags[SWITCH_RTP_FLAG_BYTESWAP]) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_byteswap")) && switch_true(val)) {
flags[SWITCH_RTP_FLAG_BYTESWAP] = 0;
2012-12-18 10:50:43 -06:00
}
if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
switch_channel_get_name(tech_pvt->channel));
if (switch_rtp_ready(tech_pvt->rtp_session)) {
if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"%s Set audio receive payload in Re-INVITE for non-matching dynamic PT to %u\n",
switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"%s Setting audio receive payload in Re-INVITE to %u\n",
switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
}
}
goto video;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(tech_pvt->channel),
remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
}
}
if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n",
switch_channel_get_name(tech_pvt->channel),
tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_audio_port,
tech_pvt->remote_sdp_audio_ip,
tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
} else {
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
}
}
}
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_audio_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->local_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
switch_channel_set_variable(tech_pvt->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
const char *rport = NULL;
switch_port_t remote_rtcp_port = 0;
if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) {
remote_rtcp_port = (switch_port_t)atoi(rport);
}
if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port,
remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
}
goto video;
}
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
sofia_glue_tech_proxy_remote_addr(tech_pvt, NULL);
2012-12-18 16:06:29 -06:00
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
2012-12-18 10:50:43 -06:00
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
2012-12-18 10:50:43 -06:00
}
timer_name = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_channel_get_name(tech_pvt->channel),
tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_audio_port,
tech_pvt->remote_sdp_audio_ip,
tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
}
} else {
timer_name = tech_pvt->profile->timer_name;
if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
timer_name = (char *) var;
}
}
if (switch_channel_up(tech_pvt->channel) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_audio_port,
tech_pvt->remote_sdp_audio_ip,
tech_pvt->remote_sdp_audio_port,
tech_pvt->agreed_pt,
tech_pvt->read_impl.samples_per_packet,
tech_pvt->codec_ms * 1000,
2012-12-18 16:06:29 -06:00
flags, timer_name, &err, switch_core_session_get_pool(tech_pvt->session));
2012-12-18 10:50:43 -06:00
}
if (switch_rtp_ready(tech_pvt->rtp_session)) {
uint8_t vad_in = sofia_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
uint8_t vad_out = sofia_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
uint8_t inb = sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
uint32_t stun_ping = 0;
const char *ssrc;
switch_core_media_set_rtp_session(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, tech_pvt->rtp_session);
2012-12-18 10:50:43 -06:00
if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_ssrc"))) {
uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
switch_rtp_set_ssrc(tech_pvt->rtp_session, ssrc_ul);
}
switch_channel_set_flag(tech_pvt->channel, CF_FS_RTP);
switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_pt", "%d", tech_pvt->agreed_pt);
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_in")) && switch_true(val)) {
vad_in = 1;
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_out")) && switch_true(val)) {
vad_out = 1;
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_in")) && switch_true(val)) {
vad_in = 0;
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_out")) && switch_true(val)) {
vad_out = 0;
}
if ((tech_pvt->stun_flags & STUN_FLAG_SET) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_stun_ping"))) {
int ival = atoi(val);
if (ival <= 0) {
if (switch_true(val)) {
ival = 6;
}
}
stun_ping = (ival * tech_pvt->read_impl.samples_per_second) / tech_pvt->read_impl.samples_per_packet;
}
tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_ssrc", "%u", tech_pvt->ssrc);
sofia_set_flag(tech_pvt, TFLAG_RTP);
sofia_set_flag(tech_pvt, TFLAG_IO);
if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_IGNORE_MARK_BIT) {
tech_pvt->rtp_bugs |= RTP_BUG_IGNORE_MARK_BIT;
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_rtp_bugs"))) {
2012-12-20 22:57:47 -06:00
switch_core_media_parse_rtp_bugs(&tech_pvt->rtp_bugs, val);
2012-12-18 10:50:43 -06:00
}
switch_rtp_intentional_bugs(tech_pvt->rtp_session, tech_pvt->rtp_bugs | tech_pvt->profile->manual_rtp_bugs);
if ((vad_in && inb) || (vad_out && !inb)) {
switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING | SWITCH_VAD_FLAG_EVENTS_TALK | SWITCH_VAD_FLAG_EVENTS_NOTALK);
sofia_set_flag(tech_pvt, TFLAG_VAD);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP Engage VAD for %s ( %s %s )\n",
switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
}
if (stun_ping) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Setting stun ping to %s:%d\n", tech_pvt->stun_ip,
stun_ping);
switch_rtp_activate_stun_ping(tech_pvt->rtp_session, tech_pvt->stun_ip, tech_pvt->stun_port, stun_ping,
(tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0);
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port");
switch_port_t remote_port = 0;
if (rport) {
remote_port = (switch_port_t)atoi(rport);
}
if (!strcasecmp(val, "passthru")) {
switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
} else {
int interval = atoi(val);
if (interval < 100 || interval > 5000) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
"Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
} else {
switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port);
}
}
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec")) || (val = tech_pvt->profile->jb_msec)) {
int jb_msec = atoi(val);
int maxlen = 0, max_drift = 0;
char *p, *q;
if ((p = strchr(val, ':'))) {
p++;
maxlen = atoi(p);
if ((q = strchr(p, ':'))) {
q++;
max_drift = abs(atoi(q));
}
}
if (jb_msec < 20 || jb_msec > 10000) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
"Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", jb_msec);
} else {
int qlen, maxqlen = 50;
qlen = jb_msec / (tech_pvt->read_impl.microseconds_per_packet / 1000);
if (qlen < 1) {
qlen = 3;
}
if (maxlen) {
maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
}
if (maxqlen < qlen) {
maxqlen = qlen * 5;
}
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
tech_pvt->read_impl.samples_per_packet,
tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER);
if (!switch_false(switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_plc"))) {
switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER_PLC);
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
}
}
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_timeout_sec"))) {
int v = atoi(val);
if (v >= 0) {
rtp_timeout_sec = v;
}
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_hold_timeout_sec"))) {
int v = atoi(val);
if (v >= 0) {
rtp_hold_timeout_sec = v;
}
}
if (rtp_timeout_sec) {
tech_pvt->max_missed_packets = (tech_pvt->read_impl.samples_per_second * rtp_timeout_sec) / tech_pvt->read_impl.samples_per_packet;
switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
if (!rtp_hold_timeout_sec) {
rtp_hold_timeout_sec = rtp_timeout_sec * 10;
}
}
if (rtp_hold_timeout_sec) {
tech_pvt->max_missed_hold_packets = (tech_pvt->read_impl.samples_per_second * rtp_hold_timeout_sec) / tech_pvt->read_impl.samples_per_packet;
}
if (tech_pvt->te) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", tech_pvt->te);
switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_send_payload", "%d", tech_pvt->te);
}
if (tech_pvt->recv_te) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set 2833 dtmf receive payload to %u\n", tech_pvt->recv_te);
switch_rtp_set_telephony_recv_event(tech_pvt->rtp_session, tech_pvt->recv_te);
switch_channel_set_variable_printf(tech_pvt->channel, "sip_2833_recv_payload", "%d", tech_pvt->recv_te);
}
if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
}
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))) {
tech_pvt->cng_pt = 0;
}
if (((val = switch_channel_get_variable(tech_pvt->channel, "rtp_digit_delay")))) {
int delayi = atoi(val);
if (delayi < 0) delayi = 0;
delay = (uint32_t) delayi;
}
if (delay) {
switch_rtp_set_interdigit_delay(tech_pvt->rtp_session, delay);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"%s Set rtp dtmf delay to %u\n", switch_channel_get_name(tech_pvt->channel), delay);
}
if (tech_pvt->cng_pt && !sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", tech_pvt->cng_pt);
switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
}
switch_core_session_apply_crypto(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE);
2012-12-18 10:50:43 -06:00
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "Activating ZRTP PROXY MODE\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Disable NOTIMER_DURING_BRIDGE\n");
sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Activating audio UDPTL mode\n");
switch_rtp_udptl_mode(tech_pvt->rtp_session);
}
video:
2012-12-19 14:51:28 -06:00
sofia_media_check_video_codecs(tech_pvt);
2012-12-18 10:50:43 -06:00
2012-12-20 22:57:47 -06:00
if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) {
2012-12-18 10:50:43 -06:00
/******************************************************************************************/
if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
char *remote_host = switch_rtp_get_remote_host(tech_pvt->video_rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->video_rtp_session);
if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_video_ip) && remote_port == tech_pvt->remote_sdp_video_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params are unchanged for %s.\n",
switch_channel_get_name(tech_pvt->channel));
goto video_up;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(tech_pvt->channel),
remote_host, remote_port, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
}
}
if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"VIDEO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n", switch_channel_get_name(tech_pvt->channel),
tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_video_port, tech_pvt->remote_sdp_video_ip,
tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
}
}
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_video_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
const char *rport = NULL;
switch_port_t remote_rtcp_port = 0;
sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port"))) {
remote_rtcp_port = (switch_port_t)atoi(rport);
}
if (switch_rtp_set_remote_address
(tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, remote_rtcp_port, SWITCH_TRUE,
&err) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n",
tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
}
goto video_up;
}
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
sofia_glue_tech_proxy_remote_addr(tech_pvt, NULL);
2012-12-18 16:06:29 -06:00
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
2012-12-18 10:50:43 -06:00
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
2012-12-18 10:50:43 -06:00
}
timer_name = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"PROXY VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_channel_get_name(tech_pvt->channel),
tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_video_port,
tech_pvt->remote_sdp_video_ip,
tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
}
} else {
timer_name = tech_pvt->profile->timer_name;
if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
timer_name = (char *) var;
}
}
/******************************************************************************************/
if (tech_pvt->video_rtp_session) {
goto video_up;
}
if (!tech_pvt->local_sdp_video_port) {
sofia_glue_tech_choose_video_port(tech_pvt, 1);
}
2012-12-18 16:06:29 -06:00
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
flags[SWITCH_RTP_FLAG_RAW_WRITE]++;
2012-12-18 10:50:43 -06:00
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
2012-12-18 10:50:43 -06:00
}
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
2012-12-18 10:50:43 -06:00
}
2012-12-19 14:51:28 -06:00
sofia_media_tech_set_video_codec(tech_pvt, 0);
2012-12-18 10:50:43 -06:00
2012-12-18 16:06:29 -06:00
flags[SWITCH_RTP_FLAG_USE_TIMER] = 0;
flags[SWITCH_RTP_FLAG_NOBLOCK] = 0;
flags[SWITCH_RTP_FLAG_VIDEO]++;
2012-12-18 10:50:43 -06:00
tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_video_port,
tech_pvt->remote_sdp_video_ip,
tech_pvt->remote_sdp_video_port,
tech_pvt->video_agreed_pt,
2012-12-18 16:06:29 -06:00
1, 90000, flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session));
2012-12-18 10:50:43 -06:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
switch_channel_get_name(tech_pvt->channel),
tech_pvt->local_sdp_audio_ip,
tech_pvt->local_sdp_video_port,
tech_pvt->remote_sdp_video_ip,
tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt,
0, switch_rtp_ready(tech_pvt->video_rtp_session) ? "SUCCESS" : err);
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
switch_core_media_set_rtp_session(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, tech_pvt->video_rtp_session);
2012-12-18 10:50:43 -06:00
}
if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
const char *ssrc;
switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_video_ssrc"))) {
uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
switch_rtp_set_ssrc(tech_pvt->video_rtp_session, ssrc_ul);
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_video_rtp_bugs"))) {
2012-12-20 22:57:47 -06:00
switch_core_media_parse_rtp_bugs(&tech_pvt->video_rtp_bugs, val);
2012-12-18 10:50:43 -06:00
}
switch_rtp_intentional_bugs(tech_pvt->video_rtp_session, tech_pvt->video_rtp_bugs | tech_pvt->profile->manual_video_rtp_bugs);
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);
}
switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_pt", "%d", tech_pvt->video_agreed_pt);
tech_pvt->video_ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_video_ssrc", "%u", tech_pvt->ssrc);
2012-12-18 22:02:19 -06:00
switch_core_session_apply_crypto(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, SOFIA_SECURE_VIDEO_CONFIRMED_VARIABLE);
2012-12-18 10:50:43 -06:00
if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec"))
|| (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port");
switch_port_t remote_port = 0;
if (rport) {
remote_port = (switch_port_t)atoi(rport);
}
if (!strcasecmp(val, "passthru")) {
switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
} else {
int interval = atoi(val);
if (interval < 100 || interval > 5000) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
"Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
} else {
switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port);
}
}
}
if (switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Activating video UDPTL mode\n");
switch_rtp_udptl_mode(tech_pvt->video_rtp_session);
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
goto end;
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
sofia_clear_flag_locked(tech_pvt, TFLAG_IO);
status = SWITCH_STATUS_FALSE;
goto end;
}
video_up:
sofia_set_flag(tech_pvt, TFLAG_IO);
status = SWITCH_STATUS_SUCCESS;
end:
sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
switch_core_recovery_track(tech_pvt->session);
switch_mutex_unlock(tech_pvt->sofia_mutex);
return status;
}
void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp)
{
sdp_parser_t *parser;
sdp_session_t *sdp;
private_object_t *tech_pvt = switch_core_session_get_private(session);
if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
if ((sdp = sdp_session(parser))) {
2012-12-19 22:42:03 -06:00
sofia_media_set_r_sdp_codec_string(session, switch_core_media_get_codec_string(tech_pvt->session), sdp);
2012-12-18 10:50:43 -06:00
}
sdp_parser_free(parser);
}
}
2012-12-19 14:47:04 -06:00
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);
}
2012-12-19 14:51:28 -06:00
void sofia_media_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp)
2012-12-19 14:47:04 -06:00
{
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;
}
}
2012-12-20 22:57:47 -06:00
switch_core_media_find_zrtp_hash(session, sdp);
switch_core_media_pass_zrtp_hash(session);
2012-12-19 14:47:04 -06:00
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);
}
}
2012-12-19 14:51:28 -06:00
switch_status_t sofia_media_tech_media(private_object_t *tech_pvt, const char *r_sdp)
2012-12-19 14:47:04 -06:00
{
uint8_t match = 0;
switch_assert(tech_pvt != NULL);
switch_assert(r_sdp != NULL);
if (zstr(r_sdp)) {
return SWITCH_STATUS_FALSE;
}
2012-12-19 14:51:28 -06:00
if ((match = sofia_media_negotiate_sdp(tech_pvt->session, r_sdp))) {
2012-12-19 14:47:04 -06:00
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;
}
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);
2012-12-20 22:57:47 -06:00
const char *local_sdp_audio_zrtp_hash;
2012-12-19 14:47:04 -06:00
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);
}
}
2012-12-20 22:57:47 -06:00
if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) ||
switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) && tech_pvt->te > 95) {
2012-12-19 14:47:04 -06:00
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);
}
2012-12-20 22:57:47 -06:00
local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE);
if (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", local_sdp_audio_zrtp_hash);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=zrtp-hash:%s\n", local_sdp_audio_zrtp_hash);
2012-12-19 14:47:04 -06:00
}
if (!zstr(sr)) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=%s\n", sr);
}
}
#define SDPBUFLEN 65536
2012-12-19 14:51:28 -06:00
void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch_port_t port, const char *sr, int force)
2012-12-19 14:47:04 -06:00
{
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);
2012-12-20 22:57:47 -06:00
const char *local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE);
const char *local_sdp_video_zrtp_hash = switch_core_media_get_zrtp_hash(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_TRUE);
2012-12-19 14:47:04 -06:00
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))) {
2012-12-19 14:51:28 -06:00
sofia_media_sdp_map(b_sdp, &map, &ptmap);
2012-12-19 14:47:04 -06:00
}
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);
2012-12-20 22:57:47 -06:00
if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) ||
switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) && tech_pvt->te > 95) {
2012-12-19 14:47:04 -06:00
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;
}
2012-12-20 22:57:47 -06:00
if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) ||
switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF))
2012-12-19 14:47:04 -06:00
&& 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);
}
2012-12-20 22:57:47 -06:00
if (local_sdp_audio_zrtp_hash) {
2012-12-19 14:47:04 -06:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n",
2012-12-20 22:57:47 -06:00
local_sdp_audio_zrtp_hash);
2012-12-19 14:47:04 -06:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n",
2012-12-20 22:57:47 -06:00
local_sdp_audio_zrtp_hash);
2012-12-19 14:47:04 -06:00
}
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);
}
}
}
}
}
2012-12-20 22:57:47 -06:00
if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE)) {
2012-12-19 14:47:04 -06:00
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) {
2012-12-19 14:51:28 -06:00
sofia_media_tech_set_video_codec(tech_pvt, 0);
2012-12-19 14:47:04 -06:00
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");
}
2012-12-20 22:57:47 -06:00
if (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", local_sdp_video_zrtp_hash);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", local_sdp_video_zrtp_hash);
2012-12-19 14:47:04 -06:00
}
}
}
if (map) {
switch_event_destroy(&map);
}
if (ptmap) {
switch_event_destroy(&ptmap);
}
2012-12-19 14:51:28 -06:00
sofia_media_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE);
2012-12-19 14:47:04 -06:00
switch_safe_free(buf);
}
2012-12-19 14:51:28 -06:00
void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt)
2012-12-19 14:47:04 -06:00
{
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"))) {
2012-12-19 22:42:03 -06:00
codec_string = switch_core_media_get_codec_string(tech_pvt->session);
2012-12-19 14:47:04 -06:00
}
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) {
2012-12-19 22:42:03 -06:00
char *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);
2012-12-19 14:47:04 -06:00
} else {
tech_pvt->num_codecs = switch_loadable_module_get_codecs(tech_pvt->codecs, sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
}
}
2012-12-19 22:42:03 -06:00
2012-12-19 14:51:28 -06:00
void sofia_media_tech_patch_sdp(private_object_t *tech_pvt)
2012-12-19 14:47:04 -06:00
{
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)) {
2012-12-20 22:57:47 -06:00
switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE);
2012-12-19 14:47:04 -06:00
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);
2012-12-19 14:51:28 -06:00
sofia_media_tech_set_local_sdp(tech_pvt, new_sdp, SWITCH_FALSE);
2012-12-19 14:47:04 -06:00
}
2012-12-19 14:51:28 -06:00
void sofia_media_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup)
2012-12-19 14:47:04 -06:00
{
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);
}
2012-12-19 14:51:28 -06:00
char *sofia_media_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type)
2012-12-19 14:47:04 -06:00
{
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;
}
2012-12-18 10:50:43 -06:00
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/