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