diff -Nur linphone-0.12.2/mediastreamer/audiostream.c linphone-0.12.2-ec/mediastreamer/audiostream.c
--- linphone-0.12.2/mediastreamer/audiostream.c	2004-03-17 05:29:38.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/audiostream.c	2005-02-03 09:03:43.704934040 -0500
@@ -44,6 +44,11 @@
 		}
 		ms_filter_destroy(stream->rtpsend);
 	}
+
+#ifdef _EC
+	if (stream->soundread!=NULL) ms_filter_destroy(stream->ec);
+#endif
+	
 	if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
 	if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
 	if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
@@ -93,6 +98,8 @@
 	rtp_session_set_blocking_mode(rtpr,0);
 	rtp_session_set_payload_type(rtpr,payload);
 	rtp_session_set_jitter_compensation(rtpr,jitt_comp);
+	
+	//rtp_session_set_ssrc(rtpr,rand());
 	rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);
 	*recvsend=rtpr;
 }
@@ -176,6 +183,9 @@
 		g_error("mediastream.c: No decoder availlable for payload %i.",payload);
 		return NULL;
 	}
+#ifdef _EC
+	stream->ec=ms_ec_new();
+#endif
 	/* give the sound filters some properties */
 	ms_filter_set_property(stream->soundread,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
 	ms_filter_set_property(stream->soundwrite,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
@@ -189,11 +199,21 @@
 	stream->timer=ms_timer_new();
 	
 	/* and then connect all */
+#ifndef _EC
 	ms_filter_add_link(stream->soundread,stream->encoder);
 	ms_filter_add_link(stream->encoder,stream->rtpsend);
 	ms_filter_add_link(stream->rtprecv,stream->decoder);
 	ms_filter_add_link(stream->decoder,stream->soundwrite);
+#endif	
 	
+#ifdef _EC
+	ms_filter_link(stream->soundread,0,stream->ec,1,LINK_FIFO);	
+	ms_filter_link(stream->ec,1,stream->encoder,0,LINK_FIFO);
+	ms_filter_link(stream->encoder,0,stream->rtpsend,0,LINK_FIFO);
+	ms_filter_link(stream->rtprecv,0,stream->decoder,0,LINK_FIFO);
+	ms_filter_link(stream->decoder,0,stream->ec,0,LINK_FIFO);
+	ms_filter_link(stream->ec,0,stream->soundwrite,0,LINK_FIFO);
+#endif
 	ms_sync_attach(stream->timer,stream->soundread);
 	ms_sync_attach(stream->timer,stream->rtprecv);
 	
@@ -230,11 +250,21 @@
 	ms_sync_detach(stream->timer,stream->soundread);
 	ms_sync_detach(stream->timer,stream->rtprecv);
 	
+#ifndef _EC
 	ms_filter_remove_links(stream->soundread,stream->encoder);
 	ms_filter_remove_links(stream->encoder,stream->rtpsend);
 	ms_filter_remove_links(stream->rtprecv,stream->decoder);
 	ms_filter_remove_links(stream->decoder,stream->soundwrite);
-	
+#endif
+#ifdef _EC
+	ms_filter_remove_links(stream->soundread,stream->ec);
+	ms_filter_remove_links(stream->ec,stream->encoder);
+	ms_filter_remove_links(stream->encoder,stream->rtpsend);
+	ms_filter_remove_links(stream->rtprecv,stream->decoder);
+	ms_filter_remove_links(stream->decoder,stream->ec);
+	ms_filter_remove_links(stream->ec,stream->soundwrite);
+#endif
+
 	audio_stream_free(stream);
 }
 
@@ -254,7 +284,7 @@
 		g_warning("Could not create ring player. Probably the ring file (%s) does not exist.",file);
 		return NULL;
 	}
-  if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data);
+	if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data);
 	stream->sndwrite=snd_card_create_write_filter(sndcard);
 	ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_FREQ,&tmp);
 	ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_FREQ,&tmp);
diff -Nur linphone-0.12.2/mediastreamer/Makefile.am linphone-0.12.2-ec/mediastreamer/Makefile.am
--- linphone-0.12.2/mediastreamer/Makefile.am	2004-03-03 10:38:24.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/Makefile.am	2005-02-03 09:06:08.172971560 -0500
@@ -77,6 +77,7 @@
 							hpuxsndcard.c \
 							alsacard.c alsacard.h \
 							audiostream.c mediastream.h \
+							msEC.c msEC.h\
                     $(TRUESPEECH_SOURCES)
 
 
@@ -88,7 +89,8 @@
 							../oRTP/src/libortp.la \
 							$(SUPPORTLIB) \
 							$(ALSA_LIBS) \
-							$(TRUESPEECH_LIBADD)
+							$(TRUESPEECH_LIBADD)\
+							-lvec
 
 
 
@@ -122,7 +124,7 @@
 
 if BUILD_MEDIASTREAMER
 noinst_PROGRAMS=mstest ring_test test_gsm test_lpc10 test_alaw test_mulaw \
-                        test_speex \
+                        test_speex test_ec\
 			test_rtprecv mediastream $(XINE_PLUGIN_TEST) $(SMPEG_PLUGIN_TEST) \
 			$(FFMPEG_PLUGIN_TEST) $(GDK_VO_PLUGIN_TEST)  $(V4L_PLUGIN_TEST) $(TRUESPEECH_TEST)
 endif
@@ -159,6 +161,9 @@
 test_mulaw_SOURCES=test_mulaw.c
 test_mulaw_LDADD=libmediastreamer.la
 
+#test program to test echo canceler objects
+test_ec_SOURCES=test_ec.c
+test_ec_LDADD=libmediastreamer.la
 
 #test program to test rtprecv object 
 test_rtprecv_SOURCES=test_rtprecv.c
diff -Nur linphone-0.12.2/mediastreamer/mediastream.h linphone-0.12.2-ec/mediastreamer/mediastream.h
--- linphone-0.12.2/mediastreamer/mediastream.h	2004-03-17 05:42:35.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/mediastream.h	2004-12-24 14:27:14.000000000 -0500
@@ -36,6 +36,8 @@
 #include "msringplayer.h"
 
 
+#define _EC
+
 struct _AudioStream
 {
 	MSSync *timer;
@@ -47,6 +49,9 @@
 	MSFilter *decoder;
 	MSFilter *rtprecv;
 	MSFilter *rtpsend;
+#ifdef _EC
+	MSFilter *ec;
+#endif
 };
 
 
diff -Nur linphone-0.12.2/mediastreamer/ms.c linphone-0.12.2-ec/mediastreamer/ms.c
--- linphone-0.12.2/mediastreamer/ms.c	2003-07-17 09:40:04.000000000 -0400
+++ linphone-0.12.2-ec/mediastreamer/ms.c	2005-02-03 08:59:31.613257800 -0500
@@ -65,15 +65,17 @@
 	return 1;
 }
 
-static GList *g_list_append_if_new(GList *l,gpointer data)
+static GList *g_list_append_if_new(GList *l,gpointer data,GList *l2)
 {
-	GList *res=l;
-	if (g_list_find(res,data)==NULL)
-		res=g_list_append(res,data);
+	GList *res=l,*res2=l2;
+	if (g_list_find(res2,data)==NULL) {
+		if (g_list_find(res,data)==NULL)
+			res=g_list_append(res,data);
+	}
 	return(res);
 }
 
-static GList *get_nexts(MSFilter *f,GList *l)
+static GList *get_nexts(MSFilter *f,GList *l,GList *compare)
 {
 	int i;
 	MSFifo *fifo;
@@ -84,17 +86,20 @@
 	for (i=0;i	<f->klass->max_foutputs;i++)
 	{
 		fifo=f->outfifos[i];
-		if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data);
+		if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data,compare);
 	}
 	/* check queues*/
 	for (i=0;i	<f->klass->max_qoutputs;i++)
 	{
 		q=f->outqueues[i];
-		if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data);
+		if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data,compare);
 	}
 	return(res);
 }
 	
+
+
+
 /* compile graphs attached to a sync source*/
 int ms_compile(MSSync *sync)
 {
@@ -108,7 +113,6 @@
 	/* get the list of filters attached to this sync*/
 	for (i=0;i<sync->filters;i++)
 	{
-		//printf("found filter !\n");
 		list1=g_list_append(list1,sync->attached_filters[i]);
 	}
 	/* find the processing chain */
@@ -118,7 +122,6 @@
 		/* sort the list by types of filter*/
 		list1=g_list_sort(list1,compare);
 		/* save into the processing chain list*/
-		//printf("list1 :%i elements\n",g_list_length(list1));
 		proc_chain=g_list_concat(proc_chain,list1);
 		/* get all following filters. They are appended to list2*/
 		elem=list1;
@@ -130,7 +133,7 @@
 			{
 				sync->samples_per_tick=0;
 			}
-			list2=get_nexts(f,list2);
+			list2=get_nexts(f,list2,proc_chain);
 			elem=g_list_next(elem);
 		}
 		list1=list2;
@@ -142,12 +145,13 @@
 }
 
 /*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/
+#include <sys/time.h>
 void *ms_thread_run(void *sync_ptr)
 {
 	MSSync *sync=(MSSync*) sync_ptr;
 	GList *filter;
 	MSFilter *f;
-	
+struct timeval t0, t1, t2;
 	
 	ms_sync_lock(sync);  
 	while(sync->run)
@@ -168,7 +172,6 @@
 			if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE)
 			{
 				/* execute it once */
-				ms_trace("Running source filter %s.",f->klass->name);
 				ms_filter_process(f);
 			}
 			else
@@ -176,7 +179,6 @@
 				/* make the filter process its input data until it has no more */
 				while ( ms_filter_fifos_have_data(f) && ms_filter_queues_have_data(f) )
 				{
-					ms_trace("Running filter %s.",f->klass->name);
 					ms_filter_process(f);
 				}
 			}
diff -Nur linphone-0.12.2/mediastreamer/msEC.c linphone-0.12.2-ec/mediastreamer/msEC.c
--- linphone-0.12.2/mediastreamer/msEC.c	1969-12-31 19:00:00.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/msEC.c	2005-01-21 14:22:36.000000000 -0500
@@ -0,0 +1,119 @@
+/*
+ *  Acoustic Echo Canceler Media Streamer Control
+ *  Copyright (C) 2004 Charles Eidsness <charles@cooper-street.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License.
+ * 
+ * History:
+ *
+ * 2004-09-30 Charles Eidsness -- Original version				  
+ *				  
+ */
+
+#include <msEC.h>
+#include <string.h>
+#include <vec.h>
+
+extern MSFilter * ms_ec_new(void);
+
+MSFilterInfo ECInfo = {
+	"Echo Canceller",
+	0,
+	MS_FILTER_OTHER,
+	ms_ec_new,
+	"This is an echo canceller.",
+};
+
+static MSECClass *ms_ec_class=NULL;
+
+MSFilter * ms_ec_new(void)
+{
+	MSEC *r;
+
+	r=g_new(MSEC,1);
+	ms_ec_init(r);
+	if (ms_ec_class==NULL)
+	{
+		ms_ec_class=g_new(MSECClass,1);
+		ms_ec_class_init(ms_ec_class);
+	}
+	MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ec_class);
+	return(MS_FILTER(r));
+}
+	
+void ms_ec_init(MSEC *r)
+{
+	ms_filter_init(MS_FILTER(r));
+	MS_FILTER(r)->infifos=r->f_inputs;
+	MS_FILTER(r)->outfifos=r->f_outputs;
+	MS_FILTER(r)->r_mingran=MSEC_DEF_GRAN;
+	memset(r->f_inputs,0,sizeof(MSFifo*)*MSEC_MAX_INPUTS);
+	memset(r->f_outputs,0,sizeof(MSFifo*)*MSEC_MAX_OUTPUTS);
+	r->ec_state = vec_create();
+	vec_version(r->ec_state);
+	r->synced = 0;
+	r->syncCount = 0;
+
+}
+
+void ms_ec_class_init(MSECClass *klass)
+{
+	ms_filter_class_init(MS_FILTER_CLASS(klass));
+	ms_filter_class_set_name(MS_FILTER_CLASS(klass),"EC");
+	MS_FILTER_CLASS(klass)->info=&ECInfo;
+	MS_FILTER_CLASS(klass)->max_finputs=MSEC_MAX_INPUTS;
+	MS_FILTER_CLASS(klass)->max_foutputs=MSEC_MAX_OUTPUTS;
+	MS_FILTER_CLASS(klass)->r_maxgran=MSEC_DEF_GRAN;
+	MS_FILTER_CLASS(klass)->w_maxgran=MSEC_DEF_GRAN;
+	MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ec_destroy;
+	MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ec_process;
+}
+	
+void ms_ec_process(MSEC *r)
+{
+	short *i_sig=NULL,*i_ref=NULL,*o_sig,*o_ref;
+	MSFifo *fi_sig,*fi_ref,*fo_sig,*fo_ref;
+	unsigned int leni_sig,leni_ref,leno_sig,leno_ref;
+	unsigned int i = 0;
+
+	fi_ref=r->f_inputs[0];
+	fi_sig=r->f_inputs[1];
+	fo_ref=r->f_outputs[0];
+	fo_sig=r->f_outputs[1];
+
+	
+	if ((fi_ref->readsize >= MSEC_DEF_GRAN) &&
+					(fi_sig->readsize >= MSEC_DEF_GRAN)) {
+		leni_ref=ms_fifo_get_read_ptr(fi_ref,MSEC_DEF_GRAN,(void**)&i_ref);
+		g_return_if_fail(i_ref!=NULL);
+		leno_ref=ms_fifo_get_write_ptr(fo_ref,MSEC_DEF_GRAN,(void**)&o_ref);
+		g_return_if_fail(o_ref!=NULL);
+		leni_sig=ms_fifo_get_read_ptr(fi_sig,MSEC_DEF_GRAN,(void**)&i_sig);
+		g_return_if_fail(i_sig!=NULL);
+		leno_sig=ms_fifo_get_write_ptr(fo_sig,MSEC_DEF_GRAN,(void**)&o_sig);
+		g_return_if_fail(o_sig!=NULL);
+		memcpy(o_ref,i_ref,MSEC_DEF_GRAN);
+		for( i = 0; i < MSEC_DEF_GRAN/sizeof(short); i++)
+			o_sig[i] = vec_process(r->ec_state, i_sig[i], i_ref[i]);
+	} else if (fi_ref->readsize >= MSEC_DEF_GRAN) {
+		leni_ref=ms_fifo_get_read_ptr(fi_ref,MSEC_DEF_GRAN,(void**)&i_ref);
+		g_return_if_fail(i_ref!=NULL);
+		leno_ref=ms_fifo_get_write_ptr(fo_ref,MSEC_DEF_GRAN,(void**)&o_ref);
+		g_return_if_fail(o_ref!=NULL);
+		memcpy(o_ref,i_ref,MSEC_DEF_GRAN);
+	} else if (fi_sig->readsize >= MSEC_DEF_GRAN) {
+		leni_sig=ms_fifo_get_read_ptr(fi_sig,MSEC_DEF_GRAN,(void**)&i_sig);
+		g_return_if_fail(i_sig!=NULL);
+		leno_sig=ms_fifo_get_write_ptr(fo_sig,MSEC_DEF_GRAN,(void**)&o_sig);
+		g_return_if_fail(o_sig!=NULL);
+		memcpy(o_sig,i_sig,MSEC_DEF_GRAN);
+	}
+
+}
+
+void ms_ec_destroy(MSEC *r)
+{
+	vec_destroy(r->ec_state);
+	g_free(r);
+}
diff -Nur linphone-0.12.2/mediastreamer/msEC.h linphone-0.12.2-ec/mediastreamer/msEC.h
--- linphone-0.12.2/mediastreamer/msEC.h	1969-12-31 19:00:00.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/msEC.h	2005-01-21 14:18:49.000000000 -0500
@@ -0,0 +1,53 @@
+/*
+ *  Acoustic Echo Canceler Media Streamer Control Header File
+ *  Copyright (C) 2004 Charles Eidsness <charles@cooper-street.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License.
+ * 
+ * History:
+ *
+ * 2004-09-30 Charles Eidsness -- Original version				  
+ *				  
+ */
+
+#ifndef MSEC_H
+#define MSEC_H
+
+#include <msfilter.h>
+#include <vec.h>
+
+
+#define MSEC_MAX_INPUTS  2
+#define MSEC_MAX_OUTPUTS  2
+
+#define MSEC_DEF_GRAN 320*2 /* the default granularity*/
+
+typedef struct _MSEC
+{
+    MSFilter filter;
+    MSFifo *f_inputs[MSEC_MAX_INPUTS];
+    MSFifo *f_outputs[MSEC_MAX_OUTPUTS];
+    echocan * ec_state;
+    int synced;
+    int syncCount;
+      
+} MSEC;
+
+typedef struct _MSECClass
+{
+	MSFilterClass parent_class;
+} MSECClass;
+
+/* PUBLIC */
+#define MS_EC(filter) ((MSEC*)(filter))
+#define MS_EC_CLASS(klass) ((MSECClass*)(klass))
+MSFilter * ms_ec_new(void);
+
+/* FOR INTERNAL USE*/
+void ms_ec_init(MSEC *r);
+void ms_ec_class_init(MSECClass *klass);
+void ms_ec_destroy( MSEC *r);
+void ms_ec_process(MSEC *r);
+
+#endif
diff -Nur linphone-0.12.2/mediastreamer/msfilter.c linphone-0.12.2-ec/mediastreamer/msfilter.c
--- linphone-0.12.2/mediastreamer/msfilter.c	2003-08-07 12:00:36.000000000 -0400
+++ linphone-0.12.2-ec/mediastreamer/msfilter.c	2004-12-14 18:59:42.000000000 -0500
@@ -355,6 +355,8 @@
  *
  * Returns: 1 if it can be executed, 0 else.
  */
+#include "msEC.h"
+/* this is yuck but at least works */
 gint ms_filter_fifos_have_data(MSFilter *f)
 {
 	gint i,j;
@@ -362,17 +364,34 @@
 	gint max_inputs=f->klass->max_finputs;
 	gint con_inputs=f->finputs;
 	MSFifo *fifo;
+	MSEC * ec = (MSEC *)f;
 	/* test queues */
-	for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
-	{
-		fifo=f->infifos[i];
-		if (fifo!=NULL)
+	if (strcmp(f->klass->name,"EC")) {
+		for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
 		{
-			j++;
-			val=1;
-    	if (fifo->readsize==0) return 0;
-			if (fifo->readsize<f->r_mingran) return 0;
+			fifo=f->infifos[i];
+			if (fifo!=NULL)
+			{
+				j++;
+				val=1;
+				if (fifo->readsize==0) return 0;
+				if (fifo->readsize<f->r_mingran) return 0;
+			}
 		}
+	} else {
+		for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
+		{
+			fifo=f->infifos[i];
+			if (fifo!=NULL)
+			{
+				j++;
+				val=1;
+				if (fifo->readsize >= (2*f->r_mingran)) return 1;
+			}
+	
+		}
+		return 0;
+		
 	}
 	//printf("filter has data!\n");
 	return 1;  /*all fifos have something to read that is enough for that filter*/
@@ -400,7 +419,7 @@
 		{
 			j++;
 			val=1;
-    	if (!ms_queue_can_get(q)) return 0;
+			if (!ms_queue_can_get(q)) return 0;
 		}
 	}
 	return 1;  /*all queues have something to read that is enough for that filter*/
diff -Nur linphone-0.12.2/mediastreamer/msossread.h linphone-0.12.2-ec/mediastreamer/msossread.h
--- linphone-0.12.2/mediastreamer/msossread.h	2003-07-01 09:47:06.000000000 -0400
+++ linphone-0.12.2-ec/mediastreamer/msossread.h	2005-01-07 10:33:29.000000000 -0500
@@ -29,7 +29,7 @@
 
 #define MS_OSS_READ_MAX_INPUTS  1 /* max output per filter*/
 
-#define MS_OSS_READ_MAX_GRAN (512*2) /* the maximum granularity*/
+#define MS_OSS_READ_MAX_GRAN (320*2) /* the maximum granularity*/
 
 struct _MSOssRead
 {
diff -Nur linphone-0.12.2/mediastreamer/msosswrite.h linphone-0.12.2-ec/mediastreamer/msosswrite.h
--- linphone-0.12.2/mediastreamer/msosswrite.h	2004-02-19 05:28:02.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/msosswrite.h	2005-01-07 10:33:27.000000000 -0500
@@ -27,7 +27,7 @@
 
 #define MS_OSS_WRITE_MAX_INPUTS  1 /* max output per filter*/
 
-#define MS_OSS_WRITE_DEF_GRAN (512*2) /* the default granularity*/
+#define MS_OSS_WRITE_DEF_GRAN (320*2) /* the default granularity*/
 
 struct _MSOssWrite
 {
diff -Nur linphone-0.12.2/mediastreamer/test_speex.c linphone-0.12.2-ec/mediastreamer/test_speex.c
--- linphone-0.12.2/mediastreamer/test_speex.c	2003-06-10 16:55:31.000000000 -0400
+++ linphone-0.12.2-ec/mediastreamer/test_speex.c	2004-09-14 17:11:41.000000000 -0400
@@ -42,7 +42,7 @@
 	MSFilter *play,*enc,*dec,*rec;
 	MSSync *timer;	
 	SndCard *card;
-	int rate=16000;
+	int rate=8000;
 
 	ms_init();
 	signal(SIGINT,stop_handler);
diff -Nur linphone-0.12.2/mediastreamer/test_ec.c linphone-0.12.2-ec/mediastreamer/test_ec.c
--- linphone-0.12.2/mediastreamer/test_ec.c	1969-12-31 19:00:00.000000000 -0500
+++ linphone-0.12.2-ec/mediastreamer/test_ec.c	2004-09-30 17:04:23.000000000 -0400
@@ -0,0 +1,107 @@
+/*
+ *  Acoustic Echo Canceler Media Streamer Test
+ *  Copyright (C) 2004 Charles Eidsness <charles@cooper-street.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License.
+ * 
+ * History:
+ *
+ * 2004-09-30 Charles Eidsness -- Original version				  
+ *				  
+ */
+ 
+/*
+ * usage: test_ec -i <input.wav> -o <output.wav>
+ */
+
+#include "ms.h"
+
+#include "mssoundwrite.h"
+#include "mssoundread.h"
+#include "sndcard.h"
+#include "mstimer.h"
+#include "msEC.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static int cond=1;
+
+void stop_handler(int signum)
+{
+	cond=0;
+}
+
+int main(int argc, char *argv[])
+{
+	MSFilter *mic,*speaker,*file_in = NULL,*file_out = NULL,*ec;
+	MSSync *timer;
+	SndCard *card;
+	
+	
+	int opt;
+	
+	while((opt = getopt(argc, argv, "i:o:")) != -1) {
+		switch(opt) {
+		case 'i':
+			file_in=ms_read_new(optarg);
+			break;
+		case 'o':
+			file_out=ms_write_new(optarg);
+			break;
+		}
+	}
+	
+	if(file_in == NULL) exit(10);
+	if(file_out == NULL) exit(10);
+	
+	printf("Echo Canceller Test\n");
+	
+	ms_init();
+	signal(SIGINT,stop_handler);
+	card=snd_card_manager_get_card(snd_card_manager,0);
+	if (card==NULL)
+		g_error("No sound card detected.");
+	mic=snd_card_create_read_filter(card);
+	speaker=snd_card_create_write_filter(card);
+	ms_sound_read_set_device(MS_SOUND_READ(mic),0);
+	ms_sound_write_set_device(MS_SOUND_WRITE(speaker),0);
+
+	
+	
+
+	ec=ms_ec_new();
+	timer=ms_timer_new();
+
+	ms_filter_link(file_in,0,ec,0,LINK_FIFO);
+	ms_filter_link(ec,0,speaker,0,LINK_FIFO);
+	
+	ms_filter_link(mic,0,ec,1,LINK_FIFO);
+	ms_filter_link(ec,1,file_out,0,LINK_FIFO);
+
+	ms_sync_attach(timer,file_in);
+	ms_sync_attach(timer,mic);
+
+	ms_start(timer);
+	while(cond)
+	{
+		sleep(1);
+	}
+	printf("stoping sync...\n");
+	ms_stop(timer);
+	printf("unlinking filters...\n");
+	ms_filter_remove_links(file_in,ec);
+	ms_filter_remove_links(ec,speaker);
+	ms_filter_remove_links(mic,ec);
+	ms_filter_remove_links(ec,file_out);
+	printf("destroying filters...\n");
+	ms_filter_destroy(mic);
+	ms_filter_destroy(file_in);
+	ms_filter_destroy(file_out);
+	ms_filter_destroy(ec);
+	ms_filter_destroy(speaker);
+	ms_sync_destroy(timer);
+	exit(0);
+}
