*
* Contributor(s):
* Mathieu Rene <mrene@avgs.ca>
+ * Dragos Oancea <droancea@yahoo.com>
*
* mod_codec2 -- FreeSWITCH CODEC2 Module
*
struct codec2_context {
void *encoder;
void *decoder;
+ int mode; /* codec2 operation mode */
+ int nbit; /* nr of bits per frame */
+ int nbyte; /* nr of bytes per frame */
+ int nsam; /* nr of samples per frame */
#ifdef LOG_DATA
FILE *encoder_in;
FILE *encoder_out;
#endif
};
+struct {
+ int mode;
+ int ptime;
+ int samples_per_frame;
+} codec2_prefs;
+
#ifdef LOG_DATA
static int c2_count = 0;
#endif
if (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context)))) {
return SWITCH_STATUS_FALSE;
}
+
+ if (!codec2_prefs.mode) {
+ codec2_prefs.mode = CODEC2_MODE_2400;
+ }
+
+ if (codec2_prefs.mode == 3200) {
+ context->mode = CODEC2_MODE_3200;
+ } else if (codec2_prefs.mode == 2400) {
+ context->mode = CODEC2_MODE_2400;
+ } else if (codec2_prefs.mode == 1400) {
+ context->mode = CODEC2_MODE_1400;
+ } else if (codec2_prefs.mode == 1200) {
+ context->mode = CODEC2_MODE_1200;
+ } else {
+ /* 3200 might be better for VOIP, but forcing 2400 for backwards compatibility */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mode not supported, forcing CODEC2_MODE_2400. You can try mode 3200 too!\n");
+ context->mode = CODEC2_MODE_2400;
+ }
if (encoding) {
- context->encoder = codec2_create(CODEC2_MODE_2400);
+ context->encoder = codec2_create(context->mode);
}
if (decoding) {
- context->decoder = codec2_create(CODEC2_MODE_2400);
+ context->decoder = codec2_create(context->mode);
+ }
+
+ context->nsam = codec2_samples_per_frame(context->encoder);
+ if (!context->nsam) {
+ context->nsam = CODEC2_SAMPLES_PER_FRAME;
}
+ context->nbit = codec2_bits_per_frame(context->encoder);
+ context->nbyte = (context->nbit + 7) / 8;
codec->private_info = context;
{
struct codec2_context *context = codec->private_info;
- codec2_assert(decoded_data_len == CODEC2_SAMPLES_PER_FRAME * 2);
+ codec2_assert(decoded_data_len == context->nsam * 2);
#ifdef LOG_DATA
fwrite(decoded_data, decoded_data_len, 1, context->encoder_in);
#ifdef LOG_DATA
fwrite(encode_buf, sizeof(encode_buf), 1, context->encoder_out_unpacked);
fflush(context->encoder_out_unpacked);
- fwrite(encoded_data, 8, 1, context->encoder_out);
+ fwrite(encoded_data, context->nbyte, 1, context->encoder_out);
fflush(context->encoder_out);
#endif
- *encoded_data_len = 6;
+ *encoded_data_len = context->nbyte;
return SWITCH_STATUS_SUCCESS;
}
{
struct codec2_context *context = codec->private_info;
- codec2_assert(encoded_data_len == 8 /* aligned to 8 */);
+ codec2_assert(encoded_data_len == 8);
#ifdef LOG_DATA
fwrite(encoded_data, encoded_data_len, 1, context->decoder_in);
codec2_decode(context->decoder, decoded_data, encoded_data);
#ifdef LOG_DATA
- fwrite(decoded_data, CODEC2_SAMPLES_PER_FRAME, 2, context->decoder_out);
+ fwrite(decoded_data, context->nsam, 2, context->decoder_out);
fflush(context->decoder_out);
#endif
- *decoded_data_len = CODEC2_SAMPLES_PER_FRAME * 2; /* 160 samples */
+ *decoded_data_len = context->nsam * 2; /* eg: 160 samples for 3200,2400 */
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_SUCCESS;
}
+static switch_status_t codec2_load_config(switch_bool_t reload) {
+
+ char *cf = "codec2.conf";
+ switch_xml_t cfg, xml = NULL, param, settings;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ codec2_prefs.mode = 2400 ;
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Opening of %s failed\n", cf);
+ return status;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *key = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(key, "mode") && !zstr(val)) {
+ codec2_prefs.mode = atoi(val);
+ }
+ }
+ }
+
+ if (xml) {
+ switch_xml_free(xml);
+ }
+
+ return status;
+}
+
SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
{
switch_codec_interface_t *codec_interface;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ if ((status = codec2_load_config(SWITCH_FALSE)) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ /*there is no API call to retrieve ptime per mode, so hardcoding here*/
+ if ((codec2_prefs.mode == 3200) ||(codec2_prefs.mode == 2400)) {
+ codec2_prefs.ptime = 20000;
+ codec2_prefs.samples_per_frame = CODEC2_SAMPLES_PER_FRAME;
+ } else {
+ codec2_prefs.ptime = 40000;
+ codec2_prefs.samples_per_frame = CODEC2_SAMPLES_PER_FRAME * 2;
+ }
- SWITCH_ADD_CODEC(codec_interface, "CODEC2 2400bps");
+ SWITCH_ADD_CODEC(codec_interface, "CODEC2 3200/2400/1400/1200bps");
switch_core_codec_add_implementation(pool, codec_interface,
SWITCH_CODEC_TYPE_AUDIO,
NULL,
8000, /* samples/sec */
8000, /* samples/sec */
- 2400, /* bps */
- 20000, /* ptime */
- CODEC2_SAMPLES_PER_FRAME, /* samples decoded */
- CODEC2_SAMPLES_PER_FRAME*2, /* bytes decoded */
+ codec2_prefs.mode, /* bps */
+ codec2_prefs.ptime, /* ptime */
+ codec2_prefs.samples_per_frame, /* samples decoded */
+ codec2_prefs.samples_per_frame * 2, /* bytes decoded */
0, /* bytes encoded */
1, /* channels */
1, /* frames/packet */