forked from Mirrors/freeswitch
add bitrate patch from moc with some extra stuff for late neg mode
This commit is contained in:
parent
f126b92e2e
commit
633f193dae
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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--) {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user