diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 7275f26319..8b08db7d9d 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1339,12 +1339,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_timer_destroy(switch_timer_t *timer) \param pool the memory pool to use \return SWITCH_STATUS_SUCCESS if the handle is allocated */ -SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec, +#define switch_core_codec_init(_codec, _codec_name, _fmtp, _rate, _ms, _channels, _flags, _codec_settings, _pool) \ + switch_core_codec_init_with_bitrate(_codec, _codec_name, _fmtp, _rate, _ms, _channels, 0, _flags, _codec_settings, _pool) +SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec_t *codec, const char *codec_name, const char *fmtp, uint32_t rate, int ms, int channels, + uint32_t bitrate, uint32_t flags, const switch_codec_settings_t *codec_settings, switch_memory_pool_t *pool); SWITCH_DECLARE(switch_status_t) switch_core_codec_copy(switch_codec_t *codec, switch_codec_t *new_codec, switch_memory_pool_t *pool); diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 078b83d2fd..a6013a9386 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -570,42 +570,23 @@ struct switch_directory_handle { void *private_info; }; - /* nobody has more setting than speex so we will let them set the standard */ /*! \brief Various codec settings (currently only relevant to speex) */ struct switch_codec_settings { - /*! desired quality */ - int quality; - /*! desired complexity */ - int complexity; - /*! desired enhancement */ - int enhancement; - /*! desired vad level */ - int vad; - /*! desired vbr level */ - int vbr; - /*! desired vbr quality */ - float vbr_quality; - /*! desired abr level */ - int abr; - /*! desired dtx setting */ - int dtx; - /*! desired preprocessor settings */ - int preproc; - /*! preprocessor vad settings */ - int pp_vad; - /*! preprocessor gain control settings */ - int pp_agc; - /*! preprocessor gain level */ - float pp_agc_level; - /*! preprocessor denoise level */ - int pp_denoise; - /*! preprocessor dereverb settings */ - int pp_dereverb; - /*! preprocessor dereverb decay level */ - float pp_dereverb_decay; - /*! preprocessor dereverb level */ - float pp_dereverb_level; + int unused; +}; + +/*! an abstract handle of a fmtp parsed by codec */ +struct switch_codec_fmtp { + /*! actual samples transferred per second for those who are not moron g722 RFC writers */ + uint32_t actual_samples_per_second; + /*! bits transferred per second */ + int bits_per_second; + /*! number of microseconds of media in one packet (ptime * 1000) */ + int microseconds_per_packet; + /*! private data for the codec module to store handle specific info */ + void *private_info; + }; /*! an abstract handle to a codec module */ @@ -618,8 +599,6 @@ struct switch_codec { char *fmtp_in; /*! fmtp line for local sdp */ char *fmtp_out; - /*! codec settings for this handle */ - switch_codec_settings_t codec_settings; /*! flags to modify behaviour */ uint32_t flags; /*! the handle's memory pool */ @@ -678,6 +657,8 @@ struct switch_codec_interface { const char *interface_name; /*! a list of codec implementations related to the codec */ switch_codec_implementation_t *implementations; + /*! function to decode a codec fmtp parameters */ + switch_core_codec_fmtp_parse_func_t parse_fmtp; uint32_t codec_id; switch_thread_rwlock_t *rwlock; int refs; diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 70eaa4f80e..57c5661c7c 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1588,6 +1588,7 @@ typedef struct switch_core_thread_session switch_core_thread_session_t; typedef struct switch_codec_implementation switch_codec_implementation_t; typedef struct switch_buffer switch_buffer_t; typedef struct switch_codec_settings switch_codec_settings_t; +typedef struct switch_codec_fmtp switch_codec_fmtp_t; typedef struct switch_odbc_handle switch_odbc_handle_t; typedef struct switch_io_routines switch_io_routines_t; @@ -1646,6 +1647,7 @@ typedef switch_status_t (*switch_core_codec_decode_func_t) (switch_codec_t *code void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate, unsigned int *flag); typedef switch_status_t (*switch_core_codec_init_func_t) (switch_codec_t *, switch_codec_flag_t, const switch_codec_settings_t *codec_settings); +typedef switch_status_t (*switch_core_codec_fmtp_parse_func_t) (const char *fmtp, switch_codec_fmtp_t *codec_fmtp); typedef switch_status_t (*switch_core_codec_destroy_func_t) (switch_codec_t *); diff --git a/src/mod/codecs/mod_amr/mod_amr.c b/src/mod/codecs/mod_amr/mod_amr.c index a864254e28..e8925c4581 100644 --- a/src/mod/codecs/mod_amr/mod_amr.c +++ b/src/mod/codecs/mod_amr/mod_amr.c @@ -98,11 +98,8 @@ typedef enum { AMR_DTX_ENABLED } amr_dtx_t; -struct amr_context { - void *encoder_state; - void *decoder_state; - switch_byte_t enc_modes; - switch_byte_t enc_mode; +/*! \brief Various codec settings */ +struct amr_codec_settings { int dtx_mode; uint32_t change_period; switch_byte_t max_ptime; @@ -110,6 +107,24 @@ struct amr_context { switch_byte_t channels; switch_byte_t flags; }; +typedef struct amr_codec_settings amr_codec_settings_t; + +static amr_codec_settings_t default_codec_settings = { + /*.dtx_mode */ AMR_DTX_ENABLED, + /*.change_period */ 0, + /*.max_ptime */ 0, + /*.ptime */ 0, + /*.channels */ 0, + /*.flags */ 0, +}; + + +struct amr_context { + void *encoder_state; + void *decoder_state; + switch_byte_t enc_modes; + switch_byte_t enc_mode; +}; #define AMR_DEFAULT_BITRATE AMR_BITRATE_1220 @@ -117,6 +132,88 @@ static struct { switch_byte_t default_bitrate; } globals; +static switch_status_t switch_amr_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp) +{ + if (codec_fmtp) { + amr_codec_settings_t *codec_settings = NULL; + if (codec_fmtp->private_info) { + codec_settings = codec_fmtp->private_info; + memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings)); + } + + if (fmtp) { + int x, argc; + char *argv[10]; + char *fmtp_dup = strdup(fmtp); + + switch_assert(fmtp_dup); + + argc = switch_separate_string((char *) fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0]))); + for (x = 0; x < argc; x++) { + char *data = argv[x]; + char *arg; + switch_assert(data); + while (*data == ' ') { + data++; + } + if ((arg = strchr(data, '='))) { + *arg++ = '\0'; + /* + if (!strcasecmp(data, "bitrate")) { + bit_rate = atoi(arg); + } + */ + if (codec_settings) { + if (!strcasecmp(data, "octet-align")) { + if (atoi(arg)) { + switch_set_flag(codec_settings, AMR_OPT_OCTET_ALIGN); + } + } else if (!strcasecmp(data, "mode-change-neighbor")) { + if (atoi(arg)) { + switch_set_flag(codec_settings, AMR_OPT_MODE_CHANGE_NEIGHBOR); + } + } else if (!strcasecmp(data, "crc")) { + if (atoi(arg)) { + switch_set_flag(codec_settings, AMR_OPT_CRC); + } + } else if (!strcasecmp(data, "robust-sorting")) { + if (atoi(arg)) { + switch_set_flag(codec_settings, AMR_OPT_ROBUST_SORTING); + } + } else if (!strcasecmp(data, "interveaving")) { + if (atoi(arg)) { + switch_set_flag(codec_settings, AMR_OPT_INTERLEAVING); + } + } else if (!strcasecmp(data, "mode-change-period")) { + codec_settings->change_period = atoi(arg); + } else if (!strcasecmp(data, "ptime")) { + codec_settings->ptime = (switch_byte_t) atoi(arg); + } else if (!strcasecmp(data, "channels")) { + codec_settings->channels = (switch_byte_t) atoi(arg); + } else if (!strcasecmp(data, "maxptime")) { + codec_settings->max_ptime = (switch_byte_t) atoi(arg); + } else if (!strcasecmp(data, "mode-set")) { + int y, m_argc; + char *m_argv[7]; + m_argc = switch_separate_string(arg, ',', m_argv, (sizeof(m_argv) / sizeof(m_argv[0]))); + for (y = 0; y < m_argc; y++) { + codec_settings->enc_modes |= (1 << atoi(m_argv[y])); + } + } else if (!strcasecmp(data, "dtx")) { + codec_settings->dtx_mode = (atoi(arg)) ? AMR_DTX_ENABLED : AMR_DTX_DISABLED; + } + } + + } + } + free(fmtp_dup); + } + //codec_fmtp->bits_per_second = bit_rate; + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + #endif static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) @@ -128,7 +225,10 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_ } return SWITCH_STATUS_SUCCESS; #else + struct amr_context *context = NULL; + switch_codec_fmtp_t codec_fmtp; + amr_codec_settings_t amr_codec_settings; int encoding, decoding; int x, i, argc; char *argv[10]; @@ -141,58 +241,9 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_ return SWITCH_STATUS_FALSE; } else { - context->dtx_mode = AMR_DTX_ENABLED; - if (codec->fmtp_in) { - argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0]))); - for (x = 0; x < argc; x++) { - char *data = argv[x]; - char *arg; - while (*data && *data == ' ') { - data++; - } - if ((arg = strchr(data, '='))) { - *arg++ = '\0'; - if (!strcasecmp(data, "octet-align")) { - if (atoi(arg)) { - switch_set_flag(context, AMR_OPT_OCTET_ALIGN); - } - } else if (!strcasecmp(data, "mode-change-neighbor")) { - if (atoi(arg)) { - switch_set_flag(context, AMR_OPT_MODE_CHANGE_NEIGHBOR); - } - } else if (!strcasecmp(data, "crc")) { - if (atoi(arg)) { - switch_set_flag(context, AMR_OPT_CRC); - } - } else if (!strcasecmp(data, "robust-sorting")) { - if (atoi(arg)) { - switch_set_flag(context, AMR_OPT_ROBUST_SORTING); - } - } else if (!strcasecmp(data, "interveaving")) { - if (atoi(arg)) { - switch_set_flag(context, AMR_OPT_INTERLEAVING); - } - } else if (!strcasecmp(data, "mode-change-period")) { - context->change_period = atoi(arg); - } else if (!strcasecmp(data, "ptime")) { - context->ptime = (switch_byte_t) atoi(arg); - } else if (!strcasecmp(data, "channels")) { - context->channels = (switch_byte_t) atoi(arg); - } else if (!strcasecmp(data, "maxptime")) { - context->max_ptime = (switch_byte_t) atoi(arg); - } else if (!strcasecmp(data, "mode-set")) { - int y, m_argc; - char *m_argv[7]; - m_argc = switch_separate_string(arg, ',', m_argv, (sizeof(m_argv) / sizeof(m_argv[0]))); - for (y = 0; y < m_argc; y++) { - context->enc_modes |= (1 << atoi(m_argv[y])); - } - } else if (!strcasecmp(data, "dtx")) { - context->dtx_mode = (atoi(arg)) ? AMR_DTX_ENABLED : AMR_DTX_DISABLED; - } - } - } - } + memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); + codec_fmtp.private_info = &amr_codec_settings; + switch_amr_fmtp_parse(codec->fmtp_in, &codec_fmtp); if (context->enc_modes) { for (i = 7; i > -1; i++) { @@ -321,6 +372,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_amr_load) *module_interface = switch_loadable_module_create_module_interface(pool, modname); SWITCH_ADD_CODEC(codec_interface, "AMR"); +#ifndef AMR_PASSTHROUGH + codec_interface->parse_fmtp = switch_amr_fmtp_parse; +#endif switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 96, /* the IANA code number */ "AMR", /* the IANA code name */ diff --git a/src/mod/codecs/mod_ilbc/mod_ilbc.c b/src/mod/codecs/mod_ilbc/mod_ilbc.c index b37056c393..85298375db 100644 --- a/src/mod/codecs/mod_ilbc/mod_ilbc.c +++ b/src/mod/codecs/mod_ilbc/mod_ilbc.c @@ -40,6 +40,27 @@ struct ilbc_context { ilbc_decode_state_t decoder_object; }; +static switch_status_t switch_ilbc_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp) +{ + if (codec_fmtp) { + char *mode = NULL; + int codec_ms = 0; + + memset(codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); + + if (fmtp && (mode = strstr(fmtp, "mode=")) && (mode + 5)) { + codec_ms = atoi(mode + 5); + } + if (!codec_ms) { + /* default to 30 when no mode is defined for ilbc ONLY */ + codec_ms = 30; + } + codec_fmtp->microseconds_per_packet = (codec_ms * 1000); + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + static switch_status_t switch_ilbc_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) { struct ilbc_context *context; @@ -51,26 +72,6 @@ static switch_status_t switch_ilbc_init(switch_codec_t *codec, switch_codec_flag return SWITCH_STATUS_FALSE; } - if (codec->fmtp_in) { - int x, argc; - char *argv[10]; - argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0]))); - for (x = 0; x < argc; x++) { - char *data = argv[x]; - char *arg; - switch_assert(data); - while (*data == ' ') { - data++; - } - if ((arg = strchr(data, '='))) { - *arg++ = '\0'; - if (!strcasecmp(data, "mode")) { - mode = atoi(arg); - } - } - } - } - codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "mode=%d", mode); if (encoding) { @@ -136,6 +137,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_ilbc_load) *module_interface = switch_loadable_module_create_module_interface(pool, modname); SWITCH_ADD_CODEC(codec_interface, "iLBC"); + codec_interface->parse_fmtp = switch_ilbc_fmtp_parse; switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 98, /* the IANA code number */ diff --git a/src/mod/codecs/mod_silk/mod_silk.c b/src/mod/codecs/mod_silk/mod_silk.c index 9d0abcdf8b..ff8c2304e7 100644 --- a/src/mod/codecs/mod_silk/mod_silk.c +++ b/src/mod/codecs/mod_silk/mod_silk.c @@ -41,6 +41,22 @@ SWITCH_MODULE_DEFINITION(mod_silk, mod_silk_load, NULL, NULL); #define MAX_LBRR_DELAY 2 #define MAX_FRAME_LENGTH 480 +/*! \brief Various codec settings */ +struct silk_codec_settings { + SKP_int useinbandfec; + SKP_int usedtx; + SKP_int maxaveragebitrate; + SKP_int plpct; +}; +typedef struct silk_codec_settings silk_codec_settings_t; + +static silk_codec_settings_t default_codec_settings = { + /*.useinbandfec */ 0, + /*.usedtx */ 0, + /*.maxaveragebitrate */ 0, + /*.plpct */ 10, // 10% for now +}; + struct silk_context { SKP_SILK_SDK_EncControlStruct encoder_object; SKP_SILK_SDK_DecControlStruct decoder_object; @@ -48,12 +64,105 @@ struct silk_context { void *dec_state; }; +static switch_status_t switch_silk_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp) +{ + if (codec_fmtp) { + silk_codec_settings_t *codec_settings = NULL; + + if (codec_fmtp->private_info) { + codec_settings = codec_fmtp->private_info; + memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings)); + } + + if (fmtp) { + int x, argc; + char *argv[10]; + char *fmtp_dup = strdup(fmtp); + + switch_assert(fmtp_dup); + + argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0]))); + for (x = 0; x < argc; x++) { + char *data = argv[x]; + char *arg; + switch_assert(data); + while (*data == ' ') { + data++; + } + if ((arg = strchr(data, '='))) { + *arg++ = '\0'; + if (codec_settings) { + if (!strcasecmp(data, "useinbandfec")) { + if (switch_true(arg)) { + codec_settings->useinbandfec = 1; + } + } + if (!strcasecmp(data, "usedtx")) { + if (switch_true(arg)) { + codec_settings->usedtx = 1; + } + } + if (!strcasecmp(data, "axaveragebitrate")) { + codec_settings->maxaveragebitrate = atoi(arg); + switch(codec_fmtp->actual_samples_per_second) { + case 8000: + { + if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) { + codec_settings->maxaveragebitrate = 20000; + } + break; + } + case 12000: + { + if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) { + codec_settings->maxaveragebitrate = 25000; + } + break; + } + case 16000: + { + if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) { + codec_settings->maxaveragebitrate = 30000; + } + break; + } + case 24000: + { + if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) { + codec_settings->maxaveragebitrate = 40000; + } + break; + } + + default: + /* this should never happen but 20000 is common among all rates */ + codec_settings->maxaveragebitrate = 20000; + break; + } + + } + + } + } + } + free(fmtp_dup); + } + //codec_fmtp->bits_per_second = bit_rate; + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + + + + static switch_status_t switch_silk_init(switch_codec_t *codec, switch_codec_flag_t freeswitch_flags, const switch_codec_settings_t *codec_settings) { struct silk_context *context = NULL; - SKP_int useinbandfec = 0, usedtx = 0, maxaveragebitrate = 0, plpct =0; + switch_codec_fmtp_t codec_fmtp; + silk_codec_settings_t silk_codec_settings; SKP_int32 encSizeBytes; SKP_int32 decSizeBytes; int encoding = (freeswitch_flags & SWITCH_CODEC_FLAG_ENCODE); @@ -62,78 +171,15 @@ static switch_status_t switch_silk_init(switch_codec_t *codec, if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) { return SWITCH_STATUS_FALSE; } - - if (codec->fmtp_in) { - int x, argc; - char *argv[10]; - argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0]))); - for (x = 0; x < argc; x++) { - char *data = argv[x]; - char *arg; - switch_assert(data); - while (*data == ' ') { - data++; - } - if ((arg = strchr(data, '='))) { - *arg++ = '\0'; - if (!strcasecmp(data, "useinbandfec")) { - if (switch_true(arg)) { - useinbandfec = 1; - plpct = 10;// 10% for now - } - } - if (!strcasecmp(data, "usedtx")) { - if (switch_true(arg)) { - usedtx = 1; - } - } - if (!strcasecmp(data, "maxaveragebitrate")) { - maxaveragebitrate = atoi(arg); - switch(codec->implementation->actual_samples_per_second) { - case 8000: - { - if(maxaveragebitrate < 6000 || maxaveragebitrate > 20000) { - maxaveragebitrate = 20000; - } - break; - } - case 12000: - { - if(maxaveragebitrate < 7000 || maxaveragebitrate > 25000) { - maxaveragebitrate = 25000; - } - break; - } - case 16000: - { - if(maxaveragebitrate < 8000 || maxaveragebitrate > 30000) { - maxaveragebitrate = 30000; - } - break; - } - case 24000: - { - if(maxaveragebitrate < 12000 || maxaveragebitrate > 40000) { - maxaveragebitrate = 40000; - } - break; - } - - default: - /* this should never happen but 20000 is common among all rates */ - maxaveragebitrate = 20000; - break; - } - - } - } - } - } + + memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); + codec_fmtp.private_info = &silk_codec_settings; + switch_silk_fmtp_parse(codec->fmtp_in, &codec_fmtp); codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "useinbandfec=%s; usedtx=%s; maxaveragebitrate=%d", - useinbandfec ? "1" : "0", - usedtx ? "1" : "0", - maxaveragebitrate ? maxaveragebitrate : codec->implementation->bits_per_second); + silk_codec_settings.useinbandfec ? "1" : "0", + silk_codec_settings.usedtx ? "1" : "0", + silk_codec_settings.maxaveragebitrate ? silk_codec_settings.maxaveragebitrate : codec->implementation->bits_per_second); if (encoding) { if (SKP_Silk_SDK_Get_Encoder_Size(&encSizeBytes)) { @@ -148,11 +194,11 @@ static switch_status_t switch_silk_init(switch_codec_t *codec, context->encoder_object.sampleRate = codec->implementation->actual_samples_per_second; context->encoder_object.packetSize = codec->implementation->samples_per_packet; - context->encoder_object.useInBandFEC = useinbandfec; + context->encoder_object.useInBandFEC = silk_codec_settings.useinbandfec; context->encoder_object.complexity = 0; - context->encoder_object.bitRate = maxaveragebitrate ? maxaveragebitrate : codec->implementation->bits_per_second; - context->encoder_object.useDTX = usedtx; - context->encoder_object.packetLossPercentage = plpct;; + context->encoder_object.bitRate = silk_codec_settings.maxaveragebitrate ? silk_codec_settings.maxaveragebitrate : codec->implementation->bits_per_second; + context->encoder_object.useDTX = silk_codec_settings.usedtx; + context->encoder_object.packetLossPercentage = silk_codec_settings.plpct; } if (decoding) { @@ -299,6 +345,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_silk_load) *module_interface = switch_loadable_module_create_module_interface(pool, modname); SWITCH_ADD_CODEC(codec_interface, "SILK"); + codec_interface->parse_fmtp = switch_silk_fmtp_parse; switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 117, /* the IANA code number */ diff --git a/src/mod/codecs/mod_siren/mod_siren.c b/src/mod/codecs/mod_siren/mod_siren.c index 1ccd36eafb..4646ffc5ae 100644 --- a/src/mod/codecs/mod_siren/mod_siren.c +++ b/src/mod/codecs/mod_siren/mod_siren.c @@ -47,6 +47,40 @@ struct siren_context { g722_1_encode_state_t encoder_object; }; +static switch_status_t switch_siren_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp) +{ + if (codec_fmtp) { + int bit_rate = 0; + memset(codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); + if (fmtp) { + int x, argc; + char *argv[10]; + char *fmtp_dup = strdup(fmtp); + + switch_assert(fmtp_dup); + argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0]))); + for (x = 0; x < argc; x++) { + char *data = argv[x]; + char *arg; + switch_assert(data); + while (*data == ' ') { + data++; + } + if ((arg = strchr(data, '='))) { + *arg++ = '\0'; + if (!strcasecmp(data, "bitrate")) { + bit_rate = atoi(arg); + } + } + } + free(fmtp_dup); + } + codec_fmtp->bits_per_second = bit_rate; + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + static switch_status_t switch_siren_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) { struct siren_context *context = NULL; @@ -58,26 +92,6 @@ static switch_status_t switch_siren_init(switch_codec_t *codec, switch_codec_fla return SWITCH_STATUS_FALSE; } - if (codec->fmtp_in) { - int x, argc; - char *argv[10]; - argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0]))); - for (x = 0; x < argc; x++) { - char *data = argv[x]; - char *arg; - switch_assert(data); - while (*data == ' ') { - data++; - } - if ((arg = strchr(data, '='))) { - *arg++ = '\0'; - if (!strcasecmp(data, "bitrate")) { - bit_rate = atoi(arg); - } - } - } - } - codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "bitrate=%d", bit_rate); if (encoding) { @@ -145,6 +159,28 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_siren_load) *module_interface = switch_loadable_module_create_module_interface(pool, modname); SWITCH_ADD_CODEC(codec_interface, "Polycom(R) G722.1/G722.1C"); + codec_interface->parse_fmtp = switch_siren_fmtp_parse; + + spf = 320, bpf = 640; + for (count = 3; count > 0; count--) { + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 107, /* the IANA code number */ + "G7221", /* the IANA code name */ + "bitrate=24000", /* default fmtp to send (can be overridden by the init function) */ + 16000, /* samples transferred per second */ + 16000, /* actual samples transferred per second */ + 24000, /* bits transferred per second */ + mpf * count, /* number of microseconds per frame */ + spf * count, /* number of samples per frame */ + bpf * count, /* number of bytes per frame decompressed */ + 0, /* number of bytes per frame compressed */ + 1, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_siren_init, /* function to initialize a codec handle using this implementation */ + switch_siren_encode, /* function to encode raw data into encoded data */ + switch_siren_decode, /* function to decode encoded data into raw data */ + switch_siren_destroy); /* deinitalize a codec handle using this implementation */ + } spf = 320, bpf = 640; for (count = 3; count > 0; count--) { diff --git a/src/mod/codecs/mod_speex/mod_speex.c b/src/mod/codecs/mod_speex/mod_speex.c index 1d4a0409b8..a951b12d84 100644 --- a/src/mod/codecs/mod_speex/mod_speex.c +++ b/src/mod/codecs/mod_speex/mod_speex.c @@ -37,7 +37,46 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_speex_load); SWITCH_MODULE_DEFINITION(mod_speex, mod_speex_load, NULL, NULL); -static switch_codec_settings_t default_codec_settings = { +/* nobody has more setting than speex so we will let them set the standard */ +/*! \brief Various codec settings (currently only relevant to speex) */ +struct speex_codec_settings { + /*! desired quality */ + int quality; + /*! desired complexity */ + int complexity; + /*! desired enhancement */ + int enhancement; + /*! desired vad level */ + int vad; + /*! desired vbr level */ + int vbr; + /*! desired vbr quality */ + float vbr_quality; + /*! desired abr level */ + int abr; + /*! desired dtx setting */ + int dtx; + /*! desired preprocessor settings */ + int preproc; + /*! preprocessor vad settings */ + int pp_vad; + /*! preprocessor gain control settings */ + int pp_agc; + /*! preprocessor gain level */ + float pp_agc_level; + /*! preprocessor denoise level */ + int pp_denoise; + /*! preprocessor dereverb settings */ + int pp_dereverb; + /*! preprocessor dereverb decay level */ + float pp_dereverb_decay; + /*! preprocessor dereverb level */ + float pp_dereverb_level; +}; + +typedef struct speex_codec_settings speex_codec_settings_t; + +static speex_codec_settings_t default_codec_settings = { /*.quality */ 5, /*.complexity */ 5, /*.enhancement */ 1, @@ -58,6 +97,7 @@ static switch_codec_settings_t default_codec_settings = { struct speex_context { switch_codec_t *codec; + speex_codec_settings_t codec_settings; unsigned int flags; /* Encoder */ @@ -74,6 +114,56 @@ struct speex_context { int decoder_mode; }; +static switch_status_t switch_speex_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp) +{ + if (codec_fmtp) { + speex_codec_settings_t *codec_settings = NULL; + if (codec_fmtp->private_info) { + codec_settings = codec_fmtp->private_info; + memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings)); + } + + if (fmtp) { + int x, argc; + char *argv[10]; + char *fmtp_dup = strdup(fmtp); + + switch_assert(fmtp_dup); + + argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0]))); + + for (x = 0; x < argc; x++) { + char *data = argv[x]; + char *arg; + switch_assert(data); + while (*data == ' ') { + data++; + } + if ((arg = strchr(data, '='))) { + *arg++ = '\0'; + /* + if (!strcasecmp(data, "bitrate")) { + bit_rate = atoi(arg); + } + */ + /* + if (codec_settings) { + if (!strcasecmp(data, "vad")) { + bit_rate = atoi(arg); + } + } + */ + } + } + free(fmtp_dup); + } + /*codec_fmtp->bits_per_second = bit_rate;*/ + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + + static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) { struct speex_context *context = NULL; @@ -82,16 +172,18 @@ static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_fla encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); decoding = (flags & SWITCH_CODEC_FLAG_DECODE); - if (!codec_settings) { - codec_settings = &default_codec_settings; - } - - memcpy(&codec->codec_settings, codec_settings, sizeof(codec->codec_settings)); - if (!(encoding || decoding) || ((context = switch_core_alloc(codec->memory_pool, sizeof(*context))) == 0)) { return SWITCH_STATUS_FALSE; } else { const SpeexMode *mode = NULL; + switch_codec_fmtp_t codec_fmtp; + speex_codec_settings_t codec_settings; + + memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); + codec_fmtp.private_info = &codec_settings; + switch_speex_fmtp_parse(codec->fmtp_in, &codec_fmtp); + + memcpy(&context->codec_settings, &codec_settings, sizeof(context->codec_settings)); context->codec = codec; if (codec->implementation->actual_samples_per_second == 8000) { @@ -110,41 +202,41 @@ static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_fla speex_bits_init(&context->encoder_bits); context->encoder_state = speex_encoder_init(mode); speex_encoder_ctl(context->encoder_state, SPEEX_GET_FRAME_SIZE, &context->encoder_frame_size); - speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &codec->codec_settings.complexity); - if (codec->codec_settings.preproc) { + speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &context->codec_settings.complexity); + if (context->codec_settings.preproc) { context->pp = speex_preprocess_state_init(context->encoder_frame_size, codec->implementation->actual_samples_per_second); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &codec->codec_settings.pp_vad); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &codec->codec_settings.pp_agc); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &codec->codec_settings.pp_agc_level); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &codec->codec_settings.pp_denoise); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &codec->codec_settings.pp_dereverb); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &codec->codec_settings.pp_dereverb_decay); - speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &codec->codec_settings.pp_dereverb_level); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &context->codec_settings.pp_vad); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &context->codec_settings.pp_agc); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &context->codec_settings.pp_agc_level); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &context->codec_settings.pp_denoise); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &context->codec_settings.pp_dereverb); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &context->codec_settings.pp_dereverb_decay); + speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &context->codec_settings.pp_dereverb_level); } - if (!codec->codec_settings.abr && !codec->codec_settings.vbr) { - speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &codec->codec_settings.quality); - if (codec->codec_settings.vad) { - speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &codec->codec_settings.vad); + if (!context->codec_settings.abr && !context->codec_settings.vbr) { + speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &context->codec_settings.quality); + if (context->codec_settings.vad) { + speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &context->codec_settings.vad); } } - if (codec->codec_settings.vbr) { - speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &codec->codec_settings.vbr); - speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &codec->codec_settings.vbr_quality); + if (context->codec_settings.vbr) { + speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &context->codec_settings.vbr); + speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &context->codec_settings.vbr_quality); } - if (codec->codec_settings.abr) { - speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &codec->codec_settings.abr); + if (context->codec_settings.abr) { + speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &context->codec_settings.abr); } - if (codec->codec_settings.dtx) { - speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &codec->codec_settings.dtx); + if (context->codec_settings.dtx) { + speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &context->codec_settings.dtx); } } if (decoding) { speex_bits_init(&context->decoder_bits); context->decoder_state = speex_decoder_init(mode); - if (codec->codec_settings.enhancement) { - speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &codec->codec_settings.enhancement); + if (context->codec_settings.enhancement) { + speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &context->codec_settings.enhancement); } } @@ -178,7 +270,7 @@ static switch_status_t switch_speex_encode(switch_codec_t *codec, if (is_speech) { is_speech = speex_encode_int(context->encoder_state, buf, &context->encoder_bits) - || !context->codec->codec_settings.dtx; + || !context->codec_settings.dtx; } else { speex_bits_pack(&context->encoder_bits, 0, 5); } @@ -270,6 +362,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_speex_load) /* connect my internal structure to the blank pointer passed to me */ *module_interface = switch_loadable_module_create_module_interface(pool, modname); SWITCH_ADD_CODEC(codec_interface, "Speex"); + codec_interface->parse_fmtp = switch_speex_fmtp_parse; for (counta = 1; counta <= 3; counta++) { for (countb = 1; countb > 0; countb--) { switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 58eef2918c..0cd4b27a51 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -577,6 +577,7 @@ struct private_object { switch_codec_t read_codec; switch_codec_t write_codec; uint32_t codec_ms; + uint32_t bitrate; switch_caller_profile_t *caller_profile; uint32_t timestamp_send; switch_rtp_t *rtp_session; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 3dc90b9a68..9d4b0ae51b 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -205,7 +205,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32 switch_event_t *map = NULL, *ptmap = NULL; const char *b_sdp = NULL; - if ((b_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) { + if (!tech_pvt->rm_encoding && (b_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) { sofia_glue_sdp_map(b_sdp, &map, &ptmap); } @@ -354,12 +354,18 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32 rate = imp->samples_per_second; if (map) { - fmtp = switch_event_get_header(map, imp->iananame); + 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; + } } - - + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, rate); - if (imp->fmtp) { + + if (fmtp) { switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, fmtp); } } @@ -2535,24 +2541,26 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) } } - if (switch_core_codec_init(&tech_pvt->read_codec, + if (switch_core_codec_init_with_bitrate(&tech_pvt->read_codec, tech_pvt->iananame, tech_pvt->rm_fmtp, tech_pvt->rm_rate, tech_pvt->codec_ms, 1, + tech_pvt->bitrate, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); switch_goto_status(SWITCH_STATUS_FALSE, end); } - if (switch_core_codec_init(&tech_pvt->write_codec, + if (switch_core_codec_init_with_bitrate(&tech_pvt->write_codec, tech_pvt->iananame, tech_pvt->rm_fmtp, tech_pvt->rm_rate, tech_pvt->codec_ms, 1, + tech_pvt->bitrate, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); @@ -2593,9 +2601,9 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) switch_goto_status(SWITCH_STATUS_FALSE, end); } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples\n", + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms, - tech_pvt->read_impl.samples_per_packet); + tech_pvt->read_impl.samples_per_packet, tech_pvt->read_impl.bits_per_second); tech_pvt->read_frame.codec = &tech_pvt->read_codec; tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt; @@ -3685,11 +3693,27 @@ switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, swi for (map = m->m_rtpmaps; map; map = map->rm_next) { if (map->rm_encoding) { char buf[25] = ""; - switch_snprintf(buf, sizeof(buf), "%d", map->rm_pt); - switch_event_add_header_string(*pt, SWITCH_STACK_BOTTOM, map->rm_encoding, buf); - + char key[128] = ""; + char *br = NULL; + if (map->rm_fmtp) { - switch_event_add_header_string(*fmtp, SWITCH_STACK_BOTTOM, map->rm_encoding, 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); } } } @@ -3809,7 +3833,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s sdp_attribute_t *attr; int first = 0, last = 0; int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; - int codec_ms = 0; int sendonly = 0; int greedy = 0, x = 0, skip = 0, mine = 0; switch_channel_t *channel = switch_core_session_get_channel(session); @@ -4129,8 +4152,12 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s for (map = m->m_rtpmaps; map; map = map->rm_next) { int32_t i; uint32_t near_rate = 0; + uint32_t near_bit_rate = 0; + switch_codec_interface_t *codec_interface; const switch_codec_implementation_t *mimp = NULL, *near_match = NULL; const char *rm_encoding; + uint32_t map_bit_rate = 0; + int codec_ms = 0; if (x++ < skip) { continue; @@ -4174,31 +4201,38 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s ptime = switch_default_ptime(rm_encoding, map->rm_pt); } - if (!strcasecmp((char *) rm_encoding, "ilbc")) { - char *mode = NULL; - if (map->rm_fmtp && (mode = strstr(map->rm_fmtp, "mode=")) && (mode + 5)) { - codec_ms = atoi(mode + 5); + /* This will try to use codec specific fmtp parser */ + if (map->rm_fmtp && (codec_interface = switch_loadable_module_get_codec_interface(rm_encoding)) != 0) { + switch_codec_fmtp_t codec_fmtp; + memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); + codec_fmtp.actual_samples_per_second = map->rm_rate; + if (codec_interface->parse_fmtp && codec_interface->parse_fmtp(map->rm_fmtp, &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) { + ptime = (codec_fmtp.microseconds_per_packet / 1000); + } } - if (!codec_ms) { - /* default to 30 when no mode is defined for ilbc ONLY */ - codec_ms = 30; - } - } else { - codec_ms = ptime; + UNPROTECT_INTERFACE(codec_interface); } + if (!codec_ms) { + codec_ms = ptime; + } for (i = first; i < last && i < tech_pvt->num_codecs; i++) { const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + uint32_t bit_rate = imp->bits_per_second; uint32_t codec_rate = imp->samples_per_second; 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]/[%s:%d:%u:%d]\n", - rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, - imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n", + rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate, + imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate); if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { match = (map->rm_pt == imp->ianacode) ? 1 : 0; } else { @@ -4211,8 +4245,13 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s "Bah HUMBUG! Sticking with %s@%uh@%ui\n", imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000); } else { - if ((codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { + if ((codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate || (map_bit_rate && map_bit_rate != bit_rate) ) { near_rate = map->rm_rate; + if (map_bit_rate) { + near_bit_rate = map_bit_rate; + } else { + near_bit_rate = bit_rate; + } near_match = imp; match = 0; continue; @@ -4225,7 +4264,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s } } - if (!match && near_match) { + if (!match && near_match && !map->rm_next) { const switch_codec_implementation_t *search[1]; char *prefs[1]; char tmp[80]; @@ -4266,6 +4305,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s tech_pvt->pt = (switch_payload_t) map->rm_pt; tech_pvt->rm_rate = map->rm_rate; tech_pvt->codec_ms = mimp->microseconds_per_packet / 1000; + tech_pvt->bitrate = mimp->bits_per_second; tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address); tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port; diff --git a/src/switch_channel.c b/src/switch_channel.c index ba5560129b..ece3fa27bb 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1834,6 +1834,7 @@ SWITCH_DECLARE(void) switch_channel_event_set_basic_data(switch_channel_t *chann if (impl.iananame) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Read-Codec-Name", impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Read-Codec-Rate", "%u", impl.actual_samples_per_second); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Read-Codec-Bit-Rate", "%d", impl.bits_per_second); } switch_core_session_get_write_impl(channel->session, &impl); @@ -1841,6 +1842,7 @@ SWITCH_DECLARE(void) switch_channel_event_set_basic_data(switch_channel_t *chann if (impl.iananame) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Name", impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Rate", "%u", impl.actual_samples_per_second); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Bit-Rate", "%d", impl.bits_per_second); } /* Index Caller's Profile */ diff --git a/src/switch_core_codec.c b/src/switch_core_codec.c index ba84b0301c..f21b7cb288 100644 --- a/src/switch_core_codec.c +++ b/src/switch_core_codec.c @@ -165,6 +165,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_codec(switch_core_s switch_channel_event_set_data(session->channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-read-codec-name", session->read_impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-rate", "%d", session->read_impl.actual_samples_per_second); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-read-codec-bit-rate", "%d", session->read_impl.bits_per_second); if (session->read_impl.actual_samples_per_second != session->read_impl.samples_per_second) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-reported-read-codec-rate", "%d", session->read_impl.samples_per_second); } @@ -317,6 +318,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_write_codec(switch_core_ switch_channel_event_set_data(session->channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Name", session->write_impl.iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Write-Codec-Rate", "%d", session->write_impl.actual_samples_per_second); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Write-codec-bit-rate", "%d", session->write_impl.bits_per_second); if (session->write_impl.actual_samples_per_second != session->write_impl.samples_per_second) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Reported-Write-Codec-Rate", "%d", session->write_impl.actual_samples_per_second); @@ -494,8 +496,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_copy(switch_codec_t *codec, sw return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec, const char *codec_name, const char *fmtp, - uint32_t rate, int ms, int channels, uint32_t flags, +SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec_t *codec, const char *codec_name, const char *fmtp, + uint32_t rate, int ms, int channels, uint32_t bitrate, uint32_t flags, const switch_codec_settings_t *codec_settings, switch_memory_pool_t *pool) { switch_codec_interface_t *codec_interface; @@ -519,7 +521,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec, co /* If no specific codec interval is requested opt for 20ms above all else because lots of stuff assumes it */ if (!ms) { for (iptr = codec_interface->implementations; iptr; iptr = iptr->next) { - if ((!rate || rate == iptr->samples_per_second) && + if ((!rate || rate == iptr->samples_per_second) && (!bitrate || bitrate == iptr->bits_per_second) && (20 == (iptr->microseconds_per_packet / 1000)) && (!channels || channels == iptr->number_of_channels)) { implementation = iptr; goto found; @@ -529,7 +531,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec, co /* Either looking for a specific interval or there was no interval specified and there wasn't one @20ms available */ for (iptr = codec_interface->implementations; iptr; iptr = iptr->next) { - if ((!rate || rate == iptr->samples_per_second) && + if ((!rate || rate == iptr->samples_per_second) && (!bitrate || bitrate == iptr->bits_per_second) && (!ms || ms == (iptr->microseconds_per_packet / 1000)) && (!channels || channels == iptr->number_of_channels)) { implementation = iptr; break; diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 0cc4da3f13..7e427b5f03 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1142,11 +1142,13 @@ static void core_event_handler(switch_event_t *event) case SWITCH_EVENT_CODEC: new_sql() = switch_mprintf - ("update channels set read_codec='%q',read_rate='%q',write_codec='%q',write_rate='%q' where uuid='%q' and hostname='%q'", + ("update channels set read_codec='%q',read_rate='%q',read_bit_rate='%q',write_codec='%q',write_rate='%q',write_bit_rate='%q' where uuid='%q' and hostname='%q'", switch_event_get_header_nil(event, "channel-read-codec-name"), switch_event_get_header_nil(event, "channel-read-codec-rate"), + switch_event_get_header_nil(event, "channel-read-codec-bit-rate"), switch_event_get_header_nil(event, "channel-write-codec-name"), switch_event_get_header_nil(event, "channel-write-codec-rate"), + switch_event_get_header_nil(event, "channel-write-codec-bit-rate"), switch_event_get_header_nil(event, "unique-id"), switch_core_get_variable("hostname")); break; case SWITCH_EVENT_CHANNEL_HOLD: @@ -1471,8 +1473,10 @@ static char create_channels_sql[] = " context VARCHAR(128),\n" " read_codec VARCHAR(128),\n" " read_rate VARCHAR(32),\n" + " read_bit_rate VARCHAR(32),\n" " write_codec VARCHAR(128),\n" " write_rate VARCHAR(32),\n" + " write_bit_rate VARCHAR(32),\n" " secure VARCHAR(32),\n" " hostname VARCHAR(256),\n" " presence_id VARCHAR(4096),\n" @@ -1613,7 +1617,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ case SCDB_TYPE_ODBC: { char *err; - switch_cache_db_test_reactive(dbh, "select call_uuid from channels", "DROP TABLE channels", create_channels_sql); + switch_cache_db_test_reactive(dbh, "select call_uuid, read_bit_rate from channels", "DROP TABLE channels", create_channels_sql); switch_cache_db_test_reactive(dbh, "select call_uuid from calls", "DROP TABLE calls", create_calls_sql); switch_cache_db_test_reactive(dbh, "select ikey from interfaces", "DROP TABLE interfaces", create_interfaces_sql); switch_cache_db_test_reactive(dbh, "select hostname from tasks", "DROP TABLE tasks", create_tasks_sql); diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index fc0db74f0f..5466c18983 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -183,8 +183,8 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable if (load_interface) { for (impl = ptr->implementations; impl; impl = impl->next) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, - "Adding Codec '%s' (%s) %dhz %dms\n", - impl->iananame, ptr->interface_name, impl->actual_samples_per_second, impl->microseconds_per_packet / 1000); + "Adding Codec '%s' (%s) %dhz %dms %dbps\n", + impl->iananame, ptr->interface_name, impl->actual_samples_per_second, impl->microseconds_per_packet / 1000, impl->bits_per_second); if (!switch_core_hash_find(loadable_modules.codec_hash, impl->iananame)) { switch_core_hash_insert(loadable_modules.codec_hash, impl->iananame, (const void *) ptr); } @@ -1600,7 +1600,7 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ for (x = 0; x < preflen; x++) { char *cur, *last = NULL, *next = NULL, *name, *p, buf[256]; - uint32_t interval = 0, rate = 0; + uint32_t interval = 0, rate = 0, bit = 0; switch_copy_string(buf, prefs[x], sizeof(buf)); last = name = next = cur = buf; @@ -1620,6 +1620,8 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ interval = atoi(cur); } else if ((strchr(cur, 'k') || strchr(cur, 'h'))) { rate = atoi(cur); + } else if (strchr(cur, 'b')) { + bit = atoi(cur); } } cur = next; @@ -1643,6 +1645,11 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ if (((!rate && (uint32_t) imp->samples_per_second != 8000) || (rate && (uint32_t) imp->samples_per_second != rate))) { continue; } + + if (bit && (uint32_t) imp->bits_per_second != bit) { + continue; + } + } @@ -1666,6 +1673,11 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ if (rate && (uint32_t) imp->samples_per_second != rate) { continue; } + + if (bit && (uint32_t) imp->bits_per_second != bit) { + continue; + } + } array[i++] = imp;