source: mediastreamer2/linphone/mediastreamer2/src/speexec.c @ 0:5a6e836a86a3

Last change on this file since 0:5a6e836a86a3 was 0:5a6e836a86a3, checked in by aymeric <aymeric@…>, 5 years ago

Initial import

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

File size: 6.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 in[2];
39        int framesize;
40        int filterlength;
41        int samplerate;
42        SpeexPreprocessState *den;
43        int ref;
44        int echo;
45        int out;
46}SpeexECState;
47
48static void speex_ec_init(MSFilter *f){
49        SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1);
50
51        s->samplerate=8000;
52        s->framesize=framesize;
53        s->filterlength=filter_length;
54
55        ms_bufferizer_init(&s->in[0]);
56        ms_bufferizer_init(&s->in[1]);
57        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
58        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
59
60        f->data=s;
61}
62
63static void speex_ec_uninit(MSFilter *f){
64        SpeexECState *s=(SpeexECState*)f->data;
65        ms_bufferizer_uninit(&s->in[0]);
66        ms_bufferizer_uninit(&s->in[1]);
67        speex_echo_state_destroy(s->ecstate);
68        if (s->den!=NULL)
69          speex_preprocess_state_destroy(s->den);
70
71        ms_free(s);
72}
73
74/*      inputs[0]= reference signal (sent to soundcard)
75        inputs[1]= echo signal  (read from soundcard)
76*/
77
78
79static void speex_ec_process(MSFilter *f){
80        SpeexECState *s=(SpeexECState*)f->data;
81        int nbytes=s->framesize*2;
82        uint8_t *in1;
83        mblk_t *om0,*om1;
84#ifdef HAVE_SPEEX_NOISE
85        spx_int32_t *noise=(spx_int32_t*)alloca(nbytes*sizeof(spx_int32_t)+1);
86#else
87        float *noise=NULL;
88#endif
89#ifdef AMD_WIN32_HACK
90        static int count=0;
91#endif
92
93        /*read input and put in bufferizers*/
94        ms_bufferizer_put_from_queue(&s->in[0],f->inputs[0]);
95        ms_bufferizer_put_from_queue(&s->in[1],f->inputs[1]);
96       
97        in1=(uint8_t*)alloca(nbytes);
98
99        ms_debug("speexec:  in0=%i, in1=%i",ms_bufferizer_get_avail(&s->in[0]),ms_bufferizer_get_avail(&s->in[1]));
100
101        while (ms_bufferizer_get_avail(&s->in[0])>=nbytes && ms_bufferizer_get_avail(&s->in[1])>=nbytes){
102                om0=allocb(nbytes,0);
103                ms_bufferizer_read(&s->in[0],(uint8_t*)om0->b_wptr,nbytes);
104                /* we have reference signal */
105                /* the reference signal is sent through outputs[0]*/
106               
107                om0->b_wptr+=nbytes;
108                ms_queue_put(f->outputs[0],om0);
109
110                ms_bufferizer_read(&s->in[1],in1,nbytes);
111                /* we have echo signal */
112                om1=allocb(nbytes,0);
113                speex_echo_cancel(s->ecstate,(short*)in1,(short*)om0->b_rptr,(short*)om1->b_wptr,(spx_int32_t*)noise);
114                if (s->den!=NULL && noise!=NULL)
115                  speex_preprocess(s->den, (short*)om1->b_wptr, (spx_int32_t*)noise);
116
117                om1->b_wptr+=nbytes;
118                ms_queue_put(f->outputs[1],om1);
119#ifdef AMD_WIN32_HACK
120                count++;
121                if (count==100*3)
122                {
123                        ms_message("periodic reset of echo canceller.");
124                        speex_echo_state_reset(s->ecstate);
125                        count=0;
126                }               
127#endif
128        }
129
130        if (ms_bufferizer_get_avail(&s->in[0])> 4*320*(s->samplerate/8000)) /* above 4*20ms -> useless */
131          {
132            /* reset evrything */
133            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]));
134            flushq(&s->in[1].q,0);
135            flushq(&s->in[0].q,0);
136            ms_bufferizer_init(&s->in[0]);
137            ms_bufferizer_init(&s->in[1]);
138            speex_echo_state_reset(s->ecstate);
139          }
140
141        while (ms_bufferizer_get_avail(&s->in[1])> 4*320*(s->samplerate/8000)){
142                om1=allocb(nbytes,0);
143                ms_bufferizer_read(&s->in[1],(uint8_t*)om1->b_wptr,nbytes);
144                om1->b_wptr+=nbytes;
145                ms_queue_put(f->outputs[1],om1);
146                ms_message("too much echo signal, sending anyway.");
147                speex_echo_state_reset(s->ecstate);
148        }
149       
150}
151
152static int speex_ec_set_sr(MSFilter *f, void *arg){
153#ifdef SPEEX_ECHO_SET_SAMPLING_RATE
154        SpeexECState *s=(SpeexECState*)f->data;
155
156        s->samplerate = *(int*)arg;
157
158        if (s->ecstate==NULL)
159                speex_echo_state_destroy(s->ecstate);
160        if (s->den!=NULL)
161          speex_preprocess_state_destroy(s->den);
162
163        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
164        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
165        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
166#else
167        ms_error("Speex echocanceler does not support 16Khz sampling rate in this version!");
168#endif
169        return 0;
170}
171
172static int speex_ec_set_framesize(MSFilter *f, void *arg){
173        SpeexECState *s=(SpeexECState*)f->data;
174        s->framesize = *(int*)arg;
175
176        if (s->ecstate==NULL)
177                speex_echo_state_destroy(s->ecstate);
178        if (s->den!=NULL)
179          speex_preprocess_state_destroy(s->den);
180
181        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
182#ifdef SPEEX_ECHO_SET_SAMPLING_RATE
183        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
184#endif
185        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
186        return 0;
187}
188
189static int speex_ec_set_filterlength(MSFilter *f, void *arg){
190        SpeexECState *s=(SpeexECState*)f->data;
191        s->filterlength = *(int*)arg;
192
193        if (s->ecstate==NULL)
194                speex_echo_state_destroy(s->ecstate);
195        if (s->den!=NULL)
196          speex_preprocess_state_destroy(s->den);
197
198        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
199#ifdef SPEEX_ECHO_SET_SAMPLING_RATE
200        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
201#endif
202        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
203
204        return 0;
205}
206
207static MSFilterMethod speex_ec_methods[]={
208        {       MS_FILTER_SET_SAMPLE_RATE, speex_ec_set_sr },
209        {       MS_FILTER_SET_FRAMESIZE, speex_ec_set_framesize },
210        {       MS_FILTER_SET_FILTERLENGTH, speex_ec_set_filterlength },
211        {       0                       , NULL}
212};
213
214#ifdef _MSC_VER
215
216MSFilterDesc ms_speex_ec_desc={
217        MS_SPEEX_EC_ID,
218        "MSSpeexEC",
219        "Echo canceler using speex library",
220        MS_FILTER_OTHER,
221        NULL,
222        2,
223        2,
224        speex_ec_init,
225        NULL,
226        speex_ec_process,
227        NULL,
228        speex_ec_uninit,
229        speex_ec_methods
230};
231
232#else
233
234MSFilterDesc ms_speex_ec_desc={
235        .id=MS_SPEEX_EC_ID,
236        .name="MSSpeexEC",
237        .text="Echo canceler using speex library",
238        .category=MS_FILTER_OTHER,
239        .ninputs=2,
240        .noutputs=2,
241        .init=speex_ec_init,
242        .process=speex_ec_process,
243        .uninit=speex_ec_uninit,
244        .methods=speex_ec_methods
245};
246
247#endif
248
249MS_FILTER_DESC_EXPORT(ms_speex_ec_desc)
Note: See TracBrowser for help on using the repository browser.