SDP offer answer fix: declined streams must remain as inactive in future offers.

This commit is contained in:
Simon Morlat 2014-01-24 11:09:52 +01:00
parent 2394027f9e
commit 092375c98a
6 changed files with 96 additions and 69 deletions

View file

@ -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;
}

View file

@ -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; i<md->n_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;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, 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; i<md->n_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;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, 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;

View file

@ -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;

View file

@ -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;

View file

@ -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){

View file

@ -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);