From 092375c98a2328526ef3a40706dd6084cd12e656 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 Jan 2014 11:09:52 +0100 Subject: [PATCH] SDP offer answer fix: declined streams must remain as inactive in future offers. --- coreapi/callbacks.c | 59 +++++++++++++++++++++---------------- coreapi/linphonecall.c | 66 +++++++++++++++++++++++++----------------- coreapi/linphonecore.c | 30 ++++++++++--------- coreapi/private.h | 5 ++-- coreapi/sal.c | 3 +- include/sal/sal.h | 2 +- 6 files changed, 96 insertions(+), 69 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4f84da609..ab1f5a720 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -74,14 +74,28 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ SalMediaDescription *oldmd=call->resultdesc; + bool_t all_muted=FALSE; + bool_t send_ringbacktone=FALSE; linphone_core_stop_ringing(lc); - if (new_md!=NULL){ - sal_media_description_ref(new_md); - call->media_pending=FALSE; - }else{ - call->media_pending=TRUE; + if (!new_md) { + ms_error("linphone_core_update_streams() called with null media description"); + return; } + if (call->biggestdesc==NULL || new_md->n_total_streams>call->biggestdesc->n_total_streams){ + /*we have been offered and now are ready to proceed, or we added a new stream*/ + /*store the media description to remember the mapping of calls*/ + if (call->biggestdesc){ + sal_media_description_unref(call->biggestdesc); + call->biggestdesc=NULL; + } + if (sal_call_is_offerer(call->op)) + call->biggestdesc=sal_media_description_ref(call->localdesc); + else + call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op)); + } + sal_media_description_ref(new_md); + call->expect_media_in_ack=FALSE; call->resultdesc=new_md; if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){ /* we already started media: check if we really need to restart it*/ @@ -121,23 +135,18 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia linphone_call_init_media_streams (call); } - if (new_md) { - bool_t all_muted=FALSE; - bool_t send_ringbacktone=FALSE; - - if (call->audiostream==NULL){ - /*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/ - linphone_call_init_media_streams (call); - } - if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ - send_ringbacktone=TRUE; - } - if (call->state==LinphoneCallIncomingEarlyMedia || - (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){ - all_muted=TRUE; - } - linphone_call_start_media_streams(call,all_muted,send_ringbacktone); + if (call->audiostream==NULL){ + /*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/ + linphone_call_init_media_streams (call); } + if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ + send_ringbacktone=TRUE; + } + if (call->state==LinphoneCallIncomingEarlyMedia || + (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){ + all_muted=TRUE; + } + linphone_call_start_media_streams(call,all_muted,send_ringbacktone); if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); } @@ -413,10 +422,10 @@ static void call_ack(SalOp *op){ ms_warning("No call to be ACK'd"); return ; } - if (call->media_pending){ + if (call->expect_media_in_ack){ SalMediaDescription *md=sal_call_get_final_media_description(op); if (md && !sal_media_description_empty(md)){ - linphone_core_update_streams (lc,call,md); + linphone_core_update_streams(lc,call,md); linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); }else{ /*send a bye*/ @@ -430,7 +439,7 @@ static void call_ack(SalOp *op){ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ SalMediaDescription *md; SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op); - if ((rmd!=NULL) && (call->ice_session!=NULL)) { + if (rmd!=NULL && call->ice_session!=NULL) { linphone_core_update_ice_from_remote_media_description(call,rmd); linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session); } @@ -492,7 +501,7 @@ static void call_updating(SalOp *op){ if (rmd==NULL){ /* case of a reINVITE without SDP */ call_accept_update(lc,call); - call->media_pending=TRUE; + call->expect_media_in_ack=TRUE; return; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 88e7c49e2..e7a1390cc 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -229,6 +229,35 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St } } +static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ + LinphoneCore *lc=call->core; + int i; + SalMediaDescription *old_md=call->localdesc; + bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); + + for(i=0; in_active_streams; i++) { + if (md->streams[i].proto == SalProtoRtpSavp) { + if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ + int j; + ms_message("Keeping same crypto keys."); + for(j=0;jstreams[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, SAL_SRTP_KEY_SIZE)) + 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, SAL_SRTP_KEY_SIZE)) + md->streams[i].crypto[1].algo = 0; + md->streams[i].crypto[2].algo = 0; + } + } + } +} + void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ MSList *l; PayloadType *pt; @@ -237,7 +266,6 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * const char *me; SalMediaDescription *md=sal_media_description_new(); LinphoneAddress *addr; - bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); char* local_ip=call->localip; linphone_core_adapt_to_network(lc,call->ping_time,&call->params); @@ -250,8 +278,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); - md->n_total_streams=(old_md ? old_md->n_total_streams : 1); - md->n_active_streams=1; + md->n_total_streams=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1); + strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); @@ -260,6 +288,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ + md->n_active_streams=1; strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr)); strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr)); md->streams[0].rtp_port=call->audio_port; @@ -292,34 +321,15 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * for (i = md->n_active_streams; i < md->n_total_streams; i++) { md->streams[i].rtp_port = 0; md->streams[i].rtcp_port = 0; - md->streams[i].proto = SalProtoRtpAvp; - md->streams[i].type = old_md->streams[i].type; + md->streams[i].proto = call->biggestdesc->streams[i].proto; + md->streams[i].type = call->biggestdesc->streams[i].type; md->streams[i].dir = SalStreamInactive; l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1); md->streams[i].payloads = l; } - for(i=0; in_active_streams; i++) { - if (md->streams[i].proto == SalProtoRtpSavp) { - if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ - int j; - ms_message("Keeping same crypto keys."); - for(j=0;jstreams[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, SAL_SRTP_KEY_SIZE)) - 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, SAL_SRTP_KEY_SIZE)) - md->streams[i].crypto[1].algo = 0; - md->streams[i].crypto[2].algo = 0; - } - } - } + setup_encryption_keys(call,md); + update_media_description_from_stun(md,&call->ac,&call->vc); if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(md, call->ice_session); @@ -817,6 +827,10 @@ static void linphone_call_destroy(LinphoneCall *obj) sal_op_release(obj->op); obj->op=NULL; } + if (obj->biggestdesc!=NULL){ + sal_media_description_unref(obj->biggestdesc); + obj->biggestdesc=NULL; + } if (obj->resultdesc!=NULL) { sal_media_description_unref(obj->resultdesc); obj->resultdesc=NULL; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f49ae5bc4..522c93f23 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2558,20 +2558,22 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } } - - if (!lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; - sal_call_set_local_media_description(call->op,call->localdesc); - } real_url=linphone_address_as_string(call->log->to); from=linphone_address_as_string(call->log->from); - err=sal_call(call->op,from,real_url); - call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/ - - if (lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; + + if (!lc->sip_conf.sdp_200_ack){ + /*we are offering, set local media description before sending the call*/ sal_call_set_local_media_description(call->op,call->localdesc); } + err=sal_call(call->op,from,real_url); + if (lc->sip_conf.sdp_200_ack){ + /*we are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive*/ + sal_call_set_local_media_description(call->op,call->localdesc); + } + + call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/ + barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,barmsg); @@ -2954,7 +2956,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (propose_early_media || ringback_tone!=NULL){ linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); md=sal_call_get_final_media_description(call->op); - linphone_core_update_streams(lc,call,md); + if (md) linphone_core_update_streams(lc,call,md); } if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ linphone_core_accept_call(lc,call); @@ -3329,11 +3331,11 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, lc->current_call=call; linphone_call_set_state(call,LinphoneCallConnected,"Connected"); new_md=sal_call_get_final_media_description(call->op); - linphone_core_update_streams(lc, call, new_md); - linphone_call_fix_call_parameters(call); if (new_md){ + linphone_core_update_streams(lc, call, new_md); + linphone_call_fix_call_parameters(call); linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); - }else call->media_pending=TRUE; + }else call->expect_media_in_ack=TRUE; ms_message("call answered."); return 0; diff --git a/coreapi/private.h b/coreapi/private.h index f467c8202..32d3553a0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -158,9 +158,10 @@ struct _LinphoneCall int magic; /*used to distinguish from proxy config*/ struct _LinphoneCore *core; int af; /*the address family to prefer for RTP path, guessed from signaling path*/ + LinphoneCallDir dir; + SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/ SalMediaDescription *localdesc; SalMediaDescription *resultdesc; - LinphoneCallDir dir; struct _RtpProfile *audio_profile; struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; @@ -206,7 +207,7 @@ struct _LinphoneCall int localdesc_changed; bool_t refer_pending; - bool_t media_pending; + bool_t expect_media_in_ack; bool_t audio_muted; bool_t camera_enabled; diff --git a/coreapi/sal.c b/coreapi/sal.c index a5bcd89c2..babb2af4d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -68,8 +68,9 @@ static void sal_media_description_destroy(SalMediaDescription *md){ ms_free(md); } -void sal_media_description_ref(SalMediaDescription *md){ +SalMediaDescription * sal_media_description_ref(SalMediaDescription *md){ md->refcount++; + return md; } void sal_media_description_unref(SalMediaDescription *md){ diff --git a/include/sal/sal.h b/include/sal/sal.h index ddf94a4e2..1dfe813ba 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -233,7 +233,7 @@ typedef struct SalIsComposing { #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 SalMediaDescription *sal_media_description_new(); -void sal_media_description_ref(SalMediaDescription *md); +SalMediaDescription * sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(const SalMediaDescription *md); int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2);