mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-08-13 01:26:58 +00:00
add bitrate patch from moc with some extra stuff for late neg mode
This commit is contained in:
@@ -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 */
|
||||
|
Reference in New Issue
Block a user