freeswitch/src/switch_core_media.c

10924 lines
346 KiB
C
Raw Normal View History

2012-12-18 16:50:43 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
2014-02-05 21:02:28 +00:00
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
2012-12-18 16:50:43 +00:00
*
* 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>
*
* switch_core_media.c -- Core Media
*
*/
#include <switch.h>
#include <switch_ssl.h>
#include <switch_stun.h>
#include <switch_nat.h>
#include "private/switch_core_pvt.h"
#include <switch_curl.h>
#include <errno.h>
2013-01-26 18:52:36 +00:00
#include <sofia-sip/sdp.h>
#include <sofia-sip/su.h>
2012-12-18 16:50:43 +00:00
static switch_t38_options_t * switch_core_media_process_udptl(switch_core_session_t *session, sdp_session_t *sdp, sdp_media_t *m);
static void switch_core_media_find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp);
static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp, switch_sdp_type_t sdp_type);
2015-03-24 00:56:19 +00:00
static void gen_ice(switch_core_session_t *session, switch_media_type_t type, const char *ip, switch_port_t port);
2013-04-03 20:41:22 +00:00
//#define GOOGLE_ICE
#define RTCP_MUX
2012-12-21 04:57:47 +00:00
#define MAX_CODEC_CHECK_FRAMES 50//x:mod_sofia.h
#define MAX_MISMATCH_FRAMES 5//x:mod_sofia.h
#define type2str(type) type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio"
#define VIDEO_REFRESH_FREQ 1000000
2012-12-21 04:57:47 +00:00
2012-12-18 22:06:29 +00:00
typedef enum {
2012-12-22 17:51:03 +00:00
SMF_INIT = (1 << 0),
SMF_READY = (1 << 1),
SMF_JB_PAUSED = (1 << 2)
2012-12-18 22:06:29 +00:00
} smh_flag_t;
2012-12-18 16:50:43 +00:00
typedef struct secure_settings_s {
int crypto_tag;
unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
switch_rtp_crypto_key_type_t crypto_type;
char *local_crypto_key;
char *remote_crypto_key;
} switch_secure_settings_t;
2012-12-21 20:22:25 +00:00
2012-12-21 04:57:47 +00:00
struct media_helper {
switch_core_session_t *session;
switch_thread_cond_t *cond;
switch_mutex_t *cond_mutex;
switch_mutex_t *file_mutex;
int up;
};
typedef enum {
CRYPTO_MODE_OPTIONAL,
CRYPTO_MODE_MANDATORY,
CRYPTO_MODE_FORBIDDEN
} switch_rtp_crypto_mode_t;
2013-11-07 22:48:00 +00:00
typedef struct switch_rtp_engine_s {
switch_secure_settings_t ssec[CRYPTO_INVALID+1];
switch_rtp_crypto_key_type_t crypto_type;
switch_media_type_t type;
2012-12-21 04:57:47 +00:00
switch_rtp_t *rtp_session;
switch_frame_t read_frame;
switch_codec_t read_codec;
switch_codec_t write_codec;
switch_codec_implementation_t read_impl;
switch_codec_implementation_t write_impl;
switch_size_t last_ts;
switch_size_t last_seq;
uint32_t check_frames;
uint32_t mismatch_count;
uint32_t last_codec_ms;
uint8_t codec_reinvites;
uint32_t max_missed_packets;
uint32_t max_missed_hold_packets;
2012-12-21 20:22:25 +00:00
uint32_t ssrc;
2013-07-11 22:38:24 +00:00
uint32_t remote_ssrc;
2013-01-15 05:17:28 +00:00
switch_port_t remote_rtcp_port;
2012-12-21 20:22:25 +00:00
switch_rtp_bug_flag_t rtp_bugs;
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
char *local_sdp_ip;
switch_port_t local_sdp_port;
char *adv_sdp_ip;
switch_port_t adv_sdp_port;
char *proxy_sdp_ip;
switch_port_t proxy_sdp_port;
2012-12-21 04:57:47 +00:00
/** ZRTP **/
char *local_sdp_zrtp_hash;
char *remote_sdp_zrtp_hash;
2013-11-07 22:48:00 +00:00
payload_map_t *cur_payload_map;
payload_map_t *payload_map;
payload_map_t *pmap_tail;
2012-12-21 04:57:47 +00:00
2012-12-21 20:22:25 +00:00
uint32_t timestamp_send;
2012-12-21 04:57:47 +00:00
2013-01-14 02:12:23 +00:00
char *cand_acl[SWITCH_MAX_CAND_ACL];
int cand_acl_count;
2013-01-10 04:31:25 +00:00
ice_t ice_in;
ice_t ice_out;
2013-01-17 01:04:57 +00:00
int8_t rtcp_mux;
2013-02-01 20:29:40 +00:00
dtls_fingerprint_t local_dtls_fingerprint;
dtls_fingerprint_t remote_dtls_fingerprint;
char *remote_rtp_ice_addr;
switch_port_t remote_rtp_ice_port;
char *remote_rtcp_ice_addr;
switch_port_t remote_rtcp_ice_port;
struct media_helper mh;
switch_thread_t *media_thread;
2015-03-03 17:44:20 +00:00
2013-02-01 20:29:40 +00:00
2013-11-07 22:48:00 +00:00
uint8_t reset_codec;
uint8_t codec_negotiated;
2013-11-20 20:38:16 +00:00
uint8_t fir;
uint8_t pli;
uint8_t nack;
2015-05-14 23:01:22 +00:00
uint8_t tmmbr;
uint8_t no_crypto;
switch_codec_settings_t codec_settings;
switch_media_flow_t rmode;
switch_media_flow_t smode;
switch_thread_id_t thread_id;
} switch_rtp_engine_t;
2012-12-18 22:06:29 +00:00
struct switch_media_handle_s {
switch_core_session_t *session;
2012-12-20 04:42:03 +00:00
switch_channel_t *channel;
2012-12-21 04:57:47 +00:00
switch_core_media_flag_t media_flags[SCMF_MAX];
2012-12-18 22:06:29 +00:00
smh_flag_t flags;
switch_rtp_engine_t engines[SWITCH_MEDIA_TYPE_TOTAL];
2015-03-03 17:44:20 +00:00
switch_mutex_t *read_mutex[2];
switch_mutex_t *write_mutex[2];
char *codec_order[SWITCH_MAX_CODECS];
int codec_order_last;
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
int payload_space;
char *origin;
2012-12-22 17:51:03 +00:00
2013-06-19 02:16:48 +00:00
switch_mutex_t *mutex;
switch_mutex_t *sdp_mutex;
switch_mutex_t *control_mutex;
2012-12-22 23:34:08 +00:00
const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS];
int num_negotiated_codecs;
switch_payload_t ianacodes[SWITCH_MAX_CODECS];
2015-07-30 23:11:08 +00:00
switch_payload_t dtmf_ianacodes[SWITCH_MAX_CODECS];
switch_payload_t cng_ianacodes[SWITCH_MAX_CODECS];
char *fmtps[SWITCH_MAX_CODECS];
int video_count;
2012-12-21 04:57:47 +00:00
int rates[SWITCH_MAX_CODECS];
uint32_t num_rates;
2012-12-21 22:57:59 +00:00
uint32_t owner_id;
uint32_t session_id;
2012-12-21 20:22:25 +00:00
switch_core_media_params_t *mparams;
char *msid;
char *cname;
switch_rtp_crypto_mode_t crypto_mode;
switch_rtp_crypto_key_type_t crypto_suite_order[CRYPTO_INVALID+1];
switch_time_t video_last_key_time;
switch_time_t video_init;
switch_time_t last_codec_refresh;
switch_time_t last_video_refresh_req;
switch_timer_t video_timer;
switch_video_function_t video_function;
void *video_user_data;
int8_t video_function_running;
switch_vid_params_t vid_params;
switch_file_handle_t *video_read_fh;
switch_file_handle_t *video_write_fh;
uint64_t vid_frames;
time_t vid_started;
int ready_loops;
2012-12-18 22:06:29 +00:00
};
2012-12-18 16:50:43 +00:00
2014-02-25 23:02:47 +00:00
static switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
{ "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44},
{ "AEAD_AES_128_GCM_8", AEAD_AES_128_GCM_8, 28},
2014-02-25 23:02:47 +00:00
{ "AES_CM_256_HMAC_SHA1_80", AES_CM_256_HMAC_SHA1_80, 46},
{ "AES_CM_192_HMAC_SHA1_80", AES_CM_192_HMAC_SHA1_80, 38},
{ "AES_CM_128_HMAC_SHA1_80", AES_CM_128_HMAC_SHA1_80, 30},
{ "AES_CM_256_HMAC_SHA1_32", AES_CM_256_HMAC_SHA1_32, 46},
{ "AES_CM_192_HMAC_SHA1_32", AES_CM_192_HMAC_SHA1_32, 38},
{ "AES_CM_128_HMAC_SHA1_32", AES_CM_128_HMAC_SHA1_32, 30},
{ "AES_CM_128_NULL_AUTH", AES_CM_128_NULL_AUTH, 30}
2014-02-25 23:02:47 +00:00
};
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str)
{
int i;
for (i = 0; i < CRYPTO_INVALID; i++) {
if (!strncasecmp(str, SUITES[i].name, strlen(SUITES[i].name))) {
return SUITES[i].type;
}
}
return CRYPTO_INVALID;
}
SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto_key_type_t type)
{
switch_assert(type < CRYPTO_INVALID);
return SUITES[type].name;
}
SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type)
{
switch_assert(type < CRYPTO_INVALID);
return SUITES[type].keylen;
}
static inline switch_media_flow_t sdp_media_flow(unsigned in)
{
switch(in) {
case sdp_sendonly:
return SWITCH_MEDIA_FLOW_SENDONLY;
case sdp_recvonly:
return SWITCH_MEDIA_FLOW_RECVONLY;
case sdp_sendrecv:
return SWITCH_MEDIA_FLOW_SENDRECV;
case sdp_inactive:
return SWITCH_MEDIA_FLOW_INACTIVE;
}
return SWITCH_MEDIA_FLOW_SENDRECV;
}
2014-02-25 23:02:47 +00:00
2013-10-28 22:44:24 +00:00
static int get_channels(const char *name, int dft)
{
if (!zstr(name) && !switch_true(switch_core_get_variable("NDLB_broken_opus_sdp")) && !strcasecmp(name, "opus")) {
return 2; /* IKR???*/
}
2013-10-28 22:44:24 +00:00
return dft ? dft : 1;
}
2012-12-21 04:57:47 +00:00
static void _switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session, switch_media_type_t type)
{
switch_rtp_engine_t *aleg_engine;
switch_rtp_engine_t *bleg_engine;
2013-04-03 14:02:08 +00:00
if (!aleg_session->media_handle || !bleg_session->media_handle) return;
2012-12-21 04:57:47 +00:00
aleg_engine = &aleg_session->media_handle->engines[type];
bleg_engine = &bleg_session->media_handle->engines[type];
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG1,
"Deciding whether to pass zrtp-hash between a-leg and b-leg\n");
if (!(switch_channel_test_flag(aleg_session->channel, CF_ZRTP_PASSTHRU_REQ))) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG1,
"CF_ZRTP_PASSTHRU_REQ not set on a-leg, so not propagating zrtp-hash\n");
return;
}
if (aleg_engine->remote_sdp_zrtp_hash) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (audio) to b-leg\n");
bleg_engine->local_sdp_zrtp_hash = switch_core_session_strdup(bleg_session, aleg_engine->remote_sdp_zrtp_hash);
switch_channel_set_variable(bleg_session->channel, "l_sdp_audio_zrtp_hash", bleg_engine->local_sdp_zrtp_hash);
}
if (bleg_engine->remote_sdp_zrtp_hash) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (audio) to a-leg\n");
aleg_engine->local_sdp_zrtp_hash = switch_core_session_strdup(aleg_session, bleg_engine->remote_sdp_zrtp_hash);
switch_channel_set_variable(aleg_session->channel, "l_sdp_audio_zrtp_hash", aleg_engine->local_sdp_zrtp_hash);
}
}
SWITCH_DECLARE(uint32_t) switch_core_media_get_video_fps(switch_core_session_t *session)
{
switch_media_handle_t *smh;
time_t now;
uint32_t fps;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
return 0;
}
now = switch_epoch_time_now(NULL);
if (!(smh->vid_started && smh->vid_frames && smh->vid_started < now)) {
return 0;
}
fps = switch_round_to_step(smh->vid_frames / (now - smh->vid_started), 5);
if (fps < 15) fps = 15;
smh->vid_started = switch_epoch_time_now(NULL);
smh->vid_frames = 1;
return fps;
}
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session)
{
_switch_core_media_pass_zrtp_hash2(aleg_session, bleg_session, SWITCH_MEDIA_TYPE_AUDIO);
_switch_core_media_pass_zrtp_hash2(aleg_session, bleg_session, SWITCH_MEDIA_TYPE_VIDEO);
}
SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_core_session_t *other_session;
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between legs\n");
if (!(switch_channel_test_flag(channel, CF_ZRTP_PASSTHRU_REQ))) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set, so not propagating zrtp-hash\n");
return;
} else if (!(switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS)) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "No partner channel found, so not propagating zrtp-hash\n");
return;
} else {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Found peer channel; propagating zrtp-hash if set\n");
switch_core_media_pass_zrtp_hash2(session, other_session);
switch_core_session_rwunlock(other_session);
}
}
SWITCH_DECLARE(const char *) switch_core_media_get_zrtp_hash(switch_core_session_t *session, switch_media_type_t type, switch_bool_t local)
{
switch_rtp_engine_t *engine;
if (!session->media_handle) return NULL;
engine = &session->media_handle->engines[type];
if (local) {
return engine->local_sdp_zrtp_hash;
}
return engine->remote_sdp_zrtp_hash;
}
static void switch_core_media_find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp)
2012-12-21 04:57:47 +00:00
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_rtp_engine_t *audio_engine;
switch_rtp_engine_t *video_engine;
sdp_media_t *m;
sdp_attribute_t *attr;
int got_audio = 0, got_video = 0;
if (!session->media_handle) return;
audio_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO];
video_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Looking for zrtp-hash\n");
for (m = sdp->sdp_media; m; m = m->m_next) {
if (got_audio && got_video) break;
if (m->m_port && ((m->m_type == sdp_media_audio && !got_audio)
|| (m->m_type == sdp_media_video && !got_video))) {
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (zstr(attr->a_name)) continue;
if (strcasecmp(attr->a_name, "zrtp-hash") || !(attr->a_value)) continue;
if (m->m_type == sdp_media_audio) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
"Found audio zrtp-hash; setting r_sdp_audio_zrtp_hash=%s\n", attr->a_value);
switch_channel_set_variable(channel, "r_sdp_audio_zrtp_hash", attr->a_value);
audio_engine->remote_sdp_zrtp_hash = switch_core_session_strdup(session, attr->a_value);
got_audio++;
} else if (m->m_type == sdp_media_video) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
"Found video zrtp-hash; setting r_sdp_video_zrtp_hash=%s\n", attr->a_value);
switch_channel_set_variable(channel, "r_sdp_video_zrtp_hash", attr->a_value);
video_engine->remote_sdp_zrtp_hash = switch_core_session_strdup(session, attr->a_value);
got_video++;
}
switch_channel_set_flag(channel, CF_ZRTP_HASH);
break;
}
}
}
}
static switch_t38_options_t * switch_core_media_process_udptl(switch_core_session_t *session, sdp_session_t *sdp, sdp_media_t *m)
2012-12-21 04:57:47 +00:00
{
switch_t38_options_t *t38_options = switch_channel_get_private(session->channel, "t38_options");
sdp_attribute_t *attr;
switch_assert(sdp);
2012-12-21 04:57:47 +00:00
if (!t38_options) {
t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t));
// set some default value
t38_options->T38FaxVersion = 0;
t38_options->T38MaxBitRate = 14400;
t38_options->T38FaxRateManagement = switch_core_session_strdup(session, "transferredTCF");
t38_options->T38FaxUdpEC = switch_core_session_strdup(session, "t38UDPRedundancy");
t38_options->T38FaxMaxBuffer = 500;
t38_options->T38FaxMaxDatagram = 500;
}
t38_options->remote_port = (switch_port_t)m->m_port;
if (sdp->sdp_origin) {
t38_options->sdp_o_line = switch_core_session_strdup(session, sdp->sdp_origin->o_username);
} else {
t38_options->sdp_o_line = "unknown";
}
if (m->m_connections && m->m_connections->c_address) {
t38_options->remote_ip = switch_core_session_strdup(session, m->m_connections->c_address);
} else if (sdp->sdp_connection && sdp->sdp_connection->c_address) {
2012-12-21 04:57:47 +00:00
t38_options->remote_ip = switch_core_session_strdup(session, sdp->sdp_connection->c_address);
}
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "T38FaxVersion") && attr->a_value) {
t38_options->T38FaxVersion = (uint16_t) atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) {
t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) {
t38_options->T38FaxFillBitRemoval = switch_safe_atoi(attr->a_value, 1);
} else if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) {
t38_options->T38FaxTranscodingMMR = switch_safe_atoi(attr->a_value, 1);
} else if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) {
t38_options->T38FaxTranscodingJBIG = switch_safe_atoi(attr->a_value, 1);
} else if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) {
t38_options->T38FaxRateManagement = switch_core_session_strdup(session, attr->a_value);
} else if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) {
t38_options->T38FaxMaxBuffer = (uint32_t) atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "T38FaxMaxDatagram") && attr->a_value) {
t38_options->T38FaxMaxDatagram = (uint32_t) atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "T38FaxUdpEC") && attr->a_value) {
t38_options->T38FaxUdpEC = switch_core_session_strdup(session, attr->a_value);
} else if (!strcasecmp(attr->a_name, "T38VendorInfo") && attr->a_value) {
t38_options->T38VendorInfo = switch_core_session_strdup(session, attr->a_value);
}
}
switch_channel_set_variable(session->channel, "has_t38", "true");
switch_channel_set_private(session->channel, "t38_options", t38_options);
switch_channel_set_app_flag_key("T38", session->channel, CF_APP_T38);
switch_channel_execute_on(session->channel, "sip_execute_on_image");
switch_channel_api_on(session->channel, "sip_api_on_image");
return t38_options;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_check_autoadj(switch_core_session_t *session)
{
switch_rtp_engine_t *a_engine;
switch_rtp_engine_t *v_engine;
switch_media_handle_t *smh;
const char *val;
int x = 0;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) &&
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val)) &&
2015-01-12 17:34:42 +00:00
!switch_channel_test_flag(session->channel, CF_AVPF)) {
/* Reactivate the NAT buster flag. */
if (a_engine->rtp_session) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
x++;
}
if (v_engine->rtp_session) {
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
x++;
}
}
2012-12-21 04:57:47 +00:00
return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_get_vid_params(switch_core_session_t *session, switch_vid_params_t *vid_params)
{
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
2012-12-21 04:57:47 +00:00
*vid_params = smh->vid_params;
return SWITCH_STATUS_SUCCESS;
}
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(switch_t38_options_t *) switch_core_media_extract_t38_options(switch_core_session_t *session, const char *r_sdp)
{
sdp_media_t *m;
sdp_parser_t *parser = NULL;
sdp_session_t *sdp;
switch_t38_options_t *t38_options = NULL;
if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
2012-12-21 20:22:25 +00:00
return NULL;
2012-12-21 04:57:47 +00:00
}
if (!(sdp = sdp_session(parser))) {
sdp_parser_free(parser);
2012-12-21 20:22:25 +00:00
return NULL;
2012-12-21 04:57:47 +00:00
}
for (m = sdp->sdp_media; m; m = m->m_next) {
if (m->m_proto == sdp_proto_udptl && m->m_type == sdp_media_image && m->m_port) {
t38_options = switch_core_media_process_udptl(session, sdp, m);
break;
}
}
sdp_parser_free(parser);
return t38_options;
}
2012-12-21 22:57:59 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_process_t38_passthru(switch_core_session_t *session,
switch_core_session_t *other_session, switch_t38_options_t *t38_options)
{
char *remote_host;
switch_port_t remote_port;
char tmp[32] = "";
switch_rtp_engine_t *a_engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 22:57:59 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
2012-12-21 22:57:59 +00:00
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
remote_host = switch_rtp_get_remote_host(a_engine->rtp_session);
remote_port = switch_rtp_get_remote_port(a_engine->rtp_session);
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(session, t38_options->remote_ip);
a_engine->cur_payload_map->remote_sdp_port = t38_options->remote_port;
2012-12-21 22:57:59 +00:00
2013-11-07 22:48:00 +00:00
if (remote_host && remote_port && !strcmp(remote_host, a_engine->cur_payload_map->remote_sdp_ip) &&
remote_port == a_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 22:57:59 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Audio params are unchanged for %s.\n",
switch_channel_get_name(session->channel));
} else {
const char *err = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Audio params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
remote_host, remote_port, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port);
2012-12-21 22:57:59 +00:00
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip);
2012-12-21 22:57:59 +00:00
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
2013-11-07 22:48:00 +00:00
if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
2012-12-21 22:57:59 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
}
switch_core_media_copy_t38_options(t38_options, other_session);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core_session_t *session,
switch_media_type_t type,
const char *iananame,
uint32_t rate,
switch_payload_t *ptP,
switch_payload_t *recv_ptP,
char **fmtpP)
{
payload_map_t *pmap;
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
switch_payload_t pt = 0, recv_pt = 0;
int found = 0;
char *fmtp = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
engine = &smh->engines[type];
switch_mutex_lock(smh->sdp_mutex);
for (pmap = engine->payload_map; pmap ; pmap = pmap->next) {
if (!pmap->allocated) continue;
if (!strcasecmp(pmap->iananame, iananame) && (!rate || (rate == pmap->rate))) {
pt = pmap->pt;
recv_pt = pmap->recv_pt;
fmtp = pmap->rm_fmtp;
found++;
2013-11-25 18:08:17 +00:00
break;
}
}
2013-11-10 17:11:37 +00:00
switch_mutex_unlock(smh->sdp_mutex);
if (found) {
if (ptP) {
*ptP = pt;
}
if (recv_ptP) {
*recv_ptP = recv_pt;
}
if (!zstr(fmtp) && fmtpP) {
*fmtpP = fmtp;
}
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
2012-12-21 22:57:59 +00:00
2013-11-07 22:48:00 +00:00
SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_session_t *session,
switch_media_type_t type,
const char *name,
const char *modname,
2013-11-18 19:43:30 +00:00
const char *fmtp,
2013-11-07 22:48:00 +00:00
switch_sdp_type_t sdp_type,
uint32_t pt,
uint32_t rate,
2014-06-13 05:49:10 +00:00
uint32_t ptime,
uint32_t channels,
2013-11-07 22:48:00 +00:00
uint8_t negotiated)
{
payload_map_t *pmap;
int exists = 0;
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
2013-11-22 03:55:45 +00:00
int local_pt = 0;
2013-11-07 22:48:00 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return NULL;
}
engine = &smh->engines[type];
switch_mutex_lock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
for (pmap = engine->payload_map; pmap && pmap->allocated; pmap = pmap->next) {
exists = (!strcasecmp(name, pmap->iananame) && pmap->pt == pt && (!pmap->rate || rate == pmap->rate) && (!pmap->ptime || pmap->ptime == ptime));
2013-11-22 03:55:45 +00:00
2013-11-07 22:48:00 +00:00
if (exists) {
2013-11-20 17:00:29 +00:00
if (!zstr(fmtp) && !zstr(pmap->rm_fmtp)) {
if (strcmp(pmap->rm_fmtp, fmtp)) {
exists = 0;
2013-11-22 03:55:45 +00:00
local_pt = pmap->pt;
2013-11-20 17:00:29 +00:00
continue;
}
}
2013-11-07 22:48:00 +00:00
break;
}
}
if (!exists) {
switch_ssize_t hlen = -1;
2013-11-07 22:48:00 +00:00
if (engine->payload_map && !engine->payload_map->allocated) {
pmap = engine->payload_map;
} else {
pmap = switch_core_alloc(session->pool, sizeof(*pmap));
}
pmap->type = type;
pmap->iananame = switch_core_strdup(session->pool, name);
pmap->rm_encoding = pmap->iananame;
pmap->hash = switch_ci_hashfunc_default(pmap->iananame, &hlen);
2014-06-13 05:49:10 +00:00
pmap->channels = 1;
}
pmap->sdp_type = sdp_type;
if (ptime) {
2013-11-07 22:48:00 +00:00
pmap->ptime = ptime;
}
if (rate) {
2013-11-07 22:48:00 +00:00
pmap->rate = rate;
}
2014-06-13 05:49:10 +00:00
if (channels) {
pmap->channels = channels;
}
if (modname) {
pmap->modname = switch_core_strdup(session->pool, modname);
}
2013-11-22 03:55:45 +00:00
if (!zstr(fmtp) && (zstr(pmap->rm_fmtp) || strcmp(pmap->rm_fmtp, fmtp))) {
2013-11-18 19:43:30 +00:00
pmap->rm_fmtp = switch_core_strdup(session->pool, fmtp);
}
2013-11-07 22:48:00 +00:00
pmap->allocated = 1;
2013-11-22 03:55:45 +00:00
pmap->recv_pt = (switch_payload_t) pt;
2013-11-07 22:48:00 +00:00
if (sdp_type == SDP_TYPE_REQUEST || !exists) {
2013-11-22 03:55:45 +00:00
pmap->pt = (switch_payload_t) (local_pt ? local_pt : pt);
2013-11-07 22:48:00 +00:00
}
if (negotiated) {
pmap->negotiated = negotiated;
}
if (!exists) {
if (pmap == engine->payload_map) {
engine->pmap_tail = pmap;
} else if (!engine->payload_map) {
engine->payload_map = engine->pmap_tail = pmap;
} else {
engine->pmap_tail->next = pmap;
engine->pmap_tail = engine->pmap_tail->next;
}
}
switch_mutex_unlock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
return pmap;
}
2012-12-21 22:57:59 +00:00
2012-12-21 04:57:47 +00:00
2012-12-20 04:42:03 +00:00
SWITCH_DECLARE(const char *)switch_core_media_get_codec_string(switch_core_session_t *session)
{
const char *preferred = NULL, *fallback = NULL;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-20 04:42:03 +00:00
if (!(smh = session->media_handle)) {
preferred = "PCMU";
fallback = "PCMU";
} else {
if (!(preferred = switch_channel_get_variable(session->channel, "absolute_codec_string"))) {
preferred = switch_channel_get_variable(session->channel, "codec_string");
}
2012-12-20 04:42:03 +00:00
if (!preferred) {
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
2012-12-21 20:22:25 +00:00
preferred = smh->mparams->outbound_codec_string;
fallback = smh->mparams->inbound_codec_string;
2012-12-20 04:42:03 +00:00
} else {
2012-12-21 20:22:25 +00:00
preferred = smh->mparams->inbound_codec_string;
fallback = smh->mparams->outbound_codec_string;
2012-12-20 04:42:03 +00:00
}
}
}
return !zstr(preferred) ? preferred : fallback;
}
2013-10-15 21:24:32 +00:00
SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session)
{
int i;
switch_media_handle_t *smh;
const char *vars[] = { "rtp_last_audio_local_crypto_key",
"srtp_remote_audio_crypto_key",
"srtp_remote_audio_crypto_tag",
"srtp_remote_audio_crypto_type",
2013-10-15 21:24:32 +00:00
"srtp_remote_video_crypto_key",
"srtp_remote_video_crypto_tag",
"srtp_remote_video_crypto_type",
2013-10-15 21:24:32 +00:00
"rtp_secure_media",
"rtp_secure_media_inbound",
"rtp_secure_media_outbound",
2013-10-15 21:24:32 +00:00
NULL};
for(i = 0; vars[i] ;i++) {
switch_channel_set_variable(session->channel, vars[i], NULL);
}
if (!(smh = session->media_handle)) {
return;
}
for (i = 0; i < CRYPTO_INVALID; i++) {
memset(&smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec[i], 0, sizeof(smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec[i]));
memset(&smh->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec[i], 0, sizeof(smh->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec[i]));
}
2013-10-15 21:24:32 +00:00
}
2012-12-18 16:50:43 +00:00
2012-12-19 02:40:00 +00:00
SWITCH_DECLARE(const char *) switch_core_session_local_crypto_key(switch_core_session_t *session, switch_media_type_t type)
{
if (!session->media_handle) {
return NULL;
}
return session->media_handle->engines[type].ssec[session->media_handle->engines[type].crypto_type].local_crypto_key;
}
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(void) switch_core_media_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str)
{
if (switch_stristr("clear", str)) {
*flag_pole = 0;
}
if (switch_stristr("CISCO_SKIP_MARK_BIT_2833", str)) {
*flag_pole |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
}
if (switch_stristr("~CISCO_SKIP_MARK_BIT_2833", str)) {
*flag_pole &= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
}
if (switch_stristr("SONUS_SEND_INVALID_TIMESTAMP_2833", str)) {
*flag_pole |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
}
if (switch_stristr("~SONUS_SEND_INVALID_TIMESTAMP_2833", str)) {
*flag_pole &= ~RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
}
if (switch_stristr("IGNORE_MARK_BIT", str)) {
*flag_pole |= RTP_BUG_IGNORE_MARK_BIT;
}
if (switch_stristr("~IGNORE_MARK_BIT", str)) {
*flag_pole &= ~RTP_BUG_IGNORE_MARK_BIT;
}
if (switch_stristr("SEND_LINEAR_TIMESTAMPS", str)) {
*flag_pole |= RTP_BUG_SEND_LINEAR_TIMESTAMPS;
}
if (switch_stristr("~SEND_LINEAR_TIMESTAMPS", str)) {
*flag_pole &= ~RTP_BUG_SEND_LINEAR_TIMESTAMPS;
}
if (switch_stristr("START_SEQ_AT_ZERO", str)) {
*flag_pole |= RTP_BUG_START_SEQ_AT_ZERO;
}
if (switch_stristr("~START_SEQ_AT_ZERO", str)) {
*flag_pole &= ~RTP_BUG_START_SEQ_AT_ZERO;
}
if (switch_stristr("NEVER_SEND_MARKER", str)) {
*flag_pole |= RTP_BUG_NEVER_SEND_MARKER;
}
if (switch_stristr("~NEVER_SEND_MARKER", str)) {
*flag_pole &= ~RTP_BUG_NEVER_SEND_MARKER;
}
if (switch_stristr("IGNORE_DTMF_DURATION", str)) {
*flag_pole |= RTP_BUG_IGNORE_DTMF_DURATION;
}
if (switch_stristr("~IGNORE_DTMF_DURATION", str)) {
*flag_pole &= ~RTP_BUG_IGNORE_DTMF_DURATION;
}
if (switch_stristr("ACCEPT_ANY_PACKETS", str)) {
*flag_pole |= RTP_BUG_ACCEPT_ANY_PACKETS;
}
if (switch_stristr("~ACCEPT_ANY_PACKETS", str)) {
*flag_pole &= ~RTP_BUG_ACCEPT_ANY_PACKETS;
}
2013-07-29 15:18:05 +00:00
if (switch_stristr("ACCEPT_ANY_PAYLOAD", str)) {
*flag_pole |= RTP_BUG_ACCEPT_ANY_PAYLOAD;
}
if (switch_stristr("~ACCEPT_ANY_PAYLOAD", str)) {
*flag_pole &= ~RTP_BUG_ACCEPT_ANY_PAYLOAD;
}
2012-12-21 04:57:47 +00:00
if (switch_stristr("GEN_ONE_GEN_ALL", str)) {
*flag_pole |= RTP_BUG_GEN_ONE_GEN_ALL;
}
if (switch_stristr("~GEN_ONE_GEN_ALL", str)) {
*flag_pole &= ~RTP_BUG_GEN_ONE_GEN_ALL;
}
if (switch_stristr("CHANGE_SSRC_ON_MARKER", str)) {
*flag_pole |= RTP_BUG_CHANGE_SSRC_ON_MARKER;
}
if (switch_stristr("~CHANGE_SSRC_ON_MARKER", str)) {
*flag_pole &= ~RTP_BUG_CHANGE_SSRC_ON_MARKER;
}
if (switch_stristr("FLUSH_JB_ON_DTMF", str)) {
*flag_pole |= RTP_BUG_FLUSH_JB_ON_DTMF;
}
if (switch_stristr("~FLUSH_JB_ON_DTMF", str)) {
*flag_pole &= ~RTP_BUG_FLUSH_JB_ON_DTMF;
}
if (switch_stristr("ALWAYS_AUTO_ADJUST", str)) {
*flag_pole |= (RTP_BUG_ALWAYS_AUTO_ADJUST | RTP_BUG_ACCEPT_ANY_PACKETS);
}
if (switch_stristr("~ALWAYS_AUTO_ADJUST", str)) {
*flag_pole &= ~(RTP_BUG_ALWAYS_AUTO_ADJUST | RTP_BUG_ACCEPT_ANY_PACKETS);
}
2012-12-21 04:57:47 +00:00
}
static switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh,
switch_media_type_t type,
2013-05-17 20:39:21 +00:00
int index, switch_rtp_crypto_key_type_t ctype, switch_rtp_crypto_direction_t direction, int force)
{
unsigned char b64_key[512] = "";
unsigned char *key;
const char *val;
switch_channel_t *channel;
char *p;
switch_rtp_engine_t *engine;
switch_assert(smh);
channel = switch_core_session_get_channel(smh->session);
engine = &smh->engines[type];
if (!force && engine->ssec[ctype].local_raw_key[0]) {
2013-05-17 20:39:21 +00:00
return SWITCH_STATUS_SUCCESS;
}
2014-02-25 23:02:47 +00:00
2013-01-18 04:39:32 +00:00
//#define SAME_KEY
#ifdef SAME_KEY
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(channel, CF_AVPF) && type == SWITCH_MEDIA_TYPE_VIDEO) {
if (direction == SWITCH_RTP_CRYPTO_SEND) {
memcpy(engine->ssec[ctype].local_raw_key, smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec.local_raw_key, SUITES[ctype].keylen);
key = engine->ssec[ctype].local_raw_key;
} else {
memcpy(engine->ssec[ctype].remote_raw_key, smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec.remote_raw_key, SUITES[ctype].keylen);
key = engine->ssec[ctype].remote_raw_key;
}
} else {
#endif
if (direction == SWITCH_RTP_CRYPTO_SEND) {
key = engine->ssec[ctype].local_raw_key;
} else {
key = engine->ssec[ctype].remote_raw_key;
}
2014-02-25 23:02:47 +00:00
switch_rtp_get_random(key, SUITES[ctype].keylen);
#ifdef SAME_KEY
}
#endif
2014-02-25 23:02:47 +00:00
switch_b64_encode(key, SUITES[ctype].keylen, b64_key, sizeof(b64_key));
p = strrchr((char *) b64_key, '=');
while (p && *p && *p == '=') {
*p-- = '\0';
}
if (!index) index = ctype + 1;
engine->ssec[ctype].local_crypto_key = switch_core_session_sprintf(smh->session, "%d %s inline:%s", index, SUITES[ctype].name, b64_key);
switch_channel_set_variable_name_printf(smh->session->channel, engine->ssec[ctype].local_crypto_key, "rtp_last_%s_local_crypto_key", type2str(type));
2014-03-06 16:49:43 +00:00
switch_channel_set_flag(smh->session->channel, CF_SECURE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Set Local %s crypto Key [%s]\n",
type2str(type),
engine->ssec[ctype].local_crypto_key);
2012-12-21 20:22:25 +00:00
if (!(smh->mparams->ndlb & SM_NDLB_DISABLE_SRTP_AUTH) &&
!((val = switch_channel_get_variable(channel, "NDLB_support_asterisk_missing_srtp_auth")) && switch_true(val))) {
engine->ssec[ctype].crypto_type = ctype;
} else {
engine->ssec[ctype].crypto_type = AES_CM_128_NULL_AUTH;
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t switch_core_media_add_crypto(switch_secure_settings_t *ssec, const char *key_str, switch_rtp_crypto_direction_t direction)
{
unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
switch_rtp_crypto_key_type_t type;
char *p;
p = strchr(key_str, ' ');
if (p && *p && *(p + 1)) {
p++;
2014-02-25 23:02:47 +00:00
type = switch_core_media_crypto_str2type(p);
2014-02-25 23:02:47 +00:00
if (type == CRYPTO_INVALID) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
goto bad;
}
p = strchr(p, ' ');
if (p && *p && *(p + 1)) {
p++;
if (strncasecmp(p, "inline:", 7)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
goto bad;
}
p += 7;
switch_b64_decode(p, (char *) key, sizeof(key));
if (direction == SWITCH_RTP_CRYPTO_SEND) {
2014-02-25 23:02:47 +00:00
memcpy(ssec->local_raw_key, key, SUITES[type].keylen);
} else {
2014-02-25 23:02:47 +00:00
memcpy(ssec->remote_raw_key, key, SUITES[type].keylen);
}
return SWITCH_STATUS_SUCCESS;
}
}
bad:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error!\n");
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *session, switch_media_type_t type, switch_rtp_t *rtp_session)
{
switch_rtp_engine_t *engine;
if (!session->media_handle) return;
engine = &session->media_handle->engines[type];
engine->rtp_session = rtp_session;
2012-12-20 04:42:03 +00:00
engine->type = type;
}
2013-05-17 20:39:21 +00:00
static void switch_core_session_get_recovery_crypto_key(switch_core_session_t *session, switch_media_type_t type)
{
const char *tmp;
switch_rtp_engine_t *engine;
char *keyvar, *tagvar, *ctypevar;
2013-05-17 20:39:21 +00:00
if (!session->media_handle) return;
engine = &session->media_handle->engines[type];
2013-05-17 20:39:21 +00:00
if (type == SWITCH_MEDIA_TYPE_AUDIO) {
keyvar = "srtp_remote_audio_crypto_key";
tagvar = "srtp_remote_audio_crypto_tag";
ctypevar = "srtp_remote_audio_crypto_type";
2013-05-17 20:39:21 +00:00
} else {
keyvar = "srtp_remote_video_crypto_key";
tagvar = "srtp_remote_video_crypto_tag";
ctypevar = "srtp_remote_video_crypto_type";
2013-05-17 20:39:21 +00:00
}
if ((tmp = switch_channel_get_variable(session->channel, keyvar))) {
if ((tmp = switch_channel_get_variable(session->channel, ctypevar))) {
engine->crypto_type = switch_core_media_crypto_str2type(tmp);
}
engine->ssec[engine->crypto_type].remote_crypto_key = switch_core_session_strdup(session, tmp);
2013-05-17 20:39:21 +00:00
if ((tmp = switch_channel_get_variable(session->channel, tagvar))) {
int tv = atoi(tmp);
engine->ssec[engine->crypto_type].crypto_tag = tv;
2013-05-17 20:39:21 +00:00
} else {
engine->ssec[engine->crypto_type].crypto_tag = 1;
2013-05-17 20:39:21 +00:00
}
switch_channel_set_flag(session->channel, CF_SECURE);
}
}
2013-05-17 20:39:21 +00:00
static void switch_core_session_apply_crypto(switch_core_session_t *session, switch_media_type_t type)
{
switch_rtp_engine_t *engine;
2013-05-17 20:39:21 +00:00
const char *varname;
if (type == SWITCH_MEDIA_TYPE_AUDIO) {
varname = "rtp_secure_audio_confirmed";
} else {
varname = "rtp_secure_video_confirmed";
}
if (!session->media_handle) return;
engine = &session->media_handle->engines[type];
2013-05-17 20:39:21 +00:00
if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
return;
}
if (engine->ssec[engine->crypto_type].remote_crypto_key && switch_channel_test_flag(session->channel, CF_SECURE)) {
switch_core_media_add_crypto(&engine->ssec[engine->crypto_type], engine->ssec[engine->crypto_type].remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1,
engine->ssec[engine->crypto_type].crypto_type,
engine->ssec[engine->crypto_type].local_raw_key,
SUITES[engine->ssec[engine->crypto_type].crypto_type].keylen);
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV,
engine->ssec[engine->crypto_type].crypto_tag,
engine->ssec[engine->crypto_type].crypto_type,
engine->ssec[engine->crypto_type].remote_raw_key,
SUITES[engine->ssec[engine->crypto_type].crypto_type].keylen);
switch_channel_set_variable(session->channel, varname, "true");
switch_channel_set_variable(session->channel, "rtp_secure_media_negotiated", SUITES[engine->crypto_type].name);
}
}
static void switch_core_session_parse_crypto_prefs(switch_core_session_t *session)
{
const char *var = NULL;
const char *val = NULL;
char *suites = NULL;
switch_media_handle_t *smh;
char *fields[CRYPTO_INVALID+1];
int argc = 0, i = 0, j = 0, k = 0;
if (!(smh = session->media_handle)) {
return;
}
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
return;
}
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
var = "rtp_secure_media_inbound";
} else {
var = "rtp_secure_media_outbound";
}
if (!(val = switch_channel_get_variable(session->channel, var))) {
var = "rtp_secure_media";
val = switch_channel_get_variable(session->channel, var);
}
if (!zstr(val) && (suites = strchr(val, ':'))) {
*suites++ = '\0';
}
if (zstr(suites)) {
suites = (char *) switch_channel_get_variable(session->channel, "rtp_secure_media_suites");
}
if (zstr(val)) {
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(session->channel, CF_RECOVERING)) {
val = "optional";
} else {
val = "forbidden";
}
}
if (!strcasecmp(val, "optional")) {
smh->crypto_mode = CRYPTO_MODE_OPTIONAL;
} else if (switch_true(val) || !strcasecmp(val, "mandatory")) {
smh->crypto_mode = CRYPTO_MODE_MANDATORY;
} else {
smh->crypto_mode = CRYPTO_MODE_FORBIDDEN;
if (!switch_false(val) && strcasecmp(val, "forbidden")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "INVALID VALUE FOR %s defaulting to 'forbidden'\n", var);
}
}
if (smh->crypto_mode != CRYPTO_MODE_FORBIDDEN && !zstr(suites)) {
argc = switch_split((char *)suites, ':', fields);
for (i = 0; i < argc; i++) {
int ok = 0;
for (j = 0; j < CRYPTO_INVALID; j++) {
if (!strcasecmp(fields[i], SUITES[j].name)) {
smh->crypto_suite_order[k++] = SUITES[j].type;
ok++;
break;
}
}
if (!ok) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "INVALID SUITE SUPPLIED\n");
}
}
} else {
for (i = 0; i < CRYPTO_INVALID; i++) {
smh->crypto_suite_order[k++] = SUITES[i].type;
}
}
}
SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_session_t *session,
const char *varname,
2013-05-17 20:39:21 +00:00
switch_media_type_t type, const char *crypto, int crypto_tag, switch_sdp_type_t sdp_type)
{
int got_crypto = 0;
2014-02-25 23:02:47 +00:00
int i = 0;
int ctype = 0;
const char *vval = NULL;
switch_rtp_engine_t *engine;
switch_media_handle_t *smh;
if (!(smh = session->media_handle)) {
return 0;
2014-02-25 23:02:47 +00:00
}
if (smh->crypto_mode == CRYPTO_MODE_FORBIDDEN) {
return -1;
2014-02-25 23:02:47 +00:00
}
2015-03-24 00:56:19 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
return 0;
}
engine = &session->media_handle->engines[type];
for (i = 0; smh->crypto_suite_order[i] != CRYPTO_INVALID; i++) {
switch_rtp_crypto_key_type_t j = SUITES[smh->crypto_suite_order[i]].type;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,"looking for crypto suite [%s] in [%s]\n", SUITES[j].name, crypto);
if (switch_stristr(SUITES[j].name, crypto)) {
ctype = SUITES[j].type;
vval = SUITES[j].name;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Found suite %s\n", vval);
switch_channel_set_variable(session->channel, "rtp_secure_media_negotiated", vval);
2014-02-25 23:02:47 +00:00
break;
}
}
if (engine->ssec[engine->crypto_type].remote_crypto_key && switch_rtp_ready(engine->rtp_session)) {
/* Compare all the key. The tag may remain the same even if key changed */
if (crypto && engine->crypto_type != CRYPTO_INVALID && !strcmp(crypto, engine->ssec[engine->crypto_type].remote_crypto_key)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Existing key is still valid.\n");
2014-02-25 23:02:47 +00:00
got_crypto = 1;
} else {
const char *a = switch_stristr("AE", engine->ssec[engine->crypto_type].remote_crypto_key);
2014-02-25 23:02:47 +00:00
const char *b = switch_stristr("AE", crypto);
2013-05-17 20:39:21 +00:00
if (sdp_type == SDP_TYPE_REQUEST) {
2014-02-25 23:02:47 +00:00
if (!vval) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Unsupported Crypto [%s]\n", crypto);
2014-02-25 23:02:47 +00:00
goto end;
2013-05-17 20:39:21 +00:00
}
2014-02-25 23:02:47 +00:00
switch_channel_set_variable(session->channel, varname, vval);
switch_core_media_build_crypto(session->media_handle, type, crypto_tag, ctype, SWITCH_RTP_CRYPTO_SEND, 1);
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), engine->ssec[engine->crypto_type].crypto_type,
engine->ssec[engine->crypto_type].local_raw_key, SUITES[ctype].keylen);
}
if (a && b && !strncasecmp(a, b, 23)) {
engine->crypto_type = ctype;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto);
engine->ssec[engine->crypto_type].remote_crypto_key = switch_core_session_strdup(session, crypto);
if (engine->type == SWITCH_MEDIA_TYPE_AUDIO) {
switch_channel_set_variable(session->channel, "srtp_remote_audio_crypto_key", crypto);
switch_channel_set_variable_printf(session->channel, "srtp_remote_audio_crypto_tag", "%d", crypto_tag);
switch_channel_set_variable_printf(session->channel, "srtp_remote_audio_crypto_type", "%s", switch_core_media_crypto_type2str(ctype));
} else if (engine->type == SWITCH_MEDIA_TYPE_VIDEO) {
switch_channel_set_variable(session->channel, "srtp_remote_video_crypto_key", crypto);
switch_channel_set_variable_printf(session->channel, "srtp_remote_video_crypto_tag", "%d", crypto_tag);
switch_channel_set_variable_printf(session->channel, "srtp_remote_video_crypto_type", "%s", switch_core_media_crypto_type2str(ctype));
}
engine->ssec[engine->crypto_type].crypto_tag = crypto_tag;
2013-02-02 06:15:09 +00:00
if (switch_rtp_ready(engine->rtp_session) && switch_channel_test_flag(session->channel, CF_SECURE)) {
switch_core_media_add_crypto(&engine->ssec[engine->crypto_type], engine->ssec[engine->crypto_type].remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec[engine->crypto_type].crypto_tag,
engine->ssec[engine->crypto_type].crypto_type, engine->ssec[engine->crypto_type].remote_raw_key, SUITES[engine->ssec[engine->crypto_type].crypto_type].keylen);
}
got_crypto++;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring unacceptable key\n");
}
}
} else if (!switch_rtp_ready(engine->rtp_session)) {
2014-02-25 23:02:47 +00:00
if (!vval) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Unsupported Crypto [%s]\n", crypto);
2014-02-25 23:02:47 +00:00
goto end;
}
engine->crypto_type = ctype;
engine->ssec[engine->crypto_type].remote_crypto_key = switch_core_session_strdup(session, crypto);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", engine->ssec[engine->crypto_type].remote_crypto_key);
if (engine->type == SWITCH_MEDIA_TYPE_AUDIO) {
switch_channel_set_variable(session->channel, "srtp_remote_audio_crypto_key", crypto);
switch_channel_set_variable_printf(session->channel, "srtp_remote_audio_crypto_type", "%s", switch_core_media_crypto_type2str(ctype));
} else if (engine->type == SWITCH_MEDIA_TYPE_VIDEO) {
switch_channel_set_variable(session->channel, "srtp_remote_video_crypto_key", crypto);
switch_channel_set_variable_printf(session->channel, "srtp_remote_video_crypto_type", "%s", switch_core_media_crypto_type2str(ctype));
}
engine->ssec[engine->crypto_type].crypto_tag = crypto_tag;
got_crypto++;
2014-02-25 23:02:47 +00:00
switch_channel_set_variable(session->channel, varname, vval);
2014-03-06 16:49:43 +00:00
switch_channel_set_flag(smh->session->channel, CF_SECURE);
if (zstr(engine->ssec[engine->crypto_type].local_crypto_key)) {
2014-02-25 23:02:47 +00:00
switch_core_media_build_crypto(session->media_handle, type, crypto_tag, ctype, SWITCH_RTP_CRYPTO_SEND, 1);
}
2014-02-25 23:02:47 +00:00
}
end:
return got_crypto;
}
SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_handle_t *smh;
int i;
2013-02-02 06:15:09 +00:00
if (!switch_core_session_media_handle_ready(session) == SWITCH_STATUS_SUCCESS) {
return;
}
if (!(smh = session->media_handle)) {
return;
}
if (!(smh->crypto_mode == CRYPTO_MODE_OPTIONAL || smh->crypto_mode == CRYPTO_MODE_MANDATORY)) {
return;
}
2015-03-24 00:56:19 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
return;
}
switch_channel_set_flag(channel, CF_SECURE);
for (i = 0; smh->crypto_suite_order[i] != CRYPTO_INVALID; i++) {
switch_core_media_build_crypto(session->media_handle,
SWITCH_MEDIA_TYPE_AUDIO, 0, smh->crypto_suite_order[i], SWITCH_RTP_CRYPTO_SEND, 0);
switch_core_media_build_crypto(session->media_handle,
SWITCH_MEDIA_TYPE_VIDEO, 0, smh->crypto_suite_order[i], SWITCH_RTP_CRYPTO_SEND, 0);
}
}
#define add_stat(_i, _s) \
switch_snprintf(var_name, sizeof(var_name), "rtp_%s_%s", switch_str_nil(prefix), _s) ; \
switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \
switch_channel_set_variable(channel, var_name, var_val)
#define add_stat_double(_i, _s) \
switch_snprintf(var_name, sizeof(var_name), "rtp_%s_%s", switch_str_nil(prefix), _s) ; \
switch_snprintf(var_val, sizeof(var_val), "%0.2f", _i); \
switch_channel_set_variable(channel, var_name, var_val)
static void set_stats(switch_core_session_t *session, switch_media_type_t type, const char *prefix)
{
switch_rtp_stats_t *stats = switch_core_media_get_stats(session, type, NULL);
switch_channel_t *channel = switch_core_session_get_channel(session);
char var_name[256] = "", var_val[35] = "";
if (stats) {
stats->inbound.std_deviation = sqrt(stats->inbound.variance);
add_stat(stats->inbound.raw_bytes, "in_raw_bytes");
add_stat(stats->inbound.media_bytes, "in_media_bytes");
add_stat(stats->inbound.packet_count, "in_packet_count");
add_stat(stats->inbound.media_packet_count, "in_media_packet_count");
add_stat(stats->inbound.skip_packet_count, "in_skip_packet_count");
add_stat(stats->inbound.jb_packet_count, "in_jitter_packet_count");
add_stat(stats->inbound.dtmf_packet_count, "in_dtmf_packet_count");
add_stat(stats->inbound.cng_packet_count, "in_cng_packet_count");
add_stat(stats->inbound.flush_packet_count, "in_flush_packet_count");
add_stat(stats->inbound.largest_jb_size, "in_largest_jb_size");
add_stat_double(stats->inbound.min_variance, "in_jitter_min_variance");
add_stat_double(stats->inbound.max_variance, "in_jitter_max_variance");
add_stat_double(stats->inbound.lossrate, "in_jitter_loss_rate");
add_stat_double(stats->inbound.burstrate, "in_jitter_burst_rate");
add_stat_double(stats->inbound.mean_interval, "in_mean_interval");
add_stat(stats->inbound.flaws, "in_flaw_total");
add_stat_double(stats->inbound.R, "in_quality_percentage");
add_stat_double(stats->inbound.mos, "in_mos");
add_stat(stats->outbound.raw_bytes, "out_raw_bytes");
add_stat(stats->outbound.media_bytes, "out_media_bytes");
add_stat(stats->outbound.packet_count, "out_packet_count");
add_stat(stats->outbound.media_packet_count, "out_media_packet_count");
add_stat(stats->outbound.skip_packet_count, "out_skip_packet_count");
add_stat(stats->outbound.dtmf_packet_count, "out_dtmf_packet_count");
add_stat(stats->outbound.cng_packet_count, "out_cng_packet_count");
add_stat(stats->rtcp.packet_count, "rtcp_packet_count");
add_stat(stats->rtcp.octet_count, "rtcp_octet_count");
}
}
SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session)
{
if (!session->media_handle) {
return;
}
set_stats(session, SWITCH_MEDIA_TYPE_AUDIO, "audio");
set_stats(session, SWITCH_MEDIA_TYPE_VIDEO, "video");
}
2012-12-22 23:34:08 +00:00
SWITCH_DECLARE(void) switch_media_handle_destroy(switch_core_session_t *session)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine, *v_engine;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 23:34:08 +00:00
if (!(smh = session->media_handle)) {
return;
}
2012-12-22 23:34:08 +00:00
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (smh->video_timer.timer_interface) {
switch_core_timer_destroy(&smh->video_timer);
}
2012-12-22 23:34:08 +00:00
if (switch_core_codec_ready(&a_engine->read_codec)) {
switch_core_codec_destroy(&a_engine->read_codec);
}
if (switch_core_codec_ready(&a_engine->write_codec)) {
switch_core_codec_destroy(&a_engine->write_codec);
}
if (switch_core_codec_ready(&v_engine->read_codec)) {
switch_core_codec_destroy(&v_engine->read_codec);
}
if (switch_core_codec_ready(&v_engine->write_codec)) {
switch_core_codec_destroy(&v_engine->write_codec);
}
switch_core_session_unset_read_codec(session);
switch_core_session_unset_write_codec(session);
switch_core_media_deactivate_rtp(session);
2012-12-22 23:34:08 +00:00
}
2012-12-21 20:22:25 +00:00
SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t **smhp, switch_core_session_t *session, switch_core_media_params_t *params)
2012-12-18 22:06:29 +00:00
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_media_handle_t *smh = NULL;
int i;
2012-12-18 22:06:29 +00:00
*smhp = NULL;
2013-10-15 21:24:32 +00:00
if (zstr(params->sdp_username)) {
params->sdp_username = "FreeSWITCH";
}
2012-12-18 22:06:29 +00:00
if ((session->media_handle = switch_core_session_alloc(session, (sizeof(*smh))))) {
session->media_handle->session = session;
2013-11-07 22:48:00 +00:00
2012-12-18 22:06:29 +00:00
*smhp = session->media_handle;
2012-12-22 17:51:03 +00:00
switch_set_flag(session->media_handle, SMF_INIT);
2012-12-21 04:57:47 +00:00
session->media_handle->media_flags[SCMF_RUNNING] = 1;
2012-12-20 04:42:03 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
2013-10-15 21:24:32 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].type = SWITCH_MEDIA_TYPE_AUDIO;
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].crypto_type = CRYPTO_INVALID;
for (i = 0; i < CRYPTO_INVALID; i++) {
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec[i].crypto_type = i;
}
2012-12-20 04:42:03 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
2013-10-15 21:24:32 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].type = SWITCH_MEDIA_TYPE_VIDEO;
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].crypto_type = CRYPTO_INVALID;
switch_channel_set_variable(session->channel, "video_media_flow", "sendrecv");
switch_channel_set_variable(session->channel, "audio_media_flow", "sendrecv");
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].smode = SWITCH_MEDIA_FLOW_SENDRECV;
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].smode = SWITCH_MEDIA_FLOW_SENDRECV;
for (i = 0; i < CRYPTO_INVALID; i++) {
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec[i].crypto_type = i;
}
2013-01-10 04:31:25 +00:00
session->media_handle->mparams = params;
if (!session->media_handle->mparams->video_key_freq) {
session->media_handle->mparams->video_key_freq = 10000000;
}
if (!session->media_handle->mparams->video_key_first) {
session->media_handle->mparams->video_key_first = 1000000;
}
2013-10-15 21:24:32 +00:00
for (i = 0; i <= CRYPTO_INVALID; i++) {
session->media_handle->crypto_suite_order[i] = CRYPTO_INVALID;
}
2013-11-07 22:48:00 +00:00
2013-06-19 02:16:48 +00:00
switch_mutex_init(&session->media_handle->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&session->media_handle->sdp_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&session->media_handle->control_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
2013-06-19 02:16:48 +00:00
2013-01-10 04:31:25 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].ssrc =
(uint32_t) ((intptr_t) &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO] + (uint32_t) time(NULL));
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].ssrc =
(uint32_t) ((intptr_t) &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO] + (uint32_t) time(NULL) / 2);
2013-01-10 04:31:25 +00:00
2013-11-07 22:48:00 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t));
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].payload_map;
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].cur_payload_map->current = 1;
2013-11-07 22:48:00 +00:00
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t));
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].payload_map;
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].cur_payload_map->current = 1;
2013-11-07 22:48:00 +00:00
2013-02-21 17:11:52 +00:00
switch_channel_set_flag(session->channel, CF_DTLS_OK);
2012-12-18 22:06:29 +00:00
status = SWITCH_STATUS_SUCCESS;
}
return status;
}
2012-12-20 04:42:03 +00:00
SWITCH_DECLARE(void) switch_media_handle_set_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag)
{
switch_assert(smh);
2012-12-21 04:57:47 +00:00
smh->media_flags[flag] = 1;
}
SWITCH_DECLARE(void) switch_media_handle_set_media_flags(switch_media_handle_t *smh, switch_core_media_flag_t flags[SCMF_MAX])
{
int i;
switch_assert(smh);
for(i = 0; i < SCMF_MAX; i++) {
if (flags[i]) {
smh->media_flags[i] = flags[i];
}
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
}
SWITCH_DECLARE(void) switch_media_handle_clear_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag)
{
switch_assert(smh);
2012-12-21 04:57:47 +00:00
smh->media_flags[flag] = 0;
2012-12-20 04:42:03 +00:00
}
SWITCH_DECLARE(int32_t) switch_media_handle_test_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag)
{
switch_assert(smh);
2012-12-21 04:57:47 +00:00
return smh->media_flags[flag];
2012-12-18 22:06:29 +00:00
}
SWITCH_DECLARE(switch_media_flow_t) switch_core_session_media_flow(switch_core_session_t *session, switch_media_type_t type)
{
switch_media_flow_t flow = SWITCH_MEDIA_FLOW_SENDRECV;
switch_media_handle_t *smh;
switch_rtp_engine_t *engine = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
goto end;
}
if (!smh->media_flags[SCMF_RUNNING]) {
goto end;
}
engine = &smh->engines[type];
flow = engine->smode;
end:
return flow;
}
2012-12-18 22:06:29 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_session_media_handle_ready(switch_core_session_t *session)
{
2012-12-22 17:51:03 +00:00
if (session->media_handle && switch_test_flag(session->media_handle, SMF_INIT)) {
2012-12-18 22:06:29 +00:00
return SWITCH_STATUS_SUCCESS;
}
2013-10-15 21:24:32 +00:00
2012-12-18 22:06:29 +00:00
return SWITCH_STATUS_FALSE;
}
2013-10-15 21:24:32 +00:00
2012-12-18 22:06:29 +00:00
SWITCH_DECLARE(switch_media_handle_t *) switch_core_session_get_media_handle(switch_core_session_t *session)
{
2013-10-15 21:24:32 +00:00
if (switch_core_session_media_handle_ready(session) == SWITCH_STATUS_SUCCESS) {
2012-12-18 22:06:29 +00:00
return session->media_handle;
}
return NULL;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_clear_media_handle(switch_core_session_t *session)
{
if (!session->media_handle) {
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
2012-12-18 16:50:43 +00:00
2013-10-15 21:24:32 +00:00
SWITCH_DECLARE(switch_core_media_params_t *) switch_core_media_get_mparams(switch_media_handle_t *smh)
{
switch_assert(smh);
return smh->mparams;
}
2012-12-18 16:50:43 +00:00
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *session, switch_bool_t force)
2012-12-20 04:42:03 +00:00
{
2012-12-21 04:57:47 +00:00
const char *abs, *codec_string = NULL;
const char *ocodec = NULL;
switch_media_handle_t *smh;
2012-12-20 04:42:03 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return;
}
2012-12-20 04:42:03 +00:00
2014-01-30 18:02:28 +00:00
if (!force && (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_test_flag(session->channel, CF_PROXY_MEDIA))) {
2012-12-21 04:57:47 +00:00
return;
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (force) {
smh->mparams->num_codecs = 0;
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
if (smh->mparams->num_codecs) {
2012-12-21 04:57:47 +00:00
return;
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
smh->payload_space = 0;
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
switch_assert(smh->session != NULL);
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if ((abs = switch_channel_get_variable(session->channel, "absolute_codec_string"))) {
codec_string = abs;
goto ready;
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
if (!(codec_string = switch_channel_get_variable(session->channel, "codec_string"))) {
codec_string = switch_core_media_get_codec_string(smh->session);
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (codec_string && *codec_string == '=') {
codec_string++;
goto ready;
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if ((ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
if (!codec_string || (smh->media_flags[SCMF_DISABLE_TRANSCODING])) {
codec_string = ocodec;
} else {
if (!(codec_string = switch_core_session_sprintf(smh->session, "%s,%s", ocodec, codec_string))) {
codec_string = ocodec;
2012-12-20 04:42:03 +00:00
}
}
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
ready:
if (codec_string) {
char *tmp_codec_string = switch_core_session_strdup(smh->session, codec_string);
2013-04-16 18:02:50 +00:00
switch_channel_set_variable(session->channel, "rtp_use_codec_string", codec_string);
2012-12-21 04:57:47 +00:00
smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS);
smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
2012-12-21 04:57:47 +00:00
} else {
smh->mparams->num_codecs = switch_loadable_module_get_codecs(smh->codecs, sizeof(smh->codecs) / sizeof(smh->codecs[0]));
2012-12-21 04:57:47 +00:00
}
}
2012-12-20 04:42:03 +00:00
static void check_jb(switch_core_session_t *session, const char *input, int32_t jb_msec, int32_t maxlen)
{
const char *val;
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine = NULL, *v_engine = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2014-10-24 20:26:38 +00:00
if (!zstr(input)) {
const char *s;
if (a_engine->rtp_session) {
if (!strcasecmp(input, "pause")) {
switch_rtp_pause_jitter_buffer(a_engine->rtp_session, SWITCH_TRUE);
return;
} else if (!strcasecmp(input, "resume")) {
switch_rtp_pause_jitter_buffer(a_engine->rtp_session, SWITCH_FALSE);
return;
} else if (!strcasecmp(input, "stop")) {
switch_rtp_deactivate_jitter_buffer(a_engine->rtp_session);
return;
} else if (!strncasecmp(input, "debug:", 6)) {
s = input + 6;
if (s && !strcmp(s, "off")) {
s = NULL;
}
switch_rtp_debug_jitter_buffer(a_engine->rtp_session, s);
return;
}
2014-10-24 20:26:38 +00:00
switch_channel_set_variable(session->channel, "jitterbuffer_msec", input);
}
if (v_engine->rtp_session) {
if (!strncasecmp(input, "vbsize:", 7)) {
int frames = 0;
s = input + 7;
frames = atoi(s);
if (frames > 0) {
switch_rtp_set_video_buffer_size(v_engine->rtp_session, frames);
}
return;
} else if (!strncasecmp(input, "vdebug:", 7)) {
s = input + 7;
if (s && !strcmp(s, "off")) {
s = NULL;
}
switch_rtp_debug_jitter_buffer(v_engine->rtp_session, s);
return;
}
}
2014-10-24 20:26:38 +00:00
}
if (jb_msec || (val = switch_channel_get_variable(session->channel, "jitterbuffer_msec")) || (val = smh->mparams->jb_msec)) {
int max_drift = 0;
2014-10-24 20:26:38 +00:00
char *p, *q;
if (!jb_msec) {
jb_msec = atoi(val);
2014-10-24 20:26:38 +00:00
if ((p = strchr(val, ':'))) {
p++;
maxlen = atoi(p);
if ((q = strchr(p, ':'))) {
q++;
max_drift = abs(atoi(q));
}
}
}
if (jb_msec < 0 && jb_msec > -20) {
jb_msec = (a_engine->read_codec.implementation->microseconds_per_packet / 1000) * abs(jb_msec);
}
if (maxlen < 0 && maxlen > -20) {
maxlen = (a_engine->read_codec.implementation->microseconds_per_packet / 1000) * abs(maxlen);
}
2014-12-12 23:51:34 +00:00
if (jb_msec < 10 || jb_msec > 10000) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
2014-12-12 23:51:34 +00:00
"Invalid Jitterbuffer spec [%d] must be between 10 and 10000\n", jb_msec);
} else {
int qlen, maxqlen = 10;
qlen = jb_msec / (a_engine->read_impl.microseconds_per_packet / 1000);
if (maxlen) {
maxqlen = maxlen / (a_engine->read_impl.microseconds_per_packet / 1000);
}
if (maxqlen < qlen) {
maxqlen = qlen * 5;
}
if (switch_rtp_activate_jitter_buffer(a_engine->rtp_session, qlen, maxqlen,
a_engine->read_impl.samples_per_packet,
a_engine->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames) (%d max frames) (%d max drift)\n",
jb_msec, qlen, maxqlen, max_drift);
switch_channel_set_flag(session->channel, CF_JITTERBUFFER);
if (!switch_false(switch_channel_get_variable(session->channel, "rtp_jitter_buffer_plc"))) {
switch_channel_set_flag(session->channel, CF_JITTERBUFFER_PLC);
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen);
}
}
}
}
static void check_jb_sync(switch_core_session_t *session)
{
2015-07-29 02:42:08 +00:00
int32_t jb_sync_msec = 0;
uint32_t fps, frames = 0;
switch_media_handle_t *smh;
switch_rtp_engine_t *v_engine = NULL;
const char *var;
switch_assert(session);
if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
return;
}
if (!(smh = session->media_handle)) {
return;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2015-07-29 02:42:08 +00:00
if ((var = switch_channel_get_variable_dup(session->channel, "jb_sync_msec", SWITCH_FALSE, -1))) {
int tmp;
2015-07-29 02:42:08 +00:00
char *p;
if (!strcasecmp(var, "disabled")) {
return;
}
tmp = atol(var);
if (tmp && tmp > -50 && tmp < 10000) {
jb_sync_msec = tmp;
}
2015-07-29 02:42:08 +00:00
if ((p = strchr(var, ':'))) {
p++;
frames = atoi(p);
}
}
2015-07-29 02:42:08 +00:00
if (smh->vid_frames < 10) {
2015-07-29 02:42:08 +00:00
fps = 30;
} else {
fps = switch_core_media_get_video_fps(session);
}
2015-04-30 17:37:10 +00:00
if (!fps) return;
2015-07-29 02:42:08 +00:00
if (!frames) {
frames = fps / 7.5;
if (frames < 4) frames = 4;
}
2015-07-29 02:42:08 +00:00
if (!jb_sync_msec) {
jb_sync_msec = frames * 75;
}
//if (!frames) {
// if (jb_sync_msec < 0) {
// frames = abs(jb_sync_msec);
// jb_sync_msec = 1000 / (fps / frames);
// } else {
// frames = fps / (1000 / jb_sync_msec);
// }
//}
if (frames == switch_rtp_get_video_buffer_size(v_engine->rtp_session)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
SWITCH_LOG_DEBUG1, "%s Audio and Video Jitterbuffer settings not changed %dms %u Video Frames FPS %u\n",
switch_channel_get_name(session->channel),
jb_sync_msec, frames, fps);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
2015-07-15 16:50:36 +00:00
SWITCH_LOG_DEBUG, "%s Sync Audio and Video Jitterbuffer to %dms %u Video Frames FPS %u\n",
switch_channel_get_name(session->channel),
jb_sync_msec, frames, fps);
switch_rtp_set_video_buffer_size(v_engine->rtp_session, frames);
check_jb(session, NULL, jb_sync_msec, jb_sync_msec);
}
}
2014-12-02 16:51:21 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_read_lock_unlock(switch_core_session_t *session, switch_media_type_t type, switch_bool_t lock)
{
switch_rtp_engine_t *engine;
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (!smh->media_flags[SCMF_RUNNING]) {
return SWITCH_STATUS_FALSE;
}
engine = &smh->engines[type];
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
return SWITCH_STATUS_FALSE;
}
switch_assert(engine->rtp_session != NULL);
if (!switch_channel_up_nosig(session->channel) || !switch_rtp_ready(engine->rtp_session) || switch_channel_test_flag(session->channel, CF_NOT_READY)) {
return SWITCH_STATUS_FALSE;
}
if (lock) {
2015-03-03 17:44:20 +00:00
if (smh->read_mutex[type] && switch_mutex_trylock(smh->read_mutex[type]) != SWITCH_STATUS_SUCCESS) {
2014-12-02 16:51:21 +00:00
/* return CNG, another thread is already reading */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being read for %s\n",
switch_channel_get_name(session->channel), type2str(type));
return SWITCH_STATUS_INUSE;
}
} else {
2015-03-03 17:44:20 +00:00
switch_mutex_unlock(smh->read_mutex[type]);
2014-12-02 16:51:21 +00:00
}
return SWITCH_STATUS_SUCCESS;
}
2012-12-21 20:22:25 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session_t *session, switch_frame_t **frame,
switch_io_flag_t flags, int stream_id, switch_media_type_t type)
2012-12-21 04:57:47 +00:00
{
switch_rtcp_frame_t rtcp_frame;
switch_rtp_engine_t *engine;
switch_status_t status;
switch_media_handle_t *smh;
2013-11-07 22:48:00 +00:00
int do_cng = 0;
2012-12-20 04:42:03 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
2012-12-20 04:42:03 +00:00
if (!smh->media_flags[SCMF_RUNNING]) {
2012-12-21 04:57:47 +00:00
return SWITCH_STATUS_FALSE;
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
engine = &smh->engines[type];
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
return SWITCH_STATUS_FALSE;
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
switch_assert(engine->rtp_session != NULL);
2012-12-20 04:42:03 +00:00
2013-08-16 16:17:00 +00:00
if (!switch_channel_up_nosig(session->channel) || !switch_rtp_ready(engine->rtp_session) || switch_channel_test_flag(session->channel, CF_NOT_READY)) {
return SWITCH_STATUS_FALSE;
}
2015-03-03 17:44:20 +00:00
if (smh->read_mutex[type] && switch_mutex_trylock(smh->read_mutex[type]) != SWITCH_STATUS_SUCCESS) {
2013-08-16 16:17:00 +00:00
/* return CNG, another thread is already reading */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being read for %s\n",
switch_channel_get_name(session->channel), type2str(type));
return SWITCH_STATUS_INUSE;
}
engine->read_frame.datalen = 0;
engine->read_frame.flags = SFF_NONE;
engine->read_frame.m = SWITCH_FALSE;
engine->read_frame.img = NULL;
while (smh->media_flags[SCMF_RUNNING] && engine->read_frame.datalen == 0) {
2012-12-21 04:57:47 +00:00
engine->read_frame.flags = SFF_NONE;
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
status = switch_rtp_zerocopy_read_frame(engine->rtp_session, &engine->read_frame, flags);
2012-12-21 04:57:47 +00:00
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
if (status == SWITCH_STATUS_TIMEOUT) {
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (switch_channel_get_variable(session->channel, "execute_on_media_timeout")) {
*frame = &engine->read_frame;
switch_set_flag((*frame), SFF_CNG);
(*frame)->datalen = engine->read_impl.encoded_bytes_per_packet;
memset((*frame)->data, 0, (*frame)->datalen);
switch_channel_execute_on(session->channel, "execute_on_media_timeout");
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
switch_channel_hangup(session->channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
}
goto end;
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
if (type == SWITCH_MEDIA_TYPE_VIDEO && engine->read_frame.m) {
if (!smh->vid_started) {
smh->vid_started = switch_epoch_time_now(NULL);
}
smh->vid_frames++;
if (smh->vid_frames == 1 || ((smh->vid_frames % 300) == 0)) {
check_jb_sync(session);
}
}
2013-11-07 22:48:00 +00:00
/* re-set codec if necessary */
if (engine->reset_codec > 0) {
const char *val;
int rtp_timeout_sec = 0;
int rtp_hold_timeout_sec = 0;
engine->reset_codec = 0;
if (switch_rtp_ready(engine->rtp_session)) {
2013-11-14 20:17:22 +00:00
if (type == SWITCH_MEDIA_TYPE_VIDEO) {
switch_core_media_set_video_codec(session, 1);
} else {
if (switch_core_media_set_codec(session, 1, 0) != SWITCH_STATUS_SUCCESS) {
*frame = NULL;
switch_goto_status(SWITCH_STATUS_GENERR, end);
}
2013-11-07 22:48:00 +00:00
}
if ((val = switch_channel_get_variable(session->channel, "rtp_timeout_sec"))) {
int v = atoi(val);
if (v >= 0) {
rtp_timeout_sec = v;
}
}
if ((val = switch_channel_get_variable(session->channel, "rtp_hold_timeout_sec"))) {
int v = atoi(val);
if (v >= 0) {
rtp_hold_timeout_sec = v;
}
}
if (rtp_timeout_sec) {
engine->max_missed_packets = (engine->read_impl.samples_per_second * rtp_timeout_sec) /
engine->read_impl.samples_per_packet;
switch_rtp_set_max_missed_packets(engine->rtp_session, engine->max_missed_packets);
if (!rtp_hold_timeout_sec) {
rtp_hold_timeout_sec = rtp_timeout_sec * 10;
}
}
if (rtp_hold_timeout_sec) {
engine->max_missed_hold_packets = (engine->read_impl.samples_per_second * rtp_hold_timeout_sec) /
engine->read_impl.samples_per_packet;
}
}
check_jb(session, NULL, 0, 0);
2013-11-07 22:48:00 +00:00
engine->check_frames = 0;
engine->last_ts = 0;
engine->last_seq = 0;
2013-11-07 22:48:00 +00:00
do_cng = 1;
}
if (do_cng) {
/* return CNG for now */
*frame = &engine->read_frame;
switch_set_flag((*frame), SFF_CNG);
(*frame)->datalen = engine->read_impl.encoded_bytes_per_packet;
memset((*frame)->data, 0, (*frame)->datalen);
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
}
2012-12-21 04:57:47 +00:00
/* Try to read an RTCP frame, if successful raise an event */
if (switch_rtcp_zerocopy_read_frame(engine->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) {
switch_event_t *event;
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (switch_event_create(&event, SWITCH_EVENT_RECV_RTCP_MESSAGE) == SWITCH_STATUS_SUCCESS) {
char value[30];
char header[50];
int i;
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
char *uuid = switch_core_session_get_uuid(session);
if (uuid) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session));
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
snprintf(value, sizeof(value), "%.8x", rtcp_frame.ssrc);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SSRC", value);
snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_msw);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Most-Significant-Word", value);
snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_lsw);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Least-Significant-Word", value);
snprintf(value, sizeof(value), "%u", rtcp_frame.timestamp);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Timestamp", value);
snprintf(value, sizeof(value), "%u", rtcp_frame.packet_count);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sender-Packet-Count", value);
snprintf(value, sizeof(value), "%u", rtcp_frame.octect_count);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Octect-Packet-Count", value);
snprintf(value, sizeof(value), "%u", engine->read_frame.timestamp);
2012-12-21 04:57:47 +00:00
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-RTP-Timestamp", value);
snprintf(value, sizeof(value), "%u", engine->read_frame.rate);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Rate", value);
snprintf(value, sizeof(value), "%" SWITCH_TIME_T_FMT, switch_time_now());
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Capture-Time", value);
// Add sources info
for (i = 0; i < rtcp_frame.report_count; i++) {
snprintf(header, sizeof(header), "Source%u-SSRC", i);
snprintf(value, sizeof(value), "%.8x", rtcp_frame.reports[i].ssrc);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
snprintf(header, sizeof(header), "Source%u-Fraction", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].fraction);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
snprintf(header, sizeof(header), "Source%u-Lost", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lost);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
snprintf(header, sizeof(header), "Source%u-Loss-Avg", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].loss_avg);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
2012-12-21 04:57:47 +00:00
snprintf(header, sizeof(header), "Source%u-Highest-Sequence-Number-Received", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].highest_sequence_number_received);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
snprintf(header, sizeof(header), "Source%u-Jitter", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].jitter);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
snprintf(header, sizeof(header), "Source%u-LSR", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lsr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
snprintf(header, sizeof(header), "Source%u-DLSR", i);
snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].dlsr);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value);
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
switch_event_fire(&event);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Dispatched RTCP event\n");
}
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
/* Fast PASS! */
if (switch_test_flag((&engine->read_frame), SFF_PROXY_PACKET)) {
*frame = &engine->read_frame;
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (switch_rtp_has_dtmf(engine->rtp_session)) {
switch_dtmf_t dtmf = { 0 };
switch_rtp_dequeue_dtmf(engine->rtp_session, &dtmf);
switch_channel_queue_dtmf(session->channel, &dtmf);
}
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
if (engine->read_frame.datalen > 0) {
uint32_t bytes = 0;
int frames = 1;
2012-12-20 04:42:03 +00:00
2013-11-07 22:48:00 +00:00
/* autofix timing */
2012-12-21 04:57:47 +00:00
if (!switch_test_flag((&engine->read_frame), SFF_CNG)) {
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
*frame = NULL;
switch_goto_status(SWITCH_STATUS_GENERR, end);
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
/* check for timing issues */
if (smh->media_flags[SCMF_AUTOFIX_TIMING] && engine->check_frames < MAX_CODEC_CHECK_FRAMES) {
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
2012-12-21 04:57:47 +00:00
engine->check_frames++;
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (!engine->read_impl.encoded_bytes_per_packet) {
engine->check_frames = MAX_CODEC_CHECK_FRAMES;
goto skip;
}
2013-11-07 22:48:00 +00:00
if (smh->media_flags[SCMF_AUTOFIX_TIMING] && (engine->read_frame.datalen % 10) == 0) {
2013-07-29 15:18:05 +00:00
if (engine->last_ts && engine->read_frame.datalen != engine->read_impl.encoded_bytes_per_packet) {
2012-12-21 04:57:47 +00:00
2013-07-29 15:18:05 +00:00
uint32_t codec_ms = (int) (engine->read_frame.timestamp -
engine->last_ts) / (engine->read_impl.samples_per_second / 1000);
2012-12-21 04:57:47 +00:00
if (engine->last_seq && (int) (engine->read_frame.seq - engine->last_seq) > 1) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Correcting calculated ptime value from %d to %d to compensate for %d lost packet(s)\n", codec_ms, codec_ms / (int) (engine->read_frame.seq - engine->last_seq), (int) (engine->read_frame.seq - engine->last_seq - 1));
codec_ms = codec_ms / (int) (engine->read_frame.seq - engine->last_seq);
}
2013-07-29 15:18:05 +00:00
if ((codec_ms % 10) != 0 || codec_ms > engine->read_impl.samples_per_packet * 10) {
engine->last_ts = 0;
engine->last_seq = 0;
2013-07-29 15:18:05 +00:00
goto skip;
}
2012-12-21 04:57:47 +00:00
2013-07-29 15:18:05 +00:00
if (engine->last_codec_ms && engine->last_codec_ms == codec_ms) {
engine->mismatch_count++;
}
2012-12-21 20:22:25 +00:00
2013-07-29 15:18:05 +00:00
engine->last_codec_ms = codec_ms;
2012-12-21 20:22:25 +00:00
2013-07-29 15:18:05 +00:00
if (engine->mismatch_count > MAX_MISMATCH_FRAMES) {
2013-11-07 22:48:00 +00:00
if (codec_ms != engine->cur_payload_map->codec_ms) {
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
if (codec_ms > 120) { /* yeah right */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Your phone is trying to send timestamps that suggest an increment of %dms per packet\n"
"That seems hard to believe so I am going to go on ahead and um ignore that, mmkay?\n",
(int) codec_ms);
engine->check_frames = MAX_CODEC_CHECK_FRAMES;
goto skip;
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
engine->read_frame.datalen = 0;
2012-12-20 04:42:03 +00:00
2013-11-07 22:48:00 +00:00
if (codec_ms != engine->cur_payload_map->codec_ms) {
2013-07-29 15:18:05 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Asynchronous PTIME not supported, changing our end from %d to %d\n",
2013-11-07 22:48:00 +00:00
(int) engine->cur_payload_map->codec_ms,
2013-07-29 15:18:05 +00:00
(int) codec_ms
);
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
switch_channel_set_variable_printf(session->channel, "rtp_h_X-Broken-PTIME", "Adv=%d;Sent=%d",
2013-11-07 22:48:00 +00:00
(int) engine->cur_payload_map->codec_ms, (int) codec_ms);
2012-12-20 04:42:03 +00:00
2013-11-07 22:48:00 +00:00
engine->cur_payload_map->codec_ms = codec_ms;
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
/* mark to re-set codec */
2013-11-07 22:48:00 +00:00
engine->reset_codec = 2;
2013-07-29 15:18:05 +00:00
}
}
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
} else {
engine->mismatch_count = 0;
2012-12-21 04:57:47 +00:00
}
2012-12-20 04:42:03 +00:00
2013-07-29 15:18:05 +00:00
engine->last_ts = engine->read_frame.timestamp;
engine->last_seq = engine->read_frame.seq;
2013-07-29 15:18:05 +00:00
2012-12-20 04:42:03 +00:00
} else {
2012-12-21 04:57:47 +00:00
engine->mismatch_count = 0;
2013-07-29 15:18:05 +00:00
engine->last_ts = 0;
engine->last_seq = 0;
2012-12-20 04:42:03 +00:00
}
2013-11-07 22:48:00 +00:00
}
2012-12-20 04:42:03 +00:00
2013-11-07 22:48:00 +00:00
/* autofix payload type */
2013-07-29 15:18:05 +00:00
2013-11-07 22:48:00 +00:00
if (!engine->reset_codec &&
engine->codec_negotiated &&
(!smh->mparams->cng_pt || engine->read_frame.payload != smh->mparams->cng_pt) &&
(!smh->mparams->recv_te || engine->read_frame.payload != smh->mparams->recv_te) &&
(!smh->mparams->te || engine->read_frame.payload != smh->mparams->te) &&
2013-11-07 22:48:00 +00:00
engine->read_frame.payload != engine->cur_payload_map->recv_pt &&
engine->read_frame.payload != engine->cur_payload_map->agreed_pt &&
engine->read_frame.payload != engine->cur_payload_map->pt) {
payload_map_t *pmap;
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"alternate payload received (received %d, expecting %d)\n",
(int) engine->read_frame.payload, (int) engine->cur_payload_map->agreed_pt);
2013-07-29 15:18:05 +00:00
2013-11-07 22:48:00 +00:00
/* search for payload type */
switch_mutex_lock(smh->sdp_mutex);
for (pmap = engine->payload_map; pmap; pmap = pmap->next) {
2014-01-28 21:19:03 +00:00
if (engine->read_frame.payload == pmap->recv_pt && pmap->negotiated) {
2013-11-07 22:48:00 +00:00
engine->cur_payload_map = pmap;
engine->cur_payload_map->current = 1;
2013-11-07 22:48:00 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Changing current codec to %s (payload type %d).\n",
pmap->iananame, pmap->pt);
/* mark to re-set codec */
engine->reset_codec = 1;
break;
2013-07-29 15:18:05 +00:00
}
2013-11-07 22:48:00 +00:00
}
switch_mutex_unlock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
if (!engine->reset_codec) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Could not change to payload type %d, ignoring...\n",
(int) engine->read_frame.payload);
2013-07-29 15:18:05 +00:00
}
2012-12-21 04:57:47 +00:00
}
2013-07-29 15:18:05 +00:00
2012-12-21 04:57:47 +00:00
skip:
if ((bytes = engine->read_impl.encoded_bytes_per_packet)) {
frames = (engine->read_frame.datalen / bytes);
}
engine->read_frame.samples = (int) (frames * engine->read_impl.samples_per_packet);
if (engine->read_frame.datalen == 0) {
continue;
2012-12-20 04:42:03 +00:00
}
}
2012-12-21 04:57:47 +00:00
break;
2012-12-20 04:42:03 +00:00
}
}
2012-12-21 04:57:47 +00:00
if (engine->read_frame.datalen == 0) {
2012-12-20 04:42:03 +00:00
*frame = NULL;
}
2012-12-21 04:57:47 +00:00
*frame = &engine->read_frame;
2012-12-20 04:42:03 +00:00
status = SWITCH_STATUS_SUCCESS;
end:
2015-03-03 17:44:20 +00:00
if (smh->read_mutex[type]) {
switch_mutex_unlock(smh->read_mutex[type]);
}
return status;
2012-12-20 04:42:03 +00:00
}
2012-12-21 20:22:25 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_write_frame(switch_core_session_t *session,
switch_frame_t *frame, switch_io_flag_t flags, int stream_id, switch_media_type_t type)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
int bytes = 0, samples = 0, frames = 0;
switch_rtp_engine_t *engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 20:22:25 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (!smh->media_flags[SCMF_RUNNING]) {
2012-12-21 20:22:25 +00:00
return SWITCH_STATUS_FALSE;
}
engine = &smh->engines[type];
2015-02-17 03:21:10 +00:00
if (switch_channel_test_flag(session->channel, CF_VIDEO_ONLY) && type == SWITCH_MEDIA_TYPE_AUDIO) {
return SWITCH_STATUS_SUCCESS;
}
2012-12-21 20:22:25 +00:00
while (!(engine->read_codec.implementation && switch_rtp_ready(engine->rtp_session))) {
if (switch_channel_ready(session->channel)) {
switch_yield(10000);
} else {
return SWITCH_STATUS_GENERR;
}
}
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
return SWITCH_STATUS_GENERR;
}
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
return SWITCH_STATUS_FALSE;
}
if (!switch_test_flag(frame, SFF_CNG) && !switch_test_flag(frame, SFF_PROXY_PACKET)) {
if (engine->read_impl.encoded_bytes_per_packet) {
bytes = engine->read_impl.encoded_bytes_per_packet;
frames = ((int) frame->datalen / bytes);
} else
frames = 1;
samples = frames * engine->read_impl.samples_per_packet;
}
engine->timestamp_send += samples;
2014-02-12 03:29:03 +00:00
if (switch_rtp_write_frame(engine->rtp_session, frame) < 0) {
2012-12-21 20:22:25 +00:00
status = SWITCH_STATUS_FALSE;
}
return status;
}
2012-12-20 04:42:03 +00:00
2012-12-21 20:22:25 +00:00
//?
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(void) switch_core_media_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options");
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
switch_assert(t38_options);
if (!local_t38_options) {
local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t));
}
local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate;
local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval;
local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR;
local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG;
local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement);
local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer;
local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram;
local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC);
local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo);
local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip);
local_t38_options->remote_port = t38_options->remote_port;
switch_channel_set_private(channel, "t38_options", local_t38_options);
}
2012-12-21 20:22:25 +00:00
//?
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_get_offered_pt(switch_core_session_t *session, const switch_codec_implementation_t *mimp, switch_payload_t *pt)
2012-12-20 04:42:03 +00:00
{
2012-12-21 04:57:47 +00:00
int i = 0;
2012-12-20 04:42:03 +00:00
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2013-11-14 17:19:04 +00:00
if (!(smh = session->media_handle) || !mimp) {
2012-12-21 04:57:47 +00:00
return SWITCH_STATUS_FALSE;
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
for (i = 0; i < smh->mparams->num_codecs; i++) {
2012-12-21 04:57:47 +00:00
const switch_codec_implementation_t *imp = smh->codecs[i];
2013-05-09 15:08:08 +00:00
if (!strcasecmp(imp->iananame, mimp->iananame) && imp->actual_samples_per_second == mimp->actual_samples_per_second) {
2012-12-21 04:57:47 +00:00
*pt = smh->ianacodes[i];
return SWITCH_STATUS_SUCCESS;
}
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
return SWITCH_STATUS_FALSE;
}
//#define get_int_value(_var, _set) { const char *__v = switch_channel_get_variable(session->channel, _var); if (__v) { _set = atol(__v);} }
//?
static void switch_core_session_parse_codec_settings(switch_core_session_t *session, switch_media_type_t type)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
2014-11-16 01:27:30 +00:00
if (!(engine = &smh->engines[type])) return;
switch(type) {
case SWITCH_MEDIA_TYPE_AUDIO:
break;
2014-11-16 01:27:30 +00:00
case SWITCH_MEDIA_TYPE_VIDEO:
{
2015-01-29 22:37:29 +00:00
const char *bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth");
2015-01-29 22:37:29 +00:00
if (!bwv) {
bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth_out");
}
2015-04-24 16:17:42 +00:00
if (!bwv) {
bwv = "1mb";
}
engine->codec_settings.video.bandwidth = switch_parse_bandwidth_string(bwv);
}
break;
default:
break;
}
}
2012-12-21 20:22:25 +00:00
2012-12-21 04:57:47 +00:00
//?
2012-12-21 20:22:25 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_session_t *session, int force)
2012-12-21 04:57:47 +00:00
{
switch_media_handle_t *smh;
switch_rtp_engine_t *v_engine;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
if (!v_engine->codec_negotiated) {
2012-12-21 04:57:47 +00:00
return SWITCH_STATUS_FALSE;
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
if (v_engine->read_codec.implementation && switch_core_codec_ready(&v_engine->read_codec)) {
if (!force) {
return SWITCH_STATUS_SUCCESS;
}
2013-11-07 22:48:00 +00:00
if (strcasecmp(v_engine->read_codec.implementation->iananame, v_engine->cur_payload_map->rm_encoding) ||
v_engine->read_codec.implementation->samples_per_second != v_engine->cur_payload_map->rm_rate) {
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
2013-11-07 22:48:00 +00:00
v_engine->read_codec.implementation->iananame, v_engine->cur_payload_map->rm_encoding);
2012-12-21 04:57:47 +00:00
switch_core_codec_destroy(&v_engine->read_codec);
switch_core_codec_destroy(&v_engine->write_codec);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already using %s\n",
v_engine->read_codec.implementation->iananame);
return SWITCH_STATUS_SUCCESS;
}
}
switch_core_session_parse_codec_settings(session, SWITCH_MEDIA_TYPE_VIDEO);
2012-12-21 04:57:47 +00:00
if (switch_core_codec_init(&v_engine->read_codec,
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_encoding,
v_engine->cur_payload_map->modname,
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_fmtp,
v_engine->cur_payload_map->rm_rate,
2012-12-21 04:57:47 +00:00
0,
1,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
&v_engine->codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
return SWITCH_STATUS_FALSE;
} else {
if (switch_core_codec_init(&v_engine->write_codec,
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_encoding,
v_engine->cur_payload_map->modname,
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_fmtp,
v_engine->cur_payload_map->rm_rate,
2012-12-21 04:57:47 +00:00
0,
1,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
&v_engine->codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
return SWITCH_STATUS_FALSE;
} else {
2013-11-07 22:48:00 +00:00
v_engine->read_frame.rate = v_engine->cur_payload_map->rm_rate;
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n",
2013-11-07 22:48:00 +00:00
switch_channel_get_name(session->channel), v_engine->cur_payload_map->rm_encoding,
v_engine->cur_payload_map->rm_rate, v_engine->cur_payload_map->codec_ms);
2012-12-21 04:57:47 +00:00
v_engine->read_frame.codec = &v_engine->read_codec;
v_engine->write_codec.fmtp_out = switch_core_session_strdup(session, v_engine->write_codec.fmtp_out);
2013-11-07 22:48:00 +00:00
v_engine->write_codec.agreed_pt = v_engine->cur_payload_map->agreed_pt;
v_engine->read_codec.agreed_pt = v_engine->cur_payload_map->agreed_pt;
2012-12-21 04:57:47 +00:00
switch_core_session_set_video_read_codec(session, &v_engine->read_codec);
switch_core_session_set_video_write_codec(session, &v_engine->write_codec);
2013-10-15 21:24:32 +00:00
switch_channel_set_variable_printf(session->channel, "rtp_last_video_codec_string", "%s@%dh",
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_encoding, v_engine->cur_payload_map->rm_rate);
2013-05-17 20:39:21 +00:00
2012-12-21 04:57:47 +00:00
if (switch_rtp_ready(v_engine->rtp_session)) {
switch_core_session_message_t msg = { 0 };
msg.from = __FILE__;
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
2013-11-07 22:48:00 +00:00
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
//XX
2012-12-21 04:57:47 +00:00
switch_core_session_receive_message(session, &msg);
}
2013-01-10 04:31:25 +00:00
2013-11-07 22:48:00 +00:00
switch_channel_set_variable(session->channel, "rtp_use_video_codec_name", v_engine->cur_payload_map->rm_encoding);
switch_channel_set_variable(session->channel, "rtp_use_video_codec_fmtp", v_engine->cur_payload_map->rm_fmtp);
switch_channel_set_variable_printf(session->channel, "rtp_use_video_codec_rate", "%d", v_engine->cur_payload_map->rm_rate);
switch_channel_set_variable_printf(session->channel, "rtp_use_video_codec_ptime", "%d", 0);
2012-12-20 04:42:03 +00:00
}
}
2012-12-21 04:57:47 +00:00
return SWITCH_STATUS_SUCCESS;
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
//?
2012-12-21 20:22:25 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_t *session, int force, uint32_t codec_flags)
2012-12-21 04:57:47 +00:00
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
int resetting = 0;
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
2012-12-20 04:42:03 +00:00
2013-11-07 22:48:00 +00:00
if (!a_engine->cur_payload_map->iananame) {
2013-02-26 22:13:19 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No audio codec available\n");
2012-12-21 04:57:47 +00:00
switch_goto_status(SWITCH_STATUS_FALSE, end);
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
if (switch_core_codec_ready(&a_engine->read_codec)) {
if (!force) {
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
}
2013-11-07 22:48:00 +00:00
if (strcasecmp(a_engine->read_impl.iananame, a_engine->cur_payload_map->iananame) ||
(uint32_t) a_engine->read_impl.microseconds_per_packet / 1000 != a_engine->cur_payload_map->codec_ms ||
a_engine->read_impl.samples_per_second != a_engine->cur_payload_map->rm_rate ) {
if (session->read_resampler) {
switch_mutex_lock(session->resample_mutex);
switch_resample_destroy(&session->read_resampler);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating read resampler\n");
switch_mutex_unlock(session->resample_mutex);
}
if (session->write_resampler) {
switch_mutex_lock(session->resample_mutex);
switch_resample_destroy(&session->write_resampler);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n");
switch_mutex_unlock(session->resample_mutex);
}
switch_core_session_reset(session, 0, 0);
switch_channel_audio_sync(session->channel);
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Changing Codec from %s@%dms@%dhz to %s@%dms@%luhz\n",
a_engine->read_impl.iananame,
a_engine->read_impl.microseconds_per_packet / 1000,
2012-12-21 04:57:47 +00:00
a_engine->read_impl.samples_per_second,
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->iananame,
a_engine->cur_payload_map->codec_ms,
a_engine->cur_payload_map->rm_rate);
2012-12-21 04:57:47 +00:00
switch_yield(a_engine->read_impl.microseconds_per_packet);
switch_core_session_lock_codec_write(session);
switch_core_session_lock_codec_read(session);
resetting = 1;
switch_yield(a_engine->read_impl.microseconds_per_packet);
switch_core_codec_destroy(&a_engine->read_codec);
switch_core_codec_destroy(&a_engine->write_codec);
switch_channel_audio_sync(session->channel);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already using %s\n", a_engine->read_impl.iananame);
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
}
}
2012-12-20 04:42:03 +00:00
switch_core_session_parse_codec_settings(session, SWITCH_MEDIA_TYPE_AUDIO);
2012-12-21 04:57:47 +00:00
if (switch_core_codec_init_with_bitrate(&a_engine->read_codec,
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->iananame,
a_engine->cur_payload_map->modname,
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->rm_fmtp,
a_engine->cur_payload_map->rm_rate,
a_engine->cur_payload_map->codec_ms,
a_engine->cur_payload_map->channels,
a_engine->cur_payload_map->bitrate,
2012-12-21 04:57:47 +00:00
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | codec_flags,
&a_engine->codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
a_engine->read_codec.session = session;
if (switch_core_codec_init_with_bitrate(&a_engine->write_codec,
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->iananame,
a_engine->cur_payload_map->modname,
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->rm_fmtp,
a_engine->cur_payload_map->rm_rate,
a_engine->cur_payload_map->codec_ms,
a_engine->cur_payload_map->channels,
a_engine->cur_payload_map->bitrate,
2012-12-21 04:57:47 +00:00
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | codec_flags,
&a_engine->codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
a_engine->write_codec.session = session;
2013-11-07 22:48:00 +00:00
switch_channel_set_variable(session->channel, "rtp_use_codec_name", a_engine->cur_payload_map->iananame);
switch_channel_set_variable(session->channel, "rtp_use_codec_fmtp", a_engine->cur_payload_map->rm_fmtp);
switch_channel_set_variable_printf(session->channel, "rtp_use_codec_rate", "%d", a_engine->cur_payload_map->rm_rate);
switch_channel_set_variable_printf(session->channel, "rtp_use_codec_ptime", "%d", a_engine->cur_payload_map->codec_ms);
2014-06-13 05:49:10 +00:00
switch_channel_set_variable_printf(session->channel, "rtp_use_codec_channels", "%d", a_engine->cur_payload_map->channels);
switch_channel_set_variable_printf(session->channel, "rtp_last_audio_codec_string", "%s@%dh@%di@%dc",
a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->rm_rate, a_engine->cur_payload_map->codec_ms, a_engine->cur_payload_map->channels);
2012-12-21 04:57:47 +00:00
switch_assert(a_engine->read_codec.implementation);
switch_assert(a_engine->write_codec.implementation);
a_engine->read_impl = *a_engine->read_codec.implementation;
a_engine->write_impl = *a_engine->write_codec.implementation;
switch_core_session_set_read_impl(session, a_engine->read_codec.implementation);
switch_core_session_set_write_impl(session, a_engine->write_codec.implementation);
if (switch_rtp_ready(a_engine->rtp_session)) {
switch_assert(a_engine->read_codec.implementation);
if (switch_rtp_change_interval(a_engine->rtp_session,
a_engine->read_impl.microseconds_per_packet,
a_engine->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
}
2013-11-07 22:48:00 +00:00
a_engine->read_frame.rate = a_engine->cur_payload_map->rm_rate;
2012-12-21 04:57:47 +00:00
if (!switch_core_codec_ready(&a_engine->read_codec)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits %d channels\n",
2013-11-07 22:48:00 +00:00
switch_channel_get_name(session->channel), a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->rm_rate,
a_engine->cur_payload_map->codec_ms,
a_engine->read_impl.samples_per_packet, a_engine->read_impl.bits_per_second, a_engine->read_impl.number_of_channels);
2012-12-21 04:57:47 +00:00
a_engine->read_frame.codec = &a_engine->read_codec;
2014-06-13 05:49:10 +00:00
a_engine->read_frame.channels = a_engine->read_impl.number_of_channels;
2013-11-07 22:48:00 +00:00
a_engine->write_codec.agreed_pt = a_engine->cur_payload_map->agreed_pt;
a_engine->read_codec.agreed_pt = a_engine->cur_payload_map->agreed_pt;
2012-12-21 04:57:47 +00:00
if (force != 2) {
switch_core_session_set_real_read_codec(session, &a_engine->read_codec);
switch_core_session_set_write_codec(session, &a_engine->write_codec);
}
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->fmtp_out = switch_core_session_strdup(session, a_engine->write_codec.fmtp_out);
2012-12-21 04:57:47 +00:00
if (switch_rtp_ready(a_engine->rtp_session)) {
2013-11-07 22:48:00 +00:00
switch_rtp_set_default_payload(a_engine->rtp_session, a_engine->cur_payload_map->pt);
2012-12-21 04:57:47 +00:00
}
end:
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
if (resetting) {
switch_core_session_unlock_codec_write(session);
switch_core_session_unlock_codec_read(session);
}
return status;
}
2014-06-13 10:06:14 +00:00
static void clear_ice(switch_core_session_t *session, switch_media_type_t type)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
engine = &smh->engines[type];
engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 0;
engine->ice_in.is_chosen[0] = 0;
engine->ice_in.is_chosen[1] = 0;
engine->ice_in.cand_idx[0] = 0;
engine->ice_in.cand_idx[1] = 0;
2014-06-13 10:06:14 +00:00
memset(&engine->ice_in, 0, sizeof(engine->ice_in));
engine->remote_rtcp_port = 0;
if (engine->rtp_session) {
switch_rtp_reset(engine->rtp_session);
}
2014-06-13 10:06:14 +00:00
}
//?
SWITCH_DECLARE(void) switch_core_media_clear_ice(switch_core_session_t *session)
{
clear_ice(session, SWITCH_MEDIA_TYPE_AUDIO);
clear_ice(session, SWITCH_MEDIA_TYPE_VIDEO);
}
SWITCH_DECLARE(void) switch_core_media_pause(switch_core_session_t *session)
{
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (a_engine->rtp_session) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
if (v_engine->rtp_session) {
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
}
SWITCH_DECLARE(void) switch_core_media_resume(switch_core_session_t *session)
{
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (a_engine->rtp_session) {
switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
if (v_engine->rtp_session) {
switch_rtp_clear_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
}
2012-12-21 04:57:47 +00:00
2013-01-10 04:31:25 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_add_ice_acl(switch_core_session_t *session, switch_media_type_t type, const char *acl_name)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
engine = &smh->engines[type];
2013-01-14 02:12:23 +00:00
if (engine->cand_acl_count < SWITCH_MAX_CAND_ACL) {
engine->cand_acl[engine->cand_acl_count++] = switch_core_session_strdup(session, acl_name);
2013-01-10 04:31:25 +00:00
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
2012-12-21 04:57:47 +00:00
//?
2012-12-21 20:22:25 +00:00
SWITCH_DECLARE(void) switch_core_media_check_video_codecs(switch_core_session_t *session)
2012-12-21 04:57:47 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return;
}
if (smh->mparams->num_codecs && !switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE)) {
2012-12-21 04:57:47 +00:00
int i;
smh->video_count = 0;
for (i = 0; i < smh->mparams->num_codecs; i++) {
2012-12-21 04:57:47 +00:00
if (smh->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) {
2013-06-20 18:10:21 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
continue;
}
2012-12-21 04:57:47 +00:00
smh->video_count++;
}
}
if (smh->video_count) {
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
}
}
}
2013-02-01 20:29:40 +00:00
//?
static void generate_local_fingerprint(switch_media_handle_t *smh, switch_media_type_t type)
{
switch_rtp_engine_t *engine = &smh->engines[type];
2013-02-02 06:15:09 +00:00
if (!engine->local_dtls_fingerprint.len) {
2013-10-16 17:57:15 +00:00
if (engine->remote_dtls_fingerprint.type) {
engine->local_dtls_fingerprint.type = engine->remote_dtls_fingerprint.type;
} else {
engine->local_dtls_fingerprint.type = "sha-256";
}
2013-02-02 06:15:09 +00:00
switch_core_cert_gen_fingerprint(DTLS_SRTP_FNAME, &engine->local_dtls_fingerprint);
}
2013-02-01 20:29:40 +00:00
}
//?
static int dtls_ok(switch_core_session_t *session)
{
return switch_channel_test_flag(session->channel, CF_DTLS_OK);
}
2013-02-01 20:29:40 +00:00
#ifdef _MSC_VER
/* remove this if the break is removed from the following for loop which causes unreachable code loop */
/* for (i = 0; i < engine->cand_acl_count; i++) { */
#pragma warning(push)
#pragma warning(disable:4702)
#endif
2013-10-15 21:24:32 +00:00
//?
SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session_t *session)
{
switch_call_direction_t r = switch_channel_direction(session->channel);
if (switch_channel_test_flag(session->channel, CF_3PCC)) {
r = (r == SWITCH_CALL_DIRECTION_INBOUND) ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND;
}
2013-10-15 21:24:32 +00:00
if ((switch_channel_test_flag(session->channel, CF_REINVITE) || switch_channel_test_flag(session->channel, CF_RECOVERING))
2015-01-12 17:34:42 +00:00
&& switch_channel_test_flag(session->channel, CF_AVPF)) {
2013-10-15 21:24:32 +00:00
r = SWITCH_CALL_DIRECTION_OUTBOUND;
}
return r;
}
//?
static switch_status_t ip_choose_family(switch_media_handle_t *smh, const char *ip)
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (zstr(ip)) {
return status;
}
if (strchr(ip, ':')) {
if (!zstr(smh->mparams->rtpip6)) {
smh->mparams->rtpip = smh->mparams->rtpip6;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v6\n",
switch_channel_get_name(smh->session->channel));
status = SWITCH_STATUS_SUCCESS;
}
} else {
if (!zstr(smh->mparams->rtpip4)) {
smh->mparams->rtpip = smh->mparams->rtpip4;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v4\n",
switch_channel_get_name(smh->session->channel));
status = SWITCH_STATUS_SUCCESS;
}
}
return status;
}
//?
static switch_bool_t ip_possible(switch_media_handle_t *smh, const char *ip)
{
switch_bool_t r = SWITCH_FALSE;
if (zstr(ip)) {
return r;
}
if (strchr(ip, ':')) {
r = (switch_bool_t) !zstr(smh->mparams->rtpip6);
} else {
r = (switch_bool_t) !zstr(smh->mparams->rtpip4);
}
return r;
}
2013-01-10 04:31:25 +00:00
//?
static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
2013-01-10 04:31:25 +00:00
{
switch_rtp_engine_t *engine = &smh->engines[type];
sdp_attribute_t *attr;
2013-01-17 01:04:57 +00:00
int i = 0, got_rtcp_mux = 0;
2013-10-15 21:24:32 +00:00
const char *val;
int ice_seen = 0, cid = 0, ai = 0;
2013-01-10 04:31:25 +00:00
if (engine->ice_in.is_chosen[0] && engine->ice_in.is_chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
return SWITCH_STATUS_SUCCESS;
}
engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 0;
engine->ice_in.is_chosen[0] = 0;
engine->ice_in.is_chosen[1] = 0;
engine->ice_in.cand_idx[0] = 0;
engine->ice_in.cand_idx[1] = 0;
2013-02-02 06:15:09 +00:00
if (m) {
attr = m->m_attributes;
} else {
attr = sdp->sdp_attributes;
}
2013-01-26 23:53:15 +00:00
for (; attr; attr = attr->a_next) {
2013-01-10 04:31:25 +00:00
char *data;
char *fields[15];
2013-01-14 02:12:23 +00:00
int argc = 0, j = 0;
2013-01-10 04:31:25 +00:00
if (zstr(attr->a_name)) {
continue;
}
if (!strcasecmp(attr->a_name, "ice-ufrag")) {
engine->ice_in.ufrag = switch_core_session_strdup(smh->session, attr->a_value);
ice_seen++;
2013-01-10 04:31:25 +00:00
} else if (!strcasecmp(attr->a_name, "ice-pwd")) {
engine->ice_in.pwd = switch_core_session_strdup(smh->session, attr->a_value);
} else if (!strcasecmp(attr->a_name, "ice-options")) {
engine->ice_in.options = switch_core_session_strdup(smh->session, attr->a_value);
} else if (switch_rtp_has_dtls() && dtls_ok(smh->session) && !strcasecmp(attr->a_name, "fingerprint") && !zstr(attr->a_value)) {
2013-02-01 20:29:40 +00:00
char *p;
engine->remote_dtls_fingerprint.type = switch_core_session_strdup(smh->session, attr->a_value);
if ((p = strchr(engine->remote_dtls_fingerprint.type, ' '))) {
*p++ = '\0';
switch_set_string(engine->local_dtls_fingerprint.str, p);
}
2013-10-16 17:57:15 +00:00
//if (strcasecmp(engine->remote_dtls_fingerprint.type, "sha-256")) {
// switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "Unsupported fingerprint type.\n");
//engine->local_dtls_fingerprint.type = NULL;
//engine->remote_dtls_fingerprint.type = NULL;
//}
2013-02-01 20:29:40 +00:00
2013-02-02 06:15:09 +00:00
generate_local_fingerprint(smh, type);
2013-02-01 20:29:40 +00:00
switch_channel_set_flag(smh->session->channel, CF_DTLS);
2013-10-16 17:57:15 +00:00
2013-07-11 22:38:24 +00:00
} else if (!engine->remote_ssrc && !strcasecmp(attr->a_name, "ssrc") && attr->a_value) {
engine->remote_ssrc = (uint32_t) atol(attr->a_value);
2013-10-15 21:24:32 +00:00
if (engine->rtp_session && engine->remote_ssrc) {
switch_rtp_set_remote_ssrc(engine->rtp_session, engine->remote_ssrc);
}
2013-01-17 01:04:57 +00:00
#ifdef RTCP_MUX
} else if (!strcasecmp(attr->a_name, "rtcp-mux")) {
engine->rtcp_mux = SWITCH_TRUE;
2013-11-07 22:48:00 +00:00
engine->remote_rtcp_port = engine->cur_payload_map->remote_sdp_port;
2013-01-17 01:04:57 +00:00
got_rtcp_mux++;
#endif
2013-01-10 04:31:25 +00:00
} else if (!strcasecmp(attr->a_name, "candidate")) {
2013-05-12 13:06:31 +00:00
switch_channel_set_flag(smh->session->channel, CF_ICE);
2013-01-10 04:31:25 +00:00
2013-01-14 02:12:23 +00:00
if (!engine->cand_acl_count) {
engine->cand_acl[engine->cand_acl_count++] = "wan.auto";
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "NO candidate ACL defined, Defaulting to wan.auto\n");
2013-01-10 04:31:25 +00:00
}
if (!switch_stristr(" udp ", attr->a_value)) {
continue;
}
data = switch_core_session_strdup(smh->session, attr->a_value);
2013-01-10 04:31:25 +00:00
argc = switch_split(data, ' ', fields);
cid = fields[1] ? atoi(fields[1]) - 1 : 0;
if (argc < 5 || engine->ice_in.cand_idx[cid] >= MAX_CAND - 1) {
2013-01-10 04:31:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "Invalid data\n");
continue;
}
for (i = 0; i < argc; i++) {
2013-01-14 02:12:23 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG1, "CAND %d [%s]\n", i, fields[i]);
2013-01-10 04:31:25 +00:00
}
if (!ip_possible(smh, fields[4])) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Drop %s Candidate cid: %d proto: %s type: %s addr: %s:%s (no network path)\n",
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
cid+1, fields[2], fields[7], fields[4], fields[5]);
continue;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
cid+1, fields[2], fields[7], fields[4], fields[5]);
}
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].component_id = atoi(fields[1]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].priority = atol(fields[3]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_port = (switch_port_t)atoi(fields[5]);
j = 6;
while(j < argc && fields[j+1]) {
if (!strcasecmp(fields[j], "typ")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
} else if (!strcasecmp(fields[j], "raddr")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
} else if (!strcasecmp(fields[j], "rport")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].rport = (switch_port_t)atoi(fields[j+1]);
} else if (!strcasecmp(fields[j], "generation")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
2013-01-10 04:31:25 +00:00
}
2013-01-26 23:53:15 +00:00
j += 2;
2013-01-10 04:31:25 +00:00
}
engine->ice_in.cand_idx[cid]++;
2013-01-10 04:31:25 +00:00
}
}
if (!ice_seen) {
return SWITCH_STATUS_SUCCESS;
}
for (cid = 0; cid < 2; cid++) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Searching for %s candidate.\n", cid ? "rtcp" : "rtp");
for (ai = 0; ai < engine->cand_acl_count; ai++) {
for (i = 0; i < engine->ice_in.cand_idx[cid]; i++) {
if (switch_check_network_list_ip(engine->ice_in.cands[i][cid].con_addr, engine->cand_acl[ai])) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Choose %s candidate, index %d, %s:%d\n", cid ? "rtcp" : "rtp", i,
engine->ice_in.cands[i][cid].con_addr, engine->ice_in.cands[i][cid].con_port);
engine->ice_in.chosen[cid] = i;
engine->ice_in.is_chosen[cid] = 1;
engine->ice_in.cands[i][cid].ready++;
ip_choose_family(smh, engine->ice_in.cands[i][cid].con_addr);
if (cid == 0 && got_rtcp_mux && engine->ice_in.cand_idx[1] < MAX_CAND) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Choose same candidate, index %d, for rtcp based on rtcp-mux attribute %s:%d\n", engine->ice_in.cand_idx[1],
engine->ice_in.cands[i][cid].con_addr, engine->ice_in.cands[i][cid].con_port);
2013-10-15 21:24:32 +00:00
engine->ice_in.cands[engine->ice_in.cand_idx[1]][1] = engine->ice_in.cands[i][0];
engine->ice_in.chosen[1] = engine->ice_in.cand_idx[1];
engine->ice_in.is_chosen[1] = 1;
engine->ice_in.cand_idx[1]++;
goto done_choosing;
}
goto next_cid;
}
}
}
next_cid:
continue;
}
2013-01-10 04:31:25 +00:00
done_choosing:
if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
/* PUNT */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s no suitable candidates found.\n",
switch_channel_get_name(smh->session->channel));
return SWITCH_STATUS_FALSE;
}
2013-01-14 02:12:23 +00:00
for (i = 0; i < 2; i++) {
if (engine->ice_in.cands[engine->ice_in.chosen[i]][i].ready) {
2013-01-14 02:12:23 +00:00
if (zstr(engine->ice_in.ufrag) || zstr(engine->ice_in.pwd)) {
engine->ice_in.cands[engine->ice_in.chosen[i]][i].ready = 0;
2013-01-14 02:12:23 +00:00
}
2013-01-10 04:31:25 +00:00
}
}
2012-12-21 04:57:47 +00:00
if (engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr && engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port) {
char tmp[80] = "";
2013-11-07 22:48:00 +00:00
engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(smh->session, (char *) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"setting remote %s ice addr to index %d %s:%d based on candidate\n", type2str(type), engine->ice_in.chosen[0],
engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
engine->remote_rtp_ice_port = (switch_port_t) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port;
engine->remote_rtp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
2013-11-07 22:48:00 +00:00
engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(smh->session, (char *) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
engine->cur_payload_map->remote_sdp_port = (switch_port_t) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port;
if (!smh->mparams->remote_ip) {
smh->mparams->remote_ip = engine->cur_payload_map->remote_sdp_ip;
}
switch_snprintf(tmp, sizeof(tmp), "%d", engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
}
if (engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Setting remote rtcp %s addr to %s:%d based on candidate\n", type2str(type),
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
engine->remote_rtcp_ice_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
engine->remote_rtcp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr);
engine->remote_rtcp_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
}
2013-01-17 01:04:57 +00:00
if (m && !got_rtcp_mux) {
2013-01-17 01:04:57 +00:00
engine->rtcp_mux = -1;
}
2013-06-21 05:41:25 +00:00
if (switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
2013-10-15 21:24:32 +00:00
2013-06-21 05:41:25 +00:00
if (switch_rtp_ready(engine->rtp_session) && engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "RE-Activating %s ICE\n", type2str(type));
switch_rtp_activate_ice(engine->rtp_session,
engine->ice_in.ufrag,
engine->ice_out.ufrag,
engine->ice_out.pwd,
engine->ice_in.pwd,
IPR_RTP,
#ifdef GOOGLE_ICE
ICE_GOOGLE_JINGLE,
NULL
#else
2013-10-15 21:24:32 +00:00
switch_ice_direction(smh->session) ==
2013-06-21 05:41:25 +00:00
SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
&engine->ice_in
#endif
);
}
2013-10-15 21:24:32 +00:00
if (engine->rtp_session && ((val = switch_channel_get_variable(smh->session->channel,
type == SWITCH_MEDIA_TYPE_VIDEO ?
"rtcp_video_interval_msec" : "rtcp_audio_interval_msec"))
|| (val = type == SWITCH_MEDIA_TYPE_VIDEO ?
smh->mparams->rtcp_video_interval_msec : smh->mparams->rtcp_audio_interval_msec))) {
2014-06-13 10:06:14 +00:00
2013-10-15 21:24:32 +00:00
switch_port_t remote_rtcp_port = engine->remote_rtcp_port;
2014-06-13 10:06:14 +00:00
if (remote_rtcp_port) {
if (!strcasecmp(val, "passthru")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PASSTHRU PORT %d\n",
type2str(type), remote_rtcp_port);
switch_rtp_activate_rtcp(engine->rtp_session, -1, remote_rtcp_port, engine->rtcp_mux > 0);
} else {
int interval = atoi(val);
if (interval < 100 || interval > 500000) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_ERROR,
"Invalid rtcp interval spec [%d] must be between 100 and 500000\n", interval);
interval = 5000;
2014-06-13 10:06:14 +00:00
}
2013-06-21 05:41:25 +00:00
2014-06-13 10:06:14 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PORT %d\n", type2str(type), remote_rtcp_port);
switch_rtp_activate_rtcp(engine->rtp_session, interval, remote_rtcp_port, engine->rtcp_mux > 0);
}
2013-10-15 21:24:32 +00:00
}
}
2014-07-29 17:16:56 +00:00
if (engine->rtp_session && engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready) {
2014-03-11 16:38:31 +00:00
if (engine->rtcp_mux > 0 && !strcmp(engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr)
2013-06-21 05:41:25 +00:00
&& engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port == engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Skipping %s RTCP ICE (Same as RTP)\n", type2str(type));
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP ICE\n", type2str(type));
switch_rtp_activate_ice(engine->rtp_session,
engine->ice_in.ufrag,
engine->ice_out.ufrag,
engine->ice_out.pwd,
engine->ice_in.pwd,
IPR_RTCP,
#ifdef GOOGLE_ICE
ICE_GOOGLE_JINGLE,
NULL
#else
2013-10-15 21:24:32 +00:00
switch_ice_direction(smh->session) ==
2013-06-21 05:41:25 +00:00
SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
&engine->ice_in
#endif
);
}
}
}
return ice_seen ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_BREAK;
2013-01-10 04:31:25 +00:00
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
2012-12-21 04:57:47 +00:00
SWITCH_DECLARE(void) switch_core_session_set_ice(switch_core_session_t *session)
{
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
switch_channel_set_flag(session->channel, CF_VERBOSE_SDP);
2015-01-12 17:34:42 +00:00
switch_channel_set_flag(session->channel, CF_AVPF);
switch_channel_set_flag(session->channel, CF_ICE);
2014-12-11 06:16:18 +00:00
smh->mparams->rtcp_audio_interval_msec = SWITCH_RTCP_AUDIO_INTERVAL_MSEC;
smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
}
2013-11-07 22:48:00 +00:00
#define MAX_MATCHES 30
struct matches {
const switch_codec_implementation_t *imp;
sdp_rtpmap_t *map;
int rate;
int codec_idx;
};
static void greedy_sort(switch_media_handle_t *smh, struct matches *matches, int m_idx, const switch_codec_implementation_t **codec_array, int total_codecs)
{
int j = 0, f = 0, g;
struct matches mtmp[MAX_MATCHES] = { { 0 } };
for(j = 0; j < m_idx; j++) {
*&mtmp[j] = *&matches[j];
}
for (g = 0; g < smh->mparams->num_codecs && g < total_codecs; g++) {
const switch_codec_implementation_t *imp = codec_array[g];
for(j = 0; j < m_idx; j++) {
if (mtmp[j].imp == imp) {
*&matches[f++] = *&mtmp[j];
}
}
}
}
static void clear_pmaps(switch_rtp_engine_t *engine)
{
payload_map_t *pmap;
2014-01-30 18:02:28 +00:00
for (pmap = engine->payload_map; pmap && pmap->allocated; pmap = pmap->next) {
2013-11-07 22:48:00 +00:00
pmap->negotiated = 0;
pmap->current = 0;
2013-11-07 22:48:00 +00:00
}
}
2012-12-21 04:57:47 +00:00
//?
2013-05-17 20:39:21 +00:00
SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp, uint8_t *proceed, switch_sdp_type_t sdp_type)
2012-12-21 04:57:47 +00:00
{
uint8_t match = 0;
2015-04-16 19:24:35 +00:00
uint8_t vmatch = 0;
2012-12-21 04:57:47 +00:00
switch_payload_t best_te = 0, te = 0, cng_pt = 0;
2015-07-30 23:11:08 +00:00
unsigned long best_te_rate = 8000, cng_rate = 8000;
2012-12-21 04:57:47 +00:00
sdp_media_t *m;
sdp_attribute_t *attr;
int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
int sendonly = 0, recvonly = 0;
2013-11-07 22:48:00 +00:00
int greedy = 0, x = 0, skip = 0;
2012-12-21 04:57:47 +00:00
switch_channel_t *channel = switch_core_session_get_channel(session);
const char *val;
const char *crypto = NULL;
2013-01-10 04:31:25 +00: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, got_webrtc = 0;
2012-12-21 04:57:47 +00: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;
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2013-01-25 05:08:40 +00:00
uint32_t near_rate = 0;
const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
sdp_rtpmap_t *mmap = NULL, *near_map = NULL;
2013-11-07 22:48:00 +00:00
struct matches matches[MAX_MATCHES] = { { 0 } };
struct matches near_matches[MAX_MATCHES] = { { 0 } };
2013-01-25 05:08:40 +00:00
int codec_ms = 0;
2013-11-07 22:48:00 +00:00
uint32_t remote_codec_rate = 0, fmtp_remote_codec_rate = 0;
2013-02-21 17:11:52 +00:00
const char *tmp;
2013-11-07 22:48:00 +00:00
int m_idx = 0;
int nm_idx = 0;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return 0;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
codec_array = smh->codecs;
total_codecs = smh->mparams->num_codecs;
2012-12-21 04:57:47 +00:00
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;
}
2013-02-21 17:11:52 +00:00
if (dtls_ok(session) && (tmp = switch_channel_get_variable(smh->session->channel, "webrtc_enable_dtls")) && switch_false(tmp)) {
switch_channel_clear_flag(smh->session->channel, CF_DTLS_OK);
switch_channel_clear_flag(smh->session->channel, CF_DTLS);
}
switch_core_session_parse_crypto_prefs(session);
2013-11-07 22:48:00 +00:00
clear_pmaps(a_engine);
clear_pmaps(v_engine);
2012-12-21 04:57:47 +00:00
if (proceed) *proceed = 1;
greedy = !!switch_media_handle_test_media_flag(smh, SCMF_CODEC_GREEDY);
scrooge = !!switch_media_handle_test_media_flag(smh, SCMF_CODEC_SCROOGE);
if ((val = switch_channel_get_variable(channel, "rtp_codec_negotiation"))) {
2012-12-21 04:57:47 +00:00
if (!strcasecmp(val, "generous")) {
greedy = 0;
scrooge = 0;
} else if (!strcasecmp(val, "greedy")) {
greedy = 1;
scrooge = 0;
} else if (!strcasecmp(val, "scrooge")) {
scrooge = 1;
greedy = 1;
2012-12-20 04:42:03 +00:00
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "rtp_codec_negotiation ignored invalid value : '%s' \n", val );
2012-12-21 04:57:47 +00:00
}
}
if ((smh->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
2012-12-21 20:22:25 +00:00
if ((smh->mparams->auto_rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833)) {
2012-12-21 04:57:47 +00:00
if (strstr(smh->origin, "CiscoSystemsSIP-GW-UserAgent")) {
2012-12-21 20:22:25 +00:00
a_engine->rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
}
}
2012-12-21 20:22:25 +00:00
if ((smh->mparams->auto_rtp_bugs & RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833)) {
2012-12-21 04:57:47 +00:00
if (strstr(smh->origin, "Sonus_UAC")) {
2012-12-21 20:22:25 +00:00
a_engine->rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
2012-12-21 04:57:47 +00:00
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");
2012-12-20 04:42:03 +00:00
}
}
}
if ((val = switch_channel_get_variable(session->channel, "rtp_liberal_dtmf")) && switch_true(val)) {
2012-12-21 04:57:47 +00:00
switch_channel_set_flag(session->channel, CF_LIBERAL_DTMF);
}
2012-12-20 04:42:03 +00:00
2012-12-21 04:57:47 +00:00
if (switch_stristr("T38FaxFillBitRemoval:", r_sdp) || switch_stristr("T38FaxTranscodingMMR:", r_sdp) ||
switch_stristr("T38FaxTranscodingJBIG:", r_sdp)) {
switch_channel_set_variable(session->channel, "t38_broken_boolean", "true");
}
switch_core_media_find_zrtp_hash(session, sdp);
switch_core_media_pass_zrtp_hash(session);
check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, NULL);
check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, NULL);
if ((sdp->sdp_connection && sdp->sdp_connection->c_address && !strcmp(sdp->sdp_connection->c_address, "0.0.0.0"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "RFC2543 from March 1999 called; They want their 0.0.0.0 hold method back.....\n");
sendonly = 2; /* global sendonly always wins */
}
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
for (m = sdp->sdp_media; m; m = m->m_next) {
sdp_connection_t *connection;
switch_core_session_t *other_session;
if (!m->m_port) {
continue;
}
2012-12-21 04:57:47 +00:00
ptime = dptime;
maxptime = dmaxptime;
2015-01-12 17:34:42 +00:00
if (m->m_proto == sdp_proto_extended_srtp || m->m_proto == sdp_proto_extended_rtp) {
2013-01-10 04:31:25 +00:00
got_webrtc++;
switch_core_session_set_ice(session);
2013-01-10 04:31:25 +00:00
}
2013-07-11 22:38:24 +00:00
if (m->m_proto_name && !strcasecmp(m->m_proto_name, "UDP/TLS/RTP/SAVPF")) {
2015-01-12 17:34:42 +00:00
switch_channel_set_flag(session->channel, CF_AVPF_MOZ);
}
if (m->m_proto_name && !strcasecmp(m->m_proto_name, "UDP/RTP/AVPF")) {
switch_channel_set_flag(session->channel, CF_AVPF_MOZ);
}
2013-01-10 04:31:25 +00:00
if (m->m_proto == sdp_proto_srtp || m->m_proto == sdp_proto_extended_srtp) {
2012-12-21 04:57:47 +00:00
if (m->m_type == sdp_media_audio) {
got_savp++;
} else {
got_video_savp++;
}
} else if (m->m_proto == sdp_proto_rtp) {
if (m->m_type == sdp_media_audio) {
got_avp++;
} else {
got_video_avp++;
}
} else if (m->m_proto == sdp_proto_udptl) {
got_udptl++;
}
if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
switch_t38_options_t *t38_options = switch_core_media_process_udptl(session, sdp, m);
if (switch_channel_test_app_flag_key("T38", session->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", session->channel, CF_APP_T38);
match = 0;
goto done;
} else {
const char *var = switch_channel_get_variable(channel, "t38_passthru");
2013-06-26 15:47:40 +00:00
int pass = switch_channel_test_flag(smh->session->channel, CF_T38_PASSTHRU);
2012-12-21 04:57:47 +00:00
if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38)) {
if (proceed) *proceed = 0;
}
if (var) {
if (!(pass = switch_true(var))) {
if (!strcasecmp(var, "once")) {
pass = 2;
}
}
}
2013-06-26 15:47:40 +00:00
if ((pass == 2 && switch_channel_test_flag(smh->session->channel, CF_T38_PASSTHRU))
2012-12-22 03:30:14 +00:00
|| !switch_channel_test_flag(session->channel, CF_REINVITE) ||
2012-12-21 04:57:47 +00:00
switch_channel_test_flag(session->channel, CF_PROXY_MODE) ||
switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) ||
!switch_rtp_ready(a_engine->rtp_session)) {
pass = 0;
}
if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
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(a_engine->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session);
char tmp[32] = "";
if (!switch_channel_test_flag(other_channel, CF_ANSWERED)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
SWITCH_LOG_WARNING, "%s Error Passing T.38 to unanswered channel %s\n",
switch_channel_get_name(session->channel), switch_channel_get_name(other_channel));
switch_core_session_rwunlock(other_session);
pass = 0;
match = 0;
goto done;
}
2012-12-21 04:57:47 +00:00
if (switch_true(switch_channel_get_variable(session->channel, "t38_broken_boolean")) &&
switch_true(switch_channel_get_variable(session->channel, "t38_pass_broken_boolean"))) {
switch_channel_set_variable(other_channel, "t38_broken_boolean", "true");
}
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(session, t38_options->remote_ip);
a_engine->cur_payload_map->remote_sdp_port = t38_options->remote_port;
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
if (remote_host && remote_port && !strcmp(remote_host, a_engine->cur_payload_map->remote_sdp_ip) && remote_port == a_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
switch_channel_get_name(session->channel));
} else {
const char *err = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
remote_host, remote_port, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port);
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip);
2012-12-21 04:57:47 +00:00
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
2013-11-07 22:48:00 +00:00
if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
}
switch_core_media_copy_t38_options(t38_options, other_session);
2013-06-26 15:47:40 +00:00
switch_channel_set_flag(smh->session->channel, CF_T38_PASSTHRU);
switch_channel_set_flag(other_session->channel, CF_T38_PASSTHRU);
2012-12-21 04:57:47 +00:00
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;
int ice = 0;
nm_idx = 0;
m_idx = 0;
memset(matches, 0, sizeof(matches[0]) * MAX_MATCHES);
memset(near_matches, 0, sizeof(near_matches[0]) * MAX_MATCHES);
if (!sendonly && (m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive)) {
sendonly = 1;
}
if (!sendonly && m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")) {
sendonly = 1;
}
a_engine->rmode = sdp_media_flow(m->m_mode);
if (sdp_type == SDP_TYPE_REQUEST) {
switch(a_engine->rmode) {
case SWITCH_MEDIA_FLOW_RECVONLY:
switch_channel_set_variable(smh->session->channel, "audio_media_flow", "sendonly");
a_engine->smode = SWITCH_MEDIA_FLOW_SENDONLY;
break;
case SWITCH_MEDIA_FLOW_SENDONLY:
switch_channel_set_variable(smh->session->channel, "audio_media_flow", "recvonly");
a_engine->smode = SWITCH_MEDIA_FLOW_RECVONLY;
break;
default:
switch_channel_set_variable(smh->session->channel, "audio_media_flow", "sendrecv");
a_engine->smode = SWITCH_MEDIA_FLOW_SENDRECV;
break;
}
}
for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
if (zstr(attr->a_name)) {
continue;
}
if (!strncasecmp(attr->a_name, "ice", 3)) {
ice++;
} else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendonly")) {
sendonly = 1;
switch_channel_set_variable(session->channel, "media_audio_mode", "recvonly");
} else if (sendonly < 2 && !strcasecmp(attr->a_name, "inactive")) {
sendonly = 1;
switch_channel_set_variable(session->channel, "media_audio_mode", "inactive");
} else if (!strcasecmp(attr->a_name, "recvonly")) {
switch_channel_set_variable(session->channel, "media_audio_mode", "sendonly");
recvonly = 1;
if (switch_rtp_ready(a_engine->rtp_session)) {
switch_rtp_set_max_missed_packets(a_engine->rtp_session, 0);
a_engine->max_missed_hold_packets = 0;
a_engine->max_missed_packets = 0;
} else {
switch_channel_set_variable(session->channel, "rtp_timeout_sec", "0");
switch_channel_set_variable(session->channel, "rtp_hold_timeout_sec", "0");
}
} else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) {
sendonly = 0;
} else if (!strcasecmp(attr->a_name, "ptime")) {
ptime = dptime = atoi(attr->a_value);
} else if (!strcasecmp(attr->a_name, "maxptime")) {
maxptime = dmaxptime = atoi(attr->a_value);
}
}
if (sendonly == 2 && ice) {
sendonly = 0;
}
if (sendonly != 1 && recvonly != 1) {
switch_channel_set_variable(session->channel, "media_audio_mode", NULL);
}
if (sendonly) {
2015-02-21 06:57:10 +00:00
a_engine->smode = sdp_media_flow(sdp_sendonly);
} else if (recvonly) {
2015-02-21 06:57:10 +00:00
a_engine->smode = sdp_media_flow(sdp_recvonly);
}
if (!(switch_media_handle_test_media_flag(smh, SCMF_DISABLE_HOLD)
|| ((val = switch_channel_get_variable(session->channel, "rtp_disable_hold"))
&& switch_true(val)))
&& !smh->mparams->hold_laps) {
smh->mparams->hold_laps++;
if (switch_core_media_toggle_hold(session, sendonly)) {
reneg = switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_HOLD);
if ((val = switch_channel_get_variable(session->channel, "rtp_renegotiate_codec_on_hold"))) {
reneg = switch_true(val);
}
}
}
if (reneg) {
reneg = switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_REINVITE);
if ((val = switch_channel_get_variable(session->channel, "rtp_renegotiate_codec_on_reinvite"))) {
reneg = switch_true(val);
}
}
if (session->bugs) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Session is connected to a media bug. "
"Re-Negotiation implicitly disabled.\n");
reneg = 0;
}
if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
reneg = 0;
}
if (sdp_type == SDP_TYPE_RESPONSE && smh->num_negotiated_codecs) {
/* response to re-invite or update, only negotiated codecs are valid */
reneg = 0;
}
if (!reneg && smh->num_negotiated_codecs) {
codec_array = smh->negotiated_codecs;
total_codecs = smh->num_negotiated_codecs;
} else if (reneg) {
smh->mparams->num_codecs = 0;
switch_core_media_prepare_codecs(session, SWITCH_FALSE);
codec_array = smh->codecs;
total_codecs = smh->mparams->num_codecs;
}
2012-12-21 04:57:47 +00:00
if (switch_rtp_has_dtls() && dtls_ok(session)) {
2013-02-05 21:27:50 +00:00
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "fingerprint") && !zstr(attr->a_value)) {
got_crypto = 1;
}
2013-02-02 06:15:09 +00:00
}
}
2012-12-21 04:57:47 +00:00
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
switch_channel_set_variable(session->channel, "rtp_remote_audio_rtcp_port", attr->a_value);
2013-04-03 20:41:22 +00:00
a_engine->remote_rtcp_port = (switch_port_t)atoi(attr->a_value);
if (!smh->mparams->rtcp_audio_interval_msec) {
2014-12-11 06:16:18 +00:00
smh->mparams->rtcp_audio_interval_msec = SWITCH_RTCP_AUDIO_INTERVAL_MSEC;
}
2012-12-21 04:57:47 +00:00
} 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 < 1 && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) {
2012-12-21 04:57:47 +00:00
int crypto_tag;
2012-12-21 20:22:25 +00:00
if (!(smh->mparams->ndlb & SM_NDLB_ALLOW_CRYPTO_IN_AVP) &&
!switch_true(switch_channel_get_variable(session->channel, "rtp_allow_crypto_in_avp"))) {
2013-01-10 04:31:25 +00:00
if (m->m_proto != sdp_proto_srtp && !got_webrtc) {
2012-12-21 04:57:47 +00:00
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(session,
2013-05-17 20:39:21 +00:00
"rtp_has_crypto", SWITCH_MEDIA_TYPE_AUDIO, crypto, crypto_tag, sdp_type);
2012-12-21 04:57:47 +00:00
}
}
if (got_crypto == -1 && got_savp && !got_avp && !got_webrtc) {
2014-01-24 00:44:30 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Declining invite with only SAVP because secure media is administratively disabled\n");
match = 0;
break;
}
2012-12-21 04:57:47 +00:00
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;
}
x = 0;
2013-01-14 04:29:39 +00:00
2012-12-21 04:57:47 +00:00
for (map = m->m_rtpmaps; map; map = map->rm_next) {
2013-11-07 22:48:00 +00:00
int32_t i;
2012-12-21 04:57:47 +00:00
const char *rm_encoding;
2013-11-07 22:48:00 +00:00
uint32_t map_bit_rate = 0;
switch_codec_fmtp_t codec_fmtp = { 0 };
int map_channels = map->rm_params ? atoi(map->rm_params) : 1;
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
if (!strcasecmp(rm_encoding, "telephone-event")) {
2013-11-07 22:48:00 +00:00
if (!best_te || map->rm_rate == a_engine->cur_payload_map->rm_rate) {
2012-12-21 04:57:47 +00:00
best_te = (switch_payload_t) map->rm_pt;
2015-07-30 23:11:08 +00:00
best_te_rate = map->rm_rate;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set telephone-event payload to %u@%ld\n", best_te, best_te_rate);
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
continue;
2012-12-21 04:57:47 +00:00
}
if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && !cng_pt && !strcasecmp(rm_encoding, "CN")) {
cng_pt = (switch_payload_t) map->rm_pt;
if (a_engine->rtp_session) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
2013-01-08 18:59:02 +00:00
switch_rtp_set_cng_pt(a_engine->rtp_session, smh->mparams->cng_pt);
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
continue;
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
2013-02-07 20:34:42 +00:00
if (x++ < skip) {
continue;
}
2012-12-21 04:57:47 +00:00
if (match) {
continue;
}
codec_ms = ptime;
if (switch_channel_get_variable(session->channel, "rtp_h_X-Broken-PTIME") && a_engine->read_impl.microseconds_per_packet) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Overwriting ptime from a known broken endpoint with the currently used value of %d ms\n", a_engine->read_impl.microseconds_per_packet / 1000);
codec_ms = a_engine->read_impl.microseconds_per_packet / 1000;
}
2012-12-21 04:57:47 +00:00
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;
}
2013-11-07 22:48:00 +00:00
remote_codec_rate = map->rm_rate;
fmtp_remote_codec_rate = 0;
memset(&codec_fmtp, 0, sizeof(codec_fmtp));
2012-12-21 04:57:47 +00:00
if (zstr(map->rm_fmtp)) {
if (!strcasecmp(map->rm_encoding, "ilbc")) {
2012-12-21 04:57:47 +00:00
codec_ms = 30;
map_bit_rate = 13330;
} else if (!strcasecmp(map->rm_encoding, "isac")) {
2013-01-25 05:08:40 +00:00
codec_ms = 30;
map_bit_rate = 32000;
2012-12-21 04:57:47 +00:00
}
} 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);
}
2013-11-07 22:48:00 +00:00
if (codec_fmtp.actual_samples_per_second) {
fmtp_remote_codec_rate = codec_fmtp.actual_samples_per_second;
}
if (codec_fmtp.stereo) {
map_channels = 2;
} else if (!strcasecmp(map->rm_encoding, "opus")) {
map_channels = 1;
}
2012-12-21 04:57:47 +00:00
}
}
2013-11-07 22:48:00 +00:00
for (i = 0; i < smh->mparams->num_codecs && i < total_codecs; i++) {
2012-12-21 04:57:47 +00:00
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;
2012-12-21 04:57:47 +00:00
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:%d]/[%s:%d:%u:%d:%u:%d]\n",
rm_encoding, map->rm_pt, (int) remote_codec_rate, codec_ms, map_bit_rate, map_channels,
imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate, imp->number_of_channels);
2012-12-21 20:22:25 +00:00
if ((zstr(map->rm_encoding) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
2012-12-21 04:57:47 +00:00
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
2013-11-07 22:48:00 +00:00
match = (!strcasecmp(rm_encoding, imp->iananame) &&
((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95)) &&
2013-11-07 22:48:00 +00:00
(remote_codec_rate == codec_rate || fmtp_remote_codec_rate == imp->actual_samples_per_second)) ? 1 : 0;
if (fmtp_remote_codec_rate) {
remote_codec_rate = fmtp_remote_codec_rate;
}
2012-12-21 04:57:47 +00:00
}
if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc") &&
strcasecmp(map->rm_encoding, "isac")) {
2012-12-21 04:57:47 +00:00
/* if a bit rate is specified and doesn't match, this is not a codec match, except for ILBC */
match = 0;
}
2013-11-07 22:48:00 +00:00
if (match && remote_codec_rate && codec_rate && remote_codec_rate != codec_rate && (!strcasecmp(map->rm_encoding, "pcma") ||
2013-01-25 05:08:40 +00:00
!strcasecmp(map->rm_encoding, "pcmu"))) {
2012-12-21 04:57:47 +00:00
/* 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) || remote_codec_rate != codec_rate) {
2013-10-31 16:37:46 +00:00
/* ptime does not match */
match = 0;
2013-11-07 22:48:00 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Audio Codec Compare [%s:%d:%u:%d:%u:%d] is saved as a near-match\n",
imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate, imp->number_of_channels);
2013-10-31 16:37:46 +00:00
2013-11-07 22:48:00 +00:00
near_matches[nm_idx].codec_idx = i;
near_matches[nm_idx].rate = remote_codec_rate;
near_matches[nm_idx].imp = imp;
near_matches[nm_idx].map = map;
nm_idx++;
2013-04-23 23:08:41 +00:00
2013-10-31 16:37:46 +00:00
continue;
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
matches[m_idx].codec_idx = i;
matches[m_idx].rate = codec_rate;
matches[m_idx].imp = imp;
matches[m_idx].map = map;
m_idx++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Audio Codec Compare [%s:%d:%u:%d:%u:%d] ++++ is saved as a match\n",
imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate, imp->number_of_channels);
2013-11-07 22:48:00 +00:00
if (m_idx >= MAX_MATCHES) {
break;
}
match = 0;
}
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
if (m_idx >= MAX_MATCHES) {
2013-01-25 05:08:40 +00:00
break;
}
}
2012-12-21 04:57:47 +00:00
if (smh->crypto_mode == CRYPTO_MODE_MANDATORY && got_crypto < 1) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Crypto not negotiated but required.\n");
match = 0;
m_idx = nm_idx = 0;
}
2013-11-07 22:48:00 +00:00
if (!m_idx && nm_idx) {
int j;
2013-04-23 23:08:41 +00:00
2013-11-07 22:48:00 +00:00
for(j = 0; j < nm_idx; j++) {
const switch_codec_implementation_t *search[1];
char *prefs[1];
char tmp[80];
int num;
const switch_codec_implementation_t *timp = NULL;
near_rate = near_matches[j].rate;
near_match = near_matches[j].imp;
near_map = near_matches[j].map;
switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui%dc", near_match->iananame, near_rate ? near_rate : near_match->samples_per_second,
codec_ms, near_match->number_of_channels);
2013-11-07 22:48:00 +00:00
prefs[0] = tmp;
num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
2013-01-25 05:08:40 +00:00
2013-11-07 22:48:00 +00:00
if (num) {
timp = search[0];
} else {
timp = near_match;
}
2013-01-25 05:08:40 +00:00
2013-11-07 22:48:00 +00:00
if (!maxptime || timp->microseconds_per_packet / 1000 <= maxptime) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Substituting codec %s@%ui@%uh@%dc\n",
timp->iananame, timp->microseconds_per_packet / 1000, timp->actual_samples_per_second, timp->number_of_channels);
2013-11-07 22:48:00 +00:00
match = 1;
matches[m_idx].codec_idx = near_matches[j].codec_idx;
matches[m_idx].rate = near_rate;
matches[m_idx].imp = timp;
matches[m_idx].map = near_map;
m_idx++;
break;
}
2013-01-25 05:08:40 +00:00
}
}
2013-04-23 19:27:09 +00:00
2013-11-07 22:48:00 +00:00
if (m_idx) {
int j;
2013-11-07 22:48:00 +00:00
if (greedy) { /* sort in favor of mine */
greedy_sort(smh, matches, m_idx, codec_array, total_codecs);
}
match = 1;
a_engine->codec_negotiated = 1;
smh->num_negotiated_codecs = 0;
2013-11-07 22:48:00 +00:00
for(j = 0; j < m_idx; j++) {
payload_map_t *pmap = switch_core_media_add_payload_map(session,
2013-11-07 22:48:00 +00:00
SWITCH_MEDIA_TYPE_AUDIO,
2013-11-18 19:43:30 +00:00
matches[j].map->rm_encoding,
matches[j].imp->modname,
2013-11-18 19:43:30 +00:00
matches[j].map->rm_fmtp,
2013-11-07 22:48:00 +00:00
sdp_type,
matches[j].map->rm_pt,
matches[j].imp->samples_per_second,
matches[j].imp->microseconds_per_packet / 1000,
2014-06-13 05:49:10 +00:00
matches[j].imp->number_of_channels,
2013-11-07 22:48:00 +00:00
SWITCH_TRUE);
2013-11-07 22:48:00 +00:00
mimp = matches[j].imp;
mmap = matches[j].map;
if (j == 0) {
a_engine->cur_payload_map = pmap;
a_engine->cur_payload_map->current = 1;
if (a_engine->rtp_session) {
switch_rtp_set_default_payload(a_engine->rtp_session, pmap->pt);
}
}
2013-11-07 22:48:00 +00:00
pmap->rm_encoding = switch_core_session_strdup(session, (char *) mmap->rm_encoding);
pmap->iananame = switch_core_session_strdup(session, (char *) mimp->iananame);
2013-11-22 03:55:45 +00:00
pmap->recv_pt = (switch_payload_t) mmap->rm_pt;
2013-11-07 22:48:00 +00:00
pmap->rm_rate = mimp->samples_per_second;
pmap->adv_rm_rate = mimp->samples_per_second;
if (strcasecmp(mimp->iananame, "g722")) {
pmap->rm_rate = mimp->actual_samples_per_second;
}
pmap->codec_ms = mimp->microseconds_per_packet / 1000;
pmap->bitrate = mimp->bits_per_second;
pmap->channels = mmap->rm_params ? atoi(mmap->rm_params) : 1;
if (!strcasecmp((char *) mmap->rm_encoding, "opus")) {
if (pmap->channels == 1) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid SDP for opus. Don't ask.. but it needs a /2\n");
pmap->adv_channels = 1;
} else {
pmap->adv_channels = 2; /* IKR ???*/
}
if (!zstr((char *) mmap->rm_fmtp) && switch_stristr("stereo=1", (char *) mmap->rm_fmtp)) {
pmap->channels = 2;
} else {
pmap->channels = 1;
}
} else {
2013-11-07 22:48:00 +00:00
pmap->adv_channels = pmap->channels;
}
2013-11-07 22:48:00 +00:00
pmap->remote_sdp_ip = switch_core_session_strdup(session, (char *) connection->c_address);
pmap->remote_sdp_port = (switch_port_t) m->m_port;
pmap->rm_fmtp = switch_core_session_strdup(session, (char *) mmap->rm_fmtp);
pmap->agreed_pt = (switch_payload_t) mmap->rm_pt;
smh->negotiated_codecs[smh->num_negotiated_codecs++] = mimp;
pmap->recv_pt = (switch_payload_t)mmap->rm_pt;
}
2013-11-07 22:48:00 +00:00
}
2013-11-07 22:48:00 +00:00
if (match) {
char tmp[50];
2013-11-22 03:55:45 +00:00
//const char *mirror = switch_channel_get_variable(session->channel, "rtp_mirror_remote_audio_codec_payload");
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip);
2013-01-25 05:08:40 +00:00
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
2013-11-07 22:48:00 +00:00
if (a_engine->cur_payload_map->pt == smh->mparams->te) {
switch_payload_t pl = 0;
payload_map_t *pmap;
switch_mutex_lock(smh->sdp_mutex);
for (pmap = a_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
if (pmap->pt > pl) {
pl = pmap->pt;
}
}
switch_mutex_unlock(smh->sdp_mutex);
smh->mparams->te = (switch_payload_t) ++pl;
}
2013-11-22 03:55:45 +00:00
#if 0
2013-01-25 05:08:40 +00:00
if (!switch_true(mirror) &&
switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND &&
(!switch_channel_test_flag(session->channel, CF_REINVITE) || switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_REINVITE))) {
2013-11-14 17:19:04 +00:00
switch_core_media_get_offered_pt(session, matches[0].imp, &a_engine->cur_payload_map->recv_pt);
2013-01-25 05:08:40 +00:00
}
2013-11-22 03:55:45 +00:00
#endif
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->recv_pt);
2013-01-25 05:08:40 +00:00
switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp);
2012-12-21 04:57:47 +00:00
if (switch_core_codec_ready(&a_engine->read_codec) && strcasecmp(matches[0].imp->iananame, a_engine->read_codec.implementation->iananame)) {
2013-11-07 22:48:00 +00:00
a_engine->reset_codec = 1;
}
if (switch_core_media_set_codec(session, 0, smh->mparams->codec_flags) == SWITCH_STATUS_SUCCESS) {
if (check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m) == SWITCH_STATUS_FALSE) {
match = 0;
} else {
got_audio = 1;
}
2013-01-25 05:08:40 +00:00
} else {
match = 0;
2012-12-21 04:57:47 +00:00
}
}
2015-07-30 23:11:08 +00:00
for (map = m->m_rtpmaps; map; map = map->rm_next) {
const char *rm_encoding;
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
if (!strcasecmp(rm_encoding, "telephone-event")) {
if (!best_te || map->rm_rate == a_engine->cur_payload_map->adv_rm_rate) {
2015-07-30 23:11:08 +00:00
best_te = (switch_payload_t) map->rm_pt;
best_te_rate = map->rm_rate;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set telephone-event payload to %u@%lu\n", best_te, best_te_rate);
}
continue;
}
if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && !strcasecmp(rm_encoding, "CN")) {
if (!cng_pt || map->rm_rate == a_engine->cur_payload_map->adv_rm_rate) {
2015-07-30 23:11:08 +00:00
cng_pt = (switch_payload_t) map->rm_pt;
cng_rate = map->rm_rate;
if (a_engine->rtp_session) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u@%lu\n", cng_pt, cng_rate);
switch_rtp_set_cng_pt(a_engine->rtp_session, smh->mparams->cng_pt);
}
}
continue;
}
}
2015-08-17 17:13:55 +00:00
if (cng_rate != a_engine->cur_payload_map->adv_rm_rate) {
2015-07-30 23:11:08 +00:00
cng_rate = 8000;
}
2015-08-17 17:13:55 +00:00
if (best_te_rate != a_engine->cur_payload_map->adv_rm_rate) {
2015-07-30 23:11:08 +00:00
best_te_rate = 8000;
}
2013-02-26 22:13:19 +00:00
if (!best_te && (switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) ||
switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF))) {
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
2012-12-24 03:20:03 +00:00
"No 2833 in SDP. Liberal DTMF mode adding %d as telephone-event.\n", smh->mparams->te);
best_te = smh->mparams->te;
2012-12-21 04:57:47 +00:00
}
if (best_te) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
2012-12-22 03:30:14 +00:00
te = smh->mparams->te = (switch_payload_t) best_te;
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", best_te);
2013-06-06 18:17:20 +00:00
switch_channel_set_variable(session->channel, "dtmf_type", "rfc2833");
smh->mparams->dtmf_type = DTMF_2833;
2012-12-21 04:57:47 +00:00
if (a_engine->rtp_session) {
switch_rtp_set_telephony_event(a_engine->rtp_session, (switch_payload_t) best_te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_send_payload", "%d", best_te);
2012-12-21 04:57:47 +00:00
}
} else {
2012-12-22 03:30:14 +00:00
te = smh->mparams->recv_te = smh->mparams->te = (switch_payload_t) best_te;
2015-07-30 23:11:08 +00:00
smh->mparams->te_rate = best_te_rate;
2012-12-21 04:57:47 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send/recv payload to %u\n", te);
2013-06-06 18:17:20 +00:00
switch_channel_set_variable(session->channel, "dtmf_type", "rfc2833");
smh->mparams->dtmf_type = DTMF_2833;
2012-12-21 04:57:47 +00:00
if (a_engine->rtp_session) {
switch_rtp_set_telephony_event(a_engine->rtp_session, te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_send_payload", "%d", te);
2012-12-21 04:57:47 +00:00
switch_rtp_set_telephony_recv_event(a_engine->rtp_session, te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_recv_payload", "%d", te);
2012-12-21 04:57:47 +00:00
}
}
} else {
/* by default, use SIP INFO if 2833 is not in the SDP */
if (!switch_false(switch_channel_get_variable(channel, "rtp_info_when_no_2833"))) {
2012-12-21 04:57:47 +00:00
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(session->channel, "dtmf_type", "info");
2012-12-22 23:34:08 +00:00
smh->mparams->dtmf_type = DTMF_INFO;
2012-12-22 03:30:14 +00:00
te = smh->mparams->recv_te = smh->mparams->te = 0;
2012-12-21 04:57:47 +00:00
} else {
switch_channel_set_variable(session->channel, "dtmf_type", "none");
2012-12-22 23:34:08 +00:00
smh->mparams->dtmf_type = DTMF_NONE;
2012-12-22 03:30:14 +00:00
te = smh->mparams->recv_te = smh->mparams->te = 0;
2012-12-21 04:57:47 +00:00
}
}
} 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;
2015-04-16 19:24:35 +00:00
int i;
vmatch = 0;
2013-11-07 22:48:00 +00:00
nm_idx = 0;
m_idx = 0;
memset(matches, 0, sizeof(matches[0]) * MAX_MATCHES);
memset(near_matches, 0, sizeof(near_matches[0]) * MAX_MATCHES);
2012-12-21 04:57:47 +00:00
switch_channel_set_variable(session->channel, "video_possible", "true");
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
}
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
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;
}
v_engine->rmode = sdp_media_flow(m->m_mode);
if (sdp_type == SDP_TYPE_REQUEST) {
switch(v_engine->rmode) {
case SWITCH_MEDIA_FLOW_RECVONLY:
switch_channel_set_variable(smh->session->channel, "video_media_flow", "sendonly");
v_engine->smode = SWITCH_MEDIA_FLOW_SENDONLY;
break;
case SWITCH_MEDIA_FLOW_SENDONLY:
switch_channel_set_variable(smh->session->channel, "video_media_flow", "recvonly");
v_engine->smode = SWITCH_MEDIA_FLOW_RECVONLY;
break;
default:
switch_channel_set_variable(smh->session->channel, "video_media_flow", "sendrecv");
v_engine->smode = SWITCH_MEDIA_FLOW_SENDRECV;
break;
}
}
2012-12-21 04:57:47 +00:00
for (map = m->m_rtpmaps; map; map = map->rm_next) {
if (switch_rtp_has_dtls() && dtls_ok(session)) {
2013-02-05 21:45:35 +00:00
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "fingerprint") && !zstr(attr->a_value)) {
got_video_crypto = 1;
}
2013-02-02 06:15:09 +00:00
}
}
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) {
//framerate = atoi(attr->a_value);
2013-11-20 20:38:16 +00:00
} else if (!strcasecmp(attr->a_name, "rtcp-fb")) {
if (!zstr(attr->a_value)) {
if (switch_stristr("fir", attr->a_value)) {
v_engine->fir++;
}
if (switch_stristr("pli", attr->a_value)) {
v_engine->pli++;
}
if (switch_stristr("nack", attr->a_value)) {
v_engine->nack++;
}
2015-05-14 23:01:22 +00:00
if (switch_stristr("tmmbr", attr->a_value)) {
v_engine->tmmbr++;
}
2013-11-20 20:38:16 +00:00
2014-12-11 06:16:18 +00:00
smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
2013-11-20 20:38:16 +00:00
}
} else if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value && !strcmp(attr->a_value, "1")) {
switch_channel_set_variable(session->channel, "rtp_remote_video_rtcp_port", attr->a_value);
2013-04-03 20:41:22 +00:00
v_engine->remote_rtcp_port = (switch_port_t)atoi(attr->a_value);
if (!smh->mparams->rtcp_video_interval_msec) {
2014-12-11 06:16:18 +00:00
smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
}
2013-01-14 04:29:39 +00:00
} else if (!got_video_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) {
2012-12-21 04:57:47 +00:00
int crypto_tag;
2012-12-21 20:22:25 +00:00
if (!(smh->mparams->ndlb & SM_NDLB_ALLOW_CRYPTO_IN_AVP) &&
!switch_true(switch_channel_get_variable(session->channel, "rtp_allow_crypto_in_avp"))) {
2013-01-10 04:31:25 +00:00
if (m->m_proto != sdp_proto_srtp && !got_webrtc) {
2012-12-21 04:57:47 +00:00
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(session,
"rtp_has_video_crypto",
2013-05-17 20:39:21 +00:00
SWITCH_MEDIA_TYPE_VIDEO, crypto, crypto_tag, sdp_type);
2012-12-21 04:57:47 +00:00
}
}
2013-01-14 04:29:39 +00:00
2012-12-21 04:57:47 +00:00
if (!(rm_encoding = map->rm_encoding)) {
rm_encoding = "";
}
2012-12-21 04:57:47 +00:00
for (i = 0; i < total_codecs; i++) {
const switch_codec_implementation_t *imp = codec_array[i];
2013-06-20 18:10:21 +00:00
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
2012-12-21 04:57:47 +00:00
continue;
}
2013-11-07 22:48:00 +00:00
2012-12-21 04:57:47 +00:00
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-21 20:22:25 +00:00
if ((zstr(map->rm_encoding) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
2012-12-21 04:57:47 +00: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)) {
2013-11-07 22:48:00 +00:00
matches[m_idx].imp = imp;
matches[m_idx].map = map;
2013-11-20 17:00:29 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d] +++ is saved as a match\n",
2013-11-07 22:48:00 +00:00
imp->iananame, imp->ianacode);
m_idx++;
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
vmatch = 0;
2012-12-21 04:57:47 +00:00
}
2013-11-07 22:48:00 +00:00
}
2012-12-21 04:57:47 +00:00
if (smh->crypto_mode == CRYPTO_MODE_MANDATORY && got_video_crypto < 1) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Crypto not negotiated but required.\n");
vmatch = 0;
m_idx = 0;
}
2013-11-07 22:48:00 +00:00
if (m_idx) {
char tmp[50];
2013-11-22 03:55:45 +00:00
//const char *mirror = switch_channel_get_variable(session->channel, "rtp_mirror_remote_video_codec_payload");
2013-11-07 22:48:00 +00:00
int j = 0;
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
if (greedy) { /* sort in favor of mine */
greedy_sort(smh, matches, m_idx, codec_array, total_codecs);
}
2013-11-07 22:48:00 +00:00
vmatch = 1;
v_engine->codec_negotiated = 1;
2013-11-07 22:48:00 +00:00
for(j = 0; j < m_idx; j++) {
payload_map_t *pmap = switch_core_media_add_payload_map(session,
SWITCH_MEDIA_TYPE_VIDEO,
matches[j].map->rm_encoding,
matches[j].imp->modname,
2013-11-18 19:43:30 +00:00
matches[j].map->rm_fmtp,
2013-11-07 22:48:00 +00:00
sdp_type,
matches[j].map->rm_pt,
matches[j].imp->samples_per_second,
matches[j].imp->microseconds_per_packet / 1000,
2014-06-13 05:49:10 +00:00
matches[j].imp->number_of_channels,
2013-11-07 22:48:00 +00:00
SWITCH_TRUE);
2013-11-07 22:48:00 +00:00
if (j == 0) {
v_engine->cur_payload_map = pmap;
v_engine->cur_payload_map->current = 1;
if (v_engine->rtp_session) {
switch_rtp_set_default_payload(v_engine->rtp_session, pmap->pt);
}
2013-11-07 22:48:00 +00:00
}
mimp = matches[j].imp;
map = matches[j].map;
pmap->rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding);
2013-11-22 03:55:45 +00:00
pmap->recv_pt = (switch_payload_t) map->rm_pt;
2013-11-07 22:48:00 +00:00
pmap->rm_rate = map->rm_rate;
pmap->codec_ms = mimp->microseconds_per_packet / 1000;
pmap->remote_sdp_ip = switch_core_session_strdup(session, (char *) connection->c_address);
pmap->remote_sdp_port = (switch_port_t) m->m_port;
2013-11-07 22:48:00 +00:00
pmap->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
pmap->agreed_pt = (switch_payload_t) map->rm_pt;
smh->negotiated_codecs[smh->num_negotiated_codecs++] = mimp;
2012-12-21 04:57:47 +00:00
2013-11-22 03:55:45 +00:00
#if 0
2013-11-14 17:19:04 +00:00
if (j == 0 && (!switch_true(mirror) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) {
2013-11-07 22:48:00 +00:00
switch_core_media_get_offered_pt(session, mimp, &pmap->recv_pt);
}
2013-11-22 03:55:45 +00:00
#endif
2013-11-07 22:48:00 +00:00
}
2012-12-21 04:57:47 +00:00
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, v_engine->cur_payload_map->remote_sdp_ip);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
switch_channel_set_variable(session->channel, "rtp_video_fmtp", v_engine->cur_payload_map->rm_fmtp);
switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->agreed_pt);
switch_channel_set_variable(session->channel, "rtp_video_pt", tmp);
switch_core_media_check_video_codecs(session);
switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->recv_pt);
switch_channel_set_variable(session->channel, "rtp_video_recv_pt", tmp);
2012-12-21 04:57:47 +00:00
if (switch_core_codec_ready(&v_engine->read_codec) && strcasecmp(matches[0].imp->iananame, v_engine->read_codec.implementation->iananame)) {
2013-11-07 22:48:00 +00:00
v_engine->reset_codec = 1;
}
if (switch_core_media_set_video_codec(session, 0) == SWITCH_STATUS_SUCCESS) {
if (check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m) == SWITCH_STATUS_FALSE) {
vmatch = 0;
}
2012-12-21 04:57:47 +00:00
}
}
}
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
2015-04-16 19:24:35 +00:00
if (!match && vmatch) match = 1;
2012-12-21 04:57:47 +00:00
done:
if (parser) {
sdp_parser_free(parser);
}
2013-01-08 18:59:02 +00:00
smh->mparams->cng_pt = cng_pt;
2015-07-30 23:11:08 +00:00
smh->mparams->cng_rate = cng_rate;
2012-12-21 04:57:47 +00:00
return match;
2012-12-20 04:42:03 +00:00
}
2012-12-21 04:57:47 +00:00
//?
SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session, int sendonly)
{
int changed = 0;
2013-10-28 18:39:23 +00:00
switch_rtp_engine_t *a_engine, *v_engine;
2012-12-21 04:57:47 +00:00
switch_media_handle_t *smh;
2013-09-09 22:03:04 +00:00
switch_core_session_t *b_session = NULL;
switch_channel_t *b_channel = NULL;
2012-12-21 04:57:47 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 04:57:47 +00:00
if (!(smh = session->media_handle)) {
return 0;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
2013-10-28 18:39:23 +00:00
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2012-12-21 04:57:47 +00:00
2013-09-09 22:03:04 +00:00
if (switch_core_session_get_partner(session, &b_session) == SWITCH_STATUS_SUCCESS) {
b_channel = switch_core_session_get_channel(b_session);
2012-12-21 04:57:47 +00:00
}
if (sendonly && switch_channel_test_flag(session->channel, CF_ANSWERED)) {
if (!switch_channel_test_flag(session->channel, CF_PROTO_HOLD)) {
const char *stream;
const char *msg = "hold";
2013-09-09 22:03:04 +00:00
const char *info;
if ((switch_channel_test_flag(session->channel, CF_SLA_BARGE) || switch_channel_test_flag(session->channel, CF_SLA_BARGING)) &&
2014-02-17 17:07:28 +00:00
(!b_channel || switch_channel_test_flag(b_channel, CF_EVENT_LOCK_PRI))) {
2013-09-09 22:03:04 +00:00
switch_channel_mark_hold(session->channel, sendonly);
switch_channel_set_flag(session->channel, CF_PROTO_HOLD);
changed = 0;
goto end;
}
info = switch_channel_get_variable(session->channel, "presence_call_info");
2012-12-21 04:57:47 +00:00
if (info) {
if (switch_stristr("private", info)) {
msg = "hold-private";
}
}
if (a_engine->rtp_session) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
2013-10-28 18:39:23 +00:00
if (v_engine->rtp_session) {
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
2012-12-21 04:57:47 +00:00
switch_channel_set_flag(session->channel, CF_PROTO_HOLD);
switch_channel_mark_hold(session->channel, SWITCH_TRUE);
switch_channel_presence(session->channel, "unknown", msg, NULL);
changed = 1;
if (a_engine->max_missed_hold_packets && a_engine->rtp_session) {
2012-12-21 04:57:47 +00:00
switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_hold_packets);
}
if (!(stream = switch_channel_get_hold_music(session->channel))) {
stream = "local_stream://moh";
}
2013-09-09 22:03:04 +00:00
2014-02-17 17:07:28 +00:00
if (stream && strcasecmp(stream, "silence") && (!b_channel || !switch_channel_test_flag(b_channel, CF_EVENT_LOCK_PRI))) {
2012-12-21 04:57:47 +00:00
if (!strcasecmp(stream, "indicate_hold")) {
switch_channel_set_flag(session->channel, CF_SUSPEND);
switch_channel_set_flag(session->channel, CF_HOLD);
2014-02-17 17:07:28 +00:00
switch_ivr_hold_uuid(switch_core_session_get_uuid(b_session), NULL, 0);
2012-12-21 04:57:47 +00:00
} else {
2014-02-17 17:07:28 +00:00
switch_ivr_broadcast(switch_core_session_get_uuid(b_session), stream,
2012-12-21 04:57:47 +00:00
SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY);
switch_yield(250000);
}
}
2013-09-09 22:03:04 +00:00
2012-12-21 04:57:47 +00:00
}
} else {
if (switch_channel_test_flag(session->channel, CF_HOLD_LOCK)) {
switch_channel_set_flag(session->channel, CF_PROTO_HOLD);
switch_channel_mark_hold(session->channel, SWITCH_TRUE);
2013-10-28 18:39:23 +00:00
if (a_engine->rtp_session) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
2013-10-28 18:39:23 +00:00
if (v_engine->rtp_session) {
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
2012-12-21 04:57:47 +00:00
changed = 1;
}
switch_channel_clear_flag(session->channel, CF_HOLD_LOCK);
if (switch_channel_test_flag(session->channel, CF_PROTO_HOLD)) {
int media_on_hold_a = switch_true(switch_channel_get_variable_dup(session->channel, "bypass_media_resume_on_hold", SWITCH_FALSE, -1));
2014-10-13 15:36:51 +00:00
int media_on_hold_b = 0;
int bypass_after_hold_a = 0;
int bypass_after_hold_b = 0;
if (media_on_hold_a) {
bypass_after_hold_a = switch_true(switch_channel_get_variable_dup(session->channel, "bypass_media_after_hold", SWITCH_FALSE, -1));
}
2014-10-13 15:36:51 +00:00
if (b_channel) {
if ((media_on_hold_b = switch_true(switch_channel_get_variable_dup(b_channel, "bypass_media_resume_on_hold", SWITCH_FALSE, -1)))) {
bypass_after_hold_b = switch_true(switch_channel_get_variable_dup(b_channel, "bypass_media_after_hold", SWITCH_FALSE, -1));
}
}
2014-10-13 15:36:51 +00:00
2012-12-21 04:57:47 +00:00
switch_yield(250000);
2014-02-05 02:15:08 +00:00
if (b_channel && (switch_channel_test_flag(session->channel, CF_BYPASS_MEDIA_AFTER_HOLD) ||
switch_channel_test_flag(b_channel, CF_BYPASS_MEDIA_AFTER_HOLD) || bypass_after_hold_a || bypass_after_hold_b)) {
2014-02-05 02:15:08 +00:00
/* try to stay out from media stream */
switch_ivr_nomedia(switch_core_session_get_uuid(session), SMF_REBRIDGE);
}
if (a_engine->max_missed_packets && a_engine->rtp_session) {
2012-12-21 04:57:47 +00:00
switch_rtp_reset_media_timer(a_engine->rtp_session);
switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_packets);
}
2013-09-09 22:03:04 +00:00
if (b_channel) {
2012-12-21 04:57:47 +00:00
if (switch_channel_test_flag(session->channel, CF_HOLD)) {
switch_ivr_unhold(b_session);
switch_channel_clear_flag(session->channel, CF_SUSPEND);
switch_channel_clear_flag(session->channel, CF_HOLD);
} else {
switch_channel_stop_broadcast(b_channel);
switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
}
}
switch_core_media_check_autoadj(session);
2013-12-18 18:22:13 +00:00
2012-12-21 04:57:47 +00:00
switch_channel_clear_flag(session->channel, CF_PROTO_HOLD);
switch_channel_mark_hold(session->channel, SWITCH_FALSE);
switch_channel_presence(session->channel, "unknown", "unhold", NULL);
2013-10-28 18:39:23 +00:00
2014-09-18 21:28:41 +00:00
if (a_engine->rtp_session) {
switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
2013-10-28 18:39:23 +00:00
if (v_engine->rtp_session) {
switch_rtp_clear_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE);
}
2012-12-21 04:57:47 +00:00
changed = 1;
}
}
2013-09-09 22:03:04 +00:00
end:
if (b_session) {
switch_core_session_rwunlock(b_session);
}
2012-12-21 04:57:47 +00:00
return changed;
}
SWITCH_DECLARE(switch_file_handle_t *) switch_core_media_get_video_file(switch_core_session_t *session, switch_rw_t rw)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *v_engine;
switch_file_handle_t *fh;
switch_assert(session);
if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
return NULL;
}
if (!(smh = session->media_handle)) {
return NULL;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
switch_mutex_lock(v_engine->mh.file_mutex);
if (rw == SWITCH_RW_READ) {
fh = smh->video_read_fh;
} else {
fh = smh->video_write_fh;
}
switch_mutex_unlock(v_engine->mh.file_mutex);
return fh;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *v_engine;
switch_assert(session);
if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
return SWITCH_STATUS_FALSE;
}
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
switch_core_session_start_video_thread(session);
//if (!v_engine->media_thread) {
// return SWITCH_STATUS_FALSE;
//}
switch_mutex_lock(v_engine->mh.file_mutex);
if (rw == SWITCH_RW_READ) {
if (fh) {
switch_channel_set_flag_recursive(session->channel, CF_VIDEO_DECODED_READ);
switch_channel_set_flag(session->channel, CF_VIDEO_READ_FILE_ATTACHED);
} else if (smh->video_read_fh) {
switch_channel_clear_flag_recursive(session->channel, CF_VIDEO_DECODED_READ);
switch_core_session_video_reset(session);
}
if (!fh) {
switch_channel_clear_flag(session->channel, CF_VIDEO_READ_FILE_ATTACHED);
}
smh->video_read_fh = fh;
} else {
if (fh) {
switch_channel_set_flag(session->channel, CF_VIDEO_WRITE_FILE_ATTACHED);
} else {
switch_channel_clear_flag(session->channel, CF_VIDEO_WRITE_FILE_ATTACHED);
}
switch_core_media_gen_key_frame(session);
smh->video_write_fh = fh;
}
if (!fh) switch_channel_video_sync(session->channel);
switch_core_session_wake_video_thread(session);
switch_mutex_unlock(v_engine->mh.file_mutex);
return SWITCH_STATUS_SUCCESS;
}
2013-10-15 21:24:32 +00:00
static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, void *obj)
{
struct media_helper *mh = obj;
switch_core_session_t *session = mh->session;
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_status_t status;
switch_frame_t *read_frame = NULL;
2013-10-15 21:24:32 +00:00
switch_media_handle_t *smh;
2015-04-03 23:39:43 +00:00
uint32_t loops = 0, xloops = 0, vloops = 0;
switch_frame_t fr = { 0 };
unsigned char *buf = NULL;
switch_image_t *blank_img = NULL;
switch_rgb_color_t bgcolor;
switch_rtp_engine_t *v_engine = NULL;
const char *var;
2013-10-15 21:24:32 +00:00
if (!(smh = session->media_handle)) {
return NULL;
}
if ((var = switch_channel_get_variable(session->channel, "core_video_blank_image"))) {
blank_img = switch_img_read_png(var, SWITCH_IMG_FMT_I420);
}
if (!blank_img) {
switch_color_set_rgb(&bgcolor, "#000000");
blank_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, 352, 288, 1);
switch_img_fill(blank_img, 0, 0, blank_img->d_w, blank_img->d_h, &bgcolor);
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
v_engine->thread_id = switch_thread_self();
2013-10-15 21:24:32 +00:00
switch_core_session_read_lock(session);
mh->up = 1;
switch_mutex_lock(mh->cond_mutex);
switch_core_media_check_dtls(session, SWITCH_MEDIA_TYPE_VIDEO);
2013-10-15 21:24:32 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread started. Echo is %s\n",
switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
2014-12-04 02:34:49 +00:00
switch_core_session_request_video_refresh(session);
2013-10-15 21:24:32 +00:00
while (switch_channel_up_nosig(channel)) {
int send_blank = 0;
if (!switch_channel_test_flag(channel, CF_VIDEO)) {
if ((++loops % 100) == 0) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Waiting for video......\n");
switch_yield(20000);
continue;
}
2013-10-15 21:24:32 +00:00
if (!switch_channel_test_flag(channel, CF_VIDEO_DECODED_READ) && (++xloops > 20 || switch_channel_test_flag(channel, CF_VIDEO_PASSIVE))) {
switch_channel_set_flag(channel, CF_VIDEO_READY);
}
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
2013-10-15 21:24:32 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread paused. Echo is %s\n",
switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
switch_thread_cond_wait(mh->cond, mh->cond_mutex);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread resumed Echo is %s\n",
switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
2014-12-04 02:34:49 +00:00
switch_core_session_request_video_refresh(session);
2013-10-15 21:24:32 +00:00
}
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
2013-10-15 21:24:32 +00:00
continue;
}
if (!switch_channel_media_up(session->channel)) {
switch_yield(10000);
continue;
}
if (smh->video_function) {
int run = 0;
switch_mutex_lock(smh->control_mutex);
if (smh->video_function_running == 0) {
smh->video_function_running = 1;
run = 1;
}
switch_mutex_unlock(smh->control_mutex);
if (run) {
smh->video_function(session, smh->video_user_data);
switch_mutex_lock(smh->control_mutex);
smh->video_function = NULL;
smh->video_user_data = NULL;
smh->video_function_running = 0;
switch_mutex_unlock(smh->control_mutex);
}
}
if (v_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) {
switch_channel_set_flag(channel, CF_VIDEO_READY);
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
}
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
//if (!smh->video_write_fh || !switch_channel_test_flag(channel, CF_VIDEO_READY)) {
status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
switch_cond_next();
continue;
2015-03-04 17:22:37 +00:00
}
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
//if (switch_test_flag(read_frame, SFF_CNG)) {
// continue;
//}
//}
//if (vloops < 300 && (vloops % 100) == 0) {
// switch_core_media_gen_key_frame(session);
//switch_core_session_request_video_refresh(session);
//}
2015-03-04 17:22:37 +00:00
vloops++;
if (!buf) {
int buflen = SWITCH_RTP_MAX_BUF_LEN;
buf = switch_core_session_alloc(session, buflen);
fr.packet = buf;
fr.packetlen = buflen;
fr.data = buf + 12;
fr.buflen = buflen - 12;
switch_core_media_gen_key_frame(session);
}
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
if (v_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) {
send_blank = 1;
}
if (switch_channel_test_flag(channel, CF_VIDEO_READY)) {
switch_mutex_lock(mh->file_mutex);
if (smh->video_write_fh && switch_channel_ready(session->channel) && switch_test_flag(smh->video_write_fh, SWITCH_FILE_OPEN)) {
switch_status_t wstatus = switch_core_file_read_video(smh->video_write_fh, &fr, SVR_FLUSH);
if (wstatus == SWITCH_STATUS_SUCCESS) {
switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_NONE, 0);
switch_img_free(&fr.img);
} else if (wstatus != SWITCH_STATUS_BREAK && wstatus != SWITCH_STATUS_IGNORE) {
smh->video_write_fh = NULL;
}
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
send_blank = 0;
} else if (smh->video_read_fh && switch_test_flag(smh->video_read_fh, SWITCH_FILE_OPEN) && read_frame->img) {
switch_core_file_write_video(smh->video_read_fh, read_frame);
FS-7769: [mod_conference] Add new multi-canvas and telepresence features mod_conference new features: add conference layout "1x1+2x1" and add to layout group grid add conference flag video-bridge-first-two conference flag add conference flag video-required-for-canvas to only use avatars for members with video add conference flag video-muxing-personal-canvas add conf_verto_ prefix for variables to pass on live array subscription notice add api command conference foo vid-canvas <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-layer <member_id|all|last|non_moderator> [<newval>] add api command conference foo vid-watching-canvas <member_id|all|last|non_moderator> [<newval>] changed api command conference foo vid-layout, args are now "<layout name>|group <group name> [<canvas_id>]" add channel vars you can set before entering conference video_initial_canvas and video_initial_watching_canvas add many new output status vars to conference list api add new conference member flag "second-screen" add config param video-canvas-count add config param video-super-canvas-label-layers add config param video-super-canvas-show-all-layers add config param video-super-canvas-bgcolor verto client: add google login add hipchat js file conf_verto_hipchatURL= to control what hipchat server appears if any global device init and overrides allow passing sessid add confMan.canvasCount add handling of multiple canvases and launching them, and controlling all of their layouts re-layout moderator controls and add support for changing the watching and input canvas and layers when launching another canvas, watch subscriptions for the original call so we can automatically close the additional window maintain camera settings on call recovery
2015-07-02 22:55:04 +00:00
send_blank = 0;
}
switch_mutex_unlock(mh->file_mutex);
} else if (switch_channel_test_flag(channel, CF_VIDEO_DECODED_READ)) {
send_blank = 1;
}
2015-06-25 19:40:06 +00:00
if ((send_blank || switch_channel_test_flag(channel, CF_VIDEO_BLANK)) && !session->video_read_callback) {
fr.img = blank_img;
switch_yield(10000);
switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_FORCE, 0);
} else if (read_frame && (switch_channel_test_flag(channel, CF_VIDEO_ECHO))) {
2013-10-15 21:24:32 +00:00
switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
}
}
switch_img_free(&blank_img);
2013-10-15 21:24:32 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended\n", switch_channel_get_name(session->channel));
switch_mutex_unlock(mh->cond_mutex);
switch_core_session_rwunlock(session);
mh->up = 0;
return NULL;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_core_session_t *session)
2013-10-15 21:24:32 +00:00
{
switch_threadattr_t *thd_attr = NULL;
switch_memory_pool_t *pool = switch_core_session_get_pool(session);
switch_rtp_engine_t *v_engine = NULL;
switch_media_handle_t *smh;
if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
return SWITCH_STATUS_NOTIMPL;
}
2013-10-15 21:24:32 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
switch_mutex_lock(smh->control_mutex);
2013-10-15 21:24:32 +00:00
if (v_engine->media_thread) {
switch_mutex_unlock(smh->control_mutex);
2013-10-15 21:24:32 +00:00
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Starting Video thread\n", switch_core_session_get_name(session));
2013-10-15 21:24:32 +00:00
if (v_engine->rtp_session) {
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
}
2013-10-15 21:24:32 +00:00
v_engine->mh.session = session;
switch_threadattr_create(&thd_attr, pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_cond_create(&v_engine->mh.cond, pool);
switch_mutex_init(&v_engine->mh.cond_mutex, SWITCH_MUTEX_NESTED, pool);
switch_mutex_init(&v_engine->mh.file_mutex, SWITCH_MUTEX_NESTED, pool);
2015-03-03 17:44:20 +00:00
switch_mutex_init(&smh->read_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool);
switch_mutex_init(&smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool);
2013-10-15 21:24:32 +00:00
switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh, switch_core_session_get_pool(session));
switch_mutex_unlock(smh->control_mutex);
2013-10-15 21:24:32 +00:00
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void) switch_core_media_start_video_function(switch_core_session_t *session, switch_video_function_t video_function, void *user_data)
{
switch_media_handle_t *smh;
if (!(smh = session->media_handle)) {
return;
}
switch_core_session_start_video_thread(session);
switch_mutex_lock(smh->control_mutex);
if (!smh->video_function_running) {
smh->video_function = video_function;
smh->video_user_data = user_data;
switch_core_session_video_reset(session);
}
switch_mutex_unlock(smh->control_mutex);
}
SWITCH_DECLARE(int) switch_core_media_check_video_function(switch_core_session_t *session)
{
switch_media_handle_t *smh;
int r;
if (!(smh = session->media_handle)) {
return 0;
}
switch_mutex_lock(smh->control_mutex);
r = (smh->video_function_running > 0);
switch_mutex_unlock(smh->control_mutex);
return r;
}
SWITCH_DECLARE(void) switch_core_media_end_video_function(switch_core_session_t *session)
{
switch_media_handle_t *smh;
if (!(smh = session->media_handle)) {
return;
}
switch_mutex_lock(smh->control_mutex);
if (smh->video_function_running > 0) {
smh->video_function_running = -1;
}
switch_mutex_unlock(smh->control_mutex);
while(smh->video_function_running != 0) {
switch_yield(10000);
}
}
SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_session_t *session)
{
switch_rtp_engine_t *v_engine;
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_FALSE;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
return switch_thread_equal(switch_thread_self(), v_engine->thread_id) ? SWITCH_TRUE : SWITCH_FALSE;
}
2012-12-21 20:22:25 +00:00
//?
#define RA_PTR_LEN 512
SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_session_t *session, const char *sdp_str)
{
const char *err;
char rip[RA_PTR_LEN] = "";
char rp[RA_PTR_LEN] = "";
char rvp[RA_PTR_LEN] = "";
char *p, *ip_ptr = NULL, *port_ptr = NULL, *vid_port_ptr = NULL, *pe;
int x;
const char *val;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 20:22:25 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (zstr(sdp_str)) {
sdp_str = smh->mparams->remote_sdp_str;
}
if (zstr(sdp_str)) {
goto end;
}
if ((p = (char *) switch_stristr("c=IN IP4 ", sdp_str)) || (p = (char *) switch_stristr("c=IN IP6 ", sdp_str))) {
ip_ptr = p + 9;
}
if ((p = (char *) switch_stristr("m=audio ", sdp_str))) {
port_ptr = p + 8;
}
if ((p = (char *) switch_stristr("m=image ", sdp_str))) {
char *tmp = p + 8;
if (tmp && atoi(tmp)) {
port_ptr = tmp;
}
}
if ((p = (char *) switch_stristr("m=video ", sdp_str))) {
vid_port_ptr = p + 8;
}
if (!(ip_ptr && port_ptr)) {
goto end;
}
p = ip_ptr;
pe = p + strlen(p);
x = 0;
while (x < sizeof(rip) - 1 && p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) {
rip[x++] = *p;
p++;
if (p >= pe) {
goto end;
}
}
p = port_ptr;
x = 0;
while (x < sizeof(rp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
rp[x++] = *p;
p++;
if (p >= pe) {
goto end;
}
}
p = vid_port_ptr;
x = 0;
while (x < sizeof(rvp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
rvp[x++] = *p;
p++;
if (p >= pe) {
goto end;
}
}
if (!(*rip && *rp)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "invalid SDP\n");
goto end;
}
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(session, rip);
a_engine->cur_payload_map->remote_sdp_port = (switch_port_t) atoi(rp);
2012-12-21 20:22:25 +00:00
if (*rvp) {
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(session, rip);
v_engine->cur_payload_map->remote_sdp_port = (switch_port_t) atoi(rvp);
2013-08-13 21:00:31 +00:00
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
switch_channel_set_flag(session->channel, CF_VIDEO);
2012-12-21 20:22:25 +00:00
}
2013-11-07 22:48:00 +00:00
if (v_engine->cur_payload_map->remote_sdp_ip && v_engine->cur_payload_map->remote_sdp_port) {
if (!strcmp(v_engine->cur_payload_map->remote_sdp_ip, rip) && atoi(rvp) == v_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote video address:port [%s:%d] has not changed.\n",
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port);
2012-12-21 20:22:25 +00:00
} else {
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
switch_channel_set_flag(session->channel, CF_VIDEO);
if (switch_rtp_ready(v_engine->rtp_session)) {
const char *rport = NULL;
2013-01-15 05:17:28 +00:00
switch_port_t remote_rtcp_port = v_engine->remote_rtcp_port;
2012-12-21 20:22:25 +00:00
2013-01-15 05:17:28 +00:00
if (!remote_rtcp_port) {
if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port"))) {
2013-01-15 05:17:28 +00:00
remote_rtcp_port = (switch_port_t)atoi(rport);
}
2012-12-21 20:22:25 +00:00
}
2013-10-15 21:24:32 +00:00
2013-11-07 22:48:00 +00:00
if (switch_rtp_set_remote_address(v_engine->rtp_session, v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n",
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port);
2012-12-21 20:22:25 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_PROXY_MODE) &&
2013-02-09 04:47:18 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val)) &&
2015-01-12 17:34:42 +00:00
!switch_channel_test_flag(session->channel, CF_AVPF)) {
2012-12-21 20:22:25 +00:00
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
2013-11-07 22:48:00 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_AUTOFIX_TIMING)) {
2012-12-21 20:22:25 +00:00
v_engine->check_frames = 0;
}
}
}
}
}
if (switch_rtp_ready(a_engine->rtp_session)) {
char *remote_host = switch_rtp_get_remote_host(a_engine->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session);
const char *rport = NULL;
switch_port_t remote_rtcp_port = 0;
2013-11-07 22:48:00 +00:00
if (remote_host && remote_port && !strcmp(remote_host, a_engine->cur_payload_map->remote_sdp_ip) && remote_port == a_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote address:port [%s:%d] has not changed.\n",
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port);
2012-12-21 20:22:25 +00:00
switch_goto_status(SWITCH_STATUS_BREAK, end);
2014-02-17 17:25:19 +00:00
} else if (remote_host && ( (strcmp(remote_host, "0.0.0.0") == 0) ||
(strcmp(a_engine->cur_payload_map->remote_sdp_ip, "0.0.0.0") == 0))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Remote address changed from [%s] to [%s]. Ignoring...\n",
a_engine->cur_payload_map->remote_sdp_ip, remote_host);
switch_goto_status(SWITCH_STATUS_BREAK, end);
2012-12-21 20:22:25 +00:00
}
if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_audio_rtcp_port"))) {
2012-12-21 20:22:25 +00:00
remote_rtcp_port = (switch_port_t)atoi(rport);
}
2013-11-07 22:48:00 +00:00
if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port, remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
status = SWITCH_STATUS_GENERR;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port);
2012-12-21 20:22:25 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) &&
2013-02-09 04:47:18 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val)) &&
2015-01-12 17:34:42 +00:00
!switch_channel_test_flag(session->channel, CF_AVPF)) {
2012-12-21 20:22:25 +00:00
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
2013-11-07 22:48:00 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_AUTOFIX_TIMING)) {
2012-12-21 20:22:25 +00:00
a_engine->check_frames = 0;
}
status = SWITCH_STATUS_SUCCESS;
}
}
end:
return status;
}
//?
SWITCH_DECLARE(int) switch_core_media_check_nat(switch_media_handle_t *smh, const char *network_ip)
{
switch_assert(network_ip);
return (smh->mparams->extsipip &&
!switch_check_network_list_ip(network_ip, "loopback.auto") &&
!switch_check_network_list_ip(network_ip, smh->mparams->local_network));
}
//?
2012-12-22 03:30:14 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_ext_address_lookup(switch_core_session_t *session, char **ip, switch_port_t *port, const char *sourceip)
2012-12-21 20:22:25 +00:00
{
char *error = "";
switch_status_t status = SWITCH_STATUS_FALSE;
int x;
switch_port_t myport = *port;
switch_port_t stun_port = SWITCH_STUN_DEFAULT_PORT;
char *stun_ip = NULL;
switch_media_handle_t *smh;
switch_memory_pool_t *pool = switch_core_session_get_pool(session);
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 20:22:25 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (!sourceip) {
return status;
}
if (!strncasecmp(sourceip, "host:", 5)) {
status = (*ip = switch_stun_host_lookup(sourceip + 5, pool)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
} else if (!strncasecmp(sourceip, "stun:", 5)) {
char *p;
stun_ip = strdup(sourceip + 5);
if ((p = strchr(stun_ip, ':'))) {
int iport;
*p++ = '\0';
iport = atoi(p);
if (iport > 0 && iport < 0xFFFF) {
stun_port = (switch_port_t) iport;
}
}
if (zstr(stun_ip)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! NO STUN SERVER\n");
goto out;
}
for (x = 0; x < 5; x++) {
if ((status = switch_stun_lookup(ip, port, stun_ip, stun_port, &error, pool)) != SWITCH_STATUS_SUCCESS) {
switch_yield(100000);
} else {
break;
}
}
if (status != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! %s:%d [%s]\n", stun_ip, stun_port, error);
goto out;
}
if (!*ip) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! No IP returned\n");
goto out;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "STUN Success [%s]:[%d]\n", *ip, *port);
status = SWITCH_STATUS_SUCCESS;
if (myport == *port && !strcmp(*ip, smh->mparams->rtpip)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "STUN Not Required ip and port match. [%s]:[%d]\n", *ip, *port);
} else {
smh->mparams->stun_ip = switch_core_session_strdup(session, stun_ip);
smh->mparams->stun_port = stun_port;
smh->mparams->stun_flags |= STUN_FLAG_SET;
}
} else {
*ip = (char *) sourceip;
status = SWITCH_STATUS_SUCCESS;
}
out:
switch_safe_free(stun_ip);
return status;
}
2012-12-22 23:34:08 +00:00
//?
2013-07-29 15:18:05 +00:00
SWITCH_DECLARE(void) switch_core_media_reset_autofix(switch_core_session_t *session, switch_media_type_t type)
2012-12-22 23:34:08 +00:00
{
switch_rtp_engine_t *engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 23:34:08 +00:00
if (!(smh = session->media_handle)) {
return;
}
engine = &smh->engines[type];
engine->check_frames = 0;
engine->last_ts = 0;
engine->last_seq = 0;
2012-12-22 23:34:08 +00:00
}
2012-12-21 20:22:25 +00:00
//?
2012-12-21 22:57:59 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_session_t *session, switch_media_type_t type, int force)
2012-12-21 20:22:25 +00:00
{
char *lookup_rtpip; /* Pointer to externally looked up address */
switch_port_t sdp_port; /* The external port to be sent in the SDP */
const char *use_ip = NULL; /* The external IP to be sent in the SDP */
2012-12-21 22:57:59 +00:00
switch_rtp_engine_t *engine;
2012-12-21 20:22:25 +00:00
switch_media_handle_t *smh;
2012-12-21 22:57:59 +00:00
const char *tstr = switch_media_type2str(type);
char vname[128] = "";
2012-12-21 20:22:25 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 20:22:25 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
2012-12-21 22:57:59 +00:00
engine = &smh->engines[type];
2012-12-21 20:22:25 +00:00
lookup_rtpip = smh->mparams->rtpip;
/* Don't do anything if we're in proxy mode or if a (remote) port already has been found */
if (!force) {
if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) ||
2013-11-07 22:48:00 +00:00
switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) || engine->adv_sdp_port) {
2012-12-21 20:22:25 +00:00
return SWITCH_STATUS_SUCCESS;
}
}
/* Release the local sdp port */
2013-11-07 22:48:00 +00:00
if (engine->local_sdp_port) {
switch_rtp_release_port(smh->mparams->rtpip, engine->local_sdp_port);
2012-12-21 20:22:25 +00:00
}
/* Request a local port from the core's allocator */
2013-11-07 22:48:00 +00:00
if (!(engine->local_sdp_port = switch_rtp_request_port(smh->mparams->rtpip))) {
2012-12-21 22:57:59 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "No %s RTP ports available!\n", tstr);
2012-12-21 20:22:25 +00:00
return SWITCH_STATUS_FALSE;
}
2013-11-07 22:48:00 +00:00
engine->local_sdp_ip = smh->mparams->rtpip;
2012-12-22 03:30:14 +00:00
2013-11-07 22:48:00 +00:00
sdp_port = engine->local_sdp_port;
2012-12-21 20:22:25 +00:00
/* Check if NAT is detected */
if (!zstr(smh->mparams->remote_ip) && switch_core_media_check_nat(smh, smh->mparams->remote_ip)) {
/* Yes, map the port through switch_nat */
2013-11-07 22:48:00 +00:00
switch_nat_add_mapping(engine->local_sdp_port, SWITCH_NAT_UDP, &sdp_port, SWITCH_FALSE);
2012-12-21 20:22:25 +00:00
2012-12-21 22:57:59 +00:00
switch_snprintf(vname, sizeof(vname), "rtp_adv_%s_ip", tstr);
2012-12-21 20:22:25 +00:00
/* Find an IP address to use */
2012-12-21 22:57:59 +00:00
if (!(use_ip = switch_channel_get_variable(session->channel, vname))
2012-12-21 20:22:25 +00:00
&& !zstr(smh->mparams->extrtpip)) {
use_ip = smh->mparams->extrtpip;
}
if (use_ip) {
2012-12-22 03:30:14 +00:00
if (switch_core_media_ext_address_lookup(session, &lookup_rtpip, &sdp_port, use_ip) != SWITCH_STATUS_SUCCESS) {
2012-12-21 20:22:25 +00:00
/* Address lookup was required and fail (external ip was "host:..." or "stun:...") */
return SWITCH_STATUS_FALSE;
} else {
/* Address properly resolved, use it as external ip */
use_ip = lookup_rtpip;
}
} else {
/* No external ip found, use the profile's rtp ip */
use_ip = smh->mparams->rtpip;
}
} else {
/* No NAT traversal required, use the profile's rtp ip */
use_ip = smh->mparams->rtpip;
}
2013-11-07 22:48:00 +00:00
engine->adv_sdp_port = sdp_port;
engine->adv_sdp_ip = smh->mparams->adv_sdp_audio_ip = smh->mparams->extrtpip = switch_core_session_strdup(session, use_ip);
2012-12-22 03:30:14 +00:00
if (type == SWITCH_MEDIA_TYPE_AUDIO) {
2013-11-07 22:48:00 +00:00
switch_channel_set_variable(session->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, engine->local_sdp_ip);
2012-12-22 03:30:14 +00:00
switch_channel_set_variable_printf(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, "%d", sdp_port);
2013-11-07 22:48:00 +00:00
switch_channel_set_variable(session->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE, engine->adv_sdp_ip);
2012-12-22 03:30:14 +00:00
} else {
2013-11-07 22:48:00 +00:00
switch_channel_set_variable(session->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, engine->adv_sdp_ip);
2012-12-22 03:30:14 +00:00
switch_channel_set_variable_printf(session->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, "%d", sdp_port);
}
2012-12-21 20:22:25 +00:00
return SWITCH_STATUS_SUCCESS;
}
2013-10-15 21:24:32 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_media_handle_t *smh;
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (zstr(smh->mparams->rtpip)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no media ip\n",
switch_channel_get_name(smh->session->channel));
switch_channel_hangup(smh->session->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
return SWITCH_STATUS_FALSE;
}
2013-10-15 21:24:32 +00:00
if (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) {
if (video) {
switch_core_media_check_video_codecs(session);
if (switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE)) {
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 0);
}
}
}
return status;
}
2012-12-22 03:30:14 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_deactivate_rtp(switch_core_session_t *session)
{
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 03:30:14 +00:00
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (v_engine->media_thread) {
switch_status_t st;
switch_channel_clear_flag(session->channel, CF_VIDEO_PASSIVE);
v_engine->mh.up = 0;
switch_thread_join(&st, v_engine->media_thread);
v_engine->media_thread = NULL;
}
2012-12-22 03:30:14 +00:00
if (v_engine->rtp_session) {
switch_rtp_destroy(&v_engine->rtp_session);
2013-11-07 22:48:00 +00:00
} else if (v_engine->local_sdp_port) {
switch_rtp_release_port(smh->mparams->rtpip, v_engine->local_sdp_port);
2012-12-22 03:30:14 +00:00
}
2013-11-07 22:48:00 +00:00
if (v_engine->local_sdp_port > 0 && !zstr(smh->mparams->remote_ip) &&
2012-12-22 03:30:14 +00:00
switch_core_media_check_nat(smh, smh->mparams->remote_ip)) {
2013-11-07 22:48:00 +00:00
switch_nat_del_mapping((switch_port_t) v_engine->local_sdp_port, SWITCH_NAT_UDP);
switch_nat_del_mapping((switch_port_t) v_engine->local_sdp_port + 1, SWITCH_NAT_UDP);
2012-12-22 03:30:14 +00:00
}
if (a_engine->rtp_session) {
switch_rtp_destroy(&a_engine->rtp_session);
2013-11-07 22:48:00 +00:00
} else if (a_engine->local_sdp_port) {
switch_rtp_release_port(smh->mparams->rtpip, a_engine->local_sdp_port);
2012-12-22 03:30:14 +00:00
}
2013-11-07 22:48:00 +00:00
if (a_engine->local_sdp_port > 0 && !zstr(smh->mparams->remote_ip) &&
2012-12-22 03:30:14 +00:00
switch_core_media_check_nat(smh, smh->mparams->remote_ip)) {
2013-11-07 22:48:00 +00:00
switch_nat_del_mapping((switch_port_t) a_engine->local_sdp_port, SWITCH_NAT_UDP);
switch_nat_del_mapping((switch_port_t) a_engine->local_sdp_port + 1, SWITCH_NAT_UDP);
2012-12-22 03:30:14 +00:00
}
}
2013-01-10 04:31:25 +00:00
//?
static void gen_ice(switch_core_session_t *session, switch_media_type_t type, const char *ip, switch_port_t port)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
char tmp[33] = "";
2013-01-10 04:31:25 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
engine = &smh->engines[type];
2013-01-17 01:04:57 +00:00
#ifdef RTCP_MUX
if (!engine->rtcp_mux) {// && type == SWITCH_MEDIA_TYPE_AUDIO) {
2013-01-17 01:04:57 +00:00
engine->rtcp_mux = SWITCH_TRUE;
}
#endif
if (!smh->msid) {
switch_stun_random_string(tmp, 32, NULL);
tmp[32] = '\0';
smh->msid = switch_core_session_strdup(session, tmp);
}
if (!smh->cname) {
switch_stun_random_string(tmp, 16, NULL);
tmp[16] = '\0';
smh->cname = switch_core_session_strdup(session, tmp);
}
2013-01-10 04:31:25 +00:00
if (!engine->ice_out.ufrag) {
switch_stun_random_string(tmp, 16, NULL);
tmp[16] = '\0';
2013-01-10 04:31:25 +00:00
engine->ice_out.ufrag = switch_core_session_strdup(session, tmp);
}
if (!engine->ice_out.pwd) {
switch_stun_random_string(tmp, 24, NULL);
tmp[24] = '\0';
2013-01-10 04:31:25 +00:00
engine->ice_out.pwd = switch_core_session_strdup(session, tmp);
}
2013-01-26 23:53:15 +00:00
if (!engine->ice_out.cands[0][0].foundation) {
2013-01-10 04:31:25 +00:00
switch_stun_random_string(tmp, 10, "0123456789");
tmp[10] = '\0';
2013-01-26 23:53:15 +00:00
engine->ice_out.cands[0][0].foundation = switch_core_session_strdup(session, tmp);
2013-01-10 04:31:25 +00:00
}
2013-01-26 23:53:15 +00:00
engine->ice_out.cands[0][0].transport = "udp";
2013-01-13 07:29:05 +00:00
2013-01-26 23:53:15 +00:00
if (!engine->ice_out.cands[0][0].component_id) {
engine->ice_out.cands[0][0].component_id = 1;
engine->ice_out.cands[0][0].priority = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - engine->ice_out.cands[0][0].component_id);
2013-01-13 07:29:05 +00:00
}
2013-01-10 04:31:25 +00:00
if (!zstr(ip)) {
2013-01-26 23:53:15 +00:00
engine->ice_out.cands[0][0].con_addr = switch_core_session_strdup(session, ip);
2013-01-10 04:31:25 +00:00
}
2013-01-10 04:31:25 +00:00
if (port) {
2013-01-26 23:53:15 +00:00
engine->ice_out.cands[0][0].con_port = port;
2013-01-10 04:31:25 +00:00
}
2013-01-26 23:53:15 +00:00
engine->ice_out.cands[0][0].generation = "0";
2013-01-10 04:31:25 +00:00
//add rport stuff later
2013-01-26 23:53:15 +00:00
engine->ice_out.cands[0][0].ready = 1;
2013-01-10 04:31:25 +00:00
}
SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t *session)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *v_engine;
if (!(smh = session->media_handle)) {
return;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if ((!smh->mparams->external_video_source) && (!v_engine->rtp_session)) {
return;
}
if (!v_engine->media_thread) {
return;
}
if (!v_engine->mh.cond_mutex) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Channel %s has no cond?\n",
switch_channel_get_name(session->channel));
return;
}
if (switch_mutex_trylock(v_engine->mh.cond_mutex) == SWITCH_STATUS_SUCCESS) {
switch_thread_cond_broadcast(v_engine->mh.cond);
switch_mutex_unlock(v_engine->mh.cond_mutex);
}
}
2013-10-15 21:24:32 +00:00
static void check_dtls_reinvite(switch_core_session_t *session, switch_rtp_engine_t *engine)
{
2013-10-15 21:24:32 +00:00
if (switch_channel_test_flag(session->channel, CF_REINVITE)) {
2013-10-15 21:24:32 +00:00
if (!zstr(engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(session)) {
dtls_type_t xtype, dtype = switch_ice_direction(session) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER;
2015-03-24 00:56:19 +00:00
2013-10-15 21:24:32 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "RE-SETTING %s DTLS\n", type2str(engine->type));
2013-10-15 21:24:32 +00:00
xtype = DTLS_TYPE_RTP;
if (engine->rtcp_mux > 0) xtype |= DTLS_TYPE_RTCP;
switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype);
2013-10-15 21:24:32 +00:00
if (engine->rtcp_mux < 1) {
xtype = DTLS_TYPE_RTCP;
switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype);
}
}
}
}
2012-12-21 20:22:25 +00:00
//?
2012-12-22 03:30:14 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_session_t *session)
2012-12-21 20:22:25 +00:00
{
const char *err = NULL;
const char *val = NULL;
switch_rtp_flag_t flags[SWITCH_RTP_FLAG_INVALID] = {0};
switch_status_t status = SWITCH_STATUS_SUCCESS;
char tmp[50];
char *timer_name = NULL;
const char *var;
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2013-11-07 22:48:00 +00:00
2012-12-21 20:22:25 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
2012-12-21 20:22:25 +00:00
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (switch_channel_down(session->channel)) {
return SWITCH_STATUS_FALSE;
}
if (switch_rtp_ready(a_engine->rtp_session)) {
switch_rtp_reset_media_timer(a_engine->rtp_session);
}
2014-03-07 03:34:39 +00:00
if (a_engine->crypto_type != CRYPTO_INVALID) {
2012-12-21 20:22:25 +00:00
switch_channel_set_flag(session->channel, CF_SECURE);
}
if (switch_channel_test_flag(session->channel, CF_PROXY_MODE)) {
status = SWITCH_STATUS_SUCCESS;
goto end;
}
2012-12-22 03:30:14 +00:00
if (!switch_channel_test_flag(session->channel, CF_REINVITE)) {
2012-12-21 20:22:25 +00:00
if (switch_rtp_ready(a_engine->rtp_session)) {
if (switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE) && !switch_rtp_ready(v_engine->rtp_session)) {
goto video;
}
status = SWITCH_STATUS_SUCCESS;
goto end;
}
}
2012-12-22 03:30:14 +00:00
if ((status = switch_core_media_set_codec(session, 0, smh->mparams->codec_flags)) != SWITCH_STATUS_SUCCESS) {
2012-12-21 20:22:25 +00:00
goto end;
}
2013-11-07 22:48:00 +00:00
switch_core_media_set_video_codec(session, 0);
2012-12-21 20:22:25 +00:00
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
2015-01-12 17:34:42 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_AVPF) &&
2012-12-21 20:22:25 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
}
if (switch_media_handle_test_media_flag(smh, SCMF_PASS_RFC2833)
|| ((val = switch_channel_get_variable(session->channel, "pass_rfc2833")) && switch_true(val))) {
switch_channel_set_flag(session->channel, CF_PASS_RFC2833);
}
if (switch_media_handle_test_media_flag(smh, SCMF_AUTOFLUSH)
|| ((val = switch_channel_get_variable(session->channel, "rtp_autoflush")) && switch_true(val))) {
flags[SWITCH_RTP_FLAG_AUTOFLUSH]++;
}
if (!(switch_media_handle_test_media_flag(smh, SCMF_REWRITE_TIMESTAMPS) ||
((val = switch_channel_get_variable(session->channel, "rtp_rewrite_timestamps")) && switch_true(val)))) {
flags[SWITCH_RTP_FLAG_RAW_WRITE]++;
}
if (switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG)) {
2013-01-08 18:59:02 +00:00
smh->mparams->cng_pt = 0;
} else if (smh->mparams->cng_pt) {
2012-12-21 20:22:25 +00:00
flags[SWITCH_RTP_FLAG_AUTO_CNG]++;
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
if (!strcasecmp(a_engine->read_impl.iananame, "L16")) {
flags[SWITCH_RTP_FLAG_BYTESWAP]++;
}
#endif
if ((flags[SWITCH_RTP_FLAG_BYTESWAP]) && (val = switch_channel_get_variable(session->channel, "rtp_disable_byteswap")) && switch_true(val)) {
flags[SWITCH_RTP_FLAG_BYTESWAP] = 0;
}
2012-12-22 03:30:14 +00:00
if (a_engine->rtp_session && switch_channel_test_flag(session->channel, CF_REINVITE)) {
2012-12-21 20:22:25 +00:00
//const char *ip = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
char *remote_host = switch_rtp_get_remote_host(a_engine->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session);
2013-11-07 22:48:00 +00:00
if (remote_host && remote_port && !strcmp(remote_host, a_engine->cur_payload_map->remote_sdp_ip) &&
remote_port == a_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
switch_channel_get_name(session->channel));
a_engine->cur_payload_map->negotiated = 1;
2013-11-07 22:48:00 +00:00
//XX
2012-12-21 20:22:25 +00:00
goto video;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
remote_host, remote_port, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port);
2012-12-21 20:22:25 +00:00
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip);
2012-12-21 20:22:25 +00:00
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
}
}
if (!switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "AUDIO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
a_engine->local_sdp_ip,
a_engine->local_sdp_port,
a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port, a_engine->cur_payload_map->agreed_pt, a_engine->read_impl.microseconds_per_packet / 1000);
2012-12-21 20:22:25 +00:00
2013-11-07 22:48:00 +00:00
//XX
2012-12-21 20:22:25 +00:00
}
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->local_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, a_engine->local_sdp_ip);
2012-12-21 20:22:25 +00:00
switch_channel_set_variable(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
2013-11-07 22:48:00 +00:00
switch_channel_set_variable(session->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE, a_engine->adv_sdp_ip);
2012-12-21 20:22:25 +00:00
2012-12-22 03:30:14 +00:00
if (a_engine->rtp_session && switch_channel_test_flag(session->channel, CF_REINVITE)) {
2012-12-21 20:22:25 +00:00
const char *rport = NULL;
2013-01-15 05:17:28 +00:00
switch_port_t remote_rtcp_port = a_engine->remote_rtcp_port;
if (!remote_rtcp_port) {
if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_audio_rtcp_port"))) {
2013-01-15 05:17:28 +00:00
remote_rtcp_port = (switch_port_t)atoi(rport);
}
2012-12-21 20:22:25 +00:00
}
2013-11-07 22:48:00 +00:00
if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port,
2012-12-21 20:22:25 +00:00
remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port);
2013-09-16 17:23:49 +00:00
2013-11-07 22:48:00 +00:00
if (switch_channel_test_flag(session->channel, CF_PROTO_HOLD) && strcmp(a_engine->cur_payload_map->remote_sdp_ip, "0.0.0.0")) {
2013-09-16 17:23:49 +00:00
switch_core_media_toggle_hold(session, 0);
}
2012-12-21 20:22:25 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) &&
2013-02-09 04:47:18 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val)) &&
2015-01-12 17:34:42 +00:00
!switch_channel_test_flag(session->channel, CF_AVPF)) {
2012-12-21 20:22:25 +00:00
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
}
2013-10-15 21:24:32 +00:00
if (session && a_engine) {
check_dtls_reinvite(session, a_engine);
}
2012-12-21 20:22:25 +00:00
goto video;
}
if (switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
switch_core_media_proxy_remote_addr(session, NULL);
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
2015-01-12 17:34:42 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_AVPF) &&
2012-12-21 20:22:25 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
}
timer_name = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port,
a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port, a_engine->cur_payload_map->agreed_pt, a_engine->read_impl.microseconds_per_packet / 1000);
2012-12-21 20:22:25 +00:00
if (switch_rtp_ready(a_engine->rtp_session)) {
2013-11-07 22:48:00 +00:00
switch_rtp_set_default_payload(a_engine->rtp_session, a_engine->cur_payload_map->agreed_pt);
2012-12-21 20:22:25 +00:00
}
} else {
timer_name = smh->mparams->timer_name;
if ((var = switch_channel_get_variable(session->channel, "rtp_timer_name"))) {
timer_name = (char *) var;
}
}
if (switch_channel_up(session->channel)) {
2014-07-03 18:50:14 +00:00
switch_channel_set_variable(session->channel, "rtp_use_timer_name", timer_name);
2013-11-07 22:48:00 +00:00
a_engine->rtp_session = switch_rtp_new(a_engine->local_sdp_ip,
a_engine->local_sdp_port,
a_engine->cur_payload_map->remote_sdp_ip,
a_engine->cur_payload_map->remote_sdp_port,
a_engine->cur_payload_map->agreed_pt,
2012-12-21 20:22:25 +00:00
a_engine->read_impl.samples_per_packet,
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->codec_ms * 1000,
2012-12-21 20:22:25 +00:00
flags, timer_name, &err, switch_core_session_get_pool(session));
2013-11-07 22:48:00 +00:00
if (switch_rtp_ready(a_engine->rtp_session)) {
switch_rtp_set_payload_map(a_engine->rtp_session, &a_engine->payload_map);
}
2012-12-21 20:22:25 +00:00
}
if (switch_rtp_ready(a_engine->rtp_session)) {
uint8_t vad_in = (smh->mparams->vflags & VAD_IN);
uint8_t vad_out = (smh->mparams->vflags & VAD_OUT);
uint8_t inb = switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND;
const char *ssrc;
2015-03-03 17:44:20 +00:00
switch_mutex_init(&smh->read_mutex[SWITCH_MEDIA_TYPE_AUDIO], SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&smh->write_mutex[SWITCH_MEDIA_TYPE_AUDIO], SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
2013-01-10 04:31:25 +00:00
//switch_core_media_set_rtp_session(session, SWITCH_MEDIA_TYPE_AUDIO, a_engine->rtp_session);
2012-12-21 20:22:25 +00:00
if ((ssrc = switch_channel_get_variable(session->channel, "rtp_use_ssrc"))) {
uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
switch_rtp_set_ssrc(a_engine->rtp_session, ssrc_ul);
2013-01-13 07:29:05 +00:00
a_engine->ssrc = ssrc_ul;
} else {
switch_rtp_set_ssrc(a_engine->rtp_session, a_engine->ssrc);
2012-12-21 20:22:25 +00:00
}
2013-07-11 22:38:24 +00:00
if (a_engine->remote_ssrc) {
switch_rtp_set_remote_ssrc(a_engine->rtp_session, a_engine->remote_ssrc);
}
2012-12-21 20:22:25 +00:00
switch_channel_set_flag(session->channel, CF_FS_RTP);
2013-11-07 22:48:00 +00:00
switch_channel_set_variable_printf(session->channel, "rtp_use_pt", "%d", a_engine->cur_payload_map->agreed_pt);
2012-12-21 20:22:25 +00:00
if ((val = switch_channel_get_variable(session->channel, "rtp_enable_vad_in")) && switch_true(val)) {
vad_in = 1;
}
if ((val = switch_channel_get_variable(session->channel, "rtp_enable_vad_out")) && switch_true(val)) {
vad_out = 1;
}
if ((val = switch_channel_get_variable(session->channel, "rtp_disable_vad_in")) && switch_true(val)) {
vad_in = 0;
}
if ((val = switch_channel_get_variable(session->channel, "rtp_disable_vad_out")) && switch_true(val)) {
vad_out = 0;
}
a_engine->ssrc = switch_rtp_get_ssrc(a_engine->rtp_session);
switch_channel_set_variable_printf(session->channel, "rtp_use_ssrc", "%u", a_engine->ssrc);
if (smh->mparams->auto_rtp_bugs & RTP_BUG_IGNORE_MARK_BIT) {
a_engine->rtp_bugs |= RTP_BUG_IGNORE_MARK_BIT;
}
if ((val = switch_channel_get_variable(session->channel, "rtp_manual_rtp_bugs"))) {
2014-08-15 21:00:38 +00:00
switch_core_media_parse_rtp_bugs(&a_engine->rtp_bugs, val);
2012-12-21 20:22:25 +00:00
}
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
2014-08-15 21:00:38 +00:00
smh->mparams->manual_rtp_bugs = RTP_BUG_SEND_LINEAR_TIMESTAMPS;
}
2012-12-21 20:22:25 +00:00
switch_rtp_intentional_bugs(a_engine->rtp_session, a_engine->rtp_bugs | smh->mparams->manual_rtp_bugs);
if ((vad_in && inb) || (vad_out && !inb)) {
switch_rtp_enable_vad(a_engine->rtp_session, session, &a_engine->read_codec, SWITCH_VAD_FLAG_TALKING | SWITCH_VAD_FLAG_EVENTS_TALK | SWITCH_VAD_FLAG_EVENTS_NOTALK);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "AUDIO RTP Engage VAD for %s ( %s %s )\n",
switch_channel_get_name(switch_core_session_get_channel(session)), vad_in ? "in" : "", vad_out ? "out" : "");
}
2013-02-01 20:29:40 +00:00
if (a_engine->ice_in.cands[a_engine->ice_in.chosen[0]][0].ready) {
gen_ice(session, SWITCH_MEDIA_TYPE_AUDIO, NULL, 0);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating Audio ICE\n");
switch_rtp_activate_ice(a_engine->rtp_session,
a_engine->ice_in.ufrag,
a_engine->ice_out.ufrag,
a_engine->ice_out.pwd,
a_engine->ice_in.pwd,
2013-01-26 23:53:15 +00:00
IPR_RTP,
#ifdef GOOGLE_ICE
ICE_GOOGLE_JINGLE,
NULL
#else
2013-10-15 21:24:32 +00:00
switch_ice_direction(session) ==
SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
2013-01-26 23:53:15 +00:00
&a_engine->ice_in
#endif
);
}
2012-12-21 20:22:25 +00:00
if ((val = switch_channel_get_variable(session->channel, "rtcp_audio_interval_msec")) || (val = smh->mparams->rtcp_audio_interval_msec)) {
const char *rport = switch_channel_get_variable(session->channel, "rtp_remote_audio_rtcp_port");
2013-01-15 05:17:28 +00:00
switch_port_t remote_rtcp_port = a_engine->remote_rtcp_port;
if (!remote_rtcp_port && rport) {
remote_rtcp_port = (switch_port_t)atoi(rport);
2012-12-21 20:22:25 +00:00
}
2012-12-21 20:22:25 +00:00
if (!strcasecmp(val, "passthru")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating RTCP PASSTHRU PORT %d\n", remote_rtcp_port);
2013-01-17 01:04:57 +00:00
switch_rtp_activate_rtcp(a_engine->rtp_session, -1, remote_rtcp_port, a_engine->rtcp_mux > 0);
2012-12-21 20:22:25 +00:00
} else {
int interval = atoi(val);
if (interval < 100 || interval > 500000) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
"Invalid rtcp interval spec [%d] must be between 100 and 500000\n", interval);
interval = 5000;
2012-12-21 20:22:25 +00:00
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating RTCP PORT %d\n", remote_rtcp_port);
switch_rtp_activate_rtcp(a_engine->rtp_session, interval, remote_rtcp_port, a_engine->rtcp_mux > 0);
}
if (a_engine->ice_in.cands[a_engine->ice_in.chosen[1]][1].ready) {
2014-03-11 16:38:31 +00:00
if (a_engine->rtcp_mux > 0 && !strcmp(a_engine->ice_in.cands[a_engine->ice_in.chosen[1]][1].con_addr, a_engine->ice_in.cands[a_engine->ice_in.chosen[0]][0].con_addr)
&& a_engine->ice_in.cands[a_engine->ice_in.chosen[1]][1].con_port == a_engine->ice_in.cands[a_engine->ice_in.chosen[0]][0].con_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Skipping RTCP ICE (Same as RTP)\n");
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating RTCP ICE\n");
switch_rtp_activate_ice(a_engine->rtp_session,
a_engine->ice_in.ufrag,
a_engine->ice_out.ufrag,
a_engine->ice_out.pwd,
a_engine->ice_in.pwd,
IPR_RTCP,
#ifdef GOOGLE_ICE
ICE_GOOGLE_JINGLE,
NULL
#else
2013-10-15 21:24:32 +00:00
switch_ice_direction(session) ==
SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
&a_engine->ice_in
#endif
2013-01-26 23:53:15 +00:00
);
}
}
2012-12-21 20:22:25 +00:00
}
if (!zstr(a_engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(smh->session)) {
dtls_type_t xtype, dtype = switch_channel_direction(smh->session->channel) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER;
if (switch_channel_test_flag(smh->session->channel, CF_3PCC)) {
dtype = (dtype == DTLS_TYPE_CLIENT) ? DTLS_TYPE_SERVER : DTLS_TYPE_CLIENT;
}
xtype = DTLS_TYPE_RTP;
if (a_engine->rtcp_mux > 0 && smh->mparams->rtcp_audio_interval_msec) xtype |= DTLS_TYPE_RTCP;
switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype | xtype);
if (a_engine->rtcp_mux < 1 && smh->mparams->rtcp_audio_interval_msec) {
xtype = DTLS_TYPE_RTCP;
switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype | xtype);
}
}
check_jb(session, NULL, 0, 0);
2012-12-21 20:22:25 +00:00
2014-01-03 18:45:35 +00:00
if ((val = switch_channel_get_variable(session->channel, "rtp_timeout_sec"))) {
2012-12-21 20:22:25 +00:00
int v = atoi(val);
if (v >= 0) {
2012-12-22 03:30:14 +00:00
smh->mparams->rtp_timeout_sec = v;
2012-12-21 20:22:25 +00:00
}
}
2014-01-03 18:45:35 +00:00
if ((val = switch_channel_get_variable(session->channel, "rtp_hold_timeout_sec"))) {
2012-12-21 20:22:25 +00:00
int v = atoi(val);
if (v >= 0) {
2012-12-22 03:30:14 +00:00
smh->mparams->rtp_hold_timeout_sec = v;
2012-12-21 20:22:25 +00:00
}
}
2012-12-22 03:30:14 +00:00
if (smh->mparams->rtp_timeout_sec) {
a_engine->max_missed_packets = (a_engine->read_impl.samples_per_second * smh->mparams->rtp_timeout_sec) / a_engine->read_impl.samples_per_packet;
2012-12-21 20:22:25 +00:00
switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_packets);
2012-12-22 03:30:14 +00:00
if (!smh->mparams->rtp_hold_timeout_sec) {
smh->mparams->rtp_hold_timeout_sec = smh->mparams->rtp_timeout_sec * 10;
2012-12-21 20:22:25 +00:00
}
}
2012-12-22 03:30:14 +00:00
if (smh->mparams->rtp_hold_timeout_sec) {
a_engine->max_missed_hold_packets = (a_engine->read_impl.samples_per_second * smh->mparams->rtp_hold_timeout_sec) / a_engine->read_impl.samples_per_packet;
2012-12-21 20:22:25 +00:00
}
2012-12-22 03:30:14 +00:00
if (smh->mparams->te) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", smh->mparams->te);
switch_rtp_set_telephony_event(a_engine->rtp_session, smh->mparams->te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_send_payload", "%d", smh->mparams->te);
2012-12-21 20:22:25 +00:00
}
2012-12-22 03:30:14 +00:00
if (smh->mparams->recv_te) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf receive payload to %u\n", smh->mparams->recv_te);
switch_rtp_set_telephony_recv_event(a_engine->rtp_session, smh->mparams->recv_te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_recv_payload", "%d", smh->mparams->recv_te);
2012-12-21 20:22:25 +00:00
}
2013-11-07 22:48:00 +00:00
//XX
2012-12-21 20:22:25 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) ||
((val = switch_channel_get_variable(session->channel, "supress_cng")) && switch_true(val)) ||
((val = switch_channel_get_variable(session->channel, "suppress_cng")) && switch_true(val))) {
2013-01-08 18:59:02 +00:00
smh->mparams->cng_pt = 0;
2012-12-21 20:22:25 +00:00
}
if (((val = switch_channel_get_variable(session->channel, "rtp_digit_delay")))) {
int delayi = atoi(val);
if (delayi < 0) delayi = 0;
2012-12-22 03:30:14 +00:00
smh->mparams->dtmf_delay = (uint32_t) delayi;
2012-12-21 20:22:25 +00:00
}
2012-12-22 03:30:14 +00:00
if (smh->mparams->dtmf_delay) {
switch_rtp_set_interdigit_delay(a_engine->rtp_session, smh->mparams->dtmf_delay);
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
2012-12-22 03:30:14 +00:00
"%s Set rtp dtmf delay to %u\n", switch_channel_get_name(session->channel), smh->mparams->dtmf_delay);
2012-12-21 20:22:25 +00:00
}
2013-01-08 18:59:02 +00:00
if (smh->mparams->cng_pt && !switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", smh->mparams->cng_pt);
switch_rtp_set_cng_pt(a_engine->rtp_session, smh->mparams->cng_pt);
2012-12-21 20:22:25 +00:00
}
2013-05-17 20:39:21 +00:00
switch_core_session_apply_crypto(session, SWITCH_MEDIA_TYPE_AUDIO);
2012-12-21 20:22:25 +00:00
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip);
2012-12-21 20:22:25 +00:00
switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
if (switch_channel_test_flag(session->channel, CF_ZRTP_PASSTHRU)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating ZRTP PROXY MODE\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Disable NOTIMER_DURING_BRIDGE\n");
switch_channel_clear_flag(session->channel, CF_NOTIMER_DURING_BRIDGE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activating audio UDPTL mode\n");
switch_rtp_udptl_mode(a_engine->rtp_session);
}
2013-01-10 04:31:25 +00:00
2012-12-21 20:22:25 +00:00
video:
2013-01-14 14:50:41 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
switch_core_media_check_video_codecs(session);
}
2013-11-07 22:48:00 +00:00
if (switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE) && v_engine->cur_payload_map->rm_encoding && v_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 20:22:25 +00:00
/******************************************************************************************/
2012-12-22 03:30:14 +00:00
if (v_engine->rtp_session && switch_channel_test_flag(session->channel, CF_REINVITE)) {
2012-12-21 20:22:25 +00:00
//const char *ip = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
char *remote_host = switch_rtp_get_remote_host(v_engine->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(v_engine->rtp_session);
2013-11-07 22:48:00 +00:00
if (remote_host && remote_port && !strcmp(remote_host, v_engine->cur_payload_map->remote_sdp_ip) && remote_port == v_engine->cur_payload_map->remote_sdp_port) {
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video params are unchanged for %s.\n",
switch_channel_get_name(session->channel));
v_engine->cur_payload_map->negotiated = 1;
2012-12-21 20:22:25 +00:00
goto video_up;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video params changed for %s from %s:%d to %s:%d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
remote_host, remote_port, v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port);
2012-12-21 20:22:25 +00:00
}
}
if (!switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
if (switch_rtp_ready(v_engine->rtp_session)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
2014-06-13 10:06:14 +00:00
"VIDEO RTP [%s] %s port %d -> %s port %d codec: %u\n", switch_channel_get_name(session->channel),
v_engine->local_sdp_ip, v_engine->local_sdp_port, v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt);
2013-11-07 22:48:00 +00:00
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
2012-12-21 20:22:25 +00:00
}
}
2013-11-07 22:48:00 +00:00
switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->local_sdp_port);
switch_channel_set_variable(session->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, a_engine->adv_sdp_ip);
2012-12-21 20:22:25 +00:00
switch_channel_set_variable(session->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
2012-12-22 03:30:14 +00:00
if (v_engine->rtp_session && switch_channel_test_flag(session->channel, CF_REINVITE)) {
2012-12-21 20:22:25 +00:00
const char *rport = NULL;
2013-01-15 05:17:28 +00:00
switch_port_t remote_rtcp_port = v_engine->remote_rtcp_port;
2012-12-21 20:22:25 +00:00
2013-10-15 21:24:32 +00:00
//switch_channel_clear_flag(session->channel, CF_REINVITE);
2012-12-21 20:22:25 +00:00
2013-01-15 05:17:28 +00:00
if (!remote_rtcp_port) {
if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port"))) {
2013-01-15 05:17:28 +00:00
remote_rtcp_port = (switch_port_t)atoi(rport);
}
2012-12-21 20:22:25 +00:00
}
if (switch_rtp_set_remote_address
2013-11-07 22:48:00 +00:00
(v_engine->rtp_session, v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port, remote_rtcp_port, SWITCH_TRUE,
2012-12-21 20:22:25 +00:00
&err) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n",
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port);
2015-01-12 17:34:42 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_AVPF) &&
2012-12-21 20:22:25 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
}
goto video_up;
}
if (switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
switch_core_media_proxy_remote_addr(session, NULL);
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
2015-01-12 17:34:42 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_AVPF) &&
2012-12-21 20:22:25 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
}
timer_name = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"PROXY VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_channel_get_name(session->channel),
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip,
v_engine->local_sdp_port,
v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt, v_engine->read_impl.microseconds_per_packet / 1000);
2012-12-21 20:22:25 +00:00
if (switch_rtp_ready(v_engine->rtp_session)) {
2013-11-07 22:48:00 +00:00
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
2012-12-21 20:22:25 +00:00
}
} else {
timer_name = smh->mparams->timer_name;
if ((var = switch_channel_get_variable(session->channel, "rtp_timer_name"))) {
timer_name = (char *) var;
}
}
/******************************************************************************************/
if (v_engine->rtp_session) {
goto video_up;
}
2013-11-07 22:48:00 +00:00
if (!v_engine->local_sdp_port) {
2012-12-21 22:57:59 +00:00
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1);
2012-12-21 20:22:25 +00:00
}
memset(flags, 0, sizeof(flags));
flags[SWITCH_RTP_FLAG_DATAWAIT]++;
flags[SWITCH_RTP_FLAG_RAW_WRITE]++;
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_PROXY_MODE) &&
2013-02-09 04:47:18 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val)) &&
2015-01-12 17:34:42 +00:00
!switch_channel_test_flag(session->channel, CF_AVPF)) {
2012-12-21 20:22:25 +00:00
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
}
if (switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
}
switch_core_media_set_video_codec(session, 0);
flags[SWITCH_RTP_FLAG_USE_TIMER] = 0;
flags[SWITCH_RTP_FLAG_NOBLOCK] = 0;
flags[SWITCH_RTP_FLAG_VIDEO]++;
2014-12-04 02:34:49 +00:00
if (v_engine->fir) {
flags[SWITCH_RTP_FLAG_FIR]++;
}
if (v_engine->pli) {
flags[SWITCH_RTP_FLAG_PLI]++;
}
2012-12-21 20:22:25 +00:00
if (v_engine->nack) {
flags[SWITCH_RTP_FLAG_NACK]++;
}
2015-05-14 23:01:22 +00:00
if (v_engine->tmmbr) {
flags[SWITCH_RTP_FLAG_TMMBR]++;
}
2013-11-07 22:48:00 +00:00
v_engine->rtp_session = switch_rtp_new(a_engine->local_sdp_ip,
v_engine->local_sdp_port,
v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port,
v_engine->cur_payload_map->agreed_pt,
2012-12-21 20:22:25 +00:00
1, 90000, flags, NULL, &err, switch_core_session_get_pool(session));
2012-12-21 20:22:25 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
switch_channel_get_name(session->channel),
a_engine->local_sdp_ip,
2013-11-07 22:48:00 +00:00
v_engine->local_sdp_port,
v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt,
2012-12-21 20:22:25 +00:00
0, switch_rtp_ready(v_engine->rtp_session) ? "SUCCESS" : err);
if (switch_rtp_ready(v_engine->rtp_session)) {
const char *ssrc;
2013-11-07 22:48:00 +00:00
2013-11-20 20:38:16 +00:00
if (v_engine->fir) {
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR);
}
if (v_engine->pli) {
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PLI);
}
2013-11-22 03:55:45 +00:00
2013-11-07 22:48:00 +00:00
switch_rtp_set_payload_map(v_engine->rtp_session, &v_engine->payload_map);
2012-12-21 20:22:25 +00:00
switch_channel_set_flag(session->channel, CF_VIDEO);
switch_core_session_start_video_thread(session);
2013-11-07 22:48:00 +00:00
2012-12-21 20:22:25 +00:00
if ((ssrc = switch_channel_get_variable(session->channel, "rtp_use_video_ssrc"))) {
uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10);
switch_rtp_set_ssrc(v_engine->rtp_session, ssrc_ul);
2013-01-13 07:29:05 +00:00
v_engine->ssrc = ssrc_ul;
} else {
switch_rtp_set_ssrc(v_engine->rtp_session, v_engine->ssrc);
2012-12-21 20:22:25 +00:00
}
2013-07-11 22:38:24 +00:00
if (v_engine->remote_ssrc) {
switch_rtp_set_remote_ssrc(v_engine->rtp_session, v_engine->remote_ssrc);
}
if (v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].ready) {
2013-01-14 04:29:39 +00:00
gen_ice(session, SWITCH_MEDIA_TYPE_VIDEO, NULL, 0);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating Video ICE\n");
2013-01-14 04:29:39 +00:00
switch_rtp_activate_ice(v_engine->rtp_session,
v_engine->ice_in.ufrag,
v_engine->ice_out.ufrag,
v_engine->ice_out.pwd,
v_engine->ice_in.pwd,
2013-01-26 23:53:15 +00:00
IPR_RTP,
2013-01-14 04:29:39 +00:00
#ifdef GOOGLE_ICE
ICE_GOOGLE_JINGLE,
2013-01-26 23:53:15 +00:00
NULL
2013-01-14 04:29:39 +00:00
#else
2013-10-15 21:24:32 +00:00
switch_ice_direction(session) ==
SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
2013-01-26 23:53:15 +00:00
&v_engine->ice_in
2013-01-14 04:29:39 +00:00
#endif
);
2013-01-14 04:29:39 +00:00
}
if ((val = switch_channel_get_variable(session->channel, "rtcp_video_interval_msec")) || (val = smh->mparams->rtcp_video_interval_msec)) {
const char *rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port");
switch_port_t remote_port = v_engine->remote_rtcp_port;
if (rport) {
remote_port = (switch_port_t)atoi(rport);
}
if (!strcasecmp(val, "passthru")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating VIDEO RTCP PASSTHRU PORT %d\n", remote_port);
2013-01-17 01:04:57 +00:00
switch_rtp_activate_rtcp(v_engine->rtp_session, -1, remote_port, v_engine->rtcp_mux > 0);
} else {
int interval = atoi(val);
if (interval < 100 || interval > 500000) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
"Invalid rtcp interval spec [%d] must be between 100 and 500000\n", interval);
interval = 5000;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO,
"Activating VIDEO RTCP PORT %d interval %d mux %d\n", remote_port, interval, v_engine->rtcp_mux);
switch_rtp_activate_rtcp(v_engine->rtp_session, interval, remote_port, v_engine->rtcp_mux > 0);
}
if (v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].ready) {
2014-03-11 16:38:31 +00:00
if (v_engine->rtcp_mux > 0 && !strcmp(v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].con_addr, v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].con_addr)
&& v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].con_port == v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].con_port) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Skipping VIDEO RTCP ICE (Same as VIDEO RTP)\n");
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating VIDEO RTCP ICE\n");
switch_rtp_activate_ice(v_engine->rtp_session,
v_engine->ice_in.ufrag,
v_engine->ice_out.ufrag,
v_engine->ice_out.pwd,
v_engine->ice_in.pwd,
IPR_RTCP,
2013-01-14 04:29:39 +00:00
#ifdef GOOGLE_ICE
ICE_GOOGLE_JINGLE,
NULL
2013-01-14 04:29:39 +00:00
#else
2013-10-15 21:24:32 +00:00
switch_ice_direction(session) ==
SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
&v_engine->ice_in
2013-01-14 04:29:39 +00:00
#endif
);
}
}
2013-01-14 04:29:39 +00:00
}
if (!zstr(v_engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(smh->session)) {
dtls_type_t xtype,
dtype = switch_channel_direction(smh->session->channel) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER;
xtype = DTLS_TYPE_RTP;
if (v_engine->rtcp_mux > 0 && smh->mparams->rtcp_video_interval_msec) xtype |= DTLS_TYPE_RTCP;
switch_rtp_add_dtls(v_engine->rtp_session, &v_engine->local_dtls_fingerprint, &v_engine->remote_dtls_fingerprint, dtype | xtype);
if (v_engine->rtcp_mux < 1 && smh->mparams->rtcp_video_interval_msec) {
xtype = DTLS_TYPE_RTCP;
switch_rtp_add_dtls(v_engine->rtp_session, &v_engine->local_dtls_fingerprint, &v_engine->remote_dtls_fingerprint, dtype | xtype);
}
}
2012-12-21 20:22:25 +00:00
if ((val = switch_channel_get_variable(session->channel, "rtp_manual_video_rtp_bugs"))) {
switch_core_media_parse_rtp_bugs(&v_engine->rtp_bugs, val);
}
2015-03-24 00:56:19 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
smh->mparams->manual_video_rtp_bugs = RTP_BUG_SEND_LINEAR_TIMESTAMPS;
}
2012-12-21 20:22:25 +00:00
switch_rtp_intentional_bugs(v_engine->rtp_session, v_engine->rtp_bugs | smh->mparams->manual_video_rtp_bugs);
2013-11-07 22:48:00 +00:00
//XX
2012-12-21 20:22:25 +00:00
2013-11-07 22:48:00 +00:00
switch_channel_set_variable_printf(session->channel, "rtp_use_video_pt", "%d", v_engine->cur_payload_map->agreed_pt);
2012-12-21 20:22:25 +00:00
v_engine->ssrc = switch_rtp_get_ssrc(v_engine->rtp_session);
switch_channel_set_variable_printf(session->channel, "rtp_use_video_ssrc", "%u", v_engine->ssrc);
2013-05-17 20:39:21 +00:00
switch_core_session_apply_crypto(session, SWITCH_MEDIA_TYPE_VIDEO);
2012-12-21 20:22:25 +00:00
2012-12-21 20:22:25 +00:00
if (switch_channel_test_flag(session->channel, CF_ZRTP_PASSTHRU)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activating video UDPTL mode\n");
switch_rtp_udptl_mode(v_engine->rtp_session);
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
goto end;
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
status = SWITCH_STATUS_FALSE;
goto end;
}
video_up:
2013-10-15 21:24:32 +00:00
if (session && v_engine) {
check_dtls_reinvite(session, v_engine);
}
2012-12-21 20:22:25 +00:00
status = SWITCH_STATUS_SUCCESS;
end:
2012-12-22 03:30:14 +00:00
switch_channel_clear_flag(session->channel, CF_REINVITE);
2012-12-21 20:22:25 +00:00
switch_core_recovery_track(session);
return status;
}
2012-12-20 04:42:03 +00:00
static const char *get_media_profile_name(switch_core_session_t *session, int secure)
{
switch_assert(session);
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
if (switch_channel_test_flag(session->channel, CF_AVPF_MOZ)) {
return "UDP/TLS/RTP/SAVPF";
} else {
return "RTP/SAVPF";
}
}
2013-04-08 18:24:27 +00:00
if (secure) {
return "RTP/SAVP";
}
return "RTP/AVP";
}
2015-06-08 21:15:16 +00:00
static char *get_setup(switch_core_session_t *session, switch_sdp_type_t sdp_type)
{
if (sdp_type == SDP_TYPE_RESPONSE && !switch_channel_test_flag(session->channel, CF_RECOVERING)) {
return "active";
}
return "actpass";
2015-05-05 16:50:26 +00:00
}
2012-12-21 22:57:59 +00:00
//?
static void generate_m(switch_core_session_t *session, char *buf, size_t buflen,
switch_port_t port, const char *family, const char *ip,
2013-11-07 22:48:00 +00:00
int cur_ptime, const char *append_audio, const char *sr, int use_cng, int cng_type, switch_event_t *map, int secure,
switch_sdp_type_t sdp_type)
2012-12-21 22:57:59 +00:00
{
int i = 0;
int rate;
int already_did[128] = { 0 };
int ptime = 0, noptime = 0;
const char *local_sdp_audio_zrtp_hash;
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine;
2012-12-21 22:57:59 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 22:57:59 +00:00
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
2012-12-21 22:57:59 +00:00
//switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d RTP/%sAVP%s",
2015-01-12 17:34:42 +00:00
//port, secure ? "S" : "", switch_channel_test_flag(session->channel, CF_AVPF) ? "F" : "");
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d %s", port,
2015-01-23 21:08:00 +00:00
get_media_profile_name(session, secure || a_engine->crypto_type != CRYPTO_INVALID));
2012-12-21 22:57:59 +00:00
for (i = 0; i < smh->mparams->num_codecs; i++) {
2012-12-21 22:57:59 +00:00
const switch_codec_implementation_t *imp = smh->codecs[i];
int this_ptime = (imp->microseconds_per_packet / 1000);
if (!strcasecmp(imp->iananame, "ilbc") || !strcasecmp(imp->iananame, "isac") ) {
2012-12-21 22:57:59 +00:00
this_ptime = 20;
}
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
if (!noptime) {
if (!cur_ptime) {
if (!ptime) {
ptime = this_ptime;
}
} else {
if (this_ptime != cur_ptime) {
continue;
}
}
}
if (smh->ianacodes[i] < 128) {
if (already_did[smh->ianacodes[i]]) {
continue;
}
already_did[smh->ianacodes[i]] = 1;
}
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", smh->ianacodes[i]);
}
2012-12-22 23:34:08 +00:00
if (smh->mparams->dtmf_type == DTMF_2833 && smh->mparams->te > 95) {
int i;
for (i = 0; i < smh->num_rates; i++) {
2015-07-30 23:11:08 +00:00
if (smh->dtmf_ianacodes[i]) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", smh->dtmf_ianacodes[i]);
}
if (smh->cng_ianacodes[i] && !switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && cng_type && use_cng) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", smh->cng_ianacodes[i]);
}
}
2012-12-21 22:57:59 +00:00
}
2015-07-30 23:11:08 +00:00
//if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && cng_type && use_cng) {
//switch_snprintf(buf + strlen(buf), buflen - strlen(buf), " %d", cng_type);
//}
2012-12-21 22:57:59 +00:00
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "\n");
memset(already_did, 0, sizeof(already_did));
2012-12-21 22:57:59 +00:00
for (i = 0; i < smh->mparams->num_codecs; i++) {
2012-12-21 22:57:59 +00:00
const switch_codec_implementation_t *imp = smh->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") || !strcasecmp(imp->iananame, "isac")) {
2012-12-21 22:57:59 +00:00
this_ptime = 20;
}
if (!noptime) {
if (!cur_ptime) {
if (!ptime) {
ptime = this_ptime;
}
} else {
if (this_ptime != cur_ptime) {
continue;
}
}
}
if (smh->ianacodes[i] < 128) {
if (already_did[smh->ianacodes[i]]) {
continue;
}
already_did[smh->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;
}
}
2013-11-07 22:48:00 +00:00
if (smh->fmtps[i]) {
fmtp = smh->fmtps[i];
}
if (smh->ianacodes[i] > 95 || switch_channel_test_flag(session->channel, CF_VERBOSE_SDP)) {
2013-10-28 22:44:24 +00:00
int channels = get_channels(imp->iananame, imp->number_of_channels);
if (channels > 1) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", smh->ianacodes[i], imp->iananame, rate, channels);
} else {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d\n", smh->ianacodes[i], imp->iananame, rate);
}
2012-12-21 22:57:59 +00:00
}
if (fmtp) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fmtp:%d %s\n", smh->ianacodes[i], fmtp);
}
}
2012-12-22 23:34:08 +00:00
if ((smh->mparams->dtmf_type == DTMF_2833 || switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) ||
2012-12-22 03:30:14 +00:00
switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF)) && smh->mparams->te > 95) {
for (i = 0; i < smh->num_rates; i++) {
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d telephone-event/%d\n",
2015-07-30 23:11:08 +00:00
smh->dtmf_ianacodes[i], smh->rates[i]);
} else {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d telephone-event/%d\na=fmtp:%d 0-16\n",
2015-07-30 23:11:08 +00:00
smh->dtmf_ianacodes[i], smh->rates[i], smh->dtmf_ianacodes[i]);
}
}
2012-12-21 22:57:59 +00:00
}
2013-04-08 18:24:27 +00:00
if (!zstr(a_engine->local_dtls_fingerprint.type) && secure) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fingerprint:%s %s\na=setup:%s\n", a_engine->local_dtls_fingerprint.type,
2015-06-08 21:15:16 +00:00
a_engine->local_dtls_fingerprint.str, get_setup(session, sdp_type));
2013-02-02 06:15:09 +00:00
}
if (smh->mparams->rtcp_audio_interval_msec) {
2013-01-17 01:04:57 +00:00
if (a_engine->rtcp_mux > 0) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-mux\n");
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp:%d IN %s %s\n", port, family, ip);
2013-01-17 01:04:57 +00:00
} else {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp:%d IN %s %s\n", port + 1, family, ip);
}
}
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u\n", a_engine->ssrc);
2013-01-26 23:53:15 +00:00
if (a_engine->ice_out.cands[0][0].ready) {
char tmp1[11] = "";
char tmp2[11] = "";
uint32_t c1 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 1);
uint32_t c2 = c1 - 1;
//uint32_t c2 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 2);
//uint32_t c3 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 1);
//uint32_t c4 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 2);
ice_t *ice_out;
tmp1[10] = '\0';
tmp2[10] = '\0';
switch_stun_random_string(tmp1, 10, "0123456789");
switch_stun_random_string(tmp2, 10, "0123456789");
gen_ice(session, SWITCH_MEDIA_TYPE_AUDIO, NULL, 0);
ice_out = &a_engine->ice_out;
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ssrc:%u cname:%s\n", a_engine->ssrc, smh->cname);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ssrc:%u msid:%s a0\n", a_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ssrc:%u mslabel:%s\n", a_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ssrc:%u label:%sa0\n", a_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ice-ufrag:%s\n", ice_out->ufrag);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ice-pwd:%s\n", ice_out->pwd);
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=candidate:%s 1 %s %u %s %d typ host generation 0\n",
2013-01-26 23:53:15 +00:00
tmp1, ice_out->cands[0][0].transport, c1,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port
);
2013-11-07 22:48:00 +00:00
if (!zstr(a_engine->local_sdp_ip) && !zstr(ice_out->cands[0][0].con_addr) &&
strcmp(a_engine->local_sdp_ip, ice_out->cands[0][0].con_addr)
&& a_engine->local_sdp_port != ice_out->cands[0][0].con_port) {
2013-01-20 18:49:03 +00:00
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=candidate:%s 1 %s %u %s %d typ srflx raddr %s rport %d generation 0\n",
tmp2, ice_out->cands[0][0].transport, c2,
2013-01-26 23:53:15 +00:00
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port,
2013-11-07 22:48:00 +00:00
a_engine->local_sdp_ip, a_engine->local_sdp_port
2013-01-20 18:49:03 +00:00
);
}
if (a_engine->rtcp_mux < 1 || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND || switch_channel_test_flag(session->channel, CF_RECOVERING)) {
2013-02-02 06:15:09 +00:00
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ host generation 0\n",
tmp1, ice_out->cands[0][0].transport, c1,
2013-01-26 23:53:15 +00:00
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port + (a_engine->rtcp_mux > 0 ? 0 : 1)
2013-01-20 18:49:03 +00:00
);
2013-02-02 06:15:09 +00:00
2013-11-07 22:48:00 +00:00
if (!zstr(a_engine->local_sdp_ip) && !zstr(ice_out->cands[0][1].con_addr) &&
strcmp(a_engine->local_sdp_ip, ice_out->cands[0][1].con_addr)
&& a_engine->local_sdp_port != ice_out->cands[0][1].con_port) {
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ srflx raddr %s rport %d generation 0\n",
tmp2, ice_out->cands[0][0].transport, c2,
2013-02-02 06:15:09 +00:00
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port + (a_engine->rtcp_mux > 0 ? 0 : 1),
2013-11-07 22:48:00 +00:00
a_engine->local_sdp_ip, a_engine->local_sdp_port + (a_engine->rtcp_mux > 0 ? 0 : 1)
2013-02-02 06:15:09 +00:00
);
}
2013-01-20 18:49:03 +00:00
}
#ifdef GOOGLE_ICE
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ice-options:google-ice\n");
#endif
}
if (secure && !switch_channel_test_flag(session->channel, CF_DTLS)) {
int i;
for (i = 0; smh->crypto_suite_order[i] != CRYPTO_INVALID; i++) {
switch_rtp_crypto_key_type_t j = SUITES[smh->crypto_suite_order[i]].type;
if ((a_engine->crypto_type == j || a_engine->crypto_type == CRYPTO_INVALID) && !zstr(a_engine->ssec[j].local_crypto_key)) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=crypto:%s\n", a_engine->ssec[j].local_crypto_key);
}
}
2012-12-21 22:57:59 +00:00
//switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n");
}
2015-07-30 23:11:08 +00:00
if (cng_type) {
for (i = 0; i < smh->num_rates; i++) {
//if (smh->rates[i] == 8000) {
// switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d CN/%d\n", cng_type, smh->rates[i]);
//} else {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d CN/%d\n", smh->cng_ianacodes[i], smh->rates[i]);
//}
}
} else {
2013-09-12 15:39:57 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG)) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=silenceSupp:off - - - -\n");
}
2012-12-21 22:57:59 +00:00
}
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);
}
local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE);
if (local_sdp_audio_zrtp_hash) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(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);
}
if (!zstr(sr)) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=%s\n", sr);
}
}
//?
SWITCH_DECLARE(void) switch_core_media_check_dtmf_type(switch_core_session_t *session)
{
const char *val;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 22:57:59 +00:00
if (!(smh = session->media_handle)) {
return;
}
if ((val = switch_channel_get_variable(session->channel, "dtmf_type"))) {
if (!strcasecmp(val, "rfc2833")) {
2012-12-22 23:34:08 +00:00
smh->mparams->dtmf_type = DTMF_2833;
2012-12-21 22:57:59 +00:00
} else if (!strcasecmp(val, "info")) {
2012-12-22 23:34:08 +00:00
smh->mparams->dtmf_type = DTMF_INFO;
2012-12-21 22:57:59 +00:00
} else if (!strcasecmp(val, "none")) {
2012-12-22 23:34:08 +00:00
smh->mparams->dtmf_type = DTMF_NONE;
2012-12-21 22:57:59 +00:00
}
}
}
//?
switch_status_t switch_core_media_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt)
{
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;
}
//?
SWITCH_DECLARE(void)switch_core_media_set_local_sdp(switch_core_session_t *session, const char *sdp_str, switch_bool_t dup)
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 22:57:59 +00:00
if (!(smh = session->media_handle)) {
return;
}
if (smh->sdp_mutex) switch_mutex_lock(smh->sdp_mutex);
2012-12-21 22:57:59 +00:00
smh->mparams->local_sdp_str = dup ? switch_core_session_strdup(session, sdp_str) : (char *) sdp_str;
switch_channel_set_variable(session->channel, "rtp_local_sdp_str", smh->mparams->local_sdp_str);
if (smh->sdp_mutex) switch_mutex_unlock(smh->sdp_mutex);
2012-12-21 22:57:59 +00:00
}
2015-05-14 23:01:22 +00:00
static void add_fb(char *buf, uint32_t buflen, int pt, int fir, int nack, int pli, int tmmbr)
2015-03-24 00:56:19 +00:00
{
2015-05-14 23:01:22 +00:00
const char *zfir = "";
const char *ztmmbr = "";
char *sp = "";
if (fir) {
zfir = "fir";
}
if (tmmbr) {
ztmmbr = "tmmbr";
}
if (fir && tmmbr) {
sp = " ";
}
if (!zstr(zfir) || !zstr(ztmmbr)) {
2015-05-14 23:01:22 +00:00
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-fb:%d ccm %s%s%s\n", pt, zfir, sp, ztmmbr);
2015-03-24 00:56:19 +00:00
}
if (nack) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-fb:%d nack\n", pt);
}
if (pli) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-fb:%d nack pli\n", pt);
}
}
2012-12-21 22:57:59 +00:00
//?
#define SDPBUFLEN 65536
2013-11-07 22:48:00 +00:00
SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *session, switch_sdp_type_t sdp_type, const char *ip, switch_port_t port, const char *sr, int force)
2012-12-21 22:57:59 +00: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(session->channel, "rtp_video_fmtp");
const char *ov_fmtp = switch_channel_get_variable(session->channel, "rtp_force_video_fmtp");
const char *append_audio = switch_channel_get_variable(session->channel, "rtp_append_audio_sdp");
const char *append_video = switch_channel_get_variable(session->channel, "rtp_append_video_sdp");
2012-12-21 22:57:59 +00:00
char srbuf[128] = "";
const char *var_val;
const char *username;
const char *fmtp_out;
const char *fmtp_out_var = switch_channel_get_variable(session->channel, "rtp_force_audio_fmtp");
2012-12-21 22:57:59 +00:00
switch_event_t *map = NULL, *ptmap = NULL;
//const char *b_sdp = NULL;
//const char *local_audio_crypto_key = switch_core_session_local_crypto_key(session, SWITCH_MEDIA_TYPE_AUDIO);
2012-12-21 22:57:59 +00:00
const char *local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE);
const char *local_sdp_video_zrtp_hash = switch_core_media_get_zrtp_hash(session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_TRUE);
const char *tmp;
2012-12-21 22:57:59 +00:00
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2013-01-10 04:31:25 +00:00
ice_t *ice_out;
//int vp8 = 0;
//int red = 0;
2013-11-07 22:48:00 +00:00
payload_map_t *pmap;
int is_outbound = switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND;
const char *vbw;
int bw = 256;
2015-05-14 23:01:22 +00:00
uint8_t fir = 0, nack = 0, pli = 0, tmmbr = 0;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-21 22:57:59 +00:00
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (switch_true(switch_channel_get_variable(session->channel, "rtcp_mux"))) {
a_engine->rtcp_mux = 1;
v_engine->rtcp_mux = 1;
}
if (!smh->mparams->rtcp_audio_interval_msec) {
smh->mparams->rtcp_audio_interval_msec = (char *)switch_channel_get_variable(session->channel, "rtcp_audio_interval_msec");
}
if (!smh->mparams->rtcp_video_interval_msec) {
smh->mparams->rtcp_video_interval_msec = (char *)switch_channel_get_variable(session->channel, "rtcp_video_interval_msec");
}
2013-02-21 17:11:52 +00:00
if (dtls_ok(session) && (tmp = switch_channel_get_variable(smh->session->channel, "webrtc_enable_dtls")) && switch_false(tmp)) {
switch_channel_clear_flag(smh->session->channel, CF_DTLS_OK);
switch_channel_clear_flag(smh->session->channel, CF_DTLS);
}
2013-01-14 02:12:23 +00:00
2015-01-23 21:08:00 +00:00
if (switch_channel_test_flag(session->channel, CF_PROXY_OFF) && (tmp = switch_channel_get_variable(smh->session->channel, "uuid_media_secure_media"))) {
switch_channel_set_variable(smh->session->channel, "rtp_secure_media", tmp);
switch_core_session_parse_crypto_prefs(session);
switch_core_session_check_outgoing_crypto(session);
}
if (is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING) ||
switch_channel_test_flag(session->channel, CF_3PCC)) {
2015-01-12 17:34:42 +00:00
if (!switch_channel_test_flag(session->channel, CF_AVPF) &&
switch_true(switch_channel_get_variable(session->channel, "media_webrtc"))) {
2015-01-12 17:34:42 +00:00
switch_channel_set_flag(session->channel, CF_AVPF);
switch_channel_set_flag(session->channel, CF_ICE);
2014-12-11 06:16:18 +00:00
smh->mparams->rtcp_audio_interval_msec = SWITCH_RTCP_AUDIO_INTERVAL_MSEC;
smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
}
2013-02-02 06:15:09 +00:00
if ( switch_rtp_has_dtls() && dtls_ok(session)) {
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF) ||
switch_true(switch_channel_get_variable(smh->session->channel, "rtp_use_dtls"))) {
switch_channel_set_flag(smh->session->channel, CF_DTLS);
switch_channel_set_flag(smh->session->channel, CF_SECURE);
generate_local_fingerprint(smh, SWITCH_MEDIA_TYPE_AUDIO);
}
2013-02-02 06:15:09 +00:00
}
switch_core_session_parse_crypto_prefs(session);
switch_core_session_check_outgoing_crypto(session);
}
2013-11-07 22:48:00 +00:00
fmtp_out = a_engine->cur_payload_map->fmtp_out;
2012-12-21 22:57:59 +00:00
username = smh->mparams->sdp_username;
switch_zmalloc(buf, SDPBUFLEN);
switch_core_media_check_dtmf_type(session);
if (switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) ||
((val = switch_channel_get_variable(session->channel, "supress_cng")) && switch_true(val)) ||
((val = switch_channel_get_variable(session->channel, "suppress_cng")) && switch_true(val))) {
use_cng = 0;
2013-01-08 18:59:02 +00:00
smh->mparams->cng_pt = 0;
2012-12-21 22:57:59 +00:00
}
2013-11-07 22:48:00 +00:00
2012-12-21 22:57:59 +00:00
if (!smh->payload_space) {
int i;
/* it could be 98 but chrome reserves 98 and 99 for some internal stuff even though they should not.
Everyone expects dtmf to be at 101 and Its not worth the trouble so we'll start at 102 */
smh->payload_space = 102;
memset(smh->rates, 0, sizeof(smh->rates));
smh->num_rates = 0;
2012-12-21 22:57:59 +00:00
2014-01-30 19:26:31 +00:00
for (i = 0; i < smh->mparams->num_codecs; i++) {
int j;
2014-01-30 19:26:31 +00:00
smh->ianacodes[i] = smh->codecs[i]->ianacode;
2015-07-30 23:11:08 +00:00
if (smh->codecs[i]->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
2015-07-30 23:11:08 +00:00
if (sdp_type == SDP_TYPE_REQUEST) {
for (j = 0; j < SWITCH_MAX_CODECS; j++) {
if (smh->rates[j] == 0) {
break;
}
if (smh->rates[j] == smh->codecs[i]->samples_per_second) {
goto do_next;
}
}
2015-07-30 23:11:08 +00:00
smh->rates[smh->num_rates++] = smh->codecs[i]->samples_per_second;
}
do_next:
continue;
2014-01-30 19:26:31 +00:00
}
2013-11-07 22:48:00 +00:00
if (sdp_type == SDP_TYPE_REQUEST) {
switch_core_session_t *orig_session = NULL;
switch_core_session_get_partner(session, &orig_session);
2013-11-07 22:48:00 +00:00
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
switch_payload_t orig_pt = 0;
char *orig_fmtp = NULL;
2014-01-30 19:26:31 +00:00
//smh->ianacodes[i] = imp->ianacode;
2013-11-07 22:48:00 +00:00
if (smh->ianacodes[i] > 64) {
if (smh->mparams->dtmf_type == DTMF_2833 && smh->mparams->te > 95 && smh->mparams->te == smh->payload_space) {
smh->payload_space++;
}
if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) &&
smh->mparams->cng_pt && use_cng && smh->mparams->cng_pt == smh->payload_space) {
smh->payload_space++;
}
if (orig_session &&
switch_core_session_get_payload_code(orig_session,
imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO,
imp->iananame, imp->samples_per_second, &orig_pt, NULL, &orig_fmtp) == SWITCH_STATUS_SUCCESS) {
if (orig_pt == smh->mparams->te) {
smh->mparams->te = (switch_payload_t)smh->payload_space++;
}
smh->ianacodes[i] = orig_pt;
if (orig_fmtp) {
smh->fmtps[i] = switch_core_session_strdup(session, orig_fmtp);
}
} else {
smh->ianacodes[i] = (switch_payload_t)smh->payload_space++;
}
2012-12-21 22:57:59 +00:00
}
2013-11-07 22:48:00 +00:00
switch_core_media_add_payload_map(session,
imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO,
imp->iananame,
imp->modname,
2013-11-18 19:43:30 +00:00
NULL,
2013-11-07 22:48:00 +00:00
sdp_type,
smh->ianacodes[i],
imp->samples_per_second,
imp->microseconds_per_packet / 1000,
2014-06-13 05:49:10 +00:00
imp->number_of_channels,
2013-11-07 22:48:00 +00:00
SWITCH_FALSE);
2012-12-21 22:57:59 +00:00
}
for (i = 0; i < smh->num_rates; i++) {
if (smh->rates[i] == 8000 || smh->num_rates == 1) {
2015-07-30 23:11:08 +00:00
smh->dtmf_ianacodes[i] = smh->mparams->te;
smh->cng_ianacodes[i] = smh->mparams->cng_pt;
} else {
2015-07-30 23:11:08 +00:00
smh->dtmf_ianacodes[i] = (switch_payload_t)smh->payload_space++;
smh->cng_ianacodes[i] = (switch_payload_t)smh->payload_space++;
}
}
if (orig_session) {
switch_core_session_rwunlock(orig_session);
}
2012-12-21 22:57:59 +00:00
}
}
if (fmtp_out_var) {
fmtp_out = fmtp_out_var;
}
2014-01-30 19:26:31 +00:00
val = switch_channel_get_variable(session->channel, "verbose_sdp");
if (!val || switch_true(val)) {
switch_channel_set_flag(session->channel, CF_VERBOSE_SDP);
2012-12-21 22:57:59 +00:00
}
if (!force && !ip && zstr(sr)
&& (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_test_flag(session->channel, CF_PROXY_MEDIA))) {
switch_safe_free(buf);
return;
}
if (!ip) {
2013-11-07 22:48:00 +00:00
if (!(ip = a_engine->adv_sdp_ip)) {
ip = a_engine->proxy_sdp_ip;
2012-12-21 22:57:59 +00:00
}
}
if (!ip) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO IP!\n", switch_channel_get_name(session->channel));
switch_safe_free(buf);
return;
}
if (!port) {
2013-11-07 22:48:00 +00:00
if (!(port = a_engine->adv_sdp_port)) {
port = a_engine->proxy_sdp_port;
2012-12-21 22:57:59 +00:00
}
}
if (!port) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO PORT!\n", switch_channel_get_name(session->channel));
switch_safe_free(buf);
return;
}
//if (!a_engine->cur_payload_map->rm_encoding && (b_sdp = switch_channel_get_variable(session->channel, SWITCH_B_SDP_VARIABLE))) {
//switch_core_media_sdp_map(b_sdp, &map, &ptmap);
//}
2012-12-21 22:57:59 +00:00
if (zstr(sr)) {
if (a_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) {
sr = "sendonly";
} else if (a_engine->smode == SWITCH_MEDIA_FLOW_RECVONLY) {
sr = "recvonly";
2012-12-21 22:57:59 +00:00
} else {
sr = "sendrecv";
}
//if ((var_val = switch_channel_get_variable(session->channel, "media_audio_mode"))) {
// sr = var_val;
//} else {
// sr = "sendrecv";
//}
2012-12-21 22:57:59 +00:00
}
if (!smh->owner_id) {
smh->owner_id = (uint32_t) switch_epoch_time_now(NULL) - port;
}
if (!smh->session_id) {
smh->session_id = smh->owner_id;
}
if (switch_true(switch_channel_get_variable_dup(session->channel, "drop_dtmf", SWITCH_FALSE, -1))) {
switch_channel_set_flag(session->channel, CF_DROP_DTMF);
}
smh->session_id++;
if ((smh->mparams->ndlb & SM_NDLB_SENDRECV_IN_SESSION) ||
((var_val = switch_channel_get_variable(session->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"
2013-01-10 15:34:27 +00:00
"c=IN %s %s\n"
"t=0 0\n"
2012-12-21 22:57:59 +00:00
"%s",
username, smh->owner_id, smh->session_id, family, ip, username, family, ip, srbuf);
2013-01-10 04:31:25 +00:00
if (switch_channel_test_flag(smh->session->channel, CF_ICE)) {
gen_ice(session, SWITCH_MEDIA_TYPE_AUDIO, ip, port);
2013-01-16 05:20:13 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=msid-semantic: WMS %s\n", smh->msid);
2013-01-10 04:31:25 +00:00
}
2013-11-07 22:48:00 +00:00
if (a_engine->codec_negotiated) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=audio %d %s", port,
2014-03-07 01:35:02 +00:00
get_media_profile_name(session, !a_engine->no_crypto &&
(switch_channel_test_flag(session->channel, CF_DTLS) || a_engine->crypto_type != CRYPTO_INVALID)));
2013-11-07 22:48:00 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", a_engine->cur_payload_map->pt);
if (switch_media_handle_test_media_flag(smh, SCMF_MULTI_ANSWER_AUDIO)) {
switch_mutex_lock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
for (pmap = a_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
if (pmap->pt != a_engine->cur_payload_map->pt) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", pmap->pt);
}
}
switch_mutex_unlock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
}
2012-12-21 22:57:59 +00:00
2012-12-22 23:34:08 +00:00
if ((smh->mparams->dtmf_type == DTMF_2833 || switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) ||
2012-12-22 03:30:14 +00:00
switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF)) && smh->mparams->te > 95) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", smh->mparams->te);
2012-12-21 22:57:59 +00:00
}
2013-01-08 18:59:02 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && smh->mparams->cng_pt && use_cng) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", smh->mparams->cng_pt);
2012-12-21 22:57:59 +00:00
}
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n");
2013-01-10 04:31:25 +00:00
2013-11-07 22:48:00 +00:00
rate = a_engine->cur_payload_map->adv_rm_rate;
2013-02-27 20:16:00 +00:00
2013-11-07 22:48:00 +00:00
if (!a_engine->cur_payload_map->adv_channels) {
a_engine->cur_payload_map->adv_channels = get_channels(a_engine->cur_payload_map->rm_encoding, 1);
2013-10-28 22:44:24 +00:00
}
2013-11-07 22:48:00 +00:00
if (a_engine->cur_payload_map->adv_channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n",
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->agreed_pt, a_engine->cur_payload_map->rm_encoding, rate, a_engine->cur_payload_map->adv_channels);
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n",
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->agreed_pt, a_engine->cur_payload_map->rm_encoding, rate);
}
2012-12-21 22:57:59 +00:00
if (fmtp_out) {
2013-11-07 22:48:00 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", a_engine->cur_payload_map->agreed_pt, fmtp_out);
}
if (switch_media_handle_test_media_flag(smh, SCMF_MULTI_ANSWER_AUDIO)) {
switch_mutex_lock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
for (pmap = a_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
if (pmap->pt != a_engine->cur_payload_map->pt) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\n",
pmap->pt, pmap->iananame,
pmap->rate);
}
}
switch_mutex_unlock(smh->sdp_mutex);
2012-12-21 22:57:59 +00:00
}
2013-11-07 22:48:00 +00:00
2012-12-21 22:57:59 +00:00
if (a_engine->read_codec.implementation && !ptime) {
ptime = a_engine->read_codec.implementation->microseconds_per_packet / 1000;
}
2012-12-22 23:34:08 +00:00
if ((smh->mparams->dtmf_type == DTMF_2833 || switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) ||
2012-12-21 22:57:59 +00:00
switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF))
2012-12-22 03:30:14 +00:00
&& smh->mparams->te > 95) {
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/%d\n",
2015-07-30 23:11:08 +00:00
smh->mparams->te, smh->mparams->te_rate);
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/%d\na=fmtp:%d 0-16\n",
2015-07-30 23:11:08 +00:00
smh->mparams->te, smh->mparams->te_rate, smh->mparams->te);
}
2012-12-21 22:57:59 +00:00
}
2013-09-12 15:39:57 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=silenceSupp:off - - - -\n");
} else if (smh->mparams->cng_pt && use_cng) {
2015-07-30 23:11:08 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d CN/%lu\n", smh->mparams->cng_pt, smh->mparams->cng_rate);
2013-09-12 15:39:57 +00:00
2013-11-07 22:48:00 +00:00
if (!a_engine->codec_negotiated) {
2013-01-08 18:59:02 +00:00
smh->mparams->cng_pt = 0;
2012-12-21 22:57:59 +00:00
}
}
if (append_audio) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s%s", append_audio, end_of(append_audio) == '\n' ? "" : "\n");
}
if (ptime) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ptime:%d\n", ptime);
}
if (local_sdp_audio_zrtp_hash) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n",
local_sdp_audio_zrtp_hash);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n",
local_sdp_audio_zrtp_hash);
}
if (!zstr(sr)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=%s\n", sr);
}
2013-01-14 02:12:23 +00:00
2013-02-01 20:29:40 +00:00
if (!zstr(a_engine->local_dtls_fingerprint.type)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fingerprint:%s %s\na=setup:%s\n",
a_engine->local_dtls_fingerprint.type,
2015-06-08 21:15:16 +00:00
a_engine->local_dtls_fingerprint.str, get_setup(session, sdp_type));
2013-02-01 20:29:40 +00:00
}
2013-01-15 05:17:28 +00:00
if (smh->mparams->rtcp_audio_interval_msec) {
2013-01-17 01:04:57 +00:00
if (a_engine->rtcp_mux > 0) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp-mux\n");
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp:%d IN %s %s\n", port, family, ip);
2013-01-17 01:04:57 +00:00
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp:%d IN %s %s\n", port + 1, family, ip);
}
2013-01-15 05:17:28 +00:00
}
2013-01-14 02:12:23 +00:00
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u\n", a_engine->ssrc);
2013-01-26 23:53:15 +00:00
if (a_engine->ice_out.cands[0][0].ready) {
2013-01-14 02:12:23 +00:00
char tmp1[11] = "";
char tmp2[11] = "";
uint32_t c1 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 1);
//uint32_t c2 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 2);
//uint32_t c3 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 1);
//uint32_t c4 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 2);
uint32_t c2 = c1 - 1;
uint32_t c3 = c1 - 2;
uint32_t c4 = c1 - 3;
2013-01-14 02:12:23 +00:00
tmp1[10] = '\0';
tmp2[10] = '\0';
switch_stun_random_string(tmp1, 10, "0123456789");
switch_stun_random_string(tmp2, 10, "0123456789");
ice_out = &a_engine->ice_out;
2013-01-14 02:12:23 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-ufrag:%s\n", ice_out->ufrag);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-pwd:%s\n", ice_out->pwd);
2013-01-14 02:12:23 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 1 %s %u %s %d typ host generation 0\n",
2013-01-26 23:53:15 +00:00
tmp1, ice_out->cands[0][0].transport, c1,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port
2013-01-14 02:12:23 +00:00
);
2013-11-07 22:48:00 +00:00
if (!zstr(a_engine->local_sdp_ip) && !zstr(ice_out->cands[0][0].con_addr) &&
strcmp(a_engine->local_sdp_ip, ice_out->cands[0][0].con_addr)
&& a_engine->local_sdp_port != ice_out->cands[0][0].con_port) {
2013-01-20 18:49:03 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 1 %s %u %s %d typ srflx raddr %s rport %d generation 0\n",
2013-01-26 23:53:15 +00:00
tmp2, ice_out->cands[0][0].transport, c3,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port,
2013-11-07 22:48:00 +00:00
a_engine->local_sdp_ip, a_engine->local_sdp_port
2013-01-20 18:49:03 +00:00
);
}
2013-01-14 02:12:23 +00:00
if (a_engine->rtcp_mux < 1 || is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING)) {
2013-01-14 02:12:23 +00:00
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ host generation 0\n",
tmp1, ice_out->cands[0][0].transport, c2,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port + (a_engine->rtcp_mux > 0 ? 0 : 1)
);
2013-01-20 18:49:03 +00:00
2013-01-17 01:04:57 +00:00
2013-11-07 22:48:00 +00:00
if (!zstr(a_engine->local_sdp_ip) && !zstr(ice_out->cands[0][0].con_addr) &&
strcmp(a_engine->local_sdp_ip, ice_out->cands[0][0].con_addr)
&& a_engine->local_sdp_port != ice_out->cands[0][0].con_port) {
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ srflx raddr %s rport %d generation 0\n",
tmp2, ice_out->cands[0][0].transport, c4,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port + (a_engine->rtcp_mux > 0 ? 0 : 1),
2013-11-07 22:48:00 +00:00
a_engine->local_sdp_ip, a_engine->local_sdp_port + (a_engine->rtcp_mux > 0 ? 0 : 1)
2013-02-02 06:15:09 +00:00
);
}
2013-01-20 18:49:03 +00:00
}
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u cname:%s\n", a_engine->ssrc, smh->cname);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u msid:%s a0\n", a_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u mslabel:%s\n", a_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u label:%sa0\n", a_engine->ssrc, smh->msid);
2013-01-14 02:12:23 +00:00
#ifdef GOOGLE_ICE
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-options:google-ice\n");
#endif
}
if (a_engine->crypto_type != CRYPTO_INVALID && !switch_channel_test_flag(session->channel, CF_DTLS) &&
!zstr(a_engine->ssec[a_engine->crypto_type].local_crypto_key) && switch_channel_test_flag(session->channel, CF_SECURE)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", a_engine->ssec[a_engine->crypto_type].local_crypto_key);
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=encryption:optional\n");
2012-12-21 22:57:59 +00:00
}
} else if (smh->mparams->num_codecs) {
2012-12-21 22:57:59 +00:00
int i;
int cur_ptime = 0, this_ptime = 0, cng_type = 0;
const char *mult;
2013-01-08 18:59:02 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && smh->mparams->cng_pt && use_cng) {
cng_type = smh->mparams->cng_pt;
2012-12-21 22:57:59 +00:00
2013-11-07 22:48:00 +00:00
if (!a_engine->codec_negotiated) {
2013-01-08 18:59:02 +00:00
smh->mparams->cng_pt = 0;
2012-12-21 22:57:59 +00:00
}
}
mult = switch_channel_get_variable(session->channel, "sdp_m_per_ptime");
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF) || (mult && switch_false(mult))) {
2012-12-21 22:57:59 +00:00
char *bp = buf;
2015-01-12 17:34:42 +00:00
int both = (switch_channel_test_flag(session->channel, CF_AVPF) || switch_channel_test_flag(session->channel, CF_DTLS)) ? 0 : 1;
2012-12-21 22:57:59 +00:00
if ((!a_engine->no_crypto && switch_channel_test_flag(session->channel, CF_SECURE)) ||
2013-02-02 06:15:09 +00:00
switch_channel_test_flag(session->channel, CF_DTLS)) {
2013-11-07 22:48:00 +00:00
generate_m(session, buf, SDPBUFLEN, port, family, ip, 0, append_audio, sr, use_cng, cng_type, map, 1, sdp_type);
2012-12-21 22:57:59 +00:00
bp = (buf + strlen(buf));
if (smh->crypto_mode == CRYPTO_MODE_MANDATORY) {
2012-12-21 22:57:59 +00:00
both = 0;
}
}
if (both) {
2013-11-07 22:48:00 +00:00
generate_m(session, bp, SDPBUFLEN - strlen(buf), port, family, ip, 0, append_audio, sr, use_cng, cng_type, map, 0, sdp_type);
2012-12-21 22:57:59 +00:00
}
} else {
for (i = 0; i < smh->mparams->num_codecs; i++) {
2012-12-21 22:57:59 +00:00
const switch_codec_implementation_t *imp = smh->codecs[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
continue;
}
this_ptime = imp->microseconds_per_packet / 1000;
2013-02-04 21:50:51 +00:00
if (!strcasecmp(imp->iananame, "ilbc") || !strcasecmp(imp->iananame, "isac")) {
2012-12-21 22:57:59 +00:00
this_ptime = 20;
}
if (cur_ptime != this_ptime) {
char *bp = buf;
int both = 1;
cur_ptime = this_ptime;
if ((!a_engine->no_crypto && switch_channel_test_flag(session->channel, CF_SECURE)) ||
2013-02-02 06:15:09 +00:00
switch_channel_test_flag(session->channel, CF_DTLS)) {
2013-11-07 22:48:00 +00:00
generate_m(session, bp, SDPBUFLEN - strlen(buf), port, family, ip, cur_ptime, append_audio, sr, use_cng, cng_type, map, 1, sdp_type);
2012-12-21 22:57:59 +00:00
bp = (buf + strlen(buf));
if (smh->crypto_mode == CRYPTO_MODE_MANDATORY) {
2012-12-21 22:57:59 +00:00
both = 0;
}
}
2015-01-12 17:34:42 +00:00
if (switch_channel_test_flag(session->channel, CF_AVPF) || switch_channel_test_flag(session->channel, CF_DTLS)) {
both = 0;
}
if (both) {
2013-11-07 22:48:00 +00:00
generate_m(session, bp, SDPBUFLEN - strlen(buf), port, family, ip, cur_ptime, append_audio, sr, use_cng, cng_type, map, 0, sdp_type);
2012-12-21 22:57:59 +00:00
}
}
}
}
}
2015-02-17 03:21:10 +00:00
2012-12-21 22:57:59 +00:00
if (switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE)) {
2013-02-02 06:15:09 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
if (switch_channel_test_flag(smh->session->channel, CF_DTLS)) {
v_engine->no_crypto = 1;
2013-02-02 06:15:09 +00:00
}
}
2012-12-21 22:57:59 +00:00
2013-11-07 22:48:00 +00:00
if (!v_engine->local_sdp_port) {
2012-12-21 22:57:59 +00:00
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 0);
}
2015-01-12 17:34:42 +00:00
//if (switch_channel_test_flag(session->channel, CF_AVPF)) {
// switch_media_handle_set_media_flag(smh, SCMF_MULTI_ANSWER_VIDEO);
//}
2013-11-07 22:48:00 +00:00
if ((v_port = v_engine->adv_sdp_port)) {
int loops;
for (loops = 0; loops < 2; loops++) {
if (switch_channel_test_flag(smh->session->channel, CF_ICE)) {
gen_ice(session, SWITCH_MEDIA_TYPE_VIDEO, ip, (switch_port_t)v_port);
}
2012-12-21 22:57:59 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=video %d %s",
v_port,
get_media_profile_name(session,
(loops == 0 && switch_channel_test_flag(session->channel, CF_SECURE)
&& switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) ||
2014-03-07 01:35:02 +00:00
a_engine->crypto_type != CRYPTO_INVALID || switch_channel_test_flag(session->channel, CF_DTLS)));
2012-12-21 22:57:59 +00:00
/*****************************/
if (v_engine->codec_negotiated) {
payload_map_t *pmap;
switch_core_media_set_video_codec(session, 0);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", v_engine->cur_payload_map->agreed_pt);
2013-11-07 22:48:00 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_MULTI_ANSWER_VIDEO)) {
switch_mutex_lock(smh->sdp_mutex);
for (pmap = v_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
if (pmap->pt != v_engine->cur_payload_map->pt && pmap->negotiated) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", pmap->pt);
}
2013-11-07 22:48:00 +00:00
}
switch_mutex_unlock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
}
} else if (smh->mparams->num_codecs) {
int i;
int already_did[128] = { 0 };
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
2013-11-07 22:48:00 +00:00
2012-12-21 22:57:59 +00:00
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
2013-06-20 18:10:21 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
2012-12-21 22:57:59 +00:00
continue;
}
if (smh->ianacodes[i] < 128) {
if (already_did[smh->ianacodes[i]]) {
continue;
}
already_did[smh->ianacodes[i]] = 1;
}
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", smh->ianacodes[i]);
2013-11-07 22:48:00 +00:00
if (!ptime) {
ptime = imp->microseconds_per_packet / 1000;
}
2012-12-21 22:57:59 +00:00
}
}
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n");
2012-12-21 22:57:59 +00:00
if (v_engine->codec_negotiated) {
const char *of;
payload_map_t *pmap;
2013-10-15 21:24:32 +00:00
//if (!strcasecmp(v_engine->cur_payload_map->rm_encoding, "VP8")) {
// vp8 = v_engine->cur_payload_map->pt;
//}
2013-01-10 04:31:25 +00:00
//if (!strcasecmp(v_engine->cur_payload_map->rm_encoding, "red")) {
// red = v_engine->cur_payload_map->pt;
//}
rate = v_engine->cur_payload_map->rm_rate;
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\n",
v_engine->cur_payload_map->pt, v_engine->cur_payload_map->rm_encoding,
v_engine->cur_payload_map->rm_rate);
2013-11-07 22:48:00 +00:00
2012-12-21 22:57:59 +00:00
if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
pass_fmtp = v_engine->cur_payload_map->rm_fmtp;
} else {
2012-12-21 22:57:59 +00:00
pass_fmtp = NULL;
2012-12-21 22:57:59 +00:00
if (switch_channel_get_partner_uuid(session->channel)) {
if ((of = switch_channel_get_variable_partner(session->channel, "rtp_video_fmtp"))) {
pass_fmtp = of;
}
2012-12-21 22:57:59 +00:00
}
if (ov_fmtp) {
pass_fmtp = ov_fmtp;
} else { //if (switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) {
// seems to break eyebeam at least...
pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp");
}
2013-11-19 22:36:45 +00:00
}
2013-11-25 18:08:17 +00:00
if (pass_fmtp) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", v_engine->cur_payload_map->pt, pass_fmtp);
}
2013-11-07 22:48:00 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_MULTI_ANSWER_VIDEO)) {
switch_mutex_lock(smh->sdp_mutex);
for (pmap = v_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
if (pmap->pt != v_engine->cur_payload_map->pt && pmap->negotiated) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\n",
pmap->pt, pmap->iananame, pmap->rate);
2013-11-07 22:48:00 +00:00
}
2013-11-07 22:48:00 +00:00
}
switch_mutex_unlock(smh->sdp_mutex);
2013-11-07 22:48:00 +00:00
}
if (append_video) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s%s", append_video, end_of(append_video) == '\n' ? "" : "\n");
}
if (v_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s", "a=sendonly\n");
} else if (v_engine->smode == SWITCH_MEDIA_FLOW_RECVONLY) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s", "a=recvonly\n");
}
2012-12-21 22:57:59 +00:00
} else if (smh->mparams->num_codecs) {
int i;
int already_did[128] = { 0 };
2012-12-21 22:57:59 +00:00
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
char *fmtp = NULL;
uint32_t ianacode = smh->ianacodes[i];
int channels;
2012-12-21 22:57:59 +00:00
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
2013-06-20 18:10:21 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
2012-12-21 22:57:59 +00:00
continue;
}
if (ianacode < 128) {
if (already_did[ianacode]) {
continue;
}
already_did[ianacode] = 1;
}
if (!rate) {
rate = imp->samples_per_second;
}
2012-12-21 22:57:59 +00:00
channels = get_channels(imp->iananame, imp->number_of_channels);
//if (!strcasecmp(imp->iananame, "VP8")) {
// vp8 = ianacode;
//}
2013-07-11 22:38:24 +00:00
//if (!strcasecmp(imp->iananame, "red")) {
// red = ianacode;
//}
if (channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", ianacode, imp->iananame,
imp->samples_per_second, channels);
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", ianacode, imp->iananame,
imp->samples_per_second);
}
2012-12-21 22:57:59 +00:00
if (!zstr(ov_fmtp)) {
fmtp = (char *) ov_fmtp;
} else {
2012-12-21 22:57:59 +00:00
if (map) {
fmtp = switch_event_get_header(map, imp->iananame);
}
2012-12-21 22:57:59 +00:00
if (smh->fmtps[i]) {
fmtp = smh->fmtps[i];
}
2013-11-25 18:08:17 +00:00
if (zstr(fmtp)) fmtp = imp->fmtp;
2012-12-21 22:57:59 +00:00
if (zstr(fmtp)) fmtp = (char *) pass_fmtp;
}
2012-12-21 22:57:59 +00:00
if (!zstr(fmtp) && strcasecmp(fmtp, "_blank_")) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", ianacode, fmtp);
}
2012-12-21 22:57:59 +00:00
}
}
2012-12-21 22:57:59 +00:00
if ((is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING))
&& switch_channel_test_flag(smh->session->channel, CF_DTLS)) {
generate_local_fingerprint(smh, SWITCH_MEDIA_TYPE_VIDEO);
}
2013-02-02 06:15:09 +00:00
if (!zstr(v_engine->local_dtls_fingerprint.type)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fingerprint:%s %s\na=setup:%s\n", v_engine->local_dtls_fingerprint.type,
2015-06-08 21:15:16 +00:00
v_engine->local_dtls_fingerprint.str, get_setup(session, sdp_type));
}
2013-02-01 20:29:40 +00:00
if (smh->mparams->rtcp_video_interval_msec) {
if (v_engine->rtcp_mux > 0) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp-mux\n");
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp:%d IN %s %s\n", v_port, family, ip);
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp:%d IN %s %s\n", v_port + 1, family, ip);
}
2013-01-17 01:04:57 +00:00
}
2013-11-20 20:38:16 +00:00
2015-01-29 23:39:14 +00:00
if (!(vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth"))) {
vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth_in");
}
2015-04-24 16:17:42 +00:00
if (!vbw) {
vbw = "1mb";
}
bw = switch_parse_bandwidth_string(vbw);
if (bw > 0) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=AS:%d\n", bw);
2014-12-04 02:34:49 +00:00
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=TIAS:%d\n", bw);
}
if (sdp_type == SDP_TYPE_REQUEST) {
fir++;
pli++;
nack++;
2015-05-14 23:01:22 +00:00
tmmbr++;
}
2014-11-15 16:34:26 +00:00
/* DFF nack pli etc */
2015-03-24 00:56:19 +00:00
//nack = v_engine->nack = 0;
//pli = v_engine->pli = 0;
if (v_engine->codec_negotiated) {
2015-05-14 23:01:22 +00:00
add_fb(buf, SDPBUFLEN, v_engine->cur_payload_map->agreed_pt, v_engine->fir || fir,
v_engine->nack || nack, v_engine->pli || pli, v_engine->tmmbr || tmmbr);
2015-03-24 00:56:19 +00:00
if (switch_media_handle_test_media_flag(smh, SCMF_MULTI_ANSWER_VIDEO)) {
switch_mutex_lock(smh->sdp_mutex);
for (pmap = v_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
if (pmap->pt != v_engine->cur_payload_map->pt && pmap->negotiated) {
2015-05-14 23:01:22 +00:00
add_fb(buf, SDPBUFLEN, pmap->pt, v_engine->fir || fir, v_engine->nack || nack, v_engine->pli || pli, v_engine->tmmbr || tmmbr);
2015-03-24 00:56:19 +00:00
}
}
2015-03-24 00:56:19 +00:00
switch_mutex_unlock(smh->sdp_mutex);
}
} else if (smh->mparams->num_codecs) {
int i;
int already_did[128] = { 0 };
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
}
2015-03-24 00:56:19 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
continue;
}
2015-03-24 00:56:19 +00:00
if (smh->ianacodes[i] < 128) {
if (already_did[smh->ianacodes[i]]) {
continue;
}
already_did[smh->ianacodes[i]] = 1;
}
2015-05-14 23:01:22 +00:00
add_fb(buf, SDPBUFLEN, smh->ianacodes[i], v_engine->fir || fir, v_engine->nack || nack, v_engine->pli || pli, v_engine->pli || pli);
}
2015-03-24 00:56:19 +00:00
}
2015-03-24 00:56:19 +00:00
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u\n", v_engine->ssrc);
if (v_engine->ice_out.cands[0][0].ready) {
char tmp1[11] = "";
char tmp2[11] = "";
uint32_t c1 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 1);
//uint32_t c2 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 2);
//uint32_t c3 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 1);
//uint32_t c4 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 2);
uint32_t c2 = c1 - 1;
uint32_t c3 = c1 - 2;
uint32_t c4 = c1 - 3;
2013-07-11 22:38:24 +00:00
tmp1[10] = '\0';
tmp2[10] = '\0';
switch_stun_random_string(tmp1, 10, "0123456789");
switch_stun_random_string(tmp2, 10, "0123456789");
ice_out = &v_engine->ice_out;
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u cname:%s\n", v_engine->ssrc, smh->cname);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u msid:%s v0\n", v_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u mslabel:%s\n", v_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u label:%sv0\n", v_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-ufrag:%s\n", ice_out->ufrag);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-pwd:%s\n", ice_out->pwd);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 1 %s %u %s %d typ host generation 0\n",
tmp1, ice_out->cands[0][0].transport, c1,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port
);
if (!zstr(v_engine->local_sdp_ip) && !zstr(ice_out->cands[0][0].con_addr) &&
strcmp(v_engine->local_sdp_ip, ice_out->cands[0][0].con_addr)
&& v_engine->local_sdp_port != ice_out->cands[0][0].con_port) {
2013-01-20 18:49:03 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 1 %s %u %s %d typ srflx raddr %s rport %d generation 0\n",
tmp2, ice_out->cands[0][0].transport, c3,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port,
v_engine->local_sdp_ip, v_engine->local_sdp_port
);
}
if (v_engine->rtcp_mux < 1 || is_outbound || switch_channel_test_flag(session->channel, CF_RECOVERING)) {
2013-01-20 18:49:03 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ host generation 0\n",
tmp1, ice_out->cands[0][0].transport, c2,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port + (v_engine->rtcp_mux > 0 ? 0 : 1)
);
2013-01-17 01:04:57 +00:00
2013-02-02 06:15:09 +00:00
if (!zstr(v_engine->local_sdp_ip) && !zstr(ice_out->cands[0][1].con_addr) &&
strcmp(v_engine->local_sdp_ip, ice_out->cands[0][1].con_addr)
&& v_engine->local_sdp_port != ice_out->cands[0][1].con_port) {
2013-02-02 06:15:09 +00:00
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ srflx generation 0\n",
tmp2, ice_out->cands[0][0].transport, c4,
ice_out->cands[0][0].con_addr, ice_out->cands[0][0].con_port + (v_engine->rtcp_mux > 0 ? 0 : 1),
v_engine->local_sdp_ip, v_engine->local_sdp_port + (v_engine->rtcp_mux > 0 ? 0 : 1)
);
}
2013-02-02 06:15:09 +00:00
}
#ifdef GOOGLE_ICE
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-options:google-ice\n");
#endif
}
if (loops == 0 && switch_channel_test_flag(session->channel, CF_SECURE) && !switch_channel_test_flag(session->channel, CF_DTLS)) {
int i;
for (i = 0; smh->crypto_suite_order[i] != CRYPTO_INVALID; i++) {
switch_rtp_crypto_key_type_t j = SUITES[smh->crypto_suite_order[i]].type;
if ((a_engine->crypto_type == j || a_engine->crypto_type == CRYPTO_INVALID) && !zstr(a_engine->ssec[j].local_crypto_key)) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", v_engine->ssec[j].local_crypto_key);
}
}
//switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n");
}
if (local_sdp_video_zrtp_hash) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(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-21 22:57:59 +00:00
if (switch_channel_test_flag(session->channel, CF_DTLS) ||
!switch_channel_test_flag(session->channel, CF_SECURE) ||
smh->crypto_mode == CRYPTO_MODE_MANDATORY || smh->crypto_mode == CRYPTO_MODE_FORBIDDEN) {
break;
}
2012-12-21 22:57:59 +00:00
}
}
2012-12-21 22:57:59 +00:00
}
if (map) {
switch_event_destroy(&map);
}
if (ptmap) {
switch_event_destroy(&ptmap);
}
switch_core_media_set_local_sdp(session, buf, SWITCH_TRUE);
switch_safe_free(buf);
}
2012-12-22 03:30:14 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_absorb_sdp(switch_core_session_t *session)
{
const char *sdp_str;
switch_rtp_engine_t *a_engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 03:30:14 +00:00
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
if ((sdp_str = switch_channel_get_variable(session->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) {
2013-11-07 22:48:00 +00:00
a_engine->proxy_sdp_ip = switch_core_session_strdup(session, connection->c_address);
2012-12-22 03:30:14 +00:00
}
2013-11-07 22:48:00 +00:00
a_engine->proxy_sdp_port = (switch_port_t) m->m_port;
if (a_engine->proxy_sdp_ip && a_engine->proxy_sdp_port) {
2012-12-22 03:30:14 +00:00
break;
}
}
}
sdp_parser_free(parser);
}
switch_core_media_set_local_sdp(session, sdp_str, SWITCH_TRUE);
}
}
//?
SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t *session, switch_t38_options_t *t38_options, int insist)
2012-12-22 03:30:14 +00:00
{
char buf[2048] = "";
char max_buf[128] = "";
char max_data[128] = "";
const char *ip;
uint32_t port;
const char *family = "IP4";
const char *username;
const char *bit_removal_on = "a=T38FaxFillBitRemoval\n";
const char *bit_removal_off = "";
const char *mmr_on = "a=T38FaxTranscodingMMR\n";
const char *mmr_off = "";
const char *jbig_on = "a=T38FaxTranscodingJBIG\n";
const char *jbig_off = "";
const char *var;
int broken_boolean;
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 03:30:14 +00:00
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
switch_assert(t38_options);
ip = t38_options->local_ip;
port = t38_options->local_port;
username = smh->mparams->sdp_username;
var = switch_channel_get_variable(session->channel, "t38_broken_boolean");
broken_boolean = switch_true(var);
if (!ip) {
2013-11-07 22:48:00 +00:00
if (!(ip = a_engine->adv_sdp_ip)) {
ip = a_engine->proxy_sdp_ip;
2012-12-22 03:30:14 +00:00
}
}
if (!ip) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO IP!\n", switch_channel_get_name(session->channel));
return;
}
if (!port) {
2013-11-07 22:48:00 +00:00
if (!(port = a_engine->adv_sdp_port)) {
port = a_engine->proxy_sdp_port;
2012-12-22 03:30:14 +00:00
}
}
if (!port) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s NO PORT!\n", switch_channel_get_name(session->channel));
return;
}
if (!smh->owner_id) {
smh->owner_id = (uint32_t) switch_epoch_time_now(NULL) - port;
}
if (!smh->session_id) {
smh->session_id = smh->owner_id;
}
smh->session_id++;
family = strchr(ip, ':') ? "IP6" : "IP4";
switch_snprintf(buf, sizeof(buf),
"v=0\n"
"o=%s %010u %010u IN %s %s\n"
"s=%s\n" "c=IN %s %s\n" "t=0 0\n", username, smh->owner_id, smh->session_id, family, ip, username, family, ip);
if (t38_options->T38FaxMaxBuffer) {
switch_snprintf(max_buf, sizeof(max_buf), "a=T38FaxMaxBuffer:%d\n", t38_options->T38FaxMaxBuffer);
};
if (t38_options->T38FaxMaxDatagram) {
switch_snprintf(max_data, sizeof(max_data), "a=T38FaxMaxDatagram:%d\n", t38_options->T38FaxMaxDatagram);
};
if (broken_boolean) {
bit_removal_on = "a=T38FaxFillBitRemoval:1\n";
bit_removal_off = "a=T38FaxFillBitRemoval:0\n";
mmr_on = "a=T38FaxTranscodingMMR:1\n";
mmr_off = "a=T38FaxTranscodingMMR:0\n";
jbig_on = "a=T38FaxTranscodingJBIG:1\n";
jbig_off = "a=T38FaxTranscodingJBIG:0\n";
}
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"m=image %d udptl t38\n"
"a=T38FaxVersion:%d\n"
"a=T38MaxBitRate:%d\n"
"%s"
"%s"
"%s"
"a=T38FaxRateManagement:%s\n"
"%s"
"%s"
"a=T38FaxUdpEC:%s\n",
//"a=T38VendorInfo:%s\n",
port,
t38_options->T38FaxVersion,
t38_options->T38MaxBitRate,
t38_options->T38FaxFillBitRemoval ? bit_removal_on : bit_removal_off,
t38_options->T38FaxTranscodingMMR ? mmr_on : mmr_off,
t38_options->T38FaxTranscodingJBIG ? jbig_on : jbig_off,
t38_options->T38FaxRateManagement,
max_buf,
max_data,
t38_options->T38FaxUdpEC
//t38_options->T38VendorInfo ? t38_options->T38VendorInfo : "0 0 0"
);
if (insist) {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=audio 0 RTP/AVP 19\n");
}
switch_core_media_set_local_sdp(session, buf, SWITCH_TRUE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s image media sdp:\n%s\n",
switch_channel_get_name(session->channel), smh->mparams->local_sdp_str);
}
//?
SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session)
{
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;
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine, *v_engine;
2014-12-13 06:57:14 +00:00
payload_map_t *pmap;
2012-12-22 03:30:14 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 03:30:14 +00:00
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
2013-08-13 21:00:31 +00:00
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2012-12-22 03:30:14 +00:00
if (zstr(smh->mparams->local_sdp_str)) {
return;
}
len = strlen(smh->mparams->local_sdp_str) * 2;
if (!(smh->mparams->ndlb & SM_NDLB_NEVER_PATCH_REINVITE)) {
if (switch_channel_test_flag(session->channel, CF_ANSWERED) &&
(switch_stristr("sendonly", smh->mparams->local_sdp_str) || switch_stristr("0.0.0.0", smh->mparams->local_sdp_str))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Skip patch on hold SDP\n");
return;
}
2012-12-22 03:30:14 +00:00
}
2013-11-07 22:48:00 +00:00
if (zstr(a_engine->local_sdp_ip) || !a_engine->local_sdp_port) {// || switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
2012-12-22 03:30:14 +00:00
if (switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 1) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s I/O Error\n",
switch_channel_get_name(session->channel));
return;
}
2014-12-13 06:57:14 +00:00
clear_pmaps(a_engine);
pmap = switch_core_media_add_payload_map(session,
SWITCH_MEDIA_TYPE_AUDIO,
"PROXY",
NULL,
NULL,
2014-12-13 06:57:14 +00:00
SDP_TYPE_RESPONSE,
0,
8000,
8000,
1,
SWITCH_TRUE);
a_engine->cur_payload_map = pmap;
2012-12-22 03:30:14 +00:00
}
new_sdp = switch_core_session_alloc(session, len);
2013-11-07 22:48:00 +00:00
switch_snprintf(port_buf, sizeof(port_buf), "%u", a_engine->local_sdp_port);
2012-12-22 03:30:14 +00:00
p = smh->mparams->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;
}
2013-11-07 22:48:00 +00:00
if (a_engine->local_sdp_ip && !strncmp("c=IN IP", p, 7)) {
2012-12-22 03:30:14 +00:00
strncpy(q, p, 7);
p += 7;
q += 7;
2013-11-07 22:48:00 +00:00
strncpy(q, strchr(a_engine->adv_sdp_ip, ':') ? "6 " : "4 ", 2);
2012-12-22 03:30:14 +00:00
p +=2;
q +=2;
2013-11-07 22:48:00 +00:00
strncpy(q, a_engine->adv_sdp_ip, strlen(a_engine->adv_sdp_ip));
q += strlen(a_engine->adv_sdp_ip);
2012-12-22 03:30:14 +00:00
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(smh->mparams->sipip, ':') ? "IP6" : "IP4";
if (!smh->owner_id) {
smh->owner_id = (uint32_t) switch_epoch_time_now(NULL) * 31821U + 13849U;
}
if (!smh->session_id) {
smh->session_id = smh->owner_id;
}
smh->session_id++;
snprintf(o_line, sizeof(o_line), "o=%s %010u %010u IN %s %s\n",
smh->mparams->sdp_username, smh->owner_id, smh->session_id, family, smh->mparams->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", smh->mparams->sdp_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) {
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1);
2014-12-13 06:57:14 +00:00
clear_pmaps(v_engine);
pmap = switch_core_media_add_payload_map(session,
SWITCH_MEDIA_TYPE_AUDIO,
"PROXY-VID",
NULL,
NULL,
2014-12-13 06:57:14 +00:00
SDP_TYPE_RESPONSE,
0,
90000,
90000,
1,
SWITCH_TRUE);
v_engine->cur_payload_map = pmap;
2013-11-07 22:48:00 +00:00
switch_snprintf(vport_buf, sizeof(vport_buf), "%u", v_engine->adv_sdp_port);
2012-12-22 03:30:14 +00:00
if (switch_channel_media_ready(session->channel) && !switch_rtp_ready(v_engine->rtp_session)) {
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
switch_channel_set_flag(session->channel, CF_REINVITE);
switch_core_media_activate_rtp(session);
}
}
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(session->channel)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s too late.\n", switch_channel_get_name(session->channel));
return;
}
if (!has_ip && !has_audio) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SDP has no audio in it.\n%s\n",
switch_channel_get_name(session->channel), smh->mparams->local_sdp_str);
return;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Patched SDP\n---\n%s\n+++\n%s\n",
switch_channel_get_name(session->channel), smh->mparams->local_sdp_str, new_sdp);
switch_core_media_set_local_sdp(session, new_sdp, SWITCH_FALSE);
}
2012-12-22 17:51:03 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_start_udptl(switch_core_session_t *session, switch_t38_options_t *t38_options)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine;
2012-12-22 17:51:03 +00:00
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 17:51:03 +00:00
if (!(smh = session->media_handle)) {
return;
}
if (switch_channel_down(session->channel)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
if (switch_rtp_ready(a_engine->rtp_session)) {
char *remote_host = switch_rtp_get_remote_host(a_engine->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session);
const char *err, *val;
switch_channel_clear_flag(session->channel, CF_NOTIMER_DURING_BRIDGE);
switch_rtp_udptl_mode(a_engine->rtp_session);
if (!t38_options || !t38_options->remote_ip) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No remote address\n");
return;
}
if (remote_host && remote_port && remote_port == t38_options->remote_port && !strcmp(remote_host, t38_options->remote_ip)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote address:port [%s:%d] has not changed.\n",
t38_options->remote_ip, t38_options->remote_port);
return;
}
if (switch_rtp_set_remote_address(a_engine->rtp_session, t38_options->remote_ip,
t38_options->remote_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "IMAGE UDPTL REPORTS ERROR: [%s]\n", err);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "IMAGE UDPTL CHANGING DEST TO: [%s:%d]\n",
t38_options->remote_ip, t38_options->remote_port);
2015-01-12 17:34:42 +00:00
if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(session->channel, CF_AVPF) &&
2012-12-22 17:51:03 +00:00
!((val = switch_channel_get_variable(session->channel, "disable_udptl_auto_adjust")) && switch_true(val))) {
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
}
}
}
//?
SWITCH_DECLARE(void) switch_core_media_hard_mute(switch_core_session_t *session, switch_bool_t on)
{
switch_core_session_message_t msg = { 0 };
msg.from = __FILE__;
2012-12-22 17:51:03 +00:00
msg.message_id = SWITCH_MESSAGE_INDICATE_HARD_MUTE;
msg.numeric_arg = on;
switch_core_session_receive_message(session, &msg);
}
2012-12-22 17:51:03 +00:00
static int check_engine(switch_rtp_engine_t *engine)
{
dtls_state_t dtls_state = switch_rtp_dtls_state(engine->rtp_session, DTLS_TYPE_RTP);
int flags = 0;
switch_status_t status;
if (dtls_state == DS_READY || dtls_state >= DS_FAIL) return 0;
status = switch_rtp_zerocopy_read_frame(engine->rtp_session, &engine->read_frame, flags);
if (!SWITCH_READ_ACCEPTABLE(status)) {
return 0;
}
return 1;
}
SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session, switch_media_type_t type)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *engine;
int checking = 0;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_FALSE;
}
if (!switch_channel_media_up(session->channel)) {
return SWITCH_FALSE;
}
if (!switch_channel_test_flag(session->channel, CF_DTLS)) {
return SWITCH_TRUE;
}
engine = &smh->engines[type];
do {
if (engine->rtp_session) checking = check_engine(engine);
} while (switch_channel_ready(session->channel) && checking);
if (!checking) {
return SWITCH_TRUE;
}
return SWITCH_FALSE;
}
2012-12-22 17:51:03 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine, *v_engine;
switch_status_t status = SWITCH_STATUS_SUCCESS;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 17:51:03 +00:00
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (switch_channel_down(session->channel)) {
return SWITCH_STATUS_FALSE;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2012-12-22 17:51:03 +00:00
switch (msg->message_id) {
case SWITCH_MESSAGE_RESAMPLE_EVENT:
{
if (switch_channel_test_flag(session->channel, CF_CONFERENCE)) {
switch_channel_set_flag(session->channel, CF_CONFERENCE_RESET_MEDIA);
}
}
break;
case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
{
if (v_engine->rtp_session) {
if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR)) {
2015-01-24 07:55:57 +00:00
switch_rtp_video_refresh(v_engine->rtp_session);
}// else {
if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PLI)) {
switch_rtp_video_loss(v_engine->rtp_session);
}
// }
}
}
break;
2012-12-22 17:51:03 +00:00
case SWITCH_MESSAGE_INDICATE_PROXY_MEDIA:
{
if (switch_rtp_ready(a_engine->rtp_session)) {
if (msg->numeric_arg) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA);
} else {
switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA);
}
}
}
break;
case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER:
{
if (switch_rtp_ready(a_engine->rtp_session)) {
check_jb(session, msg->string_arg, 0, 0);
2012-12-22 17:51:03 +00:00
}
}
break;
case SWITCH_MESSAGE_INDICATE_HARD_MUTE:
{
if (session->bugs) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"%s has a media bug, hard mute not allowed.\n", switch_channel_get_name(session->channel));
} else if (a_engine->rtp_session) {
if (msg->numeric_arg) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_MUTE);
} else {
switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_MUTE);
}
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
}
break;
case SWITCH_MESSAGE_INDICATE_BITRATE_REQ:
{
if (v_engine->rtp_session) {
switch_rtp_req_bitrate(v_engine->rtp_session, msg->numeric_arg);
}
}
break;
case SWITCH_MESSAGE_INDICATE_BITRATE_ACK:
{
if (v_engine->rtp_session) {
switch_rtp_ack_bitrate(v_engine->rtp_session, msg->numeric_arg);
}
}
break;
case SWITCH_MESSAGE_INDICATE_DEBUG_MEDIA:
2012-12-22 17:51:03 +00:00
{
switch_rtp_t *rtp = a_engine->rtp_session;
const char *direction = msg->string_array_arg[0];
if (direction && *direction == 'v') {
direction++;
rtp = v_engine->rtp_session;
}
if (switch_rtp_ready(rtp) && !zstr(direction) && !zstr(msg->string_array_arg[1])) {
2013-04-26 16:07:50 +00:00
switch_rtp_flag_t flags[SWITCH_RTP_FLAG_INVALID] = {0};
int both = !strcasecmp(direction, "both");
2013-04-26 16:07:50 +00:00
int set = 0;
if (both || !strcasecmp(direction, "read")) {
2013-04-26 16:07:50 +00:00
flags[SWITCH_RTP_FLAG_DEBUG_RTP_READ]++;
set++;
}
if (both || !strcasecmp(direction, "write")) {
2013-04-26 16:07:50 +00:00
flags[SWITCH_RTP_FLAG_DEBUG_RTP_WRITE]++;
set++;
2012-12-22 17:51:03 +00:00
}
2013-04-26 16:07:50 +00:00
if (set) {
2012-12-22 17:51:03 +00:00
if (switch_true(msg->string_array_arg[1])) {
switch_rtp_set_flags(rtp, flags);
2012-12-22 17:51:03 +00:00
} else {
switch_rtp_clear_flags(rtp, flags);
2012-12-22 17:51:03 +00:00
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Options\n");
}
}
}
goto end;
case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
if (a_engine->rtp_session && switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Pass 2833 mode may not work on a transcoded call.\n");
}
goto end;
case SWITCH_MESSAGE_INDICATE_BRIDGE:
{
if (switch_rtp_ready(a_engine->rtp_session)) {
const char *val;
int ok = 0;
if (!(val = switch_channel_get_variable(session->channel, "rtp_jitter_buffer_during_bridge")) || switch_false(val)) {
2012-12-22 17:51:03 +00:00
if (switch_channel_test_flag(session->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(session->channel, CC_FS_RTP)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s PAUSE Jitterbuffer\n", switch_channel_get_name(session->channel));
switch_rtp_pause_jitter_buffer(a_engine->rtp_session, SWITCH_TRUE);
switch_set_flag(smh, SMF_JB_PAUSED);
}
}
if (switch_channel_test_flag(session->channel, CF_PASS_RFC2833) && switch_channel_test_flag_partner(session->channel, CF_FS_RTP)) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s activate passthru 2833 mode.\n", switch_channel_get_name(session->channel));
}
if ((val = switch_channel_get_variable(session->channel, "rtp_notimer_during_bridge"))) {
ok = switch_true(val);
} else {
ok = switch_channel_test_flag(session->channel, CF_RTP_NOTIMER_DURING_BRIDGE);
}
if (ok && !switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) {
ok = 0;
}
if (ok) {
switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
2013-10-28 18:39:23 +00:00
//switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
2012-12-22 17:51:03 +00:00
switch_channel_set_flag(session->channel, CF_NOTIMER_DURING_BRIDGE);
}
if (ok && switch_channel_test_flag(session->channel, CF_NOTIMER_DURING_BRIDGE)) {
/* these are not compat */
ok = 0;
} else {
if ((val = switch_channel_get_variable(session->channel, "rtp_autoflush_during_bridge"))) {
ok = switch_true(val);
} else {
ok = smh->media_flags[SCMF_RTP_AUTOFLUSH_DURING_BRIDGE];
}
}
if (ok) {
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_STICK);
switch_channel_set_flag(session->channel, CF_AUTOFLUSH_DURING_BRIDGE);
} else {
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
}
}
goto end;
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
if (switch_rtp_ready(a_engine->rtp_session)) {
if (switch_test_flag(smh, SMF_JB_PAUSED)) {
switch_clear_flag(smh, SMF_JB_PAUSED);
if (switch_channel_test_flag(session->channel, CF_JITTERBUFFER)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s RESUME Jitterbuffer\n", switch_channel_get_name(session->channel));
switch_rtp_pause_jitter_buffer(a_engine->rtp_session, SWITCH_FALSE);
}
}
if (switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s deactivate passthru 2833 mode.\n",
switch_channel_get_name(session->channel));
switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
}
if (switch_channel_test_flag(session->channel, CF_NOTIMER_DURING_BRIDGE)) {
if (!switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_UDPTL) &&
!switch_rtp_test_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA)) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
2013-10-28 18:39:23 +00:00
//switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
2012-12-22 17:51:03 +00:00
}
switch_channel_clear_flag(session->channel, CF_NOTIMER_DURING_BRIDGE);
}
if (switch_channel_test_flag(session->channel, CF_AUTOFLUSH_DURING_BRIDGE)) {
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_UNSTICK);
switch_channel_clear_flag(session->channel, CF_AUTOFLUSH_DURING_BRIDGE);
} else {
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
}
goto end;
case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
if (switch_rtp_ready(a_engine->rtp_session)) {
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
goto end;
case SWITCH_MESSAGE_INDICATE_VIDEO_SYNC:
if (switch_rtp_ready(v_engine->rtp_session)) {
switch_rtp_flush(v_engine->rtp_session);
}
goto end;
case SWITCH_MESSAGE_INDICATE_MEDIA:
{
a_engine->codec_negotiated = 0;
v_engine->codec_negotiated = 0;
if (session->track_duration) {
switch_core_session_enable_heartbeat(session, session->track_duration);
}
}
break;
2013-06-18 02:37:53 +00:00
case SWITCH_MESSAGE_INDICATE_NOMEDIA:
{
const char *uuid;
switch_core_session_t *other_session;
switch_channel_t *other_channel;
const char *ip = NULL, *port = NULL;
switch_channel_set_flag(session->channel, CF_PROXY_MODE);
2013-11-07 22:48:00 +00:00
2013-06-18 02:37:53 +00:00
switch_core_media_set_local_sdp(session, NULL, SWITCH_FALSE);
if (switch_true(switch_channel_get_variable(session->channel, "bypass_keep_codec"))) {
switch_channel_set_variable(session->channel, "absolute_codec_string", switch_channel_get_variable(session->channel, "ep_codec_string"));
}
2013-06-18 02:37:53 +00:00
if ((uuid = switch_channel_get_partner_uuid(session->channel))
&& (other_session = switch_core_session_locate(uuid))) {
other_channel = switch_core_session_get_channel(other_session);
ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
switch_core_session_rwunlock(other_session);
2014-01-30 18:02:28 +00:00
2013-06-18 02:37:53 +00:00
if (ip && port) {
2014-01-30 18:02:28 +00:00
switch_core_media_prepare_codecs(session, 1);
clear_pmaps(a_engine);
clear_pmaps(v_engine);
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, ip, (switch_port_t)atoi(port), NULL, 1);
2013-06-18 02:37:53 +00:00
}
}
2014-01-30 18:02:28 +00:00
if (!smh->mparams->local_sdp_str) {
switch_core_media_absorb_sdp(session);
}
2013-06-18 02:37:53 +00:00
if (session->track_duration) {
switch_core_session_enable_heartbeat(session, session->track_duration);
}
2013-06-18 02:37:53 +00:00
}
break;
2012-12-22 17:51:03 +00:00
default:
break;
}
2013-06-19 02:16:48 +00:00
if (smh->mutex) switch_mutex_lock(smh->mutex);
2012-12-22 17:51:03 +00:00
if (switch_channel_down(session->channel)) {
status = SWITCH_STATUS_FALSE;
goto end_lock;
}
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_MEDIA_RENEG:
{
switch_core_session_t *nsession;
2013-02-21 22:04:04 +00:00
2012-12-22 17:51:03 +00:00
if (msg->string_arg) {
switch_channel_set_variable(session->channel, "absolute_codec_string", NULL);
if (*msg->string_arg == '=') {
switch_channel_set_variable(session->channel, "codec_string", msg->string_arg);
} else {
switch_channel_set_variable_printf(session->channel, "codec_string", "=%s%s%s,%s",
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_encoding ? v_engine->cur_payload_map->rm_encoding : "",
v_engine->cur_payload_map->rm_encoding ? "," : "",
a_engine->cur_payload_map->rm_encoding, msg->string_arg);
2012-12-22 17:51:03 +00:00
}
2013-11-07 22:48:00 +00:00
a_engine->codec_negotiated = 0;
v_engine->codec_negotiated = 0;
smh->num_negotiated_codecs = 0;
2012-12-22 17:51:03 +00:00
switch_channel_clear_flag(session->channel, CF_VIDEO_POSSIBLE);
switch_core_media_prepare_codecs(session, SWITCH_TRUE);
switch_core_media_check_video_codecs(session);
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1);
2012-12-22 17:51:03 +00:00
}
2013-02-21 22:04:04 +00:00
switch_media_handle_set_media_flag(smh, SCMF_RENEG_ON_REINVITE);
2012-12-22 17:51:03 +00:00
if (msg->numeric_arg && switch_core_session_get_partner(session, &nsession) == SWITCH_STATUS_SUCCESS) {
msg->numeric_arg = 0;
switch_core_session_receive_message(nsession, msg);
switch_core_session_rwunlock(nsession);
}
}
break;
case SWITCH_MESSAGE_INDICATE_AUDIO_DATA:
{
if (switch_rtp_ready(a_engine->rtp_session)) {
if (msg->numeric_arg) {
if (switch_channel_test_flag(session->channel, CF_JITTERBUFFER)) {
switch_rtp_pause_jitter_buffer(a_engine->rtp_session, SWITCH_TRUE);
switch_set_flag(smh, SMF_JB_PAUSED);
}
rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_UNSTICK);
} else {
if (switch_test_flag(smh, SMF_JB_PAUSED)) {
switch_clear_flag(smh, SMF_JB_PAUSED);
if (switch_channel_test_flag(session->channel, CF_JITTERBUFFER)) {
switch_rtp_pause_jitter_buffer(a_engine->rtp_session, SWITCH_FALSE);
}
}
}
}
}
break;
case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:
{
switch_t38_options_t *t38_options = switch_channel_get_private(session->channel, "t38_options");
if (t38_options) {
switch_core_media_start_udptl(session, t38_options);
}
}
default:
break;
}
end_lock:
2013-06-19 02:16:48 +00:00
if (smh->mutex) switch_mutex_unlock(smh->mutex);
2012-12-22 17:51:03 +00:00
end:
if (switch_channel_down(session->channel)) {
status = SWITCH_STATUS_FALSE;
}
return status;
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_break(switch_core_session_t *session, switch_media_type_t type)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
switch_rtp_break(smh->engines[type].rtp_session);
}
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_kill_socket(switch_core_session_t *session, switch_media_type_t type)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
switch_rtp_kill_socket(smh->engines[type].rtp_session);
}
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_queue_rfc2833(switch_core_session_t *session, switch_media_type_t type, const switch_dtmf_t *dtmf)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
return switch_rtp_queue_rfc2833(smh->engines[type].rtp_session, dtmf);
}
2012-12-22 17:51:03 +00:00
return SWITCH_STATUS_FALSE;
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_queue_rfc2833_in(switch_core_session_t *session, switch_media_type_t type, const switch_dtmf_t *dtmf)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
return switch_rtp_queue_rfc2833_in(smh->engines[type].rtp_session, dtmf);
}
2012-12-22 17:51:03 +00:00
return SWITCH_STATUS_FALSE;
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(uint8_t) switch_core_media_ready(switch_core_session_t *session, switch_media_type_t type)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return 0;
}
2012-12-22 17:51:03 +00:00
return switch_rtp_ready(smh->engines[type].rtp_session);
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_set_rtp_flag(switch_core_session_t *session, switch_media_type_t type, switch_rtp_flag_t flag)
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
switch_rtp_set_flag(smh->engines[type].rtp_session, flag);
}
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_clear_rtp_flag(switch_core_session_t *session, switch_media_type_t type, switch_rtp_flag_t flag)
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
switch_rtp_clear_flag(smh->engines[type].rtp_session, flag);
}
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_set_telephony_event(switch_core_session_t *session, switch_media_type_t type, switch_payload_t te)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
switch_rtp_set_telephony_event(smh->engines[type].rtp_session, te);
}
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_set_telephony_recv_event(switch_core_session_t *session, switch_media_type_t type, switch_payload_t te)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
switch_rtp_set_telephony_recv_event(smh->engines[type].rtp_session, te);
}
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(switch_rtp_stats_t *) switch_core_media_get_stats(switch_core_session_t *session, switch_media_type_t type, switch_memory_pool_t *pool)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return NULL;
}
if (smh->engines[type].rtp_session) {
2012-12-22 17:51:03 +00:00
return switch_rtp_get_stats(smh->engines[type].rtp_session, pool);
}
return NULL;
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_udptl_mode(switch_core_session_t *session, switch_media_type_t type)
2012-12-22 17:51:03 +00:00
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
2012-12-22 17:51:03 +00:00
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
return switch_rtp_udptl_mode(smh->engines[type].rtp_session);
}
2012-12-22 17:51:03 +00:00
return SWITCH_STATUS_FALSE;
}
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(stfu_instance_t *) switch_core_media_get_jb(switch_core_session_t *session, switch_media_type_t type)
{
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return NULL;
}
if (switch_rtp_ready(smh->engines[type].rtp_session)) {
return switch_rtp_get_jitter_buffer(smh->engines[type].rtp_session);
}
2012-12-22 03:30:14 +00:00
return NULL;
}
2012-12-22 03:30:14 +00:00
2012-12-22 23:34:08 +00:00
//?
SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp, switch_sdp_type_t sdp_type)
2012-12-22 23:34:08 +00:00
{
sdp_parser_t *parser;
sdp_session_t *sdp;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 23:34:08 +00:00
if (!(smh = session->media_handle)) {
return;
}
if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
if ((sdp = sdp_session(parser))) {
switch_core_media_set_r_sdp_codec_string(session, switch_core_media_get_codec_string(session), sdp, sdp_type);
2012-12-22 23:34:08 +00:00
}
sdp_parser_free(parser);
}
}
static void add_audio_codec(sdp_rtpmap_t *map, const switch_codec_implementation_t *imp, int ptime, char *buf, switch_size_t buflen)
2012-12-22 23:34:08 +00:00
{
int codec_ms = ptime;
2014-06-13 05:49:10 +00:00
uint32_t map_bit_rate = 0, map_channels = 1;
2012-12-22 23:34:08 +00:00
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);
}
2014-06-13 05:49:10 +00:00
map_channels = map->rm_params ? atoi(map->rm_params) : 1;
2012-12-22 23:34:08 +00:00
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)) {
2013-01-25 05:08:40 +00:00
if (!strcasecmp(map->rm_encoding, "ilbc")) {
2012-12-22 23:34:08 +00:00
ptime = codec_ms = 30;
map_bit_rate = 13330;
2013-01-25 05:08:40 +00:00
} else if (!strcasecmp(map->rm_encoding, "isac")) {
ptime = codec_ms = 30;
map_bit_rate = 32000;
2012-12-22 23:34:08 +00:00
}
} 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);
}
2014-06-13 05:49:10 +00:00
if (map_channels > 1) {
switch_snprintf(bitstr, sizeof(bitstr), "@%dc", map_channels);
}
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s.%s%s%s%s", imp->modname, map->rm_encoding, ratestr, ptstr, bitstr);
2012-12-22 23:34:08 +00:00
}
static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp, switch_sdp_type_t sdp_type)
2012-12-22 23:34:08 +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);
int prefer_sdp = 0;
const char *var;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2012-12-22 23:34:08 +00:00
if (!(smh = session->media_handle)) {
return;
}
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;
}
}
switch_core_media_find_zrtp_hash(session, sdp);
switch_core_media_pass_zrtp_hash(session);
for (m = sdp->sdp_media; m; m = m->m_next) {
2013-11-12 17:17:53 +00:00
ptime = dptime;
if ((m->m_type == sdp_media_audio || m->m_type == sdp_media_video) && m->m_port) {
for (map = m->m_rtpmaps; map; map = map->rm_next) {
2013-11-12 17:17:53 +00:00
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;
}
}
switch_core_media_add_payload_map(session,
m->m_type == sdp_media_audio ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO,
map->rm_encoding,
NULL,
2013-11-18 19:43:30 +00:00
map->rm_fmtp,
sdp_type,
map->rm_pt,
2013-11-12 17:17:53 +00:00
map->rm_rate,
ptime,
2014-06-13 05:49:10 +00:00
map->rm_params ? atoi(map->rm_params) : 1,
2013-11-22 13:52:21 +00:00
SWITCH_FALSE);
}
}
}
2012-12-22 23:34:08 +00:00
for (m = sdp->sdp_media; m; m = m->m_next) {
ptime = dptime;
2012-12-22 23:34:08 +00:00
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) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
if (map->rm_encoding) {
2014-07-28 22:04:24 +00:00
match = !strcasecmp(map->rm_encoding, imp->iananame) &&
((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95));
2012-12-22 23:34:08 +00:00
} else {
match = 0;
}
}
if (match) {
add_audio_codec(map, imp, ptime, buf, sizeof(buf));
2012-12-22 23:34:08 +00:00
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) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
if (map->rm_encoding) {
2014-07-28 22:04:24 +00:00
match = !strcasecmp(map->rm_encoding, imp->iananame) &&
((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95));
2012-12-22 23:34:08 +00:00
} else {
match = 0;
}
}
if (match) {
add_audio_codec(map, imp, ptime, buf, sizeof(buf));
2012-12-22 23:34:08 +00:00
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];
2013-06-20 18:10:21 +00:00
2012-12-22 23:34:08 +00:00
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
continue;
}
2013-06-20 18:10:21 +00:00
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
continue;
}
2012-12-22 23:34:08 +00:00
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) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
match = (map->rm_pt == imp->ianacode) ? 1 : 0;
} else {
if (map->rm_encoding) {
2014-07-28 22:04:24 +00:00
match = !strcasecmp(map->rm_encoding, imp->iananame) &&
((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95));
2012-12-22 23:34:08 +00:00
} else {
match = 0;
}
}
if (match) {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s", imp->modname, imp->iananame);
2012-12-22 23:34:08 +00:00
already_did[imp->ianacode] = 1;
break;
}
}
}
}
}
if (buf[0] == ',') {
switch_channel_set_variable(channel, "ep_codec_string", buf + 1);
}
}
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_codec_chosen(switch_core_session_t *session, switch_media_type_t type)
{
switch_rtp_engine_t *engine;
switch_media_handle_t *smh;
2012-12-24 03:20:03 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
engine = &smh->engines[type];
2013-11-07 22:48:00 +00:00
if (engine->cur_payload_map->iananame) {
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
2015-01-24 08:47:17 +00:00
SWITCH_DECLARE(void) switch_core_session_stop_media(switch_core_session_t *session)
{
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2015-03-24 00:56:19 +00:00
int type;
2015-01-24 08:47:17 +00:00
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2015-03-24 00:56:19 +00:00
if (switch_core_codec_ready(&v_engine->read_codec)) {
type = 1;
switch_core_codec_control(&v_engine->read_codec, SCC_VIDEO_RESET, SCCT_INT, (void *)&type, NULL, NULL);
}
if (switch_core_codec_ready(&v_engine->write_codec)) {
type = 2;
switch_core_codec_control(&v_engine->write_codec, SCC_VIDEO_RESET, SCCT_INT, (void *)&type, NULL, NULL);
}
2015-01-24 08:47:17 +00:00
if (a_engine->rtp_session) {
switch_rtp_reset(a_engine->rtp_session);
2015-01-24 08:47:17 +00:00
}
if (v_engine->rtp_session) {
switch_rtp_reset(v_engine->rtp_session);
2015-01-24 08:47:17 +00:00
}
2015-03-24 00:56:19 +00:00
smh->msid = NULL;
smh->cname = NULL;
v_engine->ice_out.ufrag = NULL;
v_engine->ice_out.pwd = NULL;
v_engine->ice_out.cands[0][0].foundation = NULL;
v_engine->ice_out.cands[0][0].component_id = 0;
a_engine->ice_out.ufrag = NULL;
a_engine->ice_out.pwd = NULL;
a_engine->ice_out.cands[0][0].foundation = NULL;
a_engine->ice_out.cands[0][0].component_id = 0;
if (v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].ready) {
gen_ice(smh->session, SWITCH_MEDIA_TYPE_VIDEO, NULL, 0);
}
if (a_engine->ice_in.cands[a_engine->ice_in.chosen[0]][0].ready) {
gen_ice(smh->session, SWITCH_MEDIA_TYPE_AUDIO, NULL, 0);
}
smh->owner_id = 0;
smh->session_id = 0;
a_engine->local_dtls_fingerprint.len = 0;
v_engine->local_dtls_fingerprint.len = 0;
a_engine->remote_ssrc = 0;
v_engine->remote_ssrc = 0;
2015-03-24 00:56:19 +00:00
switch_channel_clear_flag(smh->session->channel, CF_VIDEO_READY);
switch_core_session_wake_video_thread(smh->session);
switch_core_session_request_video_refresh(smh->session);
2015-01-24 08:47:17 +00:00
}
//?
2013-02-27 20:16:00 +00:00
SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_t *session, switch_core_session_t *o_session)
{
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
2013-02-27 20:16:00 +00:00
const char *r_sdp = NULL;
2014-12-13 06:57:14 +00:00
payload_map_t *pmap;
2012-12-24 03:20:03 +00:00
switch_assert(session);
2013-02-27 20:16:00 +00:00
if (!switch_channel_test_flag(o_session->channel, CF_PROXY_MEDIA)) {
return;
}
if (!(smh = session->media_handle)) {
return;
}
2013-02-27 20:16:00 +00:00
r_sdp = switch_channel_get_variable(o_session->channel, SWITCH_R_SDP_VARIABLE);
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2013-02-27 20:16:00 +00:00
switch_channel_set_flag(session->channel, CF_PROXY_MEDIA);
2014-12-13 06:57:14 +00:00
clear_pmaps(a_engine);
clear_pmaps(v_engine);
2014-12-13 06:57:14 +00:00
pmap = switch_core_media_add_payload_map(session,
SWITCH_MEDIA_TYPE_AUDIO,
"PROXY",
NULL,
NULL,
2014-12-13 06:57:14 +00:00
SDP_TYPE_RESPONSE,
0,
8000,
8000,
1,
SWITCH_TRUE);
a_engine->cur_payload_map = pmap;
2013-02-27 20:16:00 +00:00
if (switch_stristr("m=video", r_sdp)) {
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1);
2014-12-13 06:57:14 +00:00
pmap = switch_core_media_add_payload_map(session,
SWITCH_MEDIA_TYPE_AUDIO,
"PROXY-VID",
NULL,
NULL,
2014-12-13 06:57:14 +00:00
SDP_TYPE_RESPONSE,
0,
90000,
90000,
1,
SWITCH_TRUE);
v_engine->cur_payload_map = pmap;
2013-02-27 20:16:00 +00:00
switch_channel_set_flag(session->channel, CF_VIDEO);
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
}
}
2012-12-24 03:20:03 +00:00
SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *session)
{
const char *ip;
const char *port;
const char *a_ip;
const char *r_ip;
const char *r_port;
const char *tmp;
switch_rtp_engine_t *a_engine, *v_engine;
switch_media_handle_t *smh;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
ip = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
port = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || !(ip && port)) {
return;
} else {
a_ip = switch_channel_get_variable(session->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE);
r_ip = switch_channel_get_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
r_port = switch_channel_get_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->iananame = a_engine->cur_payload_map->rm_encoding = (char *) switch_channel_get_variable(session->channel, "rtp_use_codec_name");
a_engine->cur_payload_map->rm_fmtp = (char *) switch_channel_get_variable(session->channel, "rtp_use_codec_fmtp");
2013-05-17 20:39:21 +00:00
if ((tmp = switch_channel_get_variable(session->channel, SWITCH_R_SDP_VARIABLE))) {
smh->mparams->remote_sdp_str = switch_core_session_strdup(session, tmp);
}
2014-07-03 18:50:14 +00:00
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_timer_name"))) {
smh->mparams->timer_name = switch_core_session_strdup(session, tmp);
}
2013-05-17 20:39:21 +00:00
if ((tmp = switch_channel_get_variable(session->channel, "rtp_last_audio_codec_string"))) {
const char *vtmp = switch_channel_get_variable(session->channel, "rtp_last_video_codec_string");
switch_channel_set_variable_printf(session->channel, "rtp_use_codec_string", "%s%s%s", tmp, vtmp ? "," : "", vtmp ? vtmp : "");
}
2013-04-16 18:02:50 +00:00
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_string"))) {
char *tmp_codec_string = switch_core_session_strdup(smh->session, tmp);
smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS);
smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_2833_send_payload"))) {
2013-04-03 20:41:22 +00:00
smh->mparams->te = (switch_payload_t)atoi(tmp);
}
2012-12-24 03:20:03 +00:00
if ((tmp = switch_channel_get_variable(session->channel, "rtp_2833_recv_payload"))) {
2013-04-03 20:41:22 +00:00
smh->mparams->recv_te = (switch_payload_t)atoi(tmp);
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_rate"))) {
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->rm_rate = atoi(tmp);
a_engine->cur_payload_map->adv_rm_rate = a_engine->cur_payload_map->rm_rate;
2012-12-24 03:20:03 +00:00
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_ptime"))) {
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->codec_ms = atoi(tmp);
2012-12-24 03:20:03 +00:00
}
2014-06-13 05:49:10 +00:00
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_channels"))) {
a_engine->cur_payload_map->channels = atoi(tmp);
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_pt"))) {
2014-10-03 00:47:05 +00:00
a_engine->cur_payload_map->pt = a_engine->cur_payload_map->agreed_pt = (switch_payload_t)(smh->payload_space = atoi(tmp));
2012-12-24 03:20:03 +00:00
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_audio_recv_pt"))) {
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->recv_pt = (switch_payload_t)atoi(tmp);
}
2014-06-13 05:49:10 +00:00
switch_core_media_set_codec(session, 0, smh->mparams->codec_flags);
2013-11-07 22:48:00 +00:00
a_engine->adv_sdp_ip = smh->mparams->extrtpip = (char *) ip;
a_engine->adv_sdp_port = a_engine->local_sdp_port = (switch_port_t)atoi(port);
a_engine->codec_negotiated = 1;
2012-12-24 03:20:03 +00:00
if (!zstr(ip)) {
2013-11-07 22:48:00 +00:00
a_engine->local_sdp_ip = switch_core_session_strdup(session, ip);
smh->mparams->rtpip = a_engine->local_sdp_ip;
2012-12-24 03:20:03 +00:00
}
if (!zstr(a_ip)) {
2013-11-07 22:48:00 +00:00
a_engine->adv_sdp_ip = switch_core_session_strdup(session, a_ip);
2012-12-24 03:20:03 +00:00
}
if (r_ip && r_port) {
2013-11-07 22:48:00 +00:00
a_engine->cur_payload_map->remote_sdp_ip = (char *) r_ip;
a_engine->cur_payload_map->remote_sdp_port = (switch_port_t)atoi(r_port);
2012-12-24 03:20:03 +00:00
}
if (switch_channel_test_flag(session->channel, CF_VIDEO)) {
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_video_pt"))) {
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->pt = v_engine->cur_payload_map->agreed_pt = (switch_payload_t)atoi(tmp);
2012-12-24 03:20:03 +00:00
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_video_recv_pt"))) {
2013-11-22 03:55:45 +00:00
v_engine->cur_payload_map->recv_pt = (switch_payload_t)atoi(tmp);
}
2012-12-24 03:20:03 +00:00
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_encoding = (char *) switch_channel_get_variable(session->channel, "rtp_use_video_codec_name");
v_engine->cur_payload_map->rm_fmtp = (char *) switch_channel_get_variable(session->channel, "rtp_use_video_codec_fmtp");
2014-12-10 21:46:01 +00:00
v_engine->codec_negotiated = 1;
2012-12-24 03:20:03 +00:00
ip = switch_channel_get_variable(session->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE);
port = switch_channel_get_variable(session->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE);
r_ip = switch_channel_get_variable(session->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE);
r_port = switch_channel_get_variable(session->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE);
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_video_codec_rate"))) {
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->rm_rate = atoi(tmp);
v_engine->cur_payload_map->adv_rm_rate = v_engine->cur_payload_map->rm_rate;
2012-12-24 03:20:03 +00:00
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_video_codec_ptime"))) {
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->codec_ms = atoi(tmp);
2012-12-24 03:20:03 +00:00
}
2013-11-07 22:48:00 +00:00
v_engine->adv_sdp_port = v_engine->local_sdp_port = (switch_port_t)atoi(port);
2014-06-13 10:06:14 +00:00
v_engine->local_sdp_ip = smh->mparams->rtpip;
2012-12-24 03:20:03 +00:00
if (r_ip && r_port) {
2013-11-07 22:48:00 +00:00
v_engine->cur_payload_map->remote_sdp_ip = (char *) r_ip;
v_engine->cur_payload_map->remote_sdp_port = (switch_port_t)atoi(r_port);
2012-12-24 03:20:03 +00:00
}
}
2012-12-22 23:34:08 +00:00
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1);
switch_core_media_set_video_codec(session, 1);
2012-12-24 03:20:03 +00:00
if (switch_core_media_activate_rtp(session) != SWITCH_STATUS_SUCCESS) {
return;
}
2013-05-17 20:39:21 +00:00
switch_core_session_get_recovery_crypto_key(session, SWITCH_MEDIA_TYPE_AUDIO);
switch_core_session_get_recovery_crypto_key(session, SWITCH_MEDIA_TYPE_VIDEO);
if ((tmp = switch_channel_get_variable(session->channel, "rtp_last_audio_local_crypto_key")) && a_engine->ssec[a_engine->crypto_type].remote_crypto_key) {
2013-05-17 20:39:21 +00:00
int idx = atoi(tmp);
a_engine->ssec[a_engine->crypto_type].local_crypto_key = switch_core_session_strdup(session, tmp);
switch_core_media_add_crypto(&a_engine->ssec[a_engine->crypto_type], a_engine->ssec[a_engine->crypto_type].local_crypto_key, SWITCH_RTP_CRYPTO_SEND);
switch_core_media_add_crypto(&a_engine->ssec[a_engine->crypto_type], a_engine->ssec[a_engine->crypto_type].remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
2013-05-17 20:39:21 +00:00
switch_channel_set_flag(smh->session->channel, CF_SECURE);
switch_rtp_add_crypto_key(a_engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, idx,
a_engine->crypto_type,
a_engine->ssec[a_engine->crypto_type].local_raw_key,
SUITES[a_engine->crypto_type].keylen);
2013-05-17 20:39:21 +00:00
switch_rtp_add_crypto_key(a_engine->rtp_session, SWITCH_RTP_CRYPTO_RECV,
a_engine->ssec[a_engine->crypto_type].crypto_tag,
a_engine->crypto_type,
a_engine->ssec[a_engine->crypto_type].remote_raw_key,
SUITES[a_engine->crypto_type].keylen);
2013-05-17 20:39:21 +00:00
}
2012-12-24 03:20:03 +00:00
if (switch_core_media_ready(session, SWITCH_MEDIA_TYPE_AUDIO)) {
switch_rtp_set_telephony_event(a_engine->rtp_session, smh->mparams->te);
switch_rtp_set_telephony_recv_event(a_engine->rtp_session, smh->mparams->recv_te);
2012-12-24 03:20:03 +00:00
}
}
2012-12-22 23:34:08 +00:00
2012-12-20 04:42:03 +00:00
SWITCH_DECLARE(void) switch_core_media_init(void)
{
switch_core_gen_certs(DTLS_SRTP_FNAME ".pem");
}
SWITCH_DECLARE(void) switch_core_media_deinit(void)
{
}
static int payload_number(const char *name)
{
if (!strcasecmp(name, "pcmu")) {
return 0;
}
if (!strcasecmp(name, "pcma")) {
return 8;
}
if (!strcasecmp(name, "gsm")) {
return 3;
}
if (!strcasecmp(name, "g722")) {
return 9;
}
if (!strcasecmp(name, "g729")) {
return 18;
}
if (!strcasecmp(name, "dvi4")) {
return 5;
}
if (!strcasecmp(name, "h261")) {
return 31;
}
if (!strcasecmp(name, "h263")) {
return 34;
}
return -1;
}
static int find_pt(const char *sdp, const char *name)
{
const char *p;
if ((p = switch_stristr(name, sdp))) {
if (p < end_of_p(sdp) && *(p+strlen(name)) == '/' && *(p-1) == ' ') {
p -= 2;
while(*p > 47 && *p < 58) {
p--;
}
p++;
if (p) {
return atoi(p);
}
}
}
return -1;
}
SWITCH_DECLARE(char *) switch_core_media_filter_sdp(const char *sdp_str, const char *cmd, const char *arg)
{
char *new_sdp = NULL;
int pt = -1, te = -1;
switch_size_t len;
const char *i;
char *o;
int in_m = 0, m_tally = 0, slash = 0;
int number = 0, skip = 0;
int remove = !strcasecmp(cmd, "remove");
int only = !strcasecmp(cmd, "only");
char *end = end_of_p((char *)sdp_str);
int tst;
end++;
if (remove || only) {
pt = payload_number(arg);
if (pt < 0) {
pt = find_pt(sdp_str, arg);
}
} else {
return NULL;
}
if (only) {
te = find_pt(sdp_str, "telephone-event");
}
len = strlen(sdp_str) + 2;
new_sdp = malloc(len);
o = new_sdp;
i = sdp_str;
while(i && *i && i < end) {
if (*i == 'm' && *(i+1) == '=') {
in_m = 1;
m_tally++;
}
if (in_m) {
if (*i == '\r' || *i == '\n') {
in_m = 0;
slash = 0;
} else {
if (*i == '/') {
slash++;
while(*i != ' ' && i < end) {
*o++ = *i++;
}
*o++ = *i++;
}
if (slash && switch_is_leading_number(i)) {
number = atoi(i);
while(i < end && ((*i > 47 && *i < 58) || *i == ' ')) {
if (remove) {
tst = (number != pt);
} else {
tst = (number == pt || number == te);
}
if (tst) {
*o++ = *i;
}
i++;
if (*i == ' ') {
break;
}
}
if (remove) {
tst = (number == pt);
} else {
tst = (number != pt && number != te);
}
if (tst) {
skip++;
}
}
}
}
while (i < end && !strncasecmp(i, "a=rtpmap:", 9)) {
const char *t = i + 9;
number = atoi(t);
if (remove) {
tst = (number == pt);
} else {
tst = (number != pt && number != te);
}
while(i < end && (*i != '\r' && *i != '\n')) {
if (!tst) *o++ = *i;
i++;
}
while(i < end && (*i == '\r' || *i == '\n')) {
if (!tst) *o++ = *i;
i++;
}
}
while (i < end && !strncasecmp(i, "a=fmtp:", 7)) {
const char *t = i + 7;
number = atoi(t);
if (remove) {
tst = (number == pt);
} else {
tst = (number != pt && number != te);
}
while(i < end && (*i != '\r' && *i != '\n')) {
if (!tst) *o++ = *i;
i++;
}
while(i < end && (*i == '\r' || *i == '\n')) {
if (!tst) *o++ = *i;
i++;
}
}
if (!skip) {
*o++ = *i;
}
skip = 0;
i++;
}
*o = '\0';
return new_sdp;
}
SWITCH_DECLARE(char *) switch_core_media_process_sdp_filter(const char *sdp, const char *cmd_buf, switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
char *cmd = switch_core_session_strdup(session, cmd_buf);
int argc = 0;
char *argv[50];
int x = 0;
char *patched_sdp = NULL;
argc = switch_split(cmd, '|', argv);
for (x = 0; x < argc; x++) {
char *command = argv[x];
char *arg = strchr(command, '(');
if (arg) {
char *e = switch_find_end_paren(arg, '(', ')');
*arg++ = '\0';
if (e) *e = '\0';
}
if (zstr(command) || zstr(arg)) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "%s SDP FILTER PARSE ERROR\n", switch_channel_get_name(channel));
} else {
char *tmp_sdp = NULL;
if (patched_sdp) {
tmp_sdp = switch_core_media_filter_sdp(patched_sdp, command, arg);
} else {
2014-10-03 20:36:23 +00:00
tmp_sdp = switch_core_media_filter_sdp(sdp, command, arg);
}
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG,
"%s Filter command %s(%s)\nFROM:\n==========\n%s\nTO:\n==========\n%s\n\n",
switch_channel_get_name(channel),
2014-10-03 20:36:23 +00:00
command, arg, patched_sdp ? patched_sdp : sdp, tmp_sdp);
if (tmp_sdp) {
switch_safe_free(patched_sdp);
2014-10-03 20:36:23 +00:00
patched_sdp = tmp_sdp;
}
}
}
return patched_sdp;
}
SWITCH_DECLARE(switch_timer_t *) switch_core_media_get_timer(switch_core_session_t *session, switch_media_type_t mtype)
{
switch_rtp_engine_t *engine = NULL;
switch_media_handle_t *smh = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
return NULL;
}
if (!(engine = &smh->engines[mtype])) {
return NULL;
}
return switch_rtp_get_media_timer(engine->rtp_session);
}
2014-12-04 02:34:49 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_session_request_video_refresh(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_handle_t *smh = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (switch_channel_test_flag(channel, CF_VIDEO)) {
switch_core_session_message_t msg = { 0 };
switch_time_t now = switch_micro_time_now();
if (smh->last_video_refresh_req && (now - smh->last_video_refresh_req) < VIDEO_REFRESH_FREQ) {
return SWITCH_STATUS_BREAK;
}
smh->last_video_refresh_req = now;
msg.from = __FILE__;
msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
switch_core_session_receive_message(session, &msg);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
2014-12-04 02:34:49 +00:00
SWITCH_DECLARE(switch_status_t) switch_core_session_send_and_request_video_refresh(switch_core_session_t *session)
{
if (switch_channel_test_flag(session->channel, CF_VIDEO)) {
2014-12-04 02:34:49 +00:00
switch_core_session_request_video_refresh(session);
switch_core_media_gen_key_frame(session);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_session_t *session,
switch_media_type_t mtype,
switch_io_type_t iotype,
switch_codec_control_command_t cmd,
switch_codec_control_type_t ctype,
void *cmd_data,
switch_codec_control_type_t *rtype,
void **ret_data)
{
switch_rtp_engine_t *engine = NULL;
switch_media_handle_t *smh = NULL;
switch_codec_t *codec = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (!(engine = &smh->engines[mtype])) {
return SWITCH_STATUS_NOTIMPL;
}
if (iotype == SWITCH_IO_READ) {
codec = &engine->read_codec;
} else {
codec = &engine->write_codec;
}
if (!switch_core_codec_ready(codec)) {
return SWITCH_STATUS_FALSE;
}
if (mtype == SWITCH_MEDIA_TYPE_VIDEO) {
if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
return SWITCH_STATUS_FALSE;
}
}
if (codec) {
if (cmd == SCC_VIDEO_REFRESH) {
switch_time_t now = switch_micro_time_now();
if (smh->last_codec_refresh && (now - smh->last_codec_refresh) < VIDEO_REFRESH_FREQ) {
return SWITCH_STATUS_BREAK;
}
smh->last_codec_refresh = now;
switch_channel_set_flag(session->channel, CF_VIDEO_REFRESH_REQ);
}
return switch_core_codec_control(codec, cmd, ctype, cmd_data, rtype, ret_data);
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_write_encoded_video_frame(switch_core_session_t *session,
switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
{
switch_io_event_hook_video_write_frame_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if (session->endpoint_interface->io_routines->write_video_frame) {
if ((status = session->endpoint_interface->io_routines->write_video_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.video_write_frame; ptr; ptr = ptr->next) {
if ((status = ptr->video_write_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
return status;
}
SWITCH_DECLARE(void) switch_core_session_video_reinit(switch_core_session_t *session)
{
switch_media_handle_t *smh;
2015-03-24 00:56:19 +00:00
int type;
switch_assert(session);
if (!(smh = session->media_handle)) {
return;
}
if (switch_channel_down(session->channel)) {
return;
}
smh->video_init = 0;
smh->video_last_key_time = 0;
2015-03-24 00:56:19 +00:00
switch_core_session_send_and_request_video_refresh(session);
type = 1;
switch_core_media_codec_control(session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_IO_READ, SCC_VIDEO_RESET, SCCT_INT, (void *)&type, NULL, NULL);
switch_core_session_request_video_refresh(session);
}
SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags,
int stream_id)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_time_t now = switch_micro_time_now();
switch_codec_t *codec = switch_core_session_get_video_write_codec(session);
switch_timer_t *timer;
switch_media_handle_t *smh;
switch_image_t *dup_img = NULL, *img = frame->img;
switch_status_t encode_status;
switch_frame_t write_frame = {0};
2015-03-03 17:44:20 +00:00
//switch_rtp_engine_t *v_engine;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (switch_channel_down(session->channel)) {
return SWITCH_STATUS_FALSE;
}
if (!codec) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s has no video codec\n", switch_core_session_get_name(session));
return SWITCH_STATUS_FALSE;
}
2015-05-01 00:19:05 +00:00
if (switch_channel_test_flag(session->channel, CF_VIDEO_PAUSE_WRITE)) {
return SWITCH_STATUS_SUCCESS;
}
2015-03-03 03:07:48 +00:00
if (!(switch_channel_test_flag(session->channel, CF_VIDEO_READY) || (flags & SWITCH_IO_FLAG_FORCE))) {
return SWITCH_STATUS_SUCCESS;
}
2015-03-03 17:44:20 +00:00
//v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
2015-03-03 23:45:32 +00:00
if (smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO] && switch_mutex_trylock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]) != SWITCH_STATUS_SUCCESS) {
2015-03-03 17:44:20 +00:00
/* return CNG, another thread is already writing */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being written to for %s\n",
switch_channel_get_name(session->channel), type2str(SWITCH_MEDIA_TYPE_VIDEO));
return SWITCH_STATUS_INUSE;
}
if (!smh->video_init && smh->mparams->video_key_first && (now - smh->video_last_key_time) > smh->mparams->video_key_first) {
2014-12-04 02:34:49 +00:00
switch_core_media_gen_key_frame(session);
if (smh->video_last_key_time) {
smh->video_init = 1;
}
smh->video_last_key_time = now;
}
if (smh->mparams->video_key_freq && (now - smh->video_last_key_time) > smh->mparams->video_key_freq) {
switch_core_media_gen_key_frame(smh->session);
smh->video_last_key_time = now;
}
if (!img) {
2015-03-03 17:44:20 +00:00
switch_status_t vstatus = switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id);
switch_goto_status(vstatus, done);
}
/* When desired, scale video to match the input signal (if output is bigger) */
if (switch_channel_test_flag(session->channel, CF_VIDEO_READY) && smh->vid_params.width &&
switch_channel_test_flag(session->channel, CF_VIDEO_MIRROR_INPUT) &&
((smh->vid_params.width != img->d_w) || (smh->vid_params.height != img->d_h))) {
2015-04-03 23:39:43 +00:00
switch_img_letterbox(img, &dup_img, smh->vid_params.width, smh->vid_params.height, "#000000f");
2015-04-03 23:39:43 +00:00
img = dup_img;
}
if (session->bugs) {
switch_media_bug_t *bp;
switch_bool_t ok = SWITCH_TRUE;
int prune = 0;
2015-06-11 23:49:34 +00:00
int patched = 0;
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
continue;
}
if (switch_test_flag(bp, SMBF_PRUNE)) {
prune++;
continue;
}
if (bp->ready && switch_test_flag(bp, SMBF_WRITE_VIDEO_STREAM)) {
switch_image_t *dimg = NULL;
2015-06-11 23:49:34 +00:00
switch_img_copy(img, &dimg);
switch_queue_push(bp->write_video_queue, dimg);
2015-06-11 23:49:34 +00:00
if (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM_BLEG)) {
switch_core_media_bug_patch_spy_frame(bp, img, SWITCH_RW_WRITE);
patched = 1;
}
}
2015-06-11 23:49:34 +00:00
if (bp->ready && img &&
(switch_test_flag(bp, SMBF_WRITE_VIDEO_PING) || (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM) && !patched))) {
switch_frame_t bug_frame = { 0 };
bug_frame.img = img;
2015-06-11 23:49:34 +00:00
if (bp->callback && switch_test_flag(bp, SMBF_WRITE_VIDEO_PING)) {
bp->ping_frame = &bug_frame;
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_VIDEO_PING) == SWITCH_FALSE
|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
ok = SWITCH_FALSE;
}
bp->ping_frame = NULL;
}
2015-06-11 23:49:34 +00:00
if (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM_BLEG) && !patched) {
switch_core_media_bug_patch_spy_frame(bp, img, SWITCH_RW_WRITE);
2015-06-11 23:49:34 +00:00
}
}
if (ok == SWITCH_FALSE) {
switch_set_flag(bp, SMBF_PRUNE);
prune++;
}
2015-06-29 21:06:13 +00:00
}
2015-06-29 21:06:13 +00:00
switch_thread_rwlock_unlock(session->bug_rwlock);
if (prune) {
switch_core_media_bug_prune(session);
}
2015-06-29 21:06:13 +00:00
}
write_frame = *frame;
frame = &write_frame;
2014-12-02 16:51:21 +00:00
frame->img = img;
if (!switch_test_flag(frame, SFF_USE_VIDEO_TIMESTAMP)) {
if (!(timer = switch_core_media_get_timer(session, SWITCH_MEDIA_TYPE_VIDEO))) {
if (!smh->video_timer.timer_interface) {
switch_core_timer_init(&smh->video_timer, "soft", 1, 90, switch_core_session_get_pool(session));
}
switch_core_timer_sync(&smh->video_timer);
timer = &smh->video_timer;
}
frame->timestamp = timer->samplecount;
}
switch_clear_flag(frame, SFF_SAME_IMAGE);
frame->m = 0;
do {
frame->datalen = SWITCH_DEFAULT_VIDEO_SIZE;
encode_status = switch_core_codec_encode_video(codec, frame);
if (encode_status == SWITCH_STATUS_SUCCESS || encode_status == SWITCH_STATUS_MORE_DATA) {
switch_assert((encode_status == SWITCH_STATUS_SUCCESS && frame->m) || !frame->m);
if (frame->flags & SFF_PICTURE_RESET) {
switch_core_session_video_reinit(session);
frame->flags &= ~SFF_PICTURE_RESET;
}
if (frame->datalen == 0) break;
switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME);
status = switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id);
}
} while(status == SWITCH_STATUS_SUCCESS && encode_status == SWITCH_STATUS_MORE_DATA);
2015-03-03 17:44:20 +00:00
done:
if (smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]) {
switch_mutex_unlock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]);
}
switch_img_free(&dup_img);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags,
int stream_id)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_io_event_hook_video_read_frame_t *ptr;
uint32_t loops = 0;
switch_media_handle_t *smh;
switch_assert(session != NULL);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
top:
loops++;
if (switch_channel_down_nosig(session->channel)) {
return SWITCH_STATUS_FALSE;
}
2015-05-01 00:19:05 +00:00
if (switch_channel_test_flag(session->channel, CF_VIDEO_PAUSE_READ)) {
*frame = &runtime.dummy_cng_frame;
switch_yield(20000);
return SWITCH_STATUS_SUCCESS;
}
if (session->endpoint_interface->io_routines->read_video_frame) {
if ((status = session->endpoint_interface->io_routines->read_video_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
for (ptr = session->event_hooks.video_read_frame; ptr; ptr = ptr->next) {
if ((status = ptr->video_read_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
break;
}
}
}
}
if (status == SWITCH_STATUS_INUSE) {
*frame = &runtime.dummy_cng_frame;
switch_cond_next();
return SWITCH_STATUS_SUCCESS;
}
if (status != SWITCH_STATUS_SUCCESS) {
goto done;
}
if (!(*frame)) {
goto done;
}
if (switch_channel_test_flag(session->channel, CF_VIDEO_DEBUG_READ)) {
if (switch_test_flag((*frame), SFF_CNG)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "VIDEO: CNG\n");
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
"VIDEO: seq: %d ts: %u len: %4d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d\n",
(*frame)->seq, (*frame)->timestamp, (*frame)->datalen,
*((uint8_t *)(*frame)->data), *((uint8_t *)(*frame)->data + 1),
*((uint8_t *)(*frame)->data + 2), *((uint8_t *)(*frame)->data + 3),
*((uint8_t *)(*frame)->data + 4), *((uint8_t *)(*frame)->data + 5),
*((uint8_t *)(*frame)->data + 6), *((uint8_t *)(*frame)->data + 7),
*((uint8_t *)(*frame)->data + 8), *((uint8_t *)(*frame)->data + 9),
*((uint8_t *)(*frame)->data + 10), (*frame)->m);
}
}
if (switch_test_flag(*frame, SFF_CNG)) {
status = SWITCH_STATUS_SUCCESS;
goto done;
}
if (switch_channel_test_flag(session->channel, CF_VIDEO_DECODED_READ) && (*frame)->img == NULL) {
switch_status_t decode_status;
(*frame)->img = NULL;
decode_status = switch_core_codec_decode_video((*frame)->codec, *frame);
if ((*frame)->img && switch_channel_test_flag(session->channel, CF_VIDEO_DEBUG_READ)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IMAGE %dx%d %dx%d\n",
(*frame)->img->w, (*frame)->img->h, (*frame)->img->d_w, (*frame)->img->d_h);
}
if ((*frame)->img && (*frame)->img->d_w && (*frame)->img->d_h && ++smh->ready_loops > 5) {
switch_channel_set_flag(session->channel, CF_VIDEO_READY);
smh->vid_params.width = (*frame)->img->d_w;
smh->vid_params.height = (*frame)->img->d_h;
}
if (switch_test_flag((*frame), SFF_WAIT_KEY_FRAME)) {
switch_core_session_request_video_refresh(session);
switch_clear_flag((*frame), SFF_WAIT_KEY_FRAME);
if (!(*frame)->img) {
*frame = &runtime.dummy_cng_frame;
switch_cond_next();
return SWITCH_STATUS_SUCCESS;
}
}
if (decode_status == SWITCH_STATUS_MORE_DATA || !(*frame)->img) {
goto top;
}
}
done:
if (session->bugs) {
switch_media_bug_t *bp;
switch_bool_t ok = SWITCH_TRUE;
int prune = 0;
2015-06-11 23:49:34 +00:00
int patched = 0;
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
continue;
}
if (switch_test_flag(bp, SMBF_PRUNE)) {
prune++;
continue;
}
if (bp->ready && switch_test_flag(bp, SMBF_READ_VIDEO_STREAM)) {
if ((*frame) && (*frame)->img) {
switch_image_t *img = NULL;
switch_img_copy((*frame)->img, &img);
switch_queue_push(bp->read_video_queue, img);
2015-06-11 23:49:34 +00:00
if (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM)) {
switch_core_media_bug_patch_spy_frame(bp, (*frame)->img, SWITCH_RW_READ);
patched = 1;
}
}
}
2015-06-11 23:49:34 +00:00
if (bp->ready && (*frame) && (*frame)->img &&
(switch_test_flag(bp, SMBF_READ_VIDEO_PING) || (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM) && !patched))) {
2015-06-11 23:49:34 +00:00
if (bp->callback && switch_test_flag(bp, SMBF_READ_VIDEO_PING)) {
bp->ping_frame = *frame;
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_VIDEO_PING) == SWITCH_FALSE
|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
ok = SWITCH_FALSE;
}
bp->ping_frame = NULL;
}
2015-06-11 23:49:34 +00:00
if (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM) && !patched) {
switch_core_media_bug_patch_spy_frame(bp, (*frame)->img, SWITCH_RW_READ);
}
}
if (ok == SWITCH_FALSE) {
switch_set_flag(bp, SMBF_PRUNE);
prune++;
}
}
2015-06-29 21:06:13 +00:00
switch_thread_rwlock_unlock(session->bug_rwlock);
2015-06-29 21:06:13 +00:00
if (prune) {
switch_core_media_bug_prune(session);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
switch_core_session_video_read_callback(session, *frame);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_read_callback(switch_core_session_t *session,
switch_core_video_thread_callback_func_t func, void *user_data)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_media_handle_t *smh;
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
switch_mutex_lock(smh->control_mutex);
if (!func) {
session->video_read_callback = NULL;
session->video_read_user_data = NULL;
} else if (session->video_read_callback) {
status = SWITCH_STATUS_FALSE;
} else {
session->video_read_callback = func;
session->video_read_user_data = user_data;
}
switch_core_session_start_video_thread(session);
switch_mutex_unlock(smh->control_mutex);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_video_read_callback(switch_core_session_t *session, switch_frame_t *frame)
{
switch_media_handle_t *smh;
switch_status_t status = SWITCH_STATUS_CONTINUE;
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
switch_mutex_lock(smh->control_mutex);
if (session->video_read_callback) {
status = session->video_read_callback(session, frame, session->video_read_user_data);
}
switch_mutex_unlock(smh->control_mutex);
return status;
}
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 noet:
2012-12-18 16:50:43 +00:00
*/
2012-12-22 17:51:03 +00:00