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