diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c
index e0b0174ad55134e3f53d7356f2687145ad8952ee..d8fdd8803b081519ee04c5268c7fd77c965f3cd8 100644
--- a/coreapi/linphonecall.c
+++ b/coreapi/linphonecall.c
@@ -208,22 +208,23 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St
 	
 }
 
-
-static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){
+void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
 	MSList *l;
 	PayloadType *pt;
+	SalMediaDescription *old_md=call->localdesc;
 	int i;
 	const char *me=linphone_core_get_identity(lc);
 	LinphoneAddress *addr=linphone_address_new(me);
 	const char *username=linphone_address_get_username (addr);
 	SalMediaDescription *md=sal_media_description_new();
+	bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
 	
 	if (call->ping_time>0) {
 		linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
 	}
 
-	md->session_id=session_id;
-	md->session_ver=session_ver;
+	md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
+	md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
 	md->nstreams=1;
 	strncpy(md->addr,call->localip,sizeof(md->addr));
 	strncpy(md->username,username,sizeof(md->username));
@@ -248,8 +249,6 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
 	pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
 	l=ms_list_append(l,pt);
 	md->streams[0].payloads=l;
-	
-
 
 	if (call->params.has_video){
 		md->nstreams++;
@@ -263,15 +262,22 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
 	
 	for(i=0; i<md->nstreams; i++) {
 		if (md->streams[i].proto == SalProtoRtpSavp) {
-			md->streams[i].crypto[0].tag = 1;
-			md->streams[i].crypto[0].algo = AES_128_SHA1_80;
-			if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
-				md->streams[i].crypto[0].algo = 0;
-			md->streams[i].crypto[1].tag = 2;
-			md->streams[i].crypto[1].algo = AES_128_SHA1_32;
-			if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
-				md->streams[i].crypto[1].algo = 0;
-			md->streams[i].crypto[2].algo = 0;
+			if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
+				int j;
+				for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
+					memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
+				}
+			}else{
+				md->streams[i].crypto[0].tag = 1;
+				md->streams[i].crypto[0].algo = AES_128_SHA1_80;
+				if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
+					md->streams[i].crypto[0].algo = 0;
+				md->streams[i].crypto[1].tag = 2;
+				md->streams[i].crypto[1].algo = AES_128_SHA1_32;
+				if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
+					md->streams[i].crypto[1].algo = 0;
+				md->streams[i].crypto[2].algo = 0;
+			}
 		}
 	}
 	update_media_description_from_stun(md,&call->ac,&call->vc);
@@ -280,22 +286,8 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
 		linphone_core_update_ice_state_in_call_stats(call);
 	}
 	linphone_address_destroy(addr);
-	return md;
-}
-
-void update_local_media_description(LinphoneCore *lc, LinphoneCall *call){
-	SalMediaDescription *md=call->localdesc;
-	if (md== NULL) {
-		call->localdesc = create_local_media_description(lc,call);
-	} else {
-		call->localdesc = _create_local_media_description(lc,call,md->session_id,md->session_ver+1);
-		sal_media_description_unref(md);
-	}
-}
-
-SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call){
-	unsigned int id=rand() & 0xfff;
-	return _create_local_media_description(lc,call,id,id);
+	call->localdesc=md;
+	if (old_md) sal_media_description_unref(old_md);
 }
 
 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
@@ -1026,11 +1018,11 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u
 			ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
 			linphone_call_send_vfu_request(call);
 			break;
-        case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
-            ms_message("First video frame decoded successfully");
-            if (call->nextVideoFrameDecoded._func != NULL)
-                call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
-            break;
+		case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
+			ms_message("First video frame decoded successfully");
+			if (call->nextVideoFrameDecoded._func != NULL)
+			call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
+			break;
 		default:
 			ms_warning("Unhandled event %i", event_id);
 			break;
@@ -1039,10 +1031,10 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u
 #endif
 
 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
-    call->nextVideoFrameDecoded._func = cb;
-    call->nextVideoFrameDecoded._user_data = user_data;
+	call->nextVideoFrameDecoded._func = cb;
+	call->nextVideoFrameDecoded._user_data = user_data;
 #ifdef VIDEO_ENABLED
-    ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
+	ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
 #endif
 }
 
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index f3d0a00302f7910c780b01970ecc82315aec8728..01667ebcb4f7608ae26d367fe7787d3cf487a4e8 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -2290,7 +2290,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){
 	linphone_call_init_media_streams(call);
 	if (lc->ringstream==NULL)
 		audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
-	call->localdesc=create_local_media_description(lc,call);
+	linphone_call_make_local_media_description(lc,call);
 	if (!lc->sip_conf.sdp_200_ack){
 		call->media_pending=TRUE;
 		sal_call_set_local_media_description(call->op,call->localdesc);
@@ -2552,7 +2552,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
 	bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
 	const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc);
 
-	call->localdesc=create_local_media_description(lc,call);
+	linphone_call_make_local_media_description(lc,call);
 	sal_call_set_local_media_description(call->op,call->localdesc);
 	md=sal_call_get_final_media_description(call->op);
 	if (md && sal_media_description_empty(md)){
@@ -2658,7 +2658,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
 			call->videostream->ice_check_list = NULL;
 		}
 		call->params = *params;
-		update_local_media_description(lc, call);
+		linphone_call_make_local_media_description(lc, call);
 		if ((call->ice_session != NULL) && !has_video && call->params.has_video) {
 			/* Defer call update until the ICE candidates gathering process has finished. */
 			ms_message("Defer call update to gather ICE candidates");
@@ -2769,7 +2769,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
 	}
 	call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op));
 	call->camera_active=call->params.has_video;
-	update_local_media_description(lc,call);
+	linphone_call_make_local_media_description(lc,call);
 	if (call->ice_session != NULL) {
 		linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
 #ifdef VIDEO_ENABLED
@@ -2885,7 +2885,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
 		call->params=*params;
 		call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op));
 		call->camera_active=call->params.has_video;
-		update_local_media_description(lc,call);
+		linphone_call_make_local_media_description(lc,call);
 		sal_call_set_local_media_description(call->op,call->localdesc);
 	}
 	
@@ -3075,7 +3075,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
 		ms_warning("Cannot pause this call, it is not active.");
 		return -1;
 	}
-	update_local_media_description(lc,call);
+	linphone_call_make_local_media_description(lc,call);
 	if (call->ice_session != NULL)
 		linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
 	if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){
@@ -3154,7 +3154,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call)
 	 prevents the participants to hear it while the 200OK comes back.*/
 	if (call->audiostream) audio_stream_play(call->audiostream, NULL);
 
-	update_local_media_description(lc,the_call);
+	linphone_call_make_local_media_description(lc,the_call);
 	if (call->ice_session != NULL)
 		linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
 	sal_call_set_local_media_description(call->op,call->localdesc);
diff --git a/coreapi/private.h b/coreapi/private.h
index 60587dbcd8dc9524e598e9bf85f380401b345a99..5ebe8b5b7611c491970ab3579db576515b6c98ae 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -582,10 +582,7 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call);
 int linphone_core_get_calls_nb(const LinphoneCore *lc);
 
 void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
-
-SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call);
-void update_local_media_description(LinphoneCore *lc, LinphoneCall *call);
-
+void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
 void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
 
 bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt,  int bandwidth_limit);
diff --git a/coreapi/sal.c b/coreapi/sal.c
index 229ee577f3a531e3b8c9d3bf85c1312c6d5e03aa..f46d9a556c9b3f4b78be57fe10cf939ed173f868 100644
--- a/coreapi/sal.c
+++ b/coreapi/sal.c
@@ -162,6 +162,10 @@ static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
 	return TRUE;
 }
 
+static bool_t is_recv_only(PayloadType *p){
+	return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
+}
+
 static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
 	const MSList *e1,*e2;
 	for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
@@ -170,6 +174,12 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
 		if (!payload_type_equals(p1,p2))
 			return FALSE;
 	}
+	if (e1!=NULL){
+		/*skip possible recv-only payloads*/
+		for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
+			ms_message("Skipping recv-only payload type...");
+		}
+	}
 	if (e1!=NULL || e2!=NULL){
 		/*means one list is longer than the other*/
 		return FALSE;