make the 'name' and 'value' fields in ast_variable const char *
[asterisk/asterisk.git] / codecs / codec_speex.c
index daaf5ed..bbb6be2 100644 (file)
  *
  * \brief Translate between signed linear and Speex (Open Codec)
  *
- * http://www.speex.org
  * \note This work was motivated by Jeremy McNamara 
  * hacked to be configurable by anthm and bkw 9/28/2004
+ *
  * \ingroup codecs
+ *
+ * \extref The Speex library - http://www.speex.org
+ *
  */
 
+/*** MODULEINFO
+       <depend>speex</depend>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
 #include <fcntl.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <netinet/in.h>
 #include <string.h>
 #include <stdio.h>
-#include <speex.h>
+#include <speex/speex.h>
 
 /* We require a post 1.1.8 version of Speex to enable preprocessing
    and better type handling */   
 #include <speex/speex_preprocess.h>
 #endif
 
+#include "asterisk/lock.h"
+#include "asterisk/translate.h"
+#include "asterisk/module.h"
+#include "asterisk/config.h"
+#include "asterisk/options.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+
+/* Sample frame data */
+#include "slin_speex_ex.h"
+#include "speex_slin_ex.h"
+
 /* codec variables */
 static int quality = 3;
 static int complexity = 2;
@@ -65,23 +89,6 @@ static float pp_dereverb_level = 0.3;
 #define TYPE_LOW        0x1
 #define TYPE_MASK       0x3
 
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/lock.h"
-#include "asterisk/translate.h"
-#include "asterisk/module.h"
-#include "asterisk/config.h"
-#include "asterisk/options.h"
-#include "asterisk/logger.h"
-#include "asterisk/channel.h"
-#include "asterisk/utils.h"
-
-/* Sample frame data */
-#include "slin_speex_ex.h"
-#include "speex_slin_ex.h"
-
 #define        BUFFER_SAMPLES  8000
 #define        SPEEX_SAMPLES   160
 
@@ -99,17 +106,16 @@ struct speex_coder_pvt {
 };
 
 
-static void *lintospeex_new(struct ast_trans_pvt *pvt)
+static int lintospeex_new(struct ast_trans_pvt *pvt)
 {
        struct speex_coder_pvt *tmp = pvt->pvt;
 
        if (!(tmp->speex = speex_encoder_init(&speex_nb_mode)))
-               return NULL;
+               return -1;
 
        speex_bits_init(&tmp->bits);
        speex_bits_reset(&tmp->bits);
        speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
-       ast_log(LOG_WARNING, "speex framesize is %d\n", tmp->framesize);
        speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
 #ifdef _SPEEX_TYPES_H
        if (preproc) {
@@ -138,20 +144,22 @@ static void *lintospeex_new(struct ast_trans_pvt *pvt)
                speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx); 
        tmp->silent_state = 0;
 
-       return tmp;
+       return 0;
 }
 
-static void *speextolin_new(struct ast_trans_pvt *pvt)
+static int speextolin_new(struct ast_trans_pvt *pvt)
 {
        struct speex_coder_pvt *tmp = pvt->pvt;
        
        if (!(tmp->speex = speex_decoder_init(&speex_nb_mode)))
-               return NULL;
+               return -1;
+
        speex_bits_init(&tmp->bits);
        speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
        if (enhancement)
                speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
-       return tmp;
+
+       return 0;
 }
 
 static struct ast_frame *lintospeex_sample(void)
@@ -215,6 +223,7 @@ static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
                }
 #endif
                pvt->samples += tmp->framesize;
+               pvt->datalen += 2 * tmp->framesize; /* 2 bytes/sample */
                return 0;
        }
 
@@ -269,11 +278,11 @@ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
 #ifdef _SPEEX_TYPES_H
                /* Preprocess audio */
                if (preproc)
-                       is_speech = speex_preprocess(tmp->pp, tmp->buf, NULL);
+                       is_speech = speex_preprocess(tmp->pp, tmp->buf + samples, NULL);
                /* Encode a frame of data */
                if (is_speech) {
                        /* If DTX enabled speex_encode returns 0 during silence */
-                       is_speech = speex_encode_int(tmp->speex, tmp->buf, &tmp->bits) || !dtx;
+                       is_speech = speex_encode_int(tmp->speex, tmp->buf + samples, &tmp->bits) || !dtx;
                } else {
                        /* 5 zeros interpreted by Speex as silence (submode 0) */
                        speex_bits_pack(&tmp->bits, 0, 5);
@@ -284,18 +293,19 @@ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
                        int x;
                        /* Convert to floating point */
                        for (x = 0; x < tmp->framesize; x++)
-                               fbuf[x] = tmp->buf[x];
+                               fbuf[x] = tmp->buf[samples + x];
                        /* Encode a frame of data */
                        is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
                }
 #endif
                samples += tmp->framesize;
                pvt->samples -= tmp->framesize;
-               /* Move the data at the end of the buffer to the front */
-               if (pvt->samples)
-                       memmove(tmp->buf, tmp->buf + tmp->framesize, pvt->samples * 2);
        }
 
+       /* Move the data at the end of the buffer to the front */
+       if (pvt->samples)
+               memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
+
        /* Use AST_FRAME_CNG to signify the start of any silence period */
        if (is_speech) {
                tmp->silent_state = 0;
@@ -337,8 +347,6 @@ static void lintospeex_destroy(struct ast_trans_pvt *arg)
        speex_bits_destroy(&pvt->bits);
 }
 
-static struct ast_module_lock me = { .usecnt = -1 };
-
 static struct ast_translator speextolin = {
        .name = "speextolin", 
        .srcfmt = AST_FORMAT_SPEEX,
@@ -350,7 +358,7 @@ static struct ast_translator speextolin = {
        .desc_size = sizeof(struct speex_coder_pvt),
        .buffer_samples = BUFFER_SAMPLES,
        .buf_size = BUFFER_SAMPLES * 2,
-       .lockp = &me,
+       .native_plc = 1,
 };
 
 static struct ast_translator lintospeex = {
@@ -365,41 +373,39 @@ static struct ast_translator lintospeex = {
        .desc_size = sizeof(struct speex_coder_pvt),
        .buffer_samples = BUFFER_SAMPLES,
        .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
-       .lockp = &me,
 };
 
-
-static void parse_config(void) 
+static int parse_config(int reload) 
 {
-       struct ast_config *cfg = ast_config_load("codecs.conf");
+       struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+       struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
        struct ast_variable *var;
        int res;
        float res_f;
 
-       if (cfg == NULL)
-               return;
+       if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
+               return -1;
+       if (cfg == CONFIG_STATUS_FILEUNCHANGED)
+               return 0;
 
        for (var = ast_variable_browse(cfg, "speex"); var; var = var->next) {
                if (!strcasecmp(var->name, "quality")) {
                        res = abs(atoi(var->value));
                        if (res > -1 && res < 11) {
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
+                               ast_verb(3, "CODEC SPEEX: Setting Quality to %d\n",res);
                                quality = res;
                        } else 
                                ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
                } else if (!strcasecmp(var->name, "complexity")) {
                        res = abs(atoi(var->value));
                        if (res > -1 && res < 11) {
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
+                               ast_verb(3, "CODEC SPEEX: Setting Complexity to %d\n",res);
                                complexity = res;
                        } else 
                                ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
                } else if (!strcasecmp(var->name, "vbr_quality")) {
                        if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
+                               ast_verb(3, "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
                                vbr_quality = res_f;
                        } else
                                ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
@@ -407,128 +413,100 @@ static void parse_config(void)
                        ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
                } else if (!strcasecmp(var->name, "enhancement")) {
                        enhancement = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
                } else if (!strcasecmp(var->name, "vbr")) {
                        vbr = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
                } else if (!strcasecmp(var->name, "abr")) {
                        res = abs(atoi(var->value));
                        if (res >= 0) {
-                               if (option_verbose > 2) {
                                        if (res > 0)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
+                                       ast_verb(3, "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
                                        else
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Disabling ABR\n");
-                               }
+                                       ast_verb(3, "CODEC SPEEX: Disabling ABR\n");
                                abr = res;
                        } else 
                                ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
                } else if (!strcasecmp(var->name, "vad")) {
                        vad = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
                } else if (!strcasecmp(var->name, "dtx")) {
                        dtx = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
                } else if (!strcasecmp(var->name, "preprocess")) {
                        preproc = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
                } else if (!strcasecmp(var->name, "pp_vad")) {
                        pp_vad = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
                } else if (!strcasecmp(var->name, "pp_agc")) {
                        pp_agc = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
                } else if (!strcasecmp(var->name, "pp_agc_level")) {
                        if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
+                               ast_verb(3, "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
                                pp_agc_level = res_f;
                        } else
                                ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
                } else if (!strcasecmp(var->name, "pp_denoise")) {
                        pp_denoise = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
                } else if (!strcasecmp(var->name, "pp_dereverb")) {
                        pp_dereverb = ast_true(var->value) ? 1 : 0;
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
+                       ast_verb(3, "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
                } else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
                        if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
+                               ast_verb(3, "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
                                pp_dereverb_decay = res_f;
                        } else
                                ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
                } else if (!strcasecmp(var->name, "pp_dereverb_level")) {
                        if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
-                               if (option_verbose > 2)
-                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
+                               ast_verb(3, "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
                                pp_dereverb_level = res_f;
                        } else
                                ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
                }
        }
        ast_config_destroy(cfg);
+       return 0;
 }
 
-int reload(void) 
+static int reload(void) 
 {
-       /*
-        * XXX reloading while there are active sessions is
-        * somewhat silly because the old state presumably
-        * wouldn't work anymore...
-        * maybe we shuld do a standard hangup localusers ?
-        */
-       ast_mutex_lock(&me.lock);
-       parse_config();
-       ast_mutex_lock(&me.lock);
-       return 0;
+       if (parse_config(1))
+               return AST_MODULE_LOAD_DECLINE;
+       return AST_MODULE_LOAD_SUCCESS;
 }
 
-int unload_module(void)
+static int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&me.lock);
+
        res = ast_unregister_translator(&lintospeex);
-       if (!res)
-               res = ast_unregister_translator(&speextolin);
-       if (me.usecnt)
-               res = -1;
-       ast_mutex_unlock(&me.lock);
+       res |= ast_unregister_translator(&speextolin);
+
        return res;
 }
 
-int load_module(void)
+static int load_module(void)
 {
        int res;
-       parse_config();
+
+       if (parse_config(0))
+               return AST_MODULE_LOAD_DECLINE;
        res=ast_register_translator(&speextolin);
        if (!res) 
                res=ast_register_translator(&lintospeex);
        else
                ast_unregister_translator(&speextolin);
-       return res;
+       if (res)
+               return AST_MODULE_LOAD_FAILURE;
+       return AST_MODULE_LOAD_SUCCESS;
 }
 
-char *description(void)
-{
-       return "Speex/PCM16 (signed linear) Codec Translator";
-}
-
-int usecount(void)
-{
-       return me.usecnt;
-}
-
-char *key()
-{
-       return ASTERISK_GPL_KEY;
-}
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder",
+               .load = load_module,
+               .unload = unload_module,
+               .reload = reload,
+              );