source: mediastreamer2/src/speexec.c @ 1028:a34b0cd9f985

Last change on this file since 1028:a34b0cd9f985 was 1028:a34b0cd9f985, checked in by Simon Morlat <simon.morlat@…>, 3 years ago

increase purge margin

File size: 7.0 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=60;
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}SpeexECState;
62
63static void speex_ec_init(MSFilter *f){
64        SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1);
65
66        s->samplerate=8000;
67        ms_bufferizer_init(&s->ref);
68        ms_bufferizer_init(&s->delayed_ref);
69        ms_bufferizer_init(&s->echo);
70        s->delay_ms=0;
71        s->tail_length_ms=250;
72        s->ecstate=NULL;
73        s->framesize=framesize;
74        s->den = NULL;
75        s->using_silence=FALSE;
76
77        f->data=s;
78}
79
80static void speex_ec_uninit(MSFilter *f){
81        SpeexECState *s=(SpeexECState*)f->data;
82        ms_bufferizer_uninit(&s->ref);
83        ms_bufferizer_uninit(&s->delayed_ref);
84        ms_free(s);
85}
86
87
88static void speex_ec_preprocess(MSFilter *f){
89        SpeexECState *s=(SpeexECState*)f->data;
90        int delay_samples=0;
91        mblk_t *m;
92
93        s->filterlength=(s->tail_length_ms*s->samplerate)/1000;
94        delay_samples=s->delay_ms*s->samplerate/1000;
95        ms_message("Initializing speex echo canceler with framesize=%i, filterlength=%i, delay_samples=%i",
96                s->framesize,s->filterlength,delay_samples);
97        s->ref_bytes_limit=(2*ref_max_delay*s->samplerate)/1000;
98        s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
99        s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
100        speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
101        speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
102        /* fill with zeroes for the time of the delay*/
103        m=allocb(delay_samples*2,0);
104        ms_bufferizer_put (&s->delayed_ref,m);
105}
106
107/*      inputs[0]= reference signal (sent to soundcard)
108 *      inputs[1]= near speech & echo signal    (read from soundcard)
109 *      outputs[1]=  near end speech, echo removed - towards far end
110*/
111static void speex_ec_process(MSFilter *f){
112        SpeexECState *s=(SpeexECState*)f->data;
113        int nbytes=s->framesize*2;
114        mblk_t *refm;
115        uint8_t *ref,*echo;
116        int size;
117       
118        if (f->inputs[0]!=NULL){
119                while((refm=ms_queue_get(f->inputs[0]))!=NULL){
120                        mblk_t *cp=dupmsg(refm);
121                        ms_bufferizer_put(&s->ref,refm);
122                        ms_bufferizer_put(&s->delayed_ref,cp);
123                }
124        }
125        if (f->inputs[1]!=NULL){
126                int maxsize;
127                ms_bufferizer_put_from_queue (&s->echo,f->inputs[1]);
128                if ((maxsize=ms_bufferizer_get_avail(&s->echo))>=s->ref_bytes_limit){
129                        ms_message("ref_bytes_limit adjusted from %i to %i",s->ref_bytes_limit,maxsize);
130                        s->ref_bytes_limit=maxsize;
131                }
132        }
133/*
134        ms_message("echo bytes=%i, ref bytes=%i",ms_bufferizer_get_avail(&s->echo),
135                   ms_bufferizer_get_avail(&s->ref));
136*/
137        ref=(uint8_t*)alloca(nbytes);
138        echo=(uint8_t*)alloca(nbytes);
139        while (ms_bufferizer_read(&s->echo,echo,nbytes)>=nbytes){
140                mblk_t *oref=allocb(nbytes,0);
141                mblk_t *oecho=allocb(nbytes,0);
142                if (ms_bufferizer_read(&s->ref,oref->b_wptr,nbytes)==0){
143                        memset(ref,0,nbytes);
144                        memset(oref->b_wptr,0,nbytes);
145                        /*missing data, use silence instead*/
146                        if (!s->using_silence){
147                                ms_warning("No ref samples, using silence instead");
148                                s->using_silence=TRUE;
149                        }
150                }else{
151                        ms_bufferizer_read(&s->delayed_ref,ref,nbytes);
152                        if (s->using_silence){
153                                ms_warning("Reference stream is back.");
154                                s->using_silence=FALSE;
155                        }
156                }
157                oref->b_wptr+=nbytes;
158                ms_queue_put(f->outputs[0],oref);
159                speex_echo_cancellation(s->ecstate,(short*)echo,(short*)ref,(short*)oecho->b_wptr);
160                speex_preprocess_run(s->den, (short*)oecho->b_wptr);
161                oecho->b_wptr+=nbytes;
162                ms_queue_put(f->outputs[1],oecho);
163        }
164        /* do not accumulate too much reference signal */
165        if ((size=ms_bufferizer_get_avail(&s->ref))> (s->ref_bytes_limit+nbytes)) {
166                /* remove nbytes bytes */
167                ms_warning("purging %i bytes from ref signal, size=%i, limit=%i",nbytes,size,s->ref_bytes_limit);
168                ms_bufferizer_skip_bytes(&s->ref,nbytes);
169                ms_bufferizer_skip_bytes(&s->delayed_ref,nbytes);
170        }
171}
172
173static void speex_ec_postprocess(MSFilter *f){
174        SpeexECState *s=(SpeexECState*)f->data;
175        ms_bufferizer_flush (&s->ref);
176        ms_bufferizer_flush (&s->delayed_ref);
177        ms_bufferizer_flush (&s->echo);
178        if (s->ecstate!=NULL){
179                speex_echo_state_destroy(s->ecstate);
180                s->ecstate=NULL;
181        }
182        if (s->den!=NULL){
183                speex_preprocess_state_destroy(s->den);
184                s->den=NULL;
185        }
186}
187
188static int speex_ec_set_sr(MSFilter *f, void *arg){
189        SpeexECState *s=(SpeexECState*)f->data;
190        s->samplerate = *(int*)arg;
191        return 0;
192}
193
194static int speex_ec_set_framesize(MSFilter *f, void *arg){
195        SpeexECState *s=(SpeexECState*)f->data;
196        s->framesize = *(int*)arg;
197        return 0;
198}
199
200static int speex_ec_set_delay(MSFilter *f, void *arg){
201        SpeexECState *s=(SpeexECState*)f->data;
202        s->delay_ms = *(int*)arg;
203        return 0;
204}
205
206static int speex_ec_set_tail_length(MSFilter *f, void *arg){
207        SpeexECState *s=(SpeexECState*)f->data;
208        s->tail_length_ms=*(int*)arg;
209        return 0;
210}
211
212
213static MSFilterMethod speex_ec_methods[]={
214        {       MS_FILTER_SET_SAMPLE_RATE, speex_ec_set_sr },
215        {       MS_ECHO_CANCELLER_SET_TAIL_LENGTH       ,       speex_ec_set_tail_length        },
216        {       MS_ECHO_CANCELLER_SET_DELAY             ,       speex_ec_set_delay              },
217        {       MS_ECHO_CANCELLER_SET_FRAMESIZE ,       speex_ec_set_framesize          },
218};
219
220#ifdef _MSC_VER
221
222MSFilterDesc ms_speex_ec_desc={
223        MS_SPEEX_EC_ID,
224        "MSSpeexEC",
225        N_("Echo canceller using speex library"),
226        MS_FILTER_OTHER,
227        NULL,
228        2,
229        2,
230        speex_ec_init,
231        speex_ec_preprocess,
232        speex_ec_process,
233        speex_ec_postprocess,
234        speex_ec_uninit,
235        speex_ec_methods
236};
237
238#else
239
240MSFilterDesc ms_speex_ec_desc={
241        .id=MS_SPEEX_EC_ID,
242        .name="MSSpeexEC",
243        .text=N_("Echo canceller using speex library"),
244        .category=MS_FILTER_OTHER,
245        .ninputs=2,
246        .noutputs=2,
247        .init=speex_ec_init,
248        .preprocess=speex_ec_preprocess,
249        .process=speex_ec_process,
250        .postprocess=speex_ec_postprocess,
251        .uninit=speex_ec_uninit,
252        .methods=speex_ec_methods
253};
254
255#endif
256
257MS_FILTER_DESC_EXPORT(ms_speex_ec_desc)
Note: See TracBrowser for help on using the repository browser.