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