]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9136: allow multiple instances of same video codec with different fmtp
authorAnthony Minessale <anthm@freeswitch.org>
Thu, 19 May 2016 21:32:47 +0000 (16:32 -0500)
committerMichael Jerris <mike@jerris.com>
Fri, 3 Jun 2016 21:16:32 +0000 (16:16 -0500)
src/include/switch_core_media.h
src/include/switch_loadable_module.h
src/include/switch_types.h
src/mod/endpoints/mod_loopback/mod_loopback.c
src/switch_core_media.c
src/switch_loadable_module.c

index 0d93ec4d581c76969bf621d8724afe8ae8822984..6f3b7244a0d9f489ed88e70f7f21dbafde4aebb8 100644 (file)
@@ -286,6 +286,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
                                                                                                                                         switch_media_type_t type,
                                                                                                                                         const char *iananame,
                                                                                                                                         uint32_t rate,
+                                                                                                                                        const char *fmtp_in,
                                                                                                                                         switch_payload_t *ptP,
                                                                                                                                         switch_payload_t *recv_ptP,
                                                                                                                                         char **fmtpP);
index 54e51d95d635576762e2925cca182006c42f0625..04cf75d3b7a1d49980dfdfa717d31a0f52e13b82 100644 (file)
@@ -117,7 +117,7 @@ SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoin
  */
 SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name, const char *modname);
 
-SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels, char **modname);
+SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels, char **modname, char **fmtp);
 
 /*!
   \brief Retrieve the dialplan interface by it's registered name
@@ -272,7 +272,7 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs(const switch_codec_impleme
   \return the number of elements added to the array
   \note this function only considers codecs that are listed in the "prefs" array and ignores the rest.
 */
-SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_implementation_t **array, int arraylen, char **prefs, int preflen);
+SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_implementation_t **array, char fmtp_array[SWITCH_MAX_CODECS][MAX_FMTP_LEN], int arraylen, char **prefs, int preflen);
 
 /*!
   \brief Execute a registered API command
index 3ffae84a4d5b45f1926021d9cee4811eb9685eb5..8279e10a7f463d31b4c329c8ad2abf9f41c2a0c9 100644 (file)
@@ -234,6 +234,8 @@ SWITCH_BEGIN_EXTERN_C
 #define SWITCH_RTCP_AUDIO_INTERVAL_MSEC "5000"
 #define SWITCH_RTCP_VIDEO_INTERVAL_MSEC "2000"
 
+#define MAX_FMTP_LEN 256
+
 /* Jitter */
 #define JITTER_VARIANCE_THRESHOLD 400.0
 /* IPDV */
index 99e83add979848d90b7fb056f69fead98bcc2715..ce9da85965f22940eb6d4417a5304c59ecf94033 100644 (file)
@@ -142,7 +142,7 @@ static switch_status_t tech_init(loopback_private_t *tech_pvt, switch_core_sessi
                if ((var = switch_channel_get_variable(channel, "loopback_initial_codec"))) {
                        char *dup = switch_core_session_strdup(session, var);
                        uint32_t bit, channels;
-                       iananame = switch_parse_codec_buf(dup, &interval, &rate, &bit, &channels, &codec_modname);
+                       iananame = switch_parse_codec_buf(dup, &interval, &rate, &bit, &channels, &codec_modname, NULL);
                }
                
        }
index 4d42eff135bb0eddcd241f6499f2a1a4b9f7f092..80ad063fb7b70a87f886de734ccd6b3a89a3b7cb 100644 (file)
@@ -189,7 +189,7 @@ struct switch_media_handle_s {
        char *codec_order[SWITCH_MAX_CODECS];
        int codec_order_last;
        const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
-
+       char fmtp[SWITCH_MAX_CODECS][MAX_FMTP_LEN];
        int payload_space;
        char *origin;
 
@@ -669,6 +669,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
                                                                                                                                         switch_media_type_t type,
                                                                                                                                         const char *iananame,
                                                                                                                                         uint32_t rate,
+                                                                                                                                        const char *fmtp_in,
                                                                                                                                         switch_payload_t *ptP,
                                                                                                                                         switch_payload_t *recv_ptP,
                                                                                                                                         char **fmtpP)
@@ -690,10 +691,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
 
        switch_mutex_lock(smh->sdp_mutex);
        for (pmap = engine->payload_map; pmap ; pmap = pmap->next) {
+               char *fmtp_a = pmap->rm_fmtp;
 
                if (!pmap->allocated) continue;
 
-               if (!strcasecmp(pmap->iananame, iananame) && (!rate || (rate == pmap->rate))) {
+               if (!fmtp_a) fmtp_a = "";
+               if (!fmtp_in) fmtp_in = "";
+
+
+               if (!strcasecmp(pmap->iananame, iananame) && !strcasecmp(fmtp_a, fmtp_in) && (!rate || (rate == pmap->rate))) {
                        pt = pmap->pt;
                        recv_pt = pmap->recv_pt;
                        fmtp = pmap->rm_fmtp;
@@ -1866,7 +1872,7 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
        tmp_codec_string = switch_core_session_strdup(smh->session, codec_string);
        switch_channel_set_variable(session->channel, "rtp_use_codec_string", codec_string);
        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);
+       smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
 
 }
 
@@ -3798,6 +3804,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
        const char *tmp;
        int m_idx = 0;
        int nm_idx = 0;
+       int vmatch_pt = 0;
 
        switch_assert(session);
 
@@ -4441,6 +4448,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                        const switch_codec_implementation_t *search[1];
                                        char *prefs[1];
                                        char tmp[80];
+                                       char fmtp[SWITCH_MAX_CODECS][MAX_FMTP_LEN];
                                        int num;
                                        const switch_codec_implementation_t *timp = NULL;
 
@@ -4452,7 +4460,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                                                        codec_ms, near_match->number_of_channels);
                                        
                                        prefs[0] = tmp;
-                                       num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
+                                       num = switch_loadable_module_get_codecs_sorted(search, fmtp, 1, prefs, 1);
                                
                                        if (num) {
                                                timp = search[0];
@@ -4757,6 +4765,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                }
                        }
 
+                       if (switch_true(switch_channel_get_variable_dup(session->channel, "inherit_codec", SWITCH_FALSE, -1))) {
+                               vmatch_pt = 1;
+                       }
+
+               compare:
 
                        for (map = m->m_rtpmaps; map; map = map->rm_next) {
 
@@ -4818,15 +4831,15 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                        
                                        }
                                }
-                               
+
                                if (!(rm_encoding = map->rm_encoding)) {
                                        rm_encoding = "";
                                }
-                               
+
                                for (i = 0; i < total_codecs; i++) {
                                        const switch_codec_implementation_t *imp = codec_array[i];
 
-                                       if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { 
+                                       if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
                                                continue;
                                        }
 
@@ -4834,8 +4847,8 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                                switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
                                                continue;
                                        }
-                                       
-                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n",
+
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CONSOLE, "Video Codec Compare [%s:%d]/[%s:%d]\n",
                                                                          rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
                                        if ((zstr(map->rm_encoding) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
                                                vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0;
@@ -4843,12 +4856,27 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                                vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
                                        }
 
-                                       if (vmatch && (map->rm_rate == imp->samples_per_second)) {
+                                       if (vmatch && vmatch_pt) {
+                                               const char *other_pt = switch_channel_get_variable_partner(channel, "rtp_video_pt");
+                                               const char *other_fmtp = switch_channel_get_variable_partner(channel, "rtp_video_fmtp");
+
+                                               const char *foo = switch_channel_get_partner_uuid(channel);
+
+                                               if (other_pt) {
+                                                       int opt = atoi(other_pt);
+
+                                                       if (map->rm_pt != opt) {
+                                                               vmatch = 0;
+                                                       }
+                                               }
+                                       }
+
+                                       if (vmatch) {
                                                matches[m_idx].imp = imp;
                                                matches[m_idx].map = map;
 
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d] +++ is saved as a match\n",
-                                                                                 imp->iananame, imp->ianacode);
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CONSOLE, "Video Codec Compare [%s:%d] +++ is saved as a match\n",
+                                                                                 imp->iananame, map->rm_pt);
                                                m_idx++;
                                        }
 
@@ -4856,6 +4884,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
                                }
                        }
 
+                       if (vmatch_pt && !m_idx) {
+                               vmatch_pt = 0;
+                               goto compare;
+                       }
+
                        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;
@@ -4920,8 +4953,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
 #endif
                                }
 
-                               
-                               
                                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);
@@ -7348,6 +7379,7 @@ static void generate_m(switch_core_session_t *session, char *buf, size_t buflen,
                        fmtp = smh->fmtps[i];
                }
 
+
                if (smh->ianacodes[i] > 95 || switch_channel_test_flag(session->channel, CF_VERBOSE_SDP)) {
                        int channels = get_channels(imp->iananame, imp->number_of_channels);
 
@@ -7794,8 +7826,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                switch_payload_t orig_pt = 0;
                                char *orig_fmtp = NULL;
 
-                               //smh->ianacodes[i] = imp->ianacode;
-                               
                                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++;
@@ -7808,7 +7838,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                        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) {
+                                                                                                                        imp->iananame, imp->samples_per_second, smh->fmtp[i], &orig_pt, NULL, &orig_fmtp) == SWITCH_STATUS_SUCCESS) {
+
                                                if (orig_pt == smh->mparams->te) {
                                                        smh->mparams->te  = (switch_payload_t)smh->payload_space++;
                                                }
@@ -8357,7 +8388,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
 
                                switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\r\n");
 
-                       
                                if (v_engine->codec_negotiated) {
                                        const char *of;
                                        payload_map_t *pmap;
@@ -8375,7 +8405,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                                                        v_engine->cur_payload_map->pt, v_engine->cur_payload_map->rm_encoding,
                                                                        v_engine->cur_payload_map->rm_rate);
 
-
                                        if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
                                                pass_fmtp = v_engine->cur_payload_map->rm_fmtp;
                                        } else {
@@ -8390,11 +8419,16 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
 
                                                if (ov_fmtp) {
                                                        pass_fmtp = ov_fmtp;
-                                               } else if (switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) { 
-                                                       pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp");
+                                               } else {
+
+                                                       pass_fmtp = v_engine->cur_payload_map->fmtp_out;
+
+                                                       if (!pass_fmtp || switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) {
+                                                               pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp");
+                                                       }
                                                }
                                        }
-                               
+
                                        if (pass_fmtp) {
                                                switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\r\n", v_engine->cur_payload_map->pt, pass_fmtp);
                                        }
@@ -8406,7 +8440,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                                        if (pmap->pt != v_engine->cur_payload_map->pt && pmap->negotiated) {
                                                                switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\r\n",
                                                                                                pmap->pt, pmap->iananame, pmap->rate);
-                                                       
                                                        }
                                                }
                                                switch_mutex_unlock(smh->sdp_mutex);
@@ -8416,7 +8449,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                        if (append_video) {
                                                switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s%s", append_video, end_of(append_video) == '\n' ? "" : "\r\n");
                                        }
-                                       
+
                                        if (v_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) {
                                                switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s", "a=sendonly\r\n");
                                        } else if (v_engine->smode == SWITCH_MEDIA_FLOW_RECVONLY) {
@@ -8471,6 +8504,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                                                                        imp->samples_per_second);
                                                }
                                        
+
+
                                                if (!zstr(ov_fmtp)) {
                                                        fmtp = (char *) ov_fmtp;
                                                } else {
@@ -8479,7 +8514,9 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                                                fmtp = switch_event_get_header(map, imp->iananame);
                                                        }
                                                
-                                                       if (smh->fmtps[i]) {
+                                                       if (!zstr(smh->fmtp[i])) {
+                                                               fmtp = smh->fmtp[i];
+                                                       } else if (smh->fmtps[i]) {
                                                                fmtp = smh->fmtps[i];
                                                        }
                                                
@@ -10102,7 +10139,6 @@ SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Setting NULL SDP is invalid\n");
                return;
        }
-
        if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
 
                if ((sdp = sdp_session(parser))) {
@@ -10189,6 +10225,8 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
        int num_codecs = 0;
        char *codec_order[SWITCH_MAX_CODECS];
        const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 };
+       char fmtp[SWITCH_MAX_CODECS][MAX_FMTP_LEN];
+
        switch_channel_t *channel = switch_core_session_get_channel(session);
        int prefer_sdp = 0;
        const char *var;
@@ -10209,7 +10247,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
                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);
+                       num_codecs = switch_loadable_module_get_codecs_sorted(codecs, fmtp, SWITCH_MAX_CODECS, codec_order, num_codecs);
                        switch_safe_free(tmp_codec_string);
                }
        } else {
@@ -10289,6 +10327,8 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
 
                        if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) {
                                for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                       match = 0;
+
                                        if (map->rm_pt > 127 || already_did[map->rm_pt]) {
                                                continue;
                                        }
@@ -10309,7 +10349,6 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
 
                                                if (match) {
                                                        add_audio_codec(map, imp, ptime, buf, sizeof(buf));
-                                                       break;
                                                }
                                        
                                        }
@@ -10322,6 +10361,8 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
                                                continue;
                                        }
                                        for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                               match = 0;
+
                                                if (map->rm_pt > 127 || already_did[map->rm_pt]) {
                                                        continue;
                                                }
@@ -10339,7 +10380,6 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
 
                                                if (match) {
                                                        add_audio_codec(map, imp, ptime, buf, sizeof(buf));
-                                                       break;
                                                }
                                        }
                                }
@@ -10355,43 +10395,86 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
                                switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
                                break;
                        }
-                       for (i = 0; i < num_codecs; i++) {
-                               const switch_codec_implementation_t *imp = codecs[i];
 
-                               if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
-                                       continue;
-                               }
-
-                               if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
-                                       switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
-                                       continue;
-                               }
 
+                       if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) {
                                for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                       match = 0;
+
                                        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) {
-                                                       match = !strcasecmp(map->rm_encoding, imp->iananame) &&
-                                                               ((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95));
+                                       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 {
-                                                       match = 0;
+                                                       if (map->rm_encoding) {
+                                                               match = !strcasecmp(map->rm_encoding, imp->iananame) &&
+                                                                       ((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95));
+                                                       } else {
+                                                               match = 0;
+                                                       }
+                                               }
+
+                                               if (match) {
+                                                       if (map->rm_fmtp) {
+                                                               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s~%s", imp->modname, imp->iananame, map->rm_fmtp);
+                                                       } else {
+                                                               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s", imp->modname, imp->iananame);
+                                                       }
+                                                       already_did[imp->ianacode] = 1;
                                                }
                                        }
+                               }
 
-                                       if (match) {
-                                               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s", imp->modname, imp->iananame);
-                                               already_did[imp->ianacode] = 1;
-                                               break;
+                       } else {
+                               for (i = 0; i < num_codecs; i++) {
+                                       const switch_codec_implementation_t *imp = codecs[i];
+
+                                       if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
+                                               continue;
+                                       }
+
+                                       if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
+                                               switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
+                                               continue;
+                                       }
+
+                                       for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                                               match = 0;
+
+                                               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) {
+                                                               match = !strcasecmp(map->rm_encoding, imp->iananame) &&
+                                                                       ((map->rm_pt < 96 && imp->ianacode < 96) || (map->rm_pt > 95 && imp->ianacode > 95));
+                                                       } else {
+                                                               match = 0;
+                                                       }
+                                               }
+
+                                               if (match) {
+                                                       if (map->rm_fmtp) {
+                                                               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s~%s", imp->modname, imp->iananame, map->rm_fmtp);
+                                                       } else {
+                                                               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s", imp->modname, imp->iananame);
+                                                       }
+                                                       already_did[imp->ianacode] = 1;
+                                               }
                                        }
                                }
                        }
                }
        }
+
        if (buf[0] == ',') {
                switch_channel_set_variable(channel, "ep_codec_string", buf + 1);
        }
@@ -10603,7 +10686,7 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s
        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);
+               smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
        }
 
        if ((tmp = switch_channel_get_variable(session->channel, "rtp_2833_send_payload"))) {
index 2b7c46cb1174f6a9b1f79ac4e2e9a4d96c6f202e..ba8a1c4a7572ac518150d96e1c761e90be637733 100644 (file)
@@ -2340,7 +2340,7 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs(const switch_codec_impleme
 
 }
 
-SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels, char **modname)
+SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels, char **modname, char **fmtp)
 {
        char *cur, *next = NULL, *name, *p;
 
@@ -2380,10 +2380,17 @@ SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uin
                name = p;
        }
 
+       if ((p = strchr(name, '~'))) {
+               *p++ = '\0';
+               if (fmtp) {
+                       *fmtp = p;
+               }
+       }
+
        return name;
 }
 
-SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_implementation_t **array, int arraylen, char **prefs, int preflen)
+SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_implementation_t **array, char fmtp_array[SWITCH_MAX_CODECS][MAX_FMTP_LEN], int arraylen, char **prefs, int preflen)
 {
        int x, i = 0, j = 0;
        switch_codec_interface_t *codec_interface;
@@ -2392,14 +2399,14 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_
        switch_mutex_lock(loadable_modules.mutex);
 
        for (x = 0; x < preflen; x++) {
-               char *name, buf[256], jbuf[256], *modname = NULL;
+               char *name, buf[256], jbuf[256], *modname = NULL, *fmtp = NULL;
                uint32_t interval = 0, rate = 0, bit = 0, channels = 1;
 
                switch_copy_string(buf, prefs[x], sizeof(buf));
-               name = switch_parse_codec_buf(buf, &interval, &rate, &bit, &channels, &modname);
+               name = switch_parse_codec_buf(buf, &interval, &rate, &bit, &channels, &modname, &fmtp);
 
                for(j = 0; j < x; j++) {
-                       char *jname, *jmodname = NULL;
+                       char *jname, *jmodname = NULL, *jfmtp = NULL;
                        uint32_t jinterval = 0, jrate = 0, jbit = 0, jchannels = 1;
                        uint32_t ointerval = interval, orate = rate, ochannels = channels;
 
@@ -2416,7 +2423,7 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_
                        }
                        
                        switch_copy_string(jbuf, prefs[j], sizeof(jbuf));
-                       jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit, &jchannels, &jmodname);
+                       jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit, &jchannels, &jmodname, &jfmtp);
 
                        if (jinterval == 0) {
                                jinterval = switch_default_ptime(jname, 0);
@@ -2430,7 +2437,8 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_
                                jchannels = 1;
                        }
 
-                       if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate && ochannels == jchannels) {
+                       if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate && ochannels == jchannels && 
+                               !strcasecmp(switch_str_nil(fmtp), switch_str_nil(jfmtp))) {
                                goto next_x;
                        }
                }
@@ -2462,7 +2470,9 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_
                                        }
                                }
 
-
+                               if (!zstr(fmtp)) {
+                                       switch_set_string(fmtp_array[i], fmtp);
+                               }
                                array[i++] = imp;
                                goto found;