%FEATURE Add new feature to filter the SDP on bypass_media calls to remove or limit codecs.

VARIABLE: bypass_media_sdp_filter

Can be set globally or per leg on the inbound side of a bypass_media bridge.

VALID FILTERS:

remove(): Removes the specified codec if it exists in the SDP.
only():   Removes all codecs besides the one specified (providing that it exists in the sdp) (will not remove telephone-event))

EXAMPLE 1 (remove everything leaving only g729):

  <action application="set" data="bypass_media_sdp_filter=only(g729)"/>
  <action application="set" data="bypass_media=true"/>
  <action application="bridge" data="sofia/internal/1238@conference.freeswitch.org"/>

EXAMPLE 2 (remove everything leaving only g729 and also remove dtmf):

  <action application="set" data="bypass_media_sdp_filter=only(g729)|remove(telephone-event)"/>
  <action application="set" data="bypass_media=true"/>
  <action application="bridge" data="sofia/internal/1238@conference.freeswitch.org"/>

EXAMPLE 3 (remove alaw and speex):

  <action application="set" data="bypass_media_sdp_filter=remove(pcma)|remove(speex)"/>
  <action application="set" data="bypass_media=true"/>
  <action application="bridge" data="sofia/internal/1238@conference.freeswitch.org"/>
This commit is contained in:
Anthony Minessale 2014-10-01 01:28:10 +05:00
parent 92a66fb1e7
commit 24084adf77
9 changed files with 306 additions and 18 deletions

View File

@ -678,7 +678,8 @@ SWITCH_DECLARE(void) switch_channel_release_device_record(switch_device_record_t
SWITCH_DECLARE(switch_status_t) switch_channel_bind_device_state_handler(switch_device_state_function_t function, void *user_data); SWITCH_DECLARE(switch_status_t) switch_channel_bind_device_state_handler(switch_device_state_function_t function, void *user_data);
SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switch_device_state_function_t function); SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switch_device_state_function_t function);
SWITCH_DECLARE(const char *) switch_channel_device_state2str(switch_device_state_t device_state); SWITCH_DECLARE(const char *) switch_channel_device_state2str(switch_device_state_t device_state);
SWITCH_DECLARE(switch_status_t) switch_channel_pass_sdp(switch_channel_t *from_channel, switch_channel_t *to_channel, const char *sdp);
SWITCH_END_EXTERN_C SWITCH_END_EXTERN_C
#endif #endif
/* For Emacs: /* For Emacs:

View File

@ -275,7 +275,7 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str); SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str);
SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto_key_type_t type); SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto_key_type_t type);
SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type); SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type);
SWITCH_DECLARE(char *) switch_core_media_filter_sdp(const char *sdp, const char *cmd, const char *arg);
SWITCH_END_EXTERN_C SWITCH_END_EXTERN_C
#endif #endif

View File

@ -418,6 +418,7 @@ SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switc
SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone); SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone);
SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame); SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame);
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str); SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
SWITCH_DECLARE(switch_bool_t) switch_is_leading_number(const char *str);
SWITCH_DECLARE(char *) switch_find_parameter(const char *str, const char *param, switch_memory_pool_t *pool); SWITCH_DECLARE(char *) switch_find_parameter(const char *str, const char *param, switch_memory_pool_t *pool);
/*! /*!

View File

@ -6567,9 +6567,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
} }
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session); other_channel = switch_core_session_get_channel(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { switch_channel_pass_sdp(channel, other_channel, r_sdp);
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
//switch_channel_pre_answer(other_channel); //switch_channel_pre_answer(other_channel);
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_PROGRESS); switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_PROGRESS);
switch_core_session_rwunlock(other_session); switch_core_session_rwunlock(other_session);
@ -6626,9 +6625,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
other_channel = switch_core_session_get_channel(other_session); other_channel = switch_core_session_get_channel(other_session);
//other_tech_pvt = switch_core_session_get_private(other_session); //other_tech_pvt = switch_core_session_get_private(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { switch_channel_pass_sdp(channel, other_channel, r_sdp);
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER); switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
switch_core_session_rwunlock(other_session); switch_core_session_rwunlock(other_session);
} }
@ -7114,10 +7111,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session); other_channel = switch_core_session_get_channel(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { switch_channel_pass_sdp(channel, other_channel, r_sdp);
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) { if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK); sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
@ -7218,10 +7213,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session); other_channel = switch_core_session_get_channel(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { switch_channel_pass_sdp(channel, other_channel, r_sdp);
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
//switch_channel_answer(other_channel); //switch_channel_answer(other_channel);
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER); switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);

View File

@ -2401,7 +2401,8 @@ static void pass_sdp(verto_pvt_t *tech_pvt)
if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session); other_channel = switch_core_session_get_channel(other_session);
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, tech_pvt->r_sdp); switch_channel_pass_sdp(tech_pvt->channel, other_channel, tech_pvt->r_sdp);
switch_channel_set_flag(other_channel, CF_PROXY_MODE); switch_channel_set_flag(other_channel, CF_PROXY_MODE);
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER); switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
switch_core_session_rwunlock(other_session); switch_core_session_rwunlock(other_session);

View File

@ -5220,6 +5220,65 @@ SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switc
return status; return status;
} }
SWITCH_DECLARE(switch_status_t) switch_channel_pass_sdp(switch_channel_t *from_channel, switch_channel_t *to_channel, const char *sdp)
{
char *use_sdp = (char *) sdp;
char *patched_sdp = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!switch_channel_get_variable(to_channel, SWITCH_B_SDP_VARIABLE)) {
const char *var;
if ((var = switch_channel_get_variable(from_channel, "bypass_media_sdp_filter"))) {
char *cmd = switch_core_session_strdup(from_channel->session, var);
int argc = 0;
char *argv[50];
int x = 0;
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(from_channel), SWITCH_LOG_WARNING, "%s SDP FILTER PARSE ERROR\n", from_channel->name);
} else {
char *tmp_sdp = NULL;
if (patched_sdp) {
tmp_sdp = switch_core_media_filter_sdp(patched_sdp, command, arg);
} else {
tmp_sdp = switch_core_media_filter_sdp(use_sdp, command, arg);
}
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(from_channel), SWITCH_LOG_DEBUG,
"Filter command %s(%s)\nFROM:\n==========\n%s\nTO:\n==========\n%s\n\n",
command, arg, patched_sdp ? patched_sdp : use_sdp, tmp_sdp);
if (tmp_sdp) {
switch_safe_free(patched_sdp);
patched_sdp = use_sdp = tmp_sdp;
}
}
}
}
switch_channel_set_variable(to_channel, SWITCH_B_SDP_VARIABLE, use_sdp);
}
switch_safe_free(patched_sdp);
return status;
}
/* For Emacs: /* For Emacs:
* Local Variables: * Local Variables:

View File

@ -8854,6 +8854,220 @@ 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);
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;
}
/* For Emacs: /* For Emacs:
* Local Variables: * Local Variables:

View File

@ -654,7 +654,7 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
} }
if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) { if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
switch_channel_set_variable(peer_channel, SWITCH_B_SDP_VARIABLE, val); switch_channel_pass_sdp(channel, peer_channel, val);
} }
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) { if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {

View File

@ -1231,6 +1231,25 @@ SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str)
return r; return r;
} }
SWITCH_DECLARE(switch_bool_t) switch_is_leading_number(const char *str)
{
const char *p;
switch_bool_t r = SWITCH_FALSE;
if (*str == '-' || *str == '+') {
str++;
}
for (p = str; p && *p; p++) {
if ((*p == '.' || (*p > 47 && *p < 58))) {
r = SWITCH_TRUE;
break;
}
}
return r;
}
SWITCH_DECLARE(const char *) switch_stristr(const char *instr, const char *str) SWITCH_DECLARE(const char *) switch_stristr(const char *instr, const char *str)
{ {
/* /*