From 05dd02d0a6d920f636f6d8cfc50b9c4115ac748b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 12 Feb 2013 14:26:55 -0600 Subject: [PATCH] make opus work, omfg .. serious??? you need to always advertise it as stereo using the standard way then specify it in the fmtp insread just to complicate things.... that's not cool =/ --- src/mod/codecs/mod_opus/mod_opus.c | 7 ++-- src/switch_core_codec.c | 5 --- src/switch_core_media.c | 60 +++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index 80d6ceacf1..ca3417b43b 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -65,7 +65,8 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag int err; context->encoder_object = opus_encoder_create(codec->implementation->actual_samples_per_second, - codec->implementation->number_of_channels, OPUS_APPLICATION_VOIP, &err); + codec->implementation->number_of_channels, + OPUS_APPLICATION_VOIP, &err); if (err != OPUS_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err)); @@ -143,7 +144,7 @@ static switch_status_t switch_opus_encode(switch_codec_t *codec, if (len > 1275) len = 1275; bytes = opus_encode(context->encoder_object, (void *) decoded_data, decoded_data_len / 2, (unsigned char *) encoded_data, len); - + if (bytes > 0) { *encoded_data_len = (uint32_t) bytes; return SWITCH_STATUS_SUCCESS; @@ -205,7 +206,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load) samples, /* number of samples per frame */ bytes, /* number of bytes per frame decompressed */ 0, /* number of bytes per frame compressed */ - 1, /* number of channels represented */ + 1,/* number of channels represented */ 1, /* number of frames per network packet */ switch_opus_init, /* function to initialize a codec handle using this implementation */ switch_opus_encode, /* function to encode raw data into encoded data */ diff --git a/src/switch_core_codec.c b/src/switch_core_codec.c index f2529af174..06089fe4cc 100644 --- a/src/switch_core_codec.c +++ b/src/switch_core_codec.c @@ -645,11 +645,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec memset(codec, 0, sizeof(*codec)); - if (channels == 2) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stereo is currently unsupported. please downsample audio source to mono.\n"); - return SWITCH_STATUS_GENERR; - } - if ((codec_interface = switch_loadable_module_get_codec_interface(codec_name)) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec %s!\n", codec_name); return SWITCH_STATUS_GENERR; diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 26516af017..9750f4f3af 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -93,7 +93,8 @@ typedef struct codec_params_s { switch_port_t adv_sdp_port; char *proxy_sdp_ip; switch_port_t proxy_sdp_port; - + int channels; + int adv_channels; } codec_params_t; @@ -182,6 +183,15 @@ struct switch_media_handle_s { }; +static int get_channels(const switch_codec_implementation_t *imp) +{ + if (!strcasecmp(imp->iananame, "opus")) { + return 2; /* IKR???*/ + } + + return imp->number_of_channels; +} + 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; @@ -1641,7 +1651,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ a_engine->codec_params.rm_fmtp, a_engine->codec_params.rm_rate, a_engine->codec_params.codec_ms, - 1, + a_engine->codec_params.channels, a_engine->codec_params.bitrate, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | codec_flags, NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { @@ -1658,7 +1668,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ a_engine->codec_params.rm_fmtp, a_engine->codec_params.rm_rate, a_engine->codec_params.codec_ms, - 1, + a_engine->codec_params.channels, a_engine->codec_params.bitrate, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | codec_flags, NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { @@ -2584,12 +2594,23 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s a_engine->codec_params.rm_rate = mimp->samples_per_second; a_engine->codec_params.codec_ms = mimp->microseconds_per_packet / 1000; a_engine->codec_params.bitrate = mimp->bits_per_second; + a_engine->codec_params.channels = map->rm_params ? atoi(map->rm_params) : 1; + if (!strcasecmp((char *) map->rm_encoding, "opus")) { + a_engine->codec_params.adv_channels = 2; /* IKR ???*/ + if (!zstr((char *) map->rm_fmtp) && switch_stristr("stereo=1", (char *) map->rm_fmtp)) { + a_engine->codec_params.channels = 2; + } else { + a_engine->codec_params.channels = 1; + } + } else { + a_engine->codec_params.adv_channels = a_engine->codec_params.channels; + } a_engine->codec_params.remote_sdp_ip = switch_core_session_strdup(session, (char *) connection->c_address); a_engine->codec_params.remote_sdp_port = (switch_port_t) m->m_port; a_engine->codec_params.rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); - + a_engine->codec_params.agreed_pt = (switch_payload_t) map->rm_pt; smh->num_negotiated_codecs = 0; smh->negotiated_codecs[smh->num_negotiated_codecs++] = mimp; @@ -4396,7 +4417,14 @@ static void generate_m(switch_core_session_t *session, char *buf, size_t buflen, } if (smh->ianacodes[i] > 95 || verbose_sdp) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d\n", smh->ianacodes[i], imp->iananame, rate); + int channels = get_channels(imp); + + 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); + } } if (fmtp) { @@ -4849,7 +4877,14 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess rate = a_engine->codec_params.rm_rate; - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", a_engine->codec_params.agreed_pt, a_engine->codec_params.rm_encoding, rate); + if (a_engine->codec_params.adv_channels > 1) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", + a_engine->codec_params.agreed_pt, a_engine->codec_params.rm_encoding, rate, a_engine->codec_params.adv_channels); + } else { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", + a_engine->codec_params.agreed_pt, a_engine->codec_params.rm_encoding, rate); + } + if (fmtp_out) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", a_engine->codec_params.agreed_pt, fmtp_out); } @@ -5164,6 +5199,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess const switch_codec_implementation_t *imp = smh->codecs[i]; char *fmtp = NULL; uint32_t ianacode = smh->ianacodes[i]; + int channels; if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { continue; @@ -5180,9 +5216,15 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess rate = imp->samples_per_second; } - - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", ianacode, imp->iananame, - imp->samples_per_second); + channels = get_channels(imp); + + 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); + } if (!zstr(ov_fmtp)) { fmtp = (char *) ov_fmtp;