freeswitch/src/mod/endpoints/mod_sofia/sofia_media.c

851 lines
22 KiB
C
Raw Normal View History

2012-12-18 16:50:43 +00: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 20:51:28 +00:00
void sofia_media_tech_absorb_sdp(private_object_t *tech_pvt)
2012-12-18 16:50:43 +00: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 20:51:28 +00:00
sofia_media_tech_set_local_sdp(tech_pvt, sdp_str, SWITCH_TRUE);
2012-12-18 16:50:43 +00:00
}
}
2012-12-19 20:51:28 +00:00
void sofia_media_proxy_codec(switch_core_session_t *session, const char *r_sdp)
2012-12-18 16:50:43 +00: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-21 20:22:25 +00:00
switch_core_media_set_codec(tech_pvt->session, 0, tech_pvt->profile->codec_flags);
2012-12-18 16:50:43 +00:00
break;
}
break;
}
}
sdp_parser_free(parser);
}
2012-12-21 04:57:47 +00:00
uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp)
2012-12-18 16:50:43 +00:00
{
2012-12-21 04:57:47 +00:00
uint8_t t, p = 0;
2012-12-18 16:50:43 +00:00
private_object_t *tech_pvt = switch_core_session_get_private(session);
2012-12-21 04:57:47 +00: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 16:50:43 +00:00
}
2012-12-21 04:57:47 +00:00
if (!p) {
sofia_set_flag(tech_pvt, TFLAG_NOREPLY);
2012-12-18 16:50:43 +00:00
}
2012-12-21 04:57:47 +00:00
return t;
2012-12-18 16:50:43 +00:00
}
2012-12-18 22:06:29 +00:00
switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt)
2012-12-18 16:50:43 +00:00
{
2012-12-21 20:22:25 +00:00
int ok;
2012-12-18 16:50:43 +00:00
switch_mutex_lock(tech_pvt->sofia_mutex);
2012-12-21 20:22:25 +00:00
switch_mutex_unlock(tech_pvt->sofia_mutex);
2012-12-18 16:50:43 +00:00
2012-12-21 20:22:25 +00:00
if (ok) {
2012-12-18 16:50:43 +00:00
sofia_set_flag(tech_pvt, TFLAG_RTP);
sofia_set_flag(tech_pvt, TFLAG_IO);
}
}
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-20 04:42:03 +00:00
sofia_media_set_r_sdp_codec_string(session, switch_core_media_get_codec_string(tech_pvt->session), sdp);
2012-12-18 16:50:43 +00:00
}
sdp_parser_free(parser);
}
}
2012-12-19 20:47:04 +00: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 20:51:28 +00: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 20:47:04 +00: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-21 04:57:47 +00:00
switch_core_media_find_zrtp_hash(session, sdp);
switch_core_media_pass_zrtp_hash(session);
2012-12-19 20:47:04 +00: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 20:51:28 +00:00
switch_status_t sofia_media_tech_media(private_object_t *tech_pvt, const char *r_sdp)
2012-12-19 20:47:04 +00: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 20:51:28 +00:00
if ((match = sofia_media_negotiate_sdp(tech_pvt->session, r_sdp))) {
2012-12-19 20:47:04 +00: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;
}
2012-12-19 20:51:28 +00:00
void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt)
2012-12-19 20:47:04 +00: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-20 04:42:03 +00:00
codec_string = switch_core_media_get_codec_string(tech_pvt->session);
2012-12-19 20:47:04 +00: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-20 04:42:03 +00: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 20:47:04 +00: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-20 04:42:03 +00:00
2012-12-19 20:51:28 +00:00
void sofia_media_tech_patch_sdp(private_object_t *tech_pvt)
2012-12-19 20:47:04 +00: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;
2012-12-22 00:21:20 +00:00
if (zstr(tech_pvt->local_sdp_str)) {
2012-12-19 20:47:04 +00:00
return;
}
2012-12-22 00:21:20 +00:00
len = strlen(tech_pvt->local_sdp_str) * 2;
2012-12-19 20:47:04 +00:00
if (switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) &&
2012-12-22 00:21:20 +00:00
(switch_stristr("sendonly", tech_pvt->local_sdp_str) || switch_stristr("0.0.0.0", tech_pvt->local_sdp_str))) {
2012-12-19 20:47:04 +00:00
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);
2012-12-22 00:21:20 +00:00
p = tech_pvt->local_sdp_str;
2012-12-19 20:47:04 +00:00
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-21 04:57:47 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE);
2012-12-19 20:47:04 +00: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",
2012-12-22 00:21:20 +00:00
switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str);
2012-12-19 20:47:04 +00:00
return;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s Patched SDP\n---\n%s\n+++\n%s\n",
2012-12-22 00:21:20 +00:00
switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str, new_sdp);
2012-12-19 20:47:04 +00:00
2012-12-19 20:51:28 +00:00
sofia_media_tech_set_local_sdp(tech_pvt, new_sdp, SWITCH_FALSE);
2012-12-19 20:47:04 +00:00
}
2012-12-19 20:51:28 +00:00
char *sofia_media_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type)
2012-12-19 20:47:04 +00: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 16:50:43 +00: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:
*/