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));
- }
+ speex_codec_settings_t *codec_settings = NULL;
+ int x, argc;
+ char *argv[10];
+ char *fmtp_dup = NULL;
- if (fmtp) {
- int x, argc;
- char *argv[10];
- char *fmtp_dup = strdup(fmtp);
+ if (!codec_fmtp) {
+ return SWITCH_STATUS_FALSE;
+ }
- switch_assert(fmtp_dup);
+ /* load default settings */
+ if (codec_fmtp->private_info) {
+ codec_settings = codec_fmtp->private_info;
+ memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "codec_fmtp->private_info is NULL\n");
+ return SWITCH_STATUS_SUCCESS;
+ }
- argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+ if (!fmtp) {
+ return SWITCH_STATUS_SUCCESS;
+ }
- for (x = 0; x < argc; x++) {
- char *data = argv[x];
- char *arg;
- switch_assert(data);
- while (*data == ' ') {
- data++;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "got fmtp: %s\n", fmtp);
+
+ fmtp_dup = strdup(fmtp);
+ switch_assert(fmtp_dup);
+
+ /* parse ; separated fmtp args */
+ 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, '='))) {
+ continue;
+ }
+ *arg++ = '\0';
+ if (zstr(arg)) {
+ continue;
+ }
+
+ if (!strcasecmp("vbr", data)) {
+ /* vbr can be on/off/vad */
+ if (!strcasecmp("vad", arg)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "enabling speex vbr=vad\n");
+ codec_settings->vbr = 0;
+ codec_settings->vad = 1;
+ codec_settings->pp_vad = 1;
+ } else {
+ if (switch_true(arg)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "enabling speex vbr\n");
+ codec_settings->vbr = 1;
+ codec_settings->vad = 0;
+ codec_settings->pp_vad = 1;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "disabling speex vbr\n");
+ codec_settings->vbr = 0;
+ codec_settings->vad = 0;
+ codec_settings->pp_vad = 0;
}
- 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);
- }
- }
- */
+ }
+ } else if (!strcasecmp("cng", data)) {
+ /* TODO don't know how to turn on CNG */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "speex cng is unsupported\n");
+ } else if (!strcasecmp("mode", data)) {
+ /* mode is a comma-separate list of preferred modes. Use the first mode in the list */
+ char *arg_dup;
+ char *mode[2];
+ if (!strncasecmp("any", arg, 3)) {
+ /* "any", keep the default setting */
+ continue;
+ }
+ arg_dup = strdup(arg);
+ if (switch_separate_string(arg_dup, ',', mode, (sizeof(mode) / sizeof(mode[0])))) {
+ int mode_num = -1;
+ char *mode_str = mode[0];
+ if (mode_str[0] == '"') {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "mode starts with \"\n");
+ mode_str++;
+ }
+ if (switch_is_number(mode_str)) {
+ mode_num = atoi(mode_str);
+ }
+ /* TODO there might be a way to set the mode directly instead of changing the quality */
+ if (codec_fmtp->actual_samples_per_second == 8000) {
+ switch (mode_num) {
+ case 1:
+ codec_settings->quality = 0;
+ break;
+ case 2:
+ codec_settings->quality = 2;
+ break;
+ case 3:
+ codec_settings->quality = 4;
+ break;
+ case 4:
+ codec_settings->quality = 6;
+ break;
+ case 5:
+ codec_settings->quality = 8;
+ break;
+ case 6:
+ codec_settings->quality = 9;
+ break;
+ case 7:
+ codec_settings->quality = 10;
+ break;
+ case 8:
+ codec_settings->quality = 1;
+ break;
+ default:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "ignoring invalid speex/8000 mode %s\n", mode_str);
+ continue;
+ }
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "choosing speex/8000 mode %s\n", mode_str);
+ codec_settings->quality = codec_settings->quality;
+ codec_settings->vbr_quality = codec_settings->quality;
+ } else {
+ if (mode_num >= 0 && mode_num <= 10) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "choosing speex/%d mode %s\n", codec_fmtp->actual_samples_per_second, mode_str);
+ codec_settings->quality = mode_num;
+ codec_settings->vbr_quality = mode_num;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "ignoring invalid speex/%d mode %s\n", codec_fmtp->actual_samples_per_second, mode_str);
+ continue;
+ }
}
}
- free(fmtp_dup);
+ free(arg_dup);
}
- /*codec_fmtp->bits_per_second = bit_rate;*/
- return SWITCH_STATUS_SUCCESS;
}
- return SWITCH_STATUS_FALSE;
+ free(fmtp_dup);
+ /*codec_fmtp->bits_per_second = bit_rate;*/
+ return SWITCH_STATUS_SUCCESS;
}
memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
codec_fmtp.private_info = &codec_settings;
+ codec_fmtp.actual_samples_per_second = codec->implementation->actual_samples_per_second;
switch_speex_fmtp_parse(codec->fmtp_in, &codec_fmtp);
memcpy(&context->codec_settings, &codec_settings, sizeof(context->codec_settings));
speex_encoder_ctl(context->encoder_state, SPEEX_GET_FRAME_SIZE, &context->encoder_frame_size);
speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &context->codec_settings.complexity);
if (context->codec_settings.preproc) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "preprocessor on\n");
context->pp = speex_preprocess_state_init(context->encoder_frame_size, codec->implementation->actual_samples_per_second);
+ if (context->codec_settings.pp_vad) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "preprocessor vad on\n");
+ }
speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &context->codec_settings.pp_vad);
+ if (context->codec_settings.pp_agc) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "preprocessor agc on\n");
+ }
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);
+ if (context->codec_settings.pp_denoise) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "preprocessor denoise on\n");
+ }
speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &context->codec_settings.pp_denoise);
+ if (context->codec_settings.pp_dereverb) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "preprocessor dereverb on\n");
+ }
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 (!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) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "vad on\n");
speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &context->codec_settings.vad);
}
}
if (context->codec_settings.vbr) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "vbr on\n");
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 (context->codec_settings.abr) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "abr on\n");
speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &context->codec_settings.abr);
}
if (context->codec_settings.dtx) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "dtx on\n");
speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &context->codec_settings.dtx);
}
}
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "initialized Speex codec \n");
codec->private_info = context;
return SWITCH_STATUS_SUCCESS;
}
if (is_speech) {
switch_clear_flag(context, SWITCH_CODEC_FLAG_SILENCE);
- *flag |= SWITCH_CODEC_FLAG_SILENCE_STOP;
*flag &= ~SFF_CNG;
} else {
if (switch_test_flag(context, SWITCH_CODEC_FLAG_SILENCE)) {
*encoded_data_len = 0;
- *flag |= SWITCH_CODEC_FLAG_SILENCE | SFF_CNG;
+ *flag |= SFF_CNG;
return SWITCH_STATUS_SUCCESS;
}
switch_set_flag(context, SWITCH_CODEC_FLAG_SILENCE);
- *flag |= SWITCH_CODEC_FLAG_SILENCE_START;
}