Commit 3c56f2ce authored by Simon Morlat's avatar Simon Morlat

make speex encoder use a generic interface

parent 4a9da817
......@@ -24,7 +24,6 @@ mediastreamer2_include_HEADERS= ice.h \
mswebcam.h \
dsptools.h \
msequalizer.h \
msspeexec.h \
msinterfaces.h \
mschanadapter.h \
msaudiomixer.h \
......
......@@ -476,6 +476,7 @@ enum _MSFilterInterfaceId{
MSFilterPlayerInterface,
MSFilterRecorderInterface,
MSFilterVideoDisplayInterface,
MSFilterEchoCancellerInterface
};
typedef enum _MSFilterInterfaceId MSFilterInterfaceId;
......@@ -501,8 +502,6 @@ typedef enum _MSFilterInterfaceId MSFilterInterfaceId;
#define MS_CONF_SPEEX_PREPROCESS_MIC MS_FILTER_EVENT(MS_CONF_ID, 1, void*)
#define MS_CONF_CHANNEL_VOLUME MS_FILTER_EVENT(MS_CONF_ID, 3, void*)
#define MS_SPEEX_EC_PREPROCESS_MIC MS_FILTER_EVENT(MS_SPEEX_EC_ID, 1, void*)
#define MS_SPEEX_EC_ECHO_STATE MS_FILTER_EVENT(MS_SPEEX_EC_ID, 2, void*)
/** @} */
/*protected/ private methods*/
......
......@@ -95,4 +95,17 @@ typedef enum _MSPlayerState MSPlayerState;
MS_FILTER_METHOD(MSFilterPlayerInterface,5,int)
/** Interface definitions for echo cancellers*/
/** sets the echo delay in milliseconds*/
#define MS_ECHO_CANCELLER_SET_DELAY \
MS_FILTER_METHOD(MSFilterEchoCancellerInterface,0,int)
#define MS_ECHO_CANCELLER_SET_FRAMESIZE \
MS_FILTER_METHOD(MSFilterEchoCancellerInterface,1,int)
/** sets tail length in milliseconds */
#define MS_ECHO_CANCELLER_SET_TAIL_LENGTH \
MS_FILTER_METHOD(MSFilterEchoCancellerInterface,2,int)
#endif
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006-2009 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
msspeexec.h : interface of the speex echo canceler integration in mediastreamer2
*/
#ifndef msspeexec_h
#define msspeexec_h
#include <mediastreamer2/msfilter.h>
/** sets the tail length in milliseconds*/
#define MS_SPEEX_EC_SET_TAIL_LENGTH MS_FILTER_METHOD(MS_SPEEX_EC_ID,0,int)
/** sets the minimum delay of the echo if known. This optimizes the convergence*/
#define MS_SPEEX_EC_SET_DELAY MS_FILTER_METHOD(MS_SPEEX_EC_ID,1,int)
/** sets the frame size for the AU-MDF algorithm, in number of fft points*/
#define MS_SPEEX_EC_SET_FRAME_SIZE MS_FILTER_METHOD(MS_SPEEX_EC_ID,2,int)
#endif
......@@ -250,11 +250,11 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
stream->ec=ms_filter_new(MS_SPEEX_EC_ID);
ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate);
if (stream->ec_tail_len!=0)
ms_filter_call_method(stream->ec,MS_SPEEX_EC_SET_TAIL_LENGTH,&stream->ec_tail_len);
ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_TAIL_LENGTH,&stream->ec_tail_len);
if (stream->ec_delay!=0)
ms_filter_call_method(stream->ec,MS_SPEEX_EC_SET_DELAY,&stream->ec_delay);
ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&stream->ec_delay);
if (stream->ec_framesize!=0)
ms_filter_call_method(stream->ec,MS_SPEEX_EC_SET_FRAME_SIZE,&stream->ec_framesize);
ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_FRAMESIZE,&stream->ec_framesize);
}
if (stream->el_type!=ELInactive || stream->use_gc || stream->use_ng){
......
......@@ -18,8 +18,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/msspeexec.h"
#include "mediastreamer2/msfilter.h"
#include <speex/speex_echo.h>
#include <speex/speex_preprocess.h>
......@@ -32,7 +31,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
static const int framesize=128;
static const int filter_length=2048; /*250 ms*/
typedef struct SpeexECState{
SpeexEchoState *ecstate;
......@@ -40,6 +38,7 @@ typedef struct SpeexECState{
MSBufferizer ref;
MSBufferizer delayed_ref;
MSBufferizer echo;
int ref_bytes_limit;
int framesize;
int filterlength;
int samplerate;
......@@ -51,15 +50,13 @@ static void speex_ec_init(MSFilter *f){
SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1);
s->samplerate=8000;
s->framesize=framesize;
s->filterlength=filter_length;
ms_bufferizer_init(&s->ref);
ms_bufferizer_init(&s->delayed_ref);
ms_bufferizer_init(&s->echo);
s->delay_ms=0;
s->playback_delay=0;
s->tail_length_ms=250;
s->ecstate=NULL;
s->framesize=framesize;
s->den = NULL;
f->data=s;
......@@ -70,10 +67,6 @@ static void speex_ec_uninit(MSFilter *f){
ms_bufferizer_uninit(&s->ref);
ms_bufferizer_uninit(&s->delayed_ref);
ms_bufferizer_uninit(&s->delayed_ref);
if (s->ecstate!=NULL)
speex_echo_state_destroy(s->ecstate);
if (s->den!=NULL)
speex_preprocess_state_destroy(s->den);
ms_free(s);
}
......@@ -83,15 +76,12 @@ static void speex_ec_preprocess(MSFilter *f){
SpeexECState *s=(SpeexECState*)f->data;
int delay_samples=0;
mblk_t *m;
if (s->ecstate!=NULL)
speex_echo_state_destroy(s->ecstate);
if (s->den!=NULL)
speex_preprocess_state_destroy(s->den);
s->filterlength=(s->tail_length_ms*s->samplerate)/1000;
delay_samples=s->delay_ms*s->samplerate/1000;
ms_message("Initializing speex echo canceler with framesize=%i, filterlength=%i, delay_samples=%i",
s->framesize,s->filterlength,delay_samples);
s->ref_bytes_limit=3*s->framesize;
s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
......@@ -116,19 +106,20 @@ static void speex_ec_process(MSFilter *f){
while((refm=ms_queue_get(f->inputs[0]))!=NULL){
mblk_t *cp=copymsg(refm);
ref_samples+=msgdsize(refm)/2;
ms_bufferizer_put(&s->ref,ref);
ms_bufferizer_put(&s->ref,refm);
ms_bufferizer_put(&s->delayed_ref,cp);
}
}
if (f->inputs[1]!=NULL){
ms_bufferizer_put_from_queue (&s->echo,f->intputs[1]);
ms_bufferizer_put_from_queue (&s->echo,f->inputs[1]);
}
ref=(uint8_t*)alloca(nbytes);
while (ms_bufferizer_get_avail(&s->echo)>=nbytes){
echo=(uint8_t*)alloca(nbytes);
while (ms_bufferizer_read(&s->echo,echo,nbytes)>=nbytes){
mblk_t *oref=allocb(nbytes,0);
if (ms_bufferizer_get_avail(&s->ref)<nbytes){
mblk_t *oecho=allocb(nbytes,0);
if (ms_bufferizer_read(&s->ref,oref->b_wptr,nbytes)==0){
memset(ref,0,nbytes);
memset(oref->b_wptr,0,nbytes);
/*missing data, use silence instead*/
......@@ -136,60 +127,27 @@ static void speex_ec_process(MSFilter *f){
}else{
ms_bufferizer_read(&s->delayed_ref,ref,nbytes);
}
speex_echo_cancellation(s->ecstate,(short*)in1,(short*)om0->b_rptr,(short*)om1->b_wptr);
speex_preprocess_run(s->den, (short*)om1->b_wptr);
ms_filter_notify(f, MS_SPEEX_EC_ECHO_STATE, (void*)s->ecstate);
ms_filter_notify(f, MS_SPEEX_EC_PREPROCESS_MIC, (void*)s->den);
om1->b_wptr+=nbytes;
ms_queue_put(f->outputs[1],om1);
#ifdef AMD_WIN32_HACK
count++;
if (count==100*3)
{
ms_message("periodic reset of echo canceller.");
speex_echo_state_reset(s->ecstate);
count=0;
}
#endif
freeb(om0);
oref->b_wptr+=nbytes;
ms_queue_put(f->outputs[0],oref);
speex_echo_cancellation(s->ecstate,(short*)echo,(short*)ref,(short*)oecho->b_wptr);
speex_preprocess_run(s->den, (short*)oecho->b_wptr);
oecho->b_wptr+=nbytes;
ms_queue_put(f->outputs[1],oecho);
}
if (ms_bufferizer_get_avail(&s->speak_delay)> 5*320*(s->samplerate/8000)) /* above 4*20ms -> useless */
{
/* do not accumulate too much reference signal */
if (ms_bufferizer_get_avail(&s->ref)> s->ref_bytes_limit) {
/* reset evrything */
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]));
flushq(&s->in[1].q,0);
flushq(&s->in[0].q,0);
flushq(&s->speak_delay.q,0);
ms_bufferizer_init(&s->in[0]);
ms_bufferizer_init(&s->in[1]);
ms_bufferizer_init(&s->speak_delay);
s->size_delay=0;
speex_echo_state_reset(s->ecstate);
}
while (ms_bufferizer_get_avail(&s->in[1])> 5*320*(s->samplerate/8000)){
om1=allocb(nbytes,0);
ms_bufferizer_read(&s->in[1],(uint8_t*)om1->b_wptr,nbytes);
om1->b_wptr+=nbytes;
ms_queue_put(f->outputs[1],om1);
ms_message("too much echo signal, sending anyway.");
speex_echo_state_reset(s->ecstate);
ms_warning("purging ref signal");
ms_bufferizer_flush(&s->ref);
ms_bufferizer_flush(&s->delayed_ref);
}
}
static void speex_ec_postprocess(MSFilter *f){
SpeexECState *s=(SpeexECState*)f->data;
ms_bufferizer_uninit(&s->in[0]);
ms_bufferizer_uninit(&s->in[1]);
ms_bufferizer_uninit(&s->speak_delay);
ms_bufferizer_init(&s->in[0]);
ms_bufferizer_init(&s->in[1]);
ms_bufferizer_init(&s->speak_delay);
s->size_delay=0;
ms_bufferizer_flush (&s->ref);
ms_bufferizer_flush (&s->delayed_ref);
ms_bufferizer_flush (&s->echo);
if (s->ecstate!=NULL){
speex_echo_state_destroy(s->ecstate);
s->ecstate=NULL;
......@@ -202,92 +160,34 @@ static void speex_ec_postprocess(MSFilter *f){
static int speex_ec_set_sr(MSFilter *f, void *arg){
SpeexECState *s=(SpeexECState*)f->data;
s->samplerate = *(int*)arg;
if (s->ecstate!=NULL){
speex_echo_state_destroy(s->ecstate);
if (s->den!=NULL)
speex_preprocess_state_destroy(s->den);
s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
}
return 0;
}
static int speex_ec_set_framesize(MSFilter *f, void *arg){
SpeexECState *s=(SpeexECState*)f->data;
s->framesize = *(int*)arg;
if (s->ecstate!=NULL){
speex_echo_state_destroy(s->ecstate);
if (s->den!=NULL)
speex_preprocess_state_destroy(s->den);
s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
}
return 0;
}
static int speex_ec_set_filterlength(MSFilter *f, void *arg){
SpeexECState *s=(SpeexECState*)f->data;
s->filterlength = (*(int*)arg)*(s->samplerate/8000);
s->tail_length_ms=0;/*trust the length in sample, not the length in milliseconds*/
if (s->ecstate!=NULL)
speex_echo_state_destroy(s->ecstate);
if (s->den!=NULL)
speex_preprocess_state_destroy(s->den);
s->ecstate=speex_echo_state_init(s->framesize,s->filterlength);
s->den = speex_preprocess_state_init(s->framesize, s->samplerate);
speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_SAMPLING_RATE, &s->samplerate);
speex_preprocess_ctl(s->den, SPEEX_PREPROCESS_SET_ECHO_STATE, s->ecstate);
return 0;
}
static int speex_ec_set_delay2(MSFilter *f, void *arg){
static int speex_ec_set_delay(MSFilter *f, void *arg){
SpeexECState *s=(SpeexECState*)f->data;
s->delay_ms = *(int*)arg;
return 0;
}
static int speex_ec_set_tail_length2(MSFilter *f, void *arg){
static int speex_ec_set_tail_length(MSFilter *f, void *arg){
SpeexECState *s=(SpeexECState*)f->data;
s->tail_length_ms=*(int*)arg;
return 0;
}
static int speex_ec_set_playbackdelay(MSFilter *f, void *arg){
SpeexECState *s=(SpeexECState*)f->data;
s->playback_delay = *(int*)arg;
flushq(&s->in[1].q,0);
flushq(&s->in[0].q,0);
flushq(&s->speak_delay.q,0);
ms_bufferizer_init(&s->in[0]);
ms_bufferizer_init(&s->in[1]);
ms_bufferizer_init(&s->speak_delay);
s->size_delay=0;
speex_echo_state_reset(s->ecstate);
return 0;
}
static MSFilterMethod speex_ec_methods[]={
{ MS_FILTER_SET_SAMPLE_RATE, speex_ec_set_sr },
{ MS_SPEEX_EC_SET_TAIL_LENGTH , speex_ec_set_tail_length2 },
{ MS_SPEEX_EC_SET_DELAY , speex_ec_set_delay2 },
{ MS_SPEEX_EC_SET_FRAME_SIZE , speex_ec_set_framesize },
/*these are kept for backward compatibility */
{ MS_FILTER_SET_FRAMESIZE, speex_ec_set_framesize },
{ MS_FILTER_SET_FILTERLENGTH, speex_ec_set_filterlength },
{ MS_FILTER_SET_PLAYBACKDELAY, speex_ec_set_playbackdelay },
{ 0 , NULL}
{ MS_ECHO_CANCELLER_SET_TAIL_LENGTH , speex_ec_set_tail_length },
{ MS_ECHO_CANCELLER_SET_DELAY , speex_ec_set_delay },
{ MS_ECHO_CANCELLER_SET_FRAMESIZE , speex_ec_set_framesize },
};
#ifdef _MSC_VER
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment