\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);
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 */
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 */
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;
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;
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 *);
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;
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
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)
}
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];
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++) {
*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 */
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;
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) {
*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 */
#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;
void *dec_state;
};
-static switch_status_t switch_silk_init(switch_codec_t *codec,
- switch_codec_flag_t freeswitch_flags,
- const switch_codec_settings_t *codec_settings)
+static switch_status_t switch_silk_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
{
- struct silk_context *context = NULL;
- SKP_int useinbandfec = 0, usedtx = 0, maxaveragebitrate = 0, plpct =0;
- SKP_int32 encSizeBytes;
- SKP_int32 decSizeBytes;
- int encoding = (freeswitch_flags & SWITCH_CODEC_FLAG_ENCODE);
- int decoding = (freeswitch_flags & SWITCH_CODEC_FLAG_DECODE);
+ if (codec_fmtp) {
+ silk_codec_settings_t *codec_settings = NULL;
- 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 (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 (!strcasecmp(data, "maxaveragebitrate")) {
- maxaveragebitrate = atoi(arg);
- switch(codec->implementation->actual_samples_per_second) {
- case 8000:
- {
- if(maxaveragebitrate < 6000 || maxaveragebitrate > 20000) {
- maxaveragebitrate = 20000;
+ if ((arg = strchr(data, '='))) {
+ *arg++ = '\0';
+ if (codec_settings) {
+ if (!strcasecmp(data, "useinbandfec")) {
+ if (switch_true(arg)) {
+ codec_settings->useinbandfec = 1;
}
- break;
}
- case 12000:
- {
- if(maxaveragebitrate < 7000 || maxaveragebitrate > 25000) {
- maxaveragebitrate = 25000;
+ if (!strcasecmp(data, "usedtx")) {
+ if (switch_true(arg)) {
+ codec_settings->usedtx = 1;
}
- break;
}
- case 16000:
- {
- if(maxaveragebitrate < 8000 || maxaveragebitrate > 30000) {
- maxaveragebitrate = 30000;
- }
- break;
- }
- case 24000:
- {
- if(maxaveragebitrate < 12000 || maxaveragebitrate > 40000) {
- maxaveragebitrate = 40000;
+ 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;
}
- break;
+
}
-
- default:
- /* this should never happen but 20000 is common among all rates */
- 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;
+ 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);
+ int decoding = (freeswitch_flags & SWITCH_CODEC_FLAG_DECODE);
+
+ if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) {
+ return SWITCH_STATUS_FALSE;
}
+
+ 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)) {
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) {
*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 */
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;
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) {
*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--) {
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,
struct speex_context {
switch_codec_t *codec;
+ speex_codec_settings_t codec_settings;
unsigned int flags;
/* Encoder */
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;
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) {
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);
}
}
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);
}
/* 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 */
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;
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);
}
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);
}
}
}
}
- 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");
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;
for (map = m->m_rtpmaps; map; map = map->rm_next) {
if (map->rm_encoding) {
char buf[25] = "";
+ char key[128] = "";
+ char *br = NULL;
+
+ if (map->rm_fmtp) {
+ if ((br = strstr(map->rm_fmtp, "bitrate="))) {
+ br += 8;
+ }
+ }
+
switch_snprintf(buf, sizeof(buf), "%d", map->rm_pt);
- switch_event_add_header_string(*pt, SWITCH_STACK_BOTTOM, map->rm_encoding, buf);
+
+ 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, map->rm_encoding, map->rm_fmtp);
+ switch_event_add_header_string(*fmtp, SWITCH_STACK_BOTTOM, key, map->rm_fmtp);
}
}
}
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);
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;
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);
- }
- if (!codec_ms) {
- /* default to 30 when no mode is defined for ilbc ONLY */
- codec_ms = 30;
+ /* 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);
+ }
}
- } 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 {
"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;
}
}
- if (!match && near_match) {
+ if (!match && near_match && !map->rm_next) {
const switch_codec_implementation_t *search[1];
char *prefs[1];
char tmp[80];
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;
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);
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 */
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);
}
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);
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;
/* 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;
/* 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;
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:
" 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"
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);
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);
}
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;
interval = atoi(cur);
} else if ((strchr(cur, 'k') || strchr(cur, 'h'))) {
rate = atoi(cur);
+ } else if (strchr(cur, 'b')) {
+ bit = atoi(cur);
}
}
cur = next;
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;
+ }
+
}
if (rate && (uint32_t) imp->samples_per_second != rate) {
continue;
}
+
+ if (bit && (uint32_t) imp->bits_per_second != bit) {
+ continue;
+ }
+
}
array[i++] = imp;