Index: include/mediastreamer2/mediastream.h
===================================================================
--- include/mediastreamer2/mediastream.h	(revision 1297)
+++ include/mediastreamer2/mediastream.h	(revision 1340)
@@ -59,7 +59,4 @@
 	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 */
 	OrtpEvQueue *evq;
 	bool_t play_dtmfs;
Index: include/mediastreamer2/msinterfaces.h
===================================================================
--- include/mediastreamer2/msinterfaces.h	(revision 1332)
+++ include/mediastreamer2/msinterfaces.h	(revision 1340)
@@ -108,4 +108,12 @@
 	MS_FILTER_METHOD(MSFilterEchoCancellerInterface,4,bool_t)
 
+/** retrieve echo canceller internal state, as a base64 encoded string */
+#define MS_ECHO_CANCELLER_GET_STATE_STRING \
+	MS_FILTER_METHOD(MSFilterEchoCancellerInterface,5,char **)
+
+/** restore a previous state suppling the echo canceller config as base64 encoded string */
+#define MS_ECHO_CANCELLER_SET_STATE_STRING \
+	MS_FILTER_METHOD(MSFilterEchoCancellerInterface,6, const char *)
+
 
 
Index: src/audiostream.c
===================================================================
--- src/audiostream.c	(revision 1330)
+++ src/audiostream.c	(revision 1340)
@@ -299,25 +299,10 @@
 
 	/*configure the echo canceller if required */
-	if (use_ec) {
-		MSFilterDesc *ec_desc=ms_filter_lookup_by_name("MSOslec");
-		if (ec_desc!=NULL)
-			stream->ec=ms_filter_new_from_desc(ec_desc);
-		else
-			stream->ec=ms_filter_new(MS_SPEEX_EC_ID);
+	if (!use_ec) {
+		ms_filter_destroy(stream->ec);
+		stream->ec=NULL;
+	}
+	if (stream->ec){
 		ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
-		if (stream->ec_tail_len!=0)
-			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_ECHO_CANCELLER_SET_DELAY,&stream->ec_delay);
-		}else{
-			/*configure from latency of sound card in case it is availlable */
-			int latency=0;
-			ms_filter_call_method(stream->soundread,MS_FILTER_GET_LATENCY,&latency);
-			latency-=20; /*keep 30 milliseconds security margin*/
-			if (latency<0) latency=0;
-			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&latency);
-		}
-		if (stream->ec_framesize!=0)
-			ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_FRAMESIZE,&stream->ec_framesize);
 	}
 
@@ -460,6 +445,15 @@
 AudioStream *audio_stream_new(int locport, bool_t ipv6){
 	AudioStream *stream=(AudioStream *)ms_new0(AudioStream,1);
+	MSFilterDesc *ec_desc=ms_filter_lookup_by_name("MSOslec");
+
 	stream->session=create_duplex_rtpsession(locport,ipv6);
+	/*some filters are created right now to allow configuration by the application before start() */
 	stream->rtpsend=ms_filter_new(MS_RTP_SEND_ID);
+	
+	if (ec_desc!=NULL)
+		stream->ec=ms_filter_new_from_desc(ec_desc);
+	else
+		stream->ec=ms_filter_new(MS_SPEEX_EC_ID);
+
 	stream->evq=ortp_ev_queue_new();
 	rtp_session_register_event_queue(stream->session,stream->evq);
@@ -486,8 +480,12 @@
 }
 
-void audio_stream_set_echo_canceller_params(AudioStream *st, int tail_len_ms, int delay_ms, int framesize){
-	st->ec_tail_len=tail_len_ms;
-	st->ec_delay=delay_ms;
-	st->ec_framesize=framesize;
+void audio_stream_set_echo_canceller_params(AudioStream *stream, int tail_len_ms, int delay_ms, int framesize){
+	if (tail_len_ms!=0)
+		ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_TAIL_LENGTH,&tail_len_ms);
+	if (delay_ms!=0){
+		ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&delay_ms);
+	}
+	if (framesize!=0)
+		ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_FRAMESIZE,&framesize);
 }
 
Index: src/macsnd.c
===================================================================
--- src/macsnd.c	(revision 1339)
+++ src/macsnd.c	(revision 1324)
@@ -68,18 +68,17 @@
 static void show_format(const char *name, AudioStreamBasicDescription * deviceFormat)
 {
-	ms_debug("Format for %s", name);
-	ms_debug("mSampleRate = %g", deviceFormat->mSampleRate);
+	ms_message("Format for %s", name);
+	ms_message("mSampleRate = %g", deviceFormat->mSampleRate);
 	unsigned int fcc= ntohl(deviceFormat->mFormatID);
 	char outName[5];
 	memcpy(outName,&fcc,4);
 	outName[4] = 0;
-	ms_debug("mFormatID = %s", outName);
-	ms_debug("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
-	ms_debug("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
-	ms_debug("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
-	ms_debug("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
-	ms_debug("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
-	ms_debug("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
-	ms_message("Format for [%s] rate [%g] channels [%ld]", outName,deviceFormat->mSampleRate,deviceFormat->mChannelsPerFrame);
+	ms_message("mFormatID = %s", outName);
+	ms_message("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
+	ms_message("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
+	ms_message("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
+	ms_message("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
+	ms_message("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
+	ms_message("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
 }
 
@@ -186,10 +185,8 @@
 	slen = sizeof(format);
 	d->rate=44100;
-	if (d->dev != -1) {
-		err = AudioDeviceGetProperty(dev, 0, cap & MS_SND_CARD_CAP_CAPTURE, kAudioDevicePropertyStreamFormat, &slen, &format);
-		if (err == kAudioHardwareNoError) {
-			show_format("device", &format);
-			d->rate=format.mSampleRate;
-		}
+	err = AudioDeviceGetProperty(dev, 0, cap & MS_SND_CARD_CAP_CAPTURE, kAudioDevicePropertyStreamFormat, &slen, &format);
+	if (err == kAudioHardwareNoError) {
+		show_format("output device", &format);
+		d->rate=format.mSampleRate;
 	}
 	return card;
@@ -269,23 +266,16 @@
 		return;
 	}
-	//first, add Default AudioUnit
-	ms_snd_card_manager_add_card(m,ca_card_new("Default", "",-1, MS_SND_CARD_CAP_CAPTURE|MS_SND_CARD_CAP_PLAYBACK));
-
 	count = slen / sizeof(AudioDeviceID);
 	for (i = 0; i < count; i++) {
 		MSSndCard *card;
 		char uidname[256]={0},devname[256]={0};
-		int card_capacity=0;
 		if (check_card_capability(devices[i],FALSE,devname,uidname,sizeof(uidname))){
-			card_capacity|=MS_SND_CARD_CAP_PLAYBACK;
+			card=ca_card_new(devname, uidname, devices[i], MS_SND_CARD_CAP_PLAYBACK);
+			ms_snd_card_manager_add_card(m, card);
 		}
 		if (check_card_capability(devices[i],TRUE,devname,uidname,sizeof(uidname))){
-			card_capacity|=MS_SND_CARD_CAP_CAPTURE;
-		}
-		if (card_capacity) {
-			card=ca_card_new(devname, uidname, devices[i], card_capacity);
+			card=ca_card_new(devname, uidname, devices[i], MS_SND_CARD_CAP_CAPTURE);
 			ms_snd_card_manager_add_card(m, card);
 		}
-
 	}
 }
@@ -362,5 +352,5 @@
 	// Get Default Input audio unit
 	desc.componentType = kAudioUnitType_Output;
-	desc.componentSubType = d->dev!=-1?kAudioUnitSubType_HALOutput:kAudioUnitSubType_DefaultOutput;
+	desc.componentSubType = kAudioUnitSubType_HALOutput;
 	desc.componentManufacturer = kAudioUnitManufacturer_Apple;
 	desc.componentFlags = 0;
@@ -382,31 +372,29 @@
 	
 	param = is_read;
-	if (d->dev!=-1) {
-		CHECK_AURESULT(AudioUnitSetProperty(d->au,
-					  kAudioOutputUnitProperty_EnableIO,
-					  kAudioUnitScope_Input,
-					  input_bus,
-					  &param,
-					  sizeof(UInt32)));
-
-		param = !is_read;
-		CHECK_AURESULT(AudioUnitSetProperty(d->au,
-					  kAudioOutputUnitProperty_EnableIO,
-					  kAudioUnitScope_Output,
-					  output_bus,
-					  &param,
-					  sizeof(UInt32)));
-
-
-
-		// Set the current device
-	
-			CHECK_AURESULT(AudioUnitSetProperty(d->au,
-					  kAudioOutputUnitProperty_CurrentDevice,
-					  kAudioUnitScope_Global,
-					  output_bus,
-					  &d->dev,
-					  sizeof(AudioDeviceID)));
-	}
+	CHECK_AURESULT(AudioUnitSetProperty(d->au,
+				  kAudioOutputUnitProperty_EnableIO,
+				  kAudioUnitScope_Input,
+				  input_bus,
+				  &param,
+				  sizeof(UInt32)));
+	
+	param = !is_read;
+	CHECK_AURESULT(AudioUnitSetProperty(d->au,
+				  kAudioOutputUnitProperty_EnableIO,
+				  kAudioUnitScope_Output,
+				  output_bus,
+				  &param,
+				  sizeof(UInt32)));
+	
+	
+	
+	// Set the current device
+	CHECK_AURESULT(AudioUnitSetProperty(d->au,
+				  kAudioOutputUnitProperty_CurrentDevice,
+				  kAudioUnitScope_Global,
+				  output_bus,
+				  &d->dev,
+				  sizeof(AudioDeviceID)));
+	
 
 	param=0;
Index: src/speexec.c
===================================================================
--- src/speexec.c	(revision 1336)
+++ src/speexec.c	(revision 1340)
@@ -23,4 +23,5 @@
 #include <speex/speex_echo.h>
 #include <speex/speex_preprocess.h>
+#include "ortp/b64.h"
 
 #ifdef HAVE_CONFIG_H
@@ -139,4 +140,5 @@
 	int min_ref_samples;
 	AudioFlowController afc;
+	char *state_str;
 #ifdef EC_DUMP
 	FILE *echofile;
@@ -160,4 +162,5 @@
 	s->framesize=framesize;
 	s->den = NULL;
+	s->state_str=NULL;
 	s->using_zeroes=FALSE;
 	s->echostarted=FALSE;
@@ -183,4 +186,5 @@
 static void speex_ec_uninit(MSFilter *f){
 	SpeexECState *s=(SpeexECState*)f->data;
+	if (s->state_str) ms_free(s->state_str);
 	ms_bufferizer_uninit(&s->delayed_ref);
 #ifdef EC_DUMP
@@ -193,4 +197,53 @@
 }
 
+#ifdef SPEEX_ECHO_GET_BLOB
+
+static void apply_config(SpeexECState *s){
+	if (s->state_str!=NULL){
+		size_t buflen=strlen(s->state_str);
+		uint8_t *buffer=alloca(buflen);
+		SpeexEchoStateBlob *blob;
+		if ((buflen=b64_decode(s->state_str,strlen(s->state_str),buffer,buflen))<=0){
+			ms_error("Could not decode base64 %s",s->state_str);
+			return;
+		}
+		blob=speex_echo_state_blob_new_from_memory(buffer,buflen);
+		if (blob==NULL){
+			ms_error("Could not create blob from config string");
+			return;
+		}
+		if (speex_echo_ctl(s->ecstate, SPEEX_ECHO_SET_BLOB, blob)!=0){
+			ms_error("Could not apply speex echo blob !");
+		}
+		speex_echo_state_blob_free(blob);
+		ms_message("speex echo state restored.");
+	}	
+}
+
+static void fetch_config(SpeexECState *s){
+	SpeexEchoStateBlob *blob=NULL;
+	char *txt;
+	size_t txt_len;
+
+	if (s->ecstate==NULL) return;
+	
+	if (speex_echo_ctl(s->ecstate, SPEEX_ECHO_GET_BLOB, &blob)!=0){
+		ms_error("Could not retrieve speex echo blob !");
+		return;
+	}
+	txt_len=(speex_echo_state_blob_get_size(blob)*4)+1;
+	txt=ms_malloc0(txt_len);
+	if (b64_encode(speex_echo_state_blob_get_data(blob),speex_echo_state_blob_get_size(blob),
+			txt,txt_len)==0){
+		ms_error("Base64 encoding failed.");
+		ms_free(txt);
+		return;
+	}
+	speex_echo_state_blob_free(blob);
+	if (s->state_str) ms_free(s->state_str);
+	s->state_str=txt;
+}
+
+#endif
 
 static void speex_ec_preprocess(MSFilter *f){
@@ -216,4 +269,9 @@
 	s->nominal_ref_samples=delay_samples;
 	audio_flow_controller_init(&s->afc);
+#ifdef SPEEX_ECHO_GET_BLOB
+	apply_config(s);
+#else
+	if (s->state_str) ms_warning("This version of speex doesn't support echo canceller restoration state. Rebuild speex and mediatreamer2 if you want to use this feature.");
+#endif
 }
 
@@ -310,4 +368,5 @@
 static void speex_ec_postprocess(MSFilter *f){
 	SpeexECState *s=(SpeexECState*)f->data;
+
 	ms_bufferizer_flush (&s->delayed_ref);
 	ms_bufferizer_flush (&s->echo);
@@ -354,4 +413,19 @@
 	SpeexECState *s=(SpeexECState*)f->data;
 	*(bool_t*)arg=s->bypass_mode;
+	return 0;
+}
+
+static int speex_ec_set_state(MSFilter *f, void *arg){
+	SpeexECState *s=(SpeexECState*)f->data;
+	s->state_str=ms_strdup((const char*)arg);
+	return 0;
+}
+
+static int speex_ec_get_state(MSFilter *f, void *arg){
+	SpeexECState *s=(SpeexECState*)f->data;
+#ifdef SPEEX_ECHO_GET_BLOB
+	fetch_config(s);
+#endif
+	*(char**)arg=s->state_str;
 	return 0;
 }
@@ -363,5 +437,7 @@
 	{	MS_ECHO_CANCELLER_SET_FRAMESIZE		,	speex_ec_set_framesize		},
 	{	MS_ECHO_CANCELLER_SET_BYPASS_MODE	,	speex_ec_set_bypass_mode	},
-	{	MS_ECHO_CANCELLER_GET_BYPASS_MODE	,	speex_ec_get_bypass_mode	}
+	{	MS_ECHO_CANCELLER_GET_BYPASS_MODE	,	speex_ec_get_bypass_mode	},
+	{	MS_ECHO_CANCELLER_GET_STATE_STRING	,	speex_ec_get_state		},
+	{	MS_ECHO_CANCELLER_SET_STATE_STRING	,	speex_ec_set_state		}
 };
 
