]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
%FEATURE Add new feature to filter the SDP on bypass_media calls to remove or limit...
authorAnthony Minessale <anthm@freeswitch.org>
Tue, 30 Sep 2014 20:28:10 +0000 (01:28 +0500)
committerAnthony Minessale <anthm@freeswitch.org>
Tue, 30 Sep 2014 20:28:10 +0000 (01:28 +0500)
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"/>

src/include/switch_channel.h
src/include/switch_core_media.h
src/include/switch_utils.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_verto/mod_verto.c
src/switch_channel.c
src/switch_core_media.c
src/switch_core_session.c
src/switch_utils.c

index a305c96a450c0906465ffa2d6163bbb069c01067..3c08d6a22d204949dd29d226491528bc4bf95908 100644 (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_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(switch_status_t) switch_channel_pass_sdp(switch_channel_t *from_channel, switch_channel_t *to_channel, const char *sdp);
+
 SWITCH_END_EXTERN_C
 #endif
 /* For Emacs:
index 59e1b02b340bcf1e752de6ad6d58b1f4b911547f..e956905e601c2221cc31da55299df2805198a85e 100644 (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(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(char *) switch_core_media_filter_sdp(const char *sdp, const char *cmd, const char *arg);
 
 SWITCH_END_EXTERN_C
 #endif
index d7c07e7171a24c6945c0619b0d69bfd40c293fdb..e8b6843d1401287a22f958d12dcef0eb038623de 100644 (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_free(switch_frame_t **frame);
 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);
 
 /*!
index 6cf16e591228db7d3ff72d0fb57b459e4fb25560..5550e78d9ed97ac5219a2dd5ad0384cd279cd01b 100644 (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) {
                                        other_channel = switch_core_session_get_channel(other_session);
-                                       if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-                                               switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
-                                       }
+                                       switch_channel_pass_sdp(channel, other_channel, r_sdp);
+
                                        //switch_channel_pre_answer(other_channel);
                                        switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_PROGRESS);
                                        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_tech_pvt = switch_core_session_get_private(other_session);
 
-                                       if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-                                               switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
-                                       }
+                                       switch_channel_pass_sdp(channel, other_channel, r_sdp);
                                        switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
                                        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) {
                                        other_channel = switch_core_session_get_channel(other_session);
-                                       if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-                                               switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
-                                       }
-
+                                       switch_channel_pass_sdp(channel, other_channel, r_sdp);
+                                       
                                        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");
                                                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) {
                                                other_channel = switch_core_session_get_channel(other_session);
-                                               if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-                                                       switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
-                                               }
-
+                                               switch_channel_pass_sdp(channel, other_channel, r_sdp);
+                                               
                                                //switch_channel_answer(other_channel);
                                                switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
 
index ce5dcd0d4b38729b17188845ae4ac8ca09e1810a..8f24ab9d394f8721a2068277d7372b27fc621825 100644 (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) {
                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_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
                switch_core_session_rwunlock(other_session);
index bfd20abc91f954d81878a82098e8eee1735321ab..0a34ab2a61740a4c6bdda5d58cfa44164017f789 100644 (file)
@@ -5220,6 +5220,65 @@ SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switc
        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:
  * Local Variables:
index 18735a957cbfff77da7f2941750aaa5368d9dc6f..e4e810b6dde7a5ed1c0deffde97e60d206287426 100644 (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:
  * Local Variables:
index 853d106e684ef0995363422ef947418a15029d3c..c5f1eaa718ce1b5d679c98273d533407555ca07c 100644 (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))) {
-                               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)) {
index f57ea00c4e9d06dc9122468af46235adbe19478b..3cde97a1272e1c339c8ad11cff0d5bcb18b1e234 100644 (file)
@@ -1231,6 +1231,25 @@ SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str)
        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)
 {
 /*