source: mediastreamer2/src/speexec.c @ 1040:8e8716785083

Last change on this file since 1040:8e8716785083 was 1040:8e8716785083, checked in by Jehan Monnier <jehan.monnier@…>, 3 years ago

reduce msandroid chunk size to minbuffsize/2

File size: 7.5 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2010  Belledonne Communications SARL
4Author: Simon Morlat <simon.morlat@linphone.org>
5
6This program is free software; you can redistribute it and/or
7modify it under the terms of the GNU General Public License
8as published by the Free Software Foundation; either version 2
9of the License, or (at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19*/
20
21#include "mediastreamer2/msfilter.h"
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 ref_max_delay=70;
35
36#if 0
37typedef struct _BufferSizeEstimator{
38        float mean;
39        float jitter;
40}BufferSizeEstimator;
41
42void buffer_size_estimator_update(BufferSizeEstimator *bse, int size){
43        static const float smooth=0.04;
44}
45
46#endif
47
48typedef struct SpeexECState{
49        SpeexEchoState *ecstate;
50        SpeexPreprocessState *den;
51        MSBufferizer ref;
52        MSBufferizer delayed_ref;
53        MSBufferizer echo;
54        int ref_bytes_limit;
55        int framesize;
56        int filterlength;
57        int samplerate;
58        int delay_ms;
59        int tail_length_ms;
60        bool_t using_silence;
61        bool_t echostarted;
62}SpeexECState;
63
64static void speex_ec_init(MSFilter *f){
65        SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1);
66
67        s->samplerate=8000;
68        ms_bufferizer_init(&s->ref);
69        ms_bufferizer_init(&s->delayed_ref);
70        ms_bufferizer_init(&s->echo);
71        s->delay_ms=0;
72        s->tail_length_ms=250;
73        s->ecstate=NULL;
74        s->framesize=framesize;
75        s->den = NULL;
76        s->using_silence=FALSE;
77        s->echostarted=FALSE;
78
79        f->data=s;
80}
81
82static void speex_ec_uninit(MSFilter *f){
83        SpeexECState *s=(SpeexECState*)f->data;
84        ms_bufferizer_uninit(&s->ref);
85        ms_bufferizer_uninit(&s->delayed_ref);
86        ms_free(s);
87}
88
89
90static void speex_ec_preprocess(MSFilter *f){
91        SpeexECState *s=(SpeexECState*)f->data;
92        int delay_samples=0;
93        mblk_t *m;
94
95        s->echostarted=FALSE;
96        s->filterlength=(s->tail_length_ms*s->samplerate)/1000;
97        delay_samples=s->delay_ms*s->samplerate/1000;
98        ms_message("Initializing speex echo canceler with framesize=%i, filterlength=%i, delay_samples=%i",
99                s->framesize,s->filterlength,delay_samples);
100        s->ref_bytes_limit=(2*ref_max_delay*s->samplerate)/1000;
101        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
102        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
103        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
104        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
105        /* fill with zeroes for the time of the delay*/
106        m=allocb(delay_samples*2,0);
107        ms_bufferizer_put (&s->delayed_ref,m);
108}
109
110/*      inputs[0]= reference signal (sent to soundcard)
111 *      inputs[1]= near speech & echo signal    (read from soundcard)
112 *      outputs[1]=  near end speech, echo removed - towards far end
113*/
114static void speex_ec_process(MSFilter *f){
115        SpeexECState *s=(SpeexECState*)f->data;
116        int nbytes=s->framesize*2;
117        mblk_t *refm;
118        uint8_t *ref,*echo;
119        int size;
120       
121        if (f->inputs[1]!=NULL){
122                int maxsize;
123                ms_bufferizer_put_from_queue (&s->echo,f->inputs[1]);
124                maxsize=ms_bufferizer_get_avail(&s->echo);
125                if (s->echostarted==FALSE && maxsize>0){
126                        ms_message("speex_ec: starting receiving echo signal");
127                        s->echostarted=TRUE;
128                }
129                if (maxsize>=s->ref_bytes_limit){
130                        ms_message("ref_bytes_limit adjusted from %i to %i",s->ref_bytes_limit,maxsize);
131                        s->ref_bytes_limit=maxsize;
132                }
133        }
134       
135        if (f->inputs[0]!=NULL){
136                while((refm=ms_queue_get(f->inputs[0]))!=NULL){
137                        mblk_t *cp=dupmsg(refm);
138                        ms_bufferizer_put(&s->ref,refm);
139                        ms_bufferizer_put(&s->delayed_ref,cp);
140                }
141        }
142       
143/*
144        ms_message("echo bytes=%i, ref bytes=%i",ms_bufferizer_get_avail(&s->echo),
145                   ms_bufferizer_get_avail(&s->ref));
146*/
147        ref=(uint8_t*)alloca(nbytes);
148        echo=(uint8_t*)alloca(nbytes);
149        while (ms_bufferizer_read(&s->echo,echo,nbytes)>=nbytes){
150                mblk_t *oref=allocb(nbytes,0);
151                mblk_t *oecho=allocb(nbytes,0);
152                if (ms_bufferizer_read(&s->ref,oref->b_wptr,nbytes)==0){
153                        memset(ref,0,nbytes);
154                        memset(oref->b_wptr,0,nbytes);
155                        /*missing data, use silence instead*/
156                        if (!s->using_silence){
157                                ms_warning("No ref samples, using silence instead");
158                                s->using_silence=TRUE;
159                        }
160                }else{
161                        ms_bufferizer_read(&s->delayed_ref,ref,nbytes);
162                        if (s->using_silence){
163                                ms_warning("Reference stream is back.");
164                                s->using_silence=FALSE;
165                        }
166                }
167                oref->b_wptr+=nbytes;
168                ms_queue_put(f->outputs[0],oref);
169                speex_echo_cancellation(s->ecstate,(short*)echo,(short*)ref,(short*)oecho->b_wptr);
170                speex_preprocess_run(s->den, (short*)oecho->b_wptr);
171                oecho->b_wptr+=nbytes;
172                ms_queue_put(f->outputs[1],oecho);
173        }
174        if (!s->echostarted){
175                /*if we have not yet receive anything from the soundcard, bypass the reference signal*/
176                while (ms_bufferizer_get_avail(&s->ref)>=nbytes){
177                        mblk_t *oref=allocb(nbytes,0);
178                        ms_bufferizer_read(&s->ref,oref->b_wptr,nbytes);
179                        oref->b_wptr+=nbytes;
180                        ms_bufferizer_skip_bytes(&s->delayed_ref,nbytes);
181                        ms_queue_put(f->outputs[0],oref);
182                }
183        }
184
185        /* do not accumulate too much reference signal */
186        if ((size=ms_bufferizer_get_avail(&s->ref))> (s->ref_bytes_limit+nbytes)) {
187                /* remove nbytes bytes */
188                ms_warning("purging %i bytes from ref signal, size=%i, limit=%i",nbytes,size,s->ref_bytes_limit);
189                ms_bufferizer_skip_bytes(&s->ref,nbytes);
190                ms_bufferizer_skip_bytes(&s->delayed_ref,nbytes);
191        }
192}
193
194static void speex_ec_postprocess(MSFilter *f){
195        SpeexECState *s=(SpeexECState*)f->data;
196        ms_bufferizer_flush (&s->ref);
197        ms_bufferizer_flush (&s->delayed_ref);
198        ms_bufferizer_flush (&s->echo);
199        if (s->ecstate!=NULL){
200                speex_echo_state_destroy(s->ecstate);
201                s->ecstate=NULL;
202        }
203        if (s->den!=NULL){
204                speex_preprocess_state_destroy(s->den);
205                s->den=NULL;
206        }
207}
208
209static int speex_ec_set_sr(MSFilter *f, void *arg){
210        SpeexECState *s=(SpeexECState*)f->data;
211        s->samplerate = *(int*)arg;
212        return 0;
213}
214
215static int speex_ec_set_framesize(MSFilter *f, void *arg){
216        SpeexECState *s=(SpeexECState*)f->data;
217        s->framesize = *(int*)arg;
218        return 0;
219}
220
221static int speex_ec_set_delay(MSFilter *f, void *arg){
222        SpeexECState *s=(SpeexECState*)f->data;
223        s->delay_ms = *(int*)arg;
224        return 0;
225}
226
227static int speex_ec_set_tail_length(MSFilter *f, void *arg){
228        SpeexECState *s=(SpeexECState*)f->data;
229        s->tail_length_ms=*(int*)arg;
230        return 0;
231}
232
233
234static MSFilterMethod speex_ec_methods[]={
235        {       MS_FILTER_SET_SAMPLE_RATE, speex_ec_set_sr },
236        {       MS_ECHO_CANCELLER_SET_TAIL_LENGTH       ,       speex_ec_set_tail_length        },
237        {       MS_ECHO_CANCELLER_SET_DELAY             ,       speex_ec_set_delay              },
238        {       MS_ECHO_CANCELLER_SET_FRAMESIZE ,       speex_ec_set_framesize          },
239};
240
241#ifdef _MSC_VER
242
243MSFilterDesc ms_speex_ec_desc={
244        MS_SPEEX_EC_ID,
245        "MSSpeexEC",
246        N_("Echo canceller using speex library"),
247        MS_FILTER_OTHER,
248        NULL,
249        2,
250        2,
251        speex_ec_init,
252        speex_ec_preprocess,
253        speex_ec_process,
254        speex_ec_postprocess,
255        speex_ec_uninit,
256        speex_ec_methods
257};
258
259#else
260
261MSFilterDesc ms_speex_ec_desc={
262        .id=MS_SPEEX_EC_ID,
263        .name="MSSpeexEC",
264        .text=N_("Echo canceller using speex library"),
265        .category=MS_FILTER_OTHER,
266        .ninputs=2,
267        .noutputs=2,
268        .init=speex_ec_init,
269        .preprocess=speex_ec_preprocess,
270        .process=speex_ec_process,
271        .postprocess=speex_ec_postprocess,
272        .uninit=speex_ec_uninit,
273        .methods=speex_ec_methods
274};
275
276#endif
277
278MS_FILTER_DESC_EXPORT(ms_speex_ec_desc)
Note: See TracBrowser for help on using the repository browser.