build_tools: Fix download_externals to handle certified branches
[asterisk/asterisk.git] / codecs / codec_speex.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*! \file
21  *
22  * \brief Translate between signed linear and Speex (Open Codec)
23  *
24  * \note This work was motivated by Jeremy McNamara 
25  * hacked to be configurable by anthm and bkw 9/28/2004
26  *
27  * \ingroup codecs
28  *
29  * The Speex library - http://www.speex.org
30  *
31  */
32
33 /*** MODULEINFO
34         <depend>speex</depend>
35         <depend>speex_preprocess</depend>
36         <use type="external">speexdsp</use>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 #include <speex/speex.h>
43
44 /* We require a post 1.1.8 version of Speex to enable preprocessing
45  * and better type handling
46  */   
47 #ifdef _SPEEX_TYPES_H
48 #include <speex/speex_preprocess.h>
49 #endif
50
51 #include "asterisk/translate.h"
52 #include "asterisk/module.h"
53 #include "asterisk/config.h"
54 #include "asterisk/utils.h"
55 #include "asterisk/frame.h"
56 #include "asterisk/linkedlists.h"
57
58 /* codec variables */
59 static int quality = 3;
60 static int complexity = 2;
61 static int enhancement = 0;
62 static int vad = 0;
63 static int vbr = 0;
64 static float vbr_quality = 4;
65 static int abr = 0;
66 static int dtx = 0;     /* set to 1 to enable silence detection */
67
68 static int preproc = 0;
69 static int pp_vad = 0;
70 static int pp_agc = 0;
71 static float pp_agc_level = 8000; /* XXX what is this 8000 ? */
72 static int pp_denoise = 0;
73 static int pp_dereverb = 0;
74 static float pp_dereverb_decay = 0.4;
75 static float pp_dereverb_level = 0.3;
76
77 #define TYPE_SILENCE     0x2
78 #define TYPE_HIGH        0x0
79 #define TYPE_LOW         0x1
80 #define TYPE_MASK        0x3
81
82 #define BUFFER_SAMPLES  8000
83 #define SPEEX_SAMPLES   160
84
85 /* Sample frame data */
86 #include "asterisk/slin.h"
87 #include "ex_speex.h"
88
89 struct speex_coder_pvt {
90         void *speex;
91         SpeexBits bits;
92         int framesize;
93         int silent_state;
94 #ifdef _SPEEX_TYPES_H
95         SpeexPreprocessState *pp;
96         spx_int16_t buf[BUFFER_SAMPLES];
97 #else
98         int16_t buf[BUFFER_SAMPLES];    /* input, waiting to be compressed */
99 #endif
100 };
101
102 static int speex_encoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile, int sampling_rate)
103 {
104         struct speex_coder_pvt *tmp = pvt->pvt;
105
106         if (!(tmp->speex = speex_encoder_init(profile)))
107                 return -1;
108
109         speex_bits_init(&tmp->bits);
110         speex_bits_reset(&tmp->bits);
111         speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
112         speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
113 #ifdef _SPEEX_TYPES_H
114         if (preproc) {
115                 tmp->pp = speex_preprocess_state_init(tmp->framesize, sampling_rate);
116                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
117                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
118                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
119                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DENOISE, &pp_denoise);
120                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB, &pp_dereverb);
121                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &pp_dereverb_decay);
122                 speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &pp_dereverb_level);
123         }
124 #endif
125         if (!abr && !vbr) {
126                 speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
127                 if (vad)
128                         speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
129         }
130         if (vbr) {
131                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
132                 speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
133         }
134         if (abr)
135                 speex_encoder_ctl(tmp->speex, SPEEX_SET_ABR, &abr);
136         if (dtx)
137                 speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx); 
138         tmp->silent_state = 0;
139
140         return 0;
141 }
142
143 static int lintospeex_new(struct ast_trans_pvt *pvt)
144 {
145         return speex_encoder_construct(pvt, &speex_nb_mode, 8000);
146 }
147
148 static int lin16tospeexwb_new(struct ast_trans_pvt *pvt)
149 {
150         return speex_encoder_construct(pvt, &speex_wb_mode, 16000);
151 }
152
153 static int lin32tospeexuwb_new(struct ast_trans_pvt *pvt)
154 {
155         return speex_encoder_construct(pvt, &speex_uwb_mode, 32000);
156 }
157
158 static int speex_decoder_construct(struct ast_trans_pvt *pvt, const SpeexMode *profile)
159 {
160         struct speex_coder_pvt *tmp = pvt->pvt;
161         
162         if (!(tmp->speex = speex_decoder_init(profile)))
163                 return -1;
164
165         speex_bits_init(&tmp->bits);
166         speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
167         if (enhancement)
168                 speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
169
170         return 0;
171 }
172
173 static int speextolin_new(struct ast_trans_pvt *pvt)
174 {
175         return speex_decoder_construct(pvt, &speex_nb_mode);
176 }
177
178 static int speexwbtolin16_new(struct ast_trans_pvt *pvt)
179 {
180         return speex_decoder_construct(pvt, &speex_wb_mode);
181 }
182
183 static int speexuwbtolin32_new(struct ast_trans_pvt *pvt)
184 {
185         return speex_decoder_construct(pvt, &speex_uwb_mode);
186 }
187
188 /*! \brief convert and store into outbuf */
189 static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
190 {
191         struct speex_coder_pvt *tmp = pvt->pvt;
192
193         /* Assuming there's space left, decode into the current buffer at
194            the tail location.  Read in as many frames as there are */
195         int x;
196         int res;
197         int16_t *dst = pvt->outbuf.i16;
198         /* XXX fout is a temporary buffer, may have different types */
199 #ifdef _SPEEX_TYPES_H
200         spx_int16_t fout[1024];
201 #else
202         float fout[1024];
203 #endif
204
205         if (f->datalen == 0) {  /* Native PLC interpolation */
206                 if (pvt->samples + tmp->framesize > BUFFER_SAMPLES) {
207                         ast_log(LOG_WARNING, "Out of buffer space\n");
208                         return -1;
209                 }
210 #ifdef _SPEEX_TYPES_H
211                 speex_decode_int(tmp->speex, NULL, dst + pvt->samples);
212 #else
213                 speex_decode(tmp->speex, NULL, fout);
214                 for (x=0;x<tmp->framesize;x++) {
215                         dst[pvt->samples + x] = (int16_t)fout[x];
216                 }
217 #endif
218                 pvt->samples += tmp->framesize;
219                 pvt->datalen += 2 * tmp->framesize; /* 2 bytes/sample */
220                 return 0;
221         }
222
223         /* Read in bits */
224         speex_bits_read_from(&tmp->bits, f->data.ptr, f->datalen);
225         for (;;) {
226 #ifdef _SPEEX_TYPES_H
227                 res = speex_decode_int(tmp->speex, &tmp->bits, fout);
228 #else
229                 res = speex_decode(tmp->speex, &tmp->bits, fout);
230 #endif
231                 if (res < 0)
232                         break;
233                 if (pvt->samples + tmp->framesize > BUFFER_SAMPLES) {
234                         ast_log(LOG_WARNING, "Out of buffer space\n");
235                         return -1;
236                 }
237                 for (x = 0 ; x < tmp->framesize; x++)
238                         dst[pvt->samples + x] = (int16_t)fout[x];
239                 pvt->samples += tmp->framesize;
240                 pvt->datalen += 2 * tmp->framesize; /* 2 bytes/sample */
241         }
242         return 0;
243 }
244
245 /*! \brief store input frame in work buffer */
246 static int lintospeex_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
247 {
248         struct speex_coder_pvt *tmp = pvt->pvt;
249
250         /* XXX We should look at how old the rest of our stream is, and if it
251            is too old, then we should overwrite it entirely, otherwise we can
252            get artifacts of earlier talk that do not belong */
253         memcpy(tmp->buf + pvt->samples, f->data.ptr, f->datalen);
254         pvt->samples += f->samples;
255         return 0;
256 }
257
258 /*! \brief convert work buffer and produce output frame */
259 static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
260 {
261         struct speex_coder_pvt *tmp = pvt->pvt;
262         struct ast_frame *result = NULL;
263         struct ast_frame *last = NULL;
264         int samples = 0; /* output samples */
265
266         while (pvt->samples >= tmp->framesize) {
267                 struct ast_frame *current;
268                 int is_speech = 1;
269
270                 speex_bits_reset(&tmp->bits);
271
272 #ifdef _SPEEX_TYPES_H
273                 /* Preprocess audio */
274                 if (preproc)
275                         is_speech = speex_preprocess(tmp->pp, tmp->buf + samples, NULL);
276                 /* Encode a frame of data */
277                 if (is_speech) {
278                         /* If DTX enabled speex_encode returns 0 during silence */
279                         is_speech = speex_encode_int(tmp->speex, tmp->buf + samples, &tmp->bits) || !dtx;
280                 } else {
281                         /* 5 zeros interpreted by Speex as silence (submode 0) */
282                         speex_bits_pack(&tmp->bits, 0, 5);
283                 }
284 #else
285                 {
286                         float fbuf[1024];
287                         int x;
288                         /* Convert to floating point */
289                         for (x = 0; x < tmp->framesize; x++)
290                                 fbuf[x] = tmp->buf[samples + x];
291                         /* Encode a frame of data */
292                         is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
293                 }
294 #endif
295                 samples += tmp->framesize;
296                 pvt->samples -= tmp->framesize;
297
298                 /* Use AST_FRAME_CNG to signify the start of any silence period */
299                 if (is_speech) {
300                         int datalen = 0; /* output bytes */
301
302                         tmp->silent_state = 0;
303                         /* Terminate bit stream */
304                         speex_bits_pack(&tmp->bits, 15, 5);
305                         datalen = speex_bits_write(&tmp->bits, pvt->outbuf.c, pvt->t->buf_size);
306                         current = ast_trans_frameout(pvt, datalen, tmp->framesize);
307                 } else if (tmp->silent_state) {
308                         current = NULL;
309                 } else {
310                         struct ast_frame frm = {
311                                 .frametype = AST_FRAME_CNG,
312                                 .src = pvt->t->name,
313                         };
314
315                         /*
316                          * XXX I don't think the AST_FRAME_CNG code has ever
317                          * really worked for speex.  There doesn't seem to be
318                          * any consumers of the frame type.  Everyone that
319                          * references the type seems to pass the frame on.
320                          */
321                         tmp->silent_state = 1;
322
323                         /* XXX what now ? format etc... */
324                         current = ast_frisolate(&frm);
325                 }
326
327                 if (!current) {
328                         continue;
329                 } else if (last) {
330                         AST_LIST_NEXT(last, frame_list) = current;
331                 } else {
332                         result = current;
333                 }
334                 last = current;
335         }
336
337         /* Move the data at the end of the buffer to the front */
338         if (samples) {
339                 memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
340         }
341
342         return result;
343 }
344
345 static void speextolin_destroy(struct ast_trans_pvt *arg)
346 {
347         struct speex_coder_pvt *pvt = arg->pvt;
348
349         speex_decoder_destroy(pvt->speex);
350         speex_bits_destroy(&pvt->bits);
351 }
352
353 static void lintospeex_destroy(struct ast_trans_pvt *arg)
354 {
355         struct speex_coder_pvt *pvt = arg->pvt;
356 #ifdef _SPEEX_TYPES_H
357         if (preproc)
358                 speex_preprocess_state_destroy(pvt->pp);
359 #endif
360         speex_encoder_destroy(pvt->speex);
361         speex_bits_destroy(&pvt->bits);
362 }
363
364 static struct ast_translator speextolin = {
365         .name = "speextolin",
366         .src_codec = {
367                 .name = "speex",
368                 .type = AST_MEDIA_TYPE_AUDIO,
369                 .sample_rate = 8000,
370         },
371         .dst_codec = {
372                 .name = "slin",
373                 .type = AST_MEDIA_TYPE_AUDIO,
374                 .sample_rate = 8000,
375         },
376         .format = "slin",
377         .newpvt = speextolin_new,
378         .framein = speextolin_framein,
379         .destroy = speextolin_destroy,
380         .sample = speex_sample,
381         .desc_size = sizeof(struct speex_coder_pvt),
382         .buffer_samples = BUFFER_SAMPLES,
383         .buf_size = BUFFER_SAMPLES * 2,
384         .native_plc = 1,
385 };
386
387 static struct ast_translator lintospeex = {
388         .name = "lintospeex", 
389         .src_codec = {
390                 .name = "slin",
391                 .type = AST_MEDIA_TYPE_AUDIO,
392                 .sample_rate = 8000,
393         },
394         .dst_codec = {
395                 .name = "speex",
396                 .type = AST_MEDIA_TYPE_AUDIO,
397                 .sample_rate = 8000,
398         },
399         .format = "speex",
400         .newpvt = lintospeex_new,
401         .framein = lintospeex_framein,
402         .frameout = lintospeex_frameout,
403         .destroy = lintospeex_destroy,
404         .sample = slin8_sample,
405         .desc_size = sizeof(struct speex_coder_pvt),
406         .buffer_samples = BUFFER_SAMPLES,
407         .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
408 };
409
410 static struct ast_translator speexwbtolin16 = {
411         .name = "speexwbtolin16",
412         .src_codec = {
413                 .name = "speex",
414                 .type = AST_MEDIA_TYPE_AUDIO,
415                 .sample_rate = 16000,
416         },
417         .dst_codec = {
418                 .name = "slin",
419                 .type = AST_MEDIA_TYPE_AUDIO,
420                 .sample_rate = 16000,
421         }, 
422         .format = "slin16",
423         .newpvt = speexwbtolin16_new,
424         .framein = speextolin_framein,
425         .destroy = speextolin_destroy,
426         .sample = speex16_sample,
427         .desc_size = sizeof(struct speex_coder_pvt),
428         .buffer_samples = BUFFER_SAMPLES,
429         .buf_size = BUFFER_SAMPLES * 2,
430         .native_plc = 1,
431 };
432
433 static struct ast_translator lin16tospeexwb = {
434         .name = "lin16tospeexwb",
435         .src_codec = {
436                 .name = "slin",
437                 .type = AST_MEDIA_TYPE_AUDIO,
438                 .sample_rate = 16000,
439         },
440         .dst_codec = {
441                 .name = "speex",
442                 .type = AST_MEDIA_TYPE_AUDIO,
443                 .sample_rate = 16000,
444         },
445         .format = "speex16",
446         .newpvt = lin16tospeexwb_new,
447         .framein = lintospeex_framein,
448         .frameout = lintospeex_frameout,
449         .destroy = lintospeex_destroy,
450         .sample = slin16_sample,
451         .desc_size = sizeof(struct speex_coder_pvt),
452         .buffer_samples = BUFFER_SAMPLES,
453         .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
454 };
455
456 static struct ast_translator speexuwbtolin32 = {
457         .name = "speexuwbtolin32",
458         .src_codec = {
459                 .name = "speex",
460                 .type = AST_MEDIA_TYPE_AUDIO,
461                 .sample_rate = 32000,
462         },
463         .dst_codec = {
464                 .name = "slin",
465                 .type = AST_MEDIA_TYPE_AUDIO,
466                 .sample_rate = 32000,
467         },
468         .format = "slin32",
469         .newpvt = speexuwbtolin32_new,
470         .framein = speextolin_framein,
471         .destroy = speextolin_destroy,
472         .desc_size = sizeof(struct speex_coder_pvt),
473         .buffer_samples = BUFFER_SAMPLES,
474         .buf_size = BUFFER_SAMPLES * 2,
475         .native_plc = 1,
476 };
477
478 static struct ast_translator lin32tospeexuwb = {
479         .name = "lin32tospeexuwb",
480         .src_codec = {
481                 .name = "slin",
482                 .type = AST_MEDIA_TYPE_AUDIO,
483                 .sample_rate = 32000,
484         },
485         .dst_codec = {
486                 .name = "speex",
487                 .type = AST_MEDIA_TYPE_AUDIO,
488                 .sample_rate = 32000,
489         },
490         .format = "speex32",
491         .newpvt = lin32tospeexuwb_new,
492         .framein = lintospeex_framein,
493         .frameout = lintospeex_frameout,
494         .destroy = lintospeex_destroy,
495         .desc_size = sizeof(struct speex_coder_pvt),
496         .buffer_samples = BUFFER_SAMPLES,
497         .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
498 };
499
500 static int parse_config(int reload) 
501 {
502         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
503         struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
504         struct ast_variable *var;
505         int res;
506         float res_f;
507
508         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
509                 return 0;
510
511         for (var = ast_variable_browse(cfg, "speex"); var; var = var->next) {
512                 if (!strcasecmp(var->name, "quality")) {
513                         res = abs(atoi(var->value));
514                         if (res > -1 && res < 11) {
515                                 ast_verb(3, "CODEC SPEEX: Setting Quality to %d\n",res);
516                                 quality = res;
517                         } else 
518                                 ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
519                 } else if (!strcasecmp(var->name, "complexity")) {
520                         res = abs(atoi(var->value));
521                         if (res > -1 && res < 11) {
522                                 ast_verb(3, "CODEC SPEEX: Setting Complexity to %d\n",res);
523                                 complexity = res;
524                         } else 
525                                 ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
526                 } else if (!strcasecmp(var->name, "vbr_quality")) {
527                         if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
528                                 ast_verb(3, "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
529                                 vbr_quality = res_f;
530                         } else
531                                 ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
532                 } else if (!strcasecmp(var->name, "abr_quality")) {
533                         ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
534                 } else if (!strcasecmp(var->name, "enhancement")) {
535                         enhancement = ast_true(var->value) ? 1 : 0;
536                         ast_verb(3, "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
537                 } else if (!strcasecmp(var->name, "vbr")) {
538                         vbr = ast_true(var->value) ? 1 : 0;
539                         ast_verb(3, "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
540                 } else if (!strcasecmp(var->name, "abr")) {
541                         res = abs(atoi(var->value));
542                         if (res >= 0) {
543                                         if (res > 0)
544                                         ast_verb(3, "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
545                                         else
546                                         ast_verb(3, "CODEC SPEEX: Disabling ABR\n");
547                                 abr = res;
548                         } else 
549                                 ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
550                 } else if (!strcasecmp(var->name, "vad")) {
551                         vad = ast_true(var->value) ? 1 : 0;
552                         ast_verb(3, "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
553                 } else if (!strcasecmp(var->name, "dtx")) {
554                         dtx = ast_true(var->value) ? 1 : 0;
555                         ast_verb(3, "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
556                 } else if (!strcasecmp(var->name, "preprocess")) {
557                         preproc = ast_true(var->value) ? 1 : 0;
558                         ast_verb(3, "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
559                 } else if (!strcasecmp(var->name, "pp_vad")) {
560                         pp_vad = ast_true(var->value) ? 1 : 0;
561                         ast_verb(3, "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
562                 } else if (!strcasecmp(var->name, "pp_agc")) {
563                         pp_agc = ast_true(var->value) ? 1 : 0;
564                         ast_verb(3, "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
565                 } else if (!strcasecmp(var->name, "pp_agc_level")) {
566                         if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0) {
567                                 ast_verb(3, "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
568                                 pp_agc_level = res_f;
569                         } else
570                                 ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
571                 } else if (!strcasecmp(var->name, "pp_denoise")) {
572                         pp_denoise = ast_true(var->value) ? 1 : 0;
573                         ast_verb(3, "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
574                 } else if (!strcasecmp(var->name, "pp_dereverb")) {
575                         pp_dereverb = ast_true(var->value) ? 1 : 0;
576                         ast_verb(3, "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
577                 } else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
578                         if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0) {
579                                 ast_verb(3, "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
580                                 pp_dereverb_decay = res_f;
581                         } else
582                                 ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
583                 } else if (!strcasecmp(var->name, "pp_dereverb_level")) {
584                         if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0) {
585                                 ast_verb(3, "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
586                                 pp_dereverb_level = res_f;
587                         } else
588                                 ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
589                 }
590         }
591         ast_config_destroy(cfg);
592         return 0;
593 }
594
595 static int reload(void) 
596 {
597         if (parse_config(1))
598                 return AST_MODULE_LOAD_DECLINE;
599         return AST_MODULE_LOAD_SUCCESS;
600 }
601
602 static int unload_module(void)
603 {
604         int res = 0;
605
606         res |= ast_unregister_translator(&speextolin);
607         res |= ast_unregister_translator(&lintospeex);
608         res |= ast_unregister_translator(&speexwbtolin16);
609         res |= ast_unregister_translator(&lin16tospeexwb);
610         res |= ast_unregister_translator(&speexuwbtolin32);
611         res |= ast_unregister_translator(&lin32tospeexuwb);
612
613
614         return res;
615 }
616
617 static int load_module(void)
618 {
619         int res = 0;
620
621         if (parse_config(0))
622                 return AST_MODULE_LOAD_DECLINE;
623
624         res |= ast_register_translator(&speextolin);
625         res |= ast_register_translator(&lintospeex);
626         res |= ast_register_translator(&speexwbtolin16);
627         res |= ast_register_translator(&lin16tospeexwb);
628         res |= ast_register_translator(&speexuwbtolin32);
629         res |= ast_register_translator(&lin32tospeexuwb);
630
631         if (res) {
632                 unload_module();
633                 return res;
634         }
635
636         return res;
637 }
638
639 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder",
640         .support_level = AST_MODULE_SUPPORT_CORE,
641         .load = load_module,
642         .unload = unload_module,
643         .reload = reload,
644 );