source: mediastreamer2/linphone/mediastreamer2/src/speexec.c @ 588:3ee4ac390aaf

Last change on this file since 588:3ee4ac390aaf was 528:4561e35b1e8e, checked in by smorlat <smorlat@…>, 4 years ago

fix indentation.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@518 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 9.7 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#include "mediastreamer2/msfilter.h"
21
22#include <speex/speex_echo.h>
23#include <speex/speex_preprocess.h>
24
25#ifdef HAVE_CONFIG_H
26#include "mediastreamer-config.h"
27#endif
28
29#ifdef WIN32
30#include <malloc.h> /* for alloca */
31#endif
32
33static const int framesize=128;
34static const int filter_length=2048; /*250 ms*/
35
36typedef struct SpeexECState{
37        SpeexEchoState *ecstate;
38        MSBufferizer speak_delay;
39        int size_delay;
40        int playback_delay;
41        MSBufferizer in[2];
42        int framesize;
43        int filterlength;
44        int samplerate;
45        SpeexPreprocessState *den;
46        int ref;
47        int echo;
48        int out;
49}SpeexECState;
50
51static void speex_ec_init(MSFilter *f){
52        SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1);
53
54        s->samplerate=8000;
55        s->framesize=framesize;
56        s->filterlength=filter_length;
57
58        ms_bufferizer_init(&s->speak_delay);
59        s->size_delay=0;
60        s->playback_delay=0;
61
62        ms_bufferizer_init(&s->in[0]);
63        ms_bufferizer_init(&s->in[1]);
64        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
65        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
66        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
67        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
68
69        f->data=s;
70}
71
72static void speex_ec_uninit(MSFilter *f){
73        SpeexECState *s=(SpeexECState*)f->data;
74        ms_bufferizer_uninit(&s->speak_delay);
75        ms_bufferizer_uninit(&s->in[0]);
76        ms_bufferizer_uninit(&s->in[1]);
77        speex_echo_state_destroy(s->ecstate);
78        if (s->den!=NULL)
79          speex_preprocess_state_destroy(s->den);
80
81        ms_free(s);
82}
83
84/*      inputs[0]= reference signal (sent to soundcard)
85        inputs[1]= echo signal  (read from soundcard)
86*/
87
88
89static void speex_ec_process(MSFilter *f){
90        SpeexECState *s=(SpeexECState*)f->data;
91        int nbytes=s->framesize*2;
92        uint8_t *in1;
93        mblk_t *om0,*om1;
94#ifdef AMD_WIN32_HACK
95        static int count=0;
96#endif
97        mblk_t *m;
98        mblk_t *md;     
99
100        if (s->size_delay<s->playback_delay){
101                while((m=ms_queue_get(f->inputs[0]))!=NULL && s->size_delay<s->playback_delay){
102                        // Duplicate queue : one to write to the output speaker, the other will be delayed for AEC
103                        int size=msgdsize(m);
104                        md = copyb(m);
105                        s->size_delay = s->size_delay + size;
106                        ms_bufferizer_put(&s->speak_delay,md);
107                        ms_bufferizer_put(&s->in[0],m);
108                }
109
110                if (s->size_delay<s->playback_delay)
111                {
112                        /* make sure we always send block with same size */
113                        while (ms_bufferizer_get_avail(&s->speak_delay)>=nbytes)
114                        {
115                                om0=allocb(nbytes,0);
116                                ms_bufferizer_read(&s->speak_delay,(uint8_t*)om0->b_wptr,nbytes);
117                                om0->b_wptr+=nbytes;
118                                ms_queue_put(f->outputs[0],om0);
119                        }
120
121                        /* make sure we always send block with same size */
122                        ms_bufferizer_put_from_queue(&s->in[1],f->inputs[1]);
123                        while (ms_bufferizer_get_avail(&s->in[1])>=nbytes)
124                        {
125                                om0=allocb(nbytes,0);
126                                ms_bufferizer_read(&s->in[1],(uint8_t*)om0->b_wptr,nbytes);
127                                om0->b_wptr+=nbytes;
128                                ms_queue_put(f->outputs[1],om0);
129                        }
130                        /* we are now equal and speaker is delayed */
131                        return;
132                }
133        }
134
135        ms_bufferizer_put_from_queue(&s->in[1],f->inputs[1]);
136
137        /*read input and put in bufferizers*/
138        while((m=ms_queue_get(f->inputs[0]))!=NULL){
139                md = copyb(m);
140                // Duplicate queue : one to write to the output speaker, the other will be delayed for AEC
141                ms_bufferizer_put(&s->in[0],m);
142                ms_bufferizer_put(&s->speak_delay,md); 
143        }
144       
145
146        in1=(uint8_t*)alloca(nbytes);
147
148        //ms_debug("speexec:  in0=%i, in1=%i",ms_bufferizer_get_avail(&s->in[0]),ms_bufferizer_get_avail(&s->in[1]));
149
150        while (ms_bufferizer_get_avail(&s->speak_delay)>=nbytes && ms_bufferizer_get_avail(&s->in[1])>=nbytes){
151                om0=allocb(nbytes,0);
152                ms_bufferizer_read(&s->speak_delay,(uint8_t*)om0->b_wptr,nbytes);
153                om0->b_wptr+=nbytes;
154                ms_queue_put(f->outputs[0],om0);
155
156                om0=allocb(nbytes,0);
157                ms_bufferizer_read(&s->in[0],(uint8_t*)om0->b_wptr,nbytes);
158                /* we have reference signal */
159                /* the reference signal is sent through outputs[0]*/
160               
161                om0->b_wptr+=nbytes;
162                //ms_queue_put(f->outputs[0],om0);
163
164                ms_bufferizer_read(&s->in[1],in1,nbytes);
165                /* we have echo signal */
166                om1=allocb(nbytes,0);
167                speex_echo_cancel(s->ecstate,(short*)in1,(short*)om0->b_rptr,(short*)om1->b_wptr,NULL);
168                speex_preprocess_run(s->den, (short*)om1->b_wptr);
169                ms_filter_notify(f, MS_SPEEX_EC_ECHO_STATE, (void*)s->ecstate);
170                ms_filter_notify(f, MS_SPEEX_EC_PREPROCESS_MIC, (void*)s->den);
171
172                om1->b_wptr+=nbytes;
173                ms_queue_put(f->outputs[1],om1);
174#ifdef AMD_WIN32_HACK
175                count++;
176                if (count==100*3)
177                {
178                        ms_message("periodic reset of echo canceller.");
179                        speex_echo_state_reset(s->ecstate);
180                        count=0;
181                }               
182#endif
183                freeb(om0);
184        }
185
186        if (ms_bufferizer_get_avail(&s->speak_delay)> 5*320*(s->samplerate/8000)) /* above 4*20ms -> useless */
187        {
188                /* reset evrything */
189                ms_warning("speexec: -reset of echo canceller- in0=%i, in1=%i",ms_bufferizer_get_avail(&s->in[0]),ms_bufferizer_get_avail(&s->in[1]));
190                flushq(&s->in[1].q,0);
191                flushq(&s->in[0].q,0);
192                flushq(&s->speak_delay.q,0);
193                ms_bufferizer_init(&s->in[0]);
194                ms_bufferizer_init(&s->in[1]);
195                ms_bufferizer_init(&s->speak_delay);
196                s->size_delay=0;
197                speex_echo_state_reset(s->ecstate);
198        }
199
200        while (ms_bufferizer_get_avail(&s->in[1])> 5*320*(s->samplerate/8000)){
201                om1=allocb(nbytes,0);
202                ms_bufferizer_read(&s->in[1],(uint8_t*)om1->b_wptr,nbytes);
203                om1->b_wptr+=nbytes;
204                ms_queue_put(f->outputs[1],om1);
205                ms_message("too much echo signal, sending anyway.");
206                speex_echo_state_reset(s->ecstate);
207        }
208       
209}
210
211static void speex_ec_postprocess(MSFilter *f){
212        SpeexECState *s=(SpeexECState*)f->data;
213        flushq(&s->in[1].q,0);
214        flushq(&s->in[0].q,0);
215        flushq(&s->speak_delay.q,0);
216        ms_bufferizer_init(&s->in[0]);
217        ms_bufferizer_init(&s->in[1]);
218        ms_bufferizer_init(&s->speak_delay);
219        s->size_delay=0;
220
221        if (s->ecstate!=NULL)
222                speex_echo_state_destroy(s->ecstate);
223        if (s->den!=NULL)
224          speex_preprocess_state_destroy(s->den);
225
226        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength*(s->samplerate/8000));
227        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
228        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
229        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
230}
231
232static int speex_ec_set_sr(MSFilter *f, void *arg){
233        SpeexECState *s=(SpeexECState*)f->data;
234
235        s->samplerate = *(int*)arg;
236
237        if (s->ecstate!=NULL)
238                speex_echo_state_destroy(s->ecstate);
239        if (s->den!=NULL)
240          speex_preprocess_state_destroy(s->den);
241
242        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength*(s->samplerate/8000));
243        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
244        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
245        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
246        return 0;
247}
248
249static int speex_ec_set_framesize(MSFilter *f, void *arg){
250        SpeexECState *s=(SpeexECState*)f->data;
251        s->framesize = *(int*)arg;
252
253        if (s->ecstate!=NULL)
254                speex_echo_state_destroy(s->ecstate);
255        if (s->den!=NULL)
256          speex_preprocess_state_destroy(s->den);
257
258        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength*(s->samplerate/8000));
259        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
260        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
261        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
262        return 0;
263}
264
265static int speex_ec_set_filterlength(MSFilter *f, void *arg){
266        SpeexECState *s=(SpeexECState*)f->data;
267        s->filterlength = *(int*)arg;
268
269        if (s->ecstate!=NULL)
270                speex_echo_state_destroy(s->ecstate);
271        if (s->den!=NULL)
272          speex_preprocess_state_destroy(s->den);
273
274        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength*(s->samplerate/8000));
275        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
276        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
277        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
278        return 0;
279}
280
281static int speex_ec_set_playbackdelay(MSFilter *f, void *arg){
282        SpeexECState *s=(SpeexECState*)f->data; 
283        s->playback_delay = *(int*)arg;
284
285        flushq(&s->in[1].q,0);
286        flushq(&s->in[0].q,0);
287        flushq(&s->speak_delay.q,0);
288        ms_bufferizer_init(&s->in[0]);
289        ms_bufferizer_init(&s->in[1]);
290        ms_bufferizer_init(&s->speak_delay);
291        s->size_delay=0;
292        speex_echo_state_reset(s->ecstate);
293        return 0;
294}
295
296static MSFilterMethod speex_ec_methods[]={
297        {       MS_FILTER_SET_SAMPLE_RATE, speex_ec_set_sr },
298        {       MS_FILTER_SET_FRAMESIZE, speex_ec_set_framesize },
299        {       MS_FILTER_SET_FILTERLENGTH, speex_ec_set_filterlength },
300        {       MS_FILTER_SET_PLAYBACKDELAY, speex_ec_set_playbackdelay },
301        {       0                       , NULL}
302};
303
304#ifdef _MSC_VER
305
306MSFilterDesc ms_speex_ec_desc={
307        MS_SPEEX_EC_ID,
308        "MSSpeexEC",
309        N_("Echo canceler using speex library"),
310        MS_FILTER_OTHER,
311        NULL,
312        2,
313        2,
314        speex_ec_init,
315        NULL,
316        speex_ec_process,
317        speex_ec_postprocess,
318        speex_ec_uninit,
319        speex_ec_methods
320};
321
322#else
323
324MSFilterDesc ms_speex_ec_desc={
325        .id=MS_SPEEX_EC_ID,
326        .name="MSSpeexEC",
327        .text=N_("Echo canceler using speex library"),
328        .category=MS_FILTER_OTHER,
329        .ninputs=2,
330        .noutputs=2,
331        .init=speex_ec_init,
332        .process=speex_ec_process,
333        .postprocess=speex_ec_postprocess,
334        .uninit=speex_ec_uninit,
335        .methods=speex_ec_methods
336};
337
338#endif
339
340MS_FILTER_DESC_EXPORT(ms_speex_ec_desc)
Note: See TracBrowser for help on using the repository browser.