From ccf741f1ff01ea65dfc65f414718d1b3c05ca58d Mon Sep 17 00:00:00 2001
From: smorlat <smorlat@3f6dc0c8-ddfe-455d-9043-3cd528dc4637>
Date: Fri, 28 Aug 2009 16:02:17 +0000
Subject: [PATCH] echo canceler refactoring and improvements.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@606 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
---
 .../include/mediastreamer2/Makefile.am        |   3 +-
 .../include/mediastreamer2/mediastream.h      |   3 +
 .../include/mediastreamer2/msspeexec.h        |  38 ++++++
 linphone/mediastreamer2/src/speexec.c         | 114 ++++++++++++------
 4 files changed, 120 insertions(+), 38 deletions(-)
 create mode 100644 linphone/mediastreamer2/include/mediastreamer2/msspeexec.h

diff --git a/linphone/mediastreamer2/include/mediastreamer2/Makefile.am b/linphone/mediastreamer2/include/mediastreamer2/Makefile.am
index 83343ab969..74673ce144 100644
--- a/linphone/mediastreamer2/include/mediastreamer2/Makefile.am
+++ b/linphone/mediastreamer2/include/mediastreamer2/Makefile.am
@@ -22,7 +22,8 @@ mediastreamer2_include_HEADERS= ice.h \
 				rfc3984.h \
 				mswebcam.h \
 				dsptools.h \
-				msequalizer.h
+				msequalizer.h \
+				msspeexec.h
 
 EXTRA_DIST=$(mediastreamer2_include_HEADERS)
 
diff --git a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h
index 9224d920a2..5a3347ee6b 100644
--- a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h
+++ b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h
@@ -53,6 +53,9 @@ struct _AudioStream
 	uint64_t last_packet_count;
 	time_t last_packet_time;
 	EchoLimiterType el_type; /*use echo limiter: two MSVolume, measured input level controlling local output level*/
+	int ec_tail_len; /*milliseconds*/
+	int ec_delay;	/*milliseconds*/
+	int ec_framesize; /* number of fft points */
 	bool_t play_dtmfs;
 	bool_t use_gc;
 	bool_t use_agc;
diff --git a/linphone/mediastreamer2/include/mediastreamer2/msspeexec.h b/linphone/mediastreamer2/include/mediastreamer2/msspeexec.h
new file mode 100644
index 0000000000..e9bc24d26f
--- /dev/null
+++ b/linphone/mediastreamer2/include/mediastreamer2/msspeexec.h
@@ -0,0 +1,38 @@
+/*
+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
diff --git a/linphone/mediastreamer2/src/speexec.c b/linphone/mediastreamer2/src/speexec.c
index f897e143fe..aecf99a3a7 100644
--- a/linphone/mediastreamer2/src/speexec.c
+++ b/linphone/mediastreamer2/src/speexec.c
@@ -17,7 +17,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/msfilter.h"
+#include "mediastreamer2/msspeexec.h"
 
 #include <speex/speex_echo.h>
 #include <speex/speex_preprocess.h>
@@ -46,6 +46,8 @@ typedef struct SpeexECState{
         int ref;
         int echo;
         int out;
+	int delay_ms;
+	int tail_length_ms;
 }SpeexECState;
 
 static void speex_ec_init(MSFilter *f){
@@ -57,14 +59,14 @@ static void speex_ec_init(MSFilter *f){
 
 	ms_bufferizer_init(&s->speak_delay);
 	s->size_delay=0;
+	s->delay_ms=0;
 	s->playback_delay=0;
+	s->tail_length_ms=250;
 
 	ms_bufferizer_init(&s->in[0]);
 	ms_bufferizer_init(&s->in[1]);
-	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);
+	s->ecstate=NULL;
+	s->den = NULL;
 
 	f->data=s;
 }
@@ -74,13 +76,33 @@ static void speex_ec_uninit(MSFilter *f){
 	ms_bufferizer_uninit(&s->speak_delay);
 	ms_bufferizer_uninit(&s->in[0]);
 	ms_bufferizer_uninit(&s->in[1]);
-	speex_echo_state_destroy(s->ecstate);
+	if (s->ecstate!=NULL)
+		speex_echo_state_destroy(s->ecstate);
 	if (s->den!=NULL)
-	  speex_preprocess_state_destroy(s->den);
+		speex_preprocess_state_destroy(s->den);
 
 	ms_free(s);
 }
 
+
+static void speex_ec_preprocess(MSFilter *f){
+	SpeexECState *s=(SpeexECState*)f->data;
+	if (s->ecstate!=NULL)
+		speex_echo_state_destroy(s->ecstate);
+	if (s->den!=NULL)
+		speex_preprocess_state_destroy(s->den);
+
+	if (s->tail_length_ms!=0)
+		s->filterlength=(s->tail_length_ms*s->samplerate)/1000;
+	if (s->delay_ms!=0)
+		s->playback_delay=s->delay_ms*s->samplerate/1000;
+
+	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);
+}
+
 /*	inputs[0]= reference signal (sent to soundcard)
 	inputs[1]= echo signal	(read from soundcard)
 */
@@ -210,23 +232,22 @@ static void speex_ec_process(MSFilter *f){
 
 static void speex_ec_postprocess(MSFilter *f){
 	SpeexECState *s=(SpeexECState*)f->data;
-	flushq(&s->in[1].q,0);
-	flushq(&s->in[0].q,0);
-	flushq(&s->speak_delay.q,0);
+	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;
 
-	if (s->ecstate!=NULL)
+	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->samplerate/8000));
-	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);
+		s->ecstate=NULL;
+	}
+	if (s->den!=NULL){
+		speex_preprocess_state_destroy(s->den);
+		s->den=NULL;
+	}
 }
 
 static int speex_ec_set_sr(MSFilter *f, void *arg){
@@ -234,15 +255,16 @@ static int speex_ec_set_sr(MSFilter *f, void *arg){
 
 	s->samplerate = *(int*)arg;
 
-	if (s->ecstate!=NULL)
+	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->samplerate/8000));
-	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);
+		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;
 }
 
@@ -250,34 +272,47 @@ static int speex_ec_set_framesize(MSFilter *f, void *arg){
 	SpeexECState *s=(SpeexECState*)f->data;
 	s->framesize = *(int*)arg;
 
-	if (s->ecstate!=NULL)
+	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->samplerate/8000));
-	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);
+		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->filterlength = (*(int*)arg)*(s->samplerate/8000);
 
 	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->samplerate/8000));
+	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){
+	SpeexECState *s=(SpeexECState*)f->data;
+	s->delay_ms = *(int*)arg;
+	return 0;
+}
+
+static int speex_ec_set_tail_length2(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;
@@ -295,6 +330,10 @@ static int speex_ec_set_playbackdelay(MSFilter *f, void *arg){
 
 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 },
@@ -312,7 +351,7 @@ MSFilterDesc ms_speex_ec_desc={
 	2,
 	2,
 	speex_ec_init,
-	NULL,
+	speex_ec_preprocess,
 	speex_ec_process,
 	speex_ec_postprocess,
 	speex_ec_uninit,
@@ -329,6 +368,7 @@ MSFilterDesc ms_speex_ec_desc={
 	.ninputs=2,
 	.noutputs=2,
 	.init=speex_ec_init,
+	.preprocess=speex_ec_preprocess,
 	.process=speex_ec_process,
 	.postprocess=speex_ec_postprocess,
 	.uninit=speex_ec_uninit,
-- 
GitLab