From dd45665ea0fc35273f1dfff0f571f7955320d94a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 22 Oct 2012 15:44:23 +0200 Subject: [PATCH] Do not restart the media streams if only network addresses have been changed in re-invite. --- coreapi/callbacks.c | 69 ++++++++++++++++++++++++++++++++++++++++++--- coreapi/sal.c | 52 +++++++++++++++++++--------------- coreapi/sal.h | 7 ++++- 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e7f6a7b2..a4a4232c 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -27,9 +27,63 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); -static bool_t media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd){ - if (call->params.in_conference!=call->current_params.in_conference) return TRUE; - return !sal_media_description_equals(oldmd,newmd) || call->up_bw!=linphone_core_get_upload_bandwidth(call->core); +static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { + if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; + if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED; + return sal_media_description_equals(oldmd, newmd); +} + +void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { + SalStreamDescription *old_audiodesc = NULL; + SalStreamDescription *old_videodesc = NULL; + SalStreamDescription *new_audiodesc = NULL; + SalStreamDescription *new_videodesc = NULL; + char *rtp_addr, *rtcp_addr; + int i; + + for (i = 0; i < old_md->nstreams; i++) { + if (old_md->streams[i].type == SalAudio) { + old_audiodesc = &old_md->streams[i]; + } else if (old_md->streams[i].type == SalVideo) { + old_videodesc = &old_md->streams[i]; + } + } + for (i = 0; i < new_md->nstreams; i++) { + if (new_md->streams[i].type == SalAudio) { + new_audiodesc = &new_md->streams[i]; + } else if (new_md->streams[i].type == SalVideo) { + new_videodesc = &new_md->streams[i]; + } + } + if (call->audiostream && new_audiodesc) { + rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr; + rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr; + ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->audiostream->session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + } +#ifdef VIDEO_ENABLED + if (call->videostream && new_videodesc) { + rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr; + rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr; + ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->videostream->session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + } +#endif + + /* Copy address and port values from new_md to old_md since we will keep old_md as resultdesc */ + strcpy(old_md->addr, new_md->addr); + if (old_audiodesc && new_audiodesc) { + strcpy(old_audiodesc->rtp_addr, new_audiodesc->rtp_addr); + strcpy(old_audiodesc->rtcp_addr, new_audiodesc->rtcp_addr); + old_audiodesc->rtp_port = new_audiodesc->rtp_port; + old_audiodesc->rtcp_port = new_audiodesc->rtcp_port; + } + if (old_videodesc && new_videodesc) { + strcpy(old_videodesc->rtp_addr, new_videodesc->rtp_addr); + strcpy(old_videodesc->rtcp_addr, new_videodesc->rtcp_addr); + old_videodesc->rtp_port = new_videodesc->rtp_port; + old_videodesc->rtcp_port = new_videodesc->rtcp_port; + } } void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ @@ -49,7 +103,8 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if ((call->audiostream && call->audiostream->ticker) || (call->videostream && call->videostream->ticker)){ /* we already started media: check if we really need to restart it*/ if (oldmd){ - if (!media_parameters_changed(call,oldmd,new_md) && !call->playing_ringbacktone){ + int md_changed = media_parameters_changed(call, oldmd, new_md); + if ((md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) && !call->playing_ringbacktone) { /*as nothing has changed, keep the oldmd */ call->resultdesc=oldmd; sal_media_description_unref(new_md); @@ -66,6 +121,12 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia } ms_message("No need to restart streams, SDP is unchanged."); return; + } else if ((md_changed == SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) && !call->playing_ringbacktone) { + call->resultdesc = oldmd; + ms_message("Network parameters have changed, update them."); + linphone_core_update_streams_destinations(lc, call, oldmd, new_md); + sal_media_description_unref(new_md); + return; }else{ ms_message("Media descriptions are different, need to restart the streams."); } diff --git a/coreapi/sal.c b/coreapi/sal.c index b349ad0a..229ee577 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -177,32 +177,40 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ return TRUE; } -bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){ - if (sd1->proto!=sd2->proto) return FALSE; - if (sd1->type!=sd2->type) return FALSE; - if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE; - if (sd1->rtp_port!=sd2->rtp_port) return FALSE; - if (strcmp(sd1->rtcp_addr,sd2->rtcp_addr)!=0) return FALSE; - if (sd1->rtcp_port!=sd2->rtcp_port) return FALSE; - if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE; - if (sd1->bandwidth!=sd2->bandwidth) return FALSE; - if (sd1->ptime!=sd2->ptime) return FALSE; - /* compare candidates: TODO */ - if (sd1->dir!=sd2->dir) return FALSE; - return TRUE; +int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) { + int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; + + /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change + needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */ + if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + + if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtp_port != sd2->rtp_port) { + if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + } + if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + + return result; } -bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){ +int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) { + int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; int i; - - if (strcmp(md1->addr,md2->addr)!=0) return FALSE; - if (md1->nstreams!=md2->nstreams) return FALSE; - if (md1->bandwidth!=md2->bandwidth) return FALSE; - for(i=0;instreams;++i){ - if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i])) - return FALSE; + + if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (md1->nstreams != md2->nstreams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + for(i = 0; i < md1->nstreams; ++i){ + result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } - return TRUE; + return result; } static void assign_string(char **str, const char *arg){ diff --git a/coreapi/sal.h b/coreapi/sal.h index 2913096c..54a075ed 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -53,6 +53,11 @@ typedef enum { SalTransportDTLS /*DTLS*/ }SalTransport; +#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 +#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01 +#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02 +#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED) + const char* sal_transport_to_string(SalTransport transport); SalTransport sal_transport_parse(const char*); /* Address manipulation API*/ @@ -189,7 +194,7 @@ SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(const SalMediaDescription *md); -bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); +int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir); SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); -- 2.39.2