diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7985f3658..784c1f1bd 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -41,14 +41,14 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c char *rtp_addr, *rtcp_addr; int i; - for (i = 0; i < old_md->nstreams; i++) { + for (i = 0; i < old_md->n_active_streams; 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++) { + for (i = 0; i < new_md->n_active_streams; i++) { if (new_md->streams[i].type == SalAudio) { new_audiodesc = &new_md->streams[i]; } else if (new_md->streams[i].type == SalVideo) { @@ -591,7 +591,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){ /* clear SRTP local params */ call->params.media_encryption = LinphoneMediaEncryptionNone; - for(i=0; ilocaldesc->nstreams; i++) { + for(i=0; ilocaldesc->n_active_streams; i++) { call->localdesc->streams[i].proto = SalProtoRtpAvp; memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6ef8e0c55..d918057e9 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -173,9 +173,10 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t propagate_encryption_changed(call); } -static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){ +static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){ MSList *l=NULL; const MSList *it; + int nb = 0; if (max_sample_rate) *max_sample_rate=0; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; @@ -186,26 +187,30 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw } if (linphone_core_check_payload_type_usability(lc,pt)){ l=ms_list_append(l,payload_type_clone(pt)); + nb++; if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt); } } + if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break; } return l; } static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){ - if (ac->port!=0){ - strcpy(md->streams[0].rtp_addr,ac->addr); - md->streams[0].rtp_port=ac->port; - if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){ - strcpy(md->addr,ac->addr); + int i; + for (i = 0; i < md->n_active_streams; i++) { + if ((md->streams[i].type == SalAudio) && (ac->port != 0)) { + strcpy(md->streams[0].rtp_addr,ac->addr); + md->streams[0].rtp_port=ac->port; + if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){ + strcpy(md->addr,ac->addr); + } + } + if ((md->streams[i].type == SalVideo) && (vc->port != 0)) { + strcpy(md->streams[1].rtp_addr,vc->addr); + md->streams[1].rtp_port=vc->port; } } - if (vc->port!=0){ - strcpy(md->streams[1].rtp_addr,vc->addr); - md->streams[1].rtp_port=vc->port; - } - } void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ @@ -218,12 +223,13 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * 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); - + linphone_core_adapt_to_network(lc,call->ping_time,&call->params); 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; + md->n_total_streams=(old_md ? old_md->n_total_streams : 1); + md->n_active_streams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); strncpy(md->username,username,sizeof(md->username)); @@ -243,22 +249,35 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[0].ptime=call->params.down_ptime; else md->streams[0].ptime=linphone_core_get_download_ptime(lc); - l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate); + l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1); pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; if (call->params.has_video){ - md->nstreams++; + md->n_active_streams++; md->streams[1].rtp_port=call->video_port; md->streams[1].rtcp_port=call->video_port+1; md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; - l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL); + l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; } - - for(i=0; instreams; i++) { + if (md->n_total_streams < md->n_active_streams) + md->n_total_streams = md->n_active_streams; + + /* Deactivate inactive streams. */ + 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].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; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1ed5ef62f..20788eb16 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2576,7 +2576,7 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ if (linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP){ int i; - for(i=0;instreams;i++){ + for(i=0;in_active_streams;i++){ SalStreamDescription *sd=&md->streams[i]; if (sd->proto!=SalProtoRtpSavp){ return TRUE; diff --git a/coreapi/misc.c b/coreapi/misc.c index 53f0d65cf..b8041c433 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -734,7 +734,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * } strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); - for (i = 0; i < desc->nstreams; i++) { + for (i = 0; i < desc->n_active_streams; i++) { SalStreamDescription *stream = &desc->streams[i]; IceCheckList *cl = ice_session_check_list(session, i); nb_candidates = 0; @@ -838,7 +838,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, ice_session_restart(call->ice_session); ice_restarted = TRUE; } else { - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { @@ -857,7 +857,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); } - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { @@ -873,7 +873,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } /* Create ICE check lists if needed and parse ICE attributes. */ - for (i = 0; i < md->nstreams; i++) { + for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl == NULL) { @@ -930,7 +930,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } } } - for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) { + for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) { ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1)); } ice_session_check_mismatch(call->ice_session); @@ -948,8 +948,8 @@ bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescr { int i; - for (i = 0; i < md->nstreams; i++) { - if ((md->streams[i].type == SalVideo) && (md->streams[i].rtp_port != 0)) + for (i = 0; i < md->n_active_streams; i++) { + if (md->streams[i].type == SalVideo) return TRUE; } return FALSE; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 541a1eee3..ab38f7636 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal.h" #include "offeranswer.h" +#include "private.h" static bool_t only_telephone_event(const MSList *l){ for(;l!=NULL;l=l->next){ @@ -267,22 +268,23 @@ static void initiate_incoming(const SalStreamDescription *local_cap, * and the returned response (remote). **/ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, - const SalMediaDescription *remote_answer, - SalMediaDescription *result){ - int i,j; - + const SalMediaDescription *remote_answer, + SalMediaDescription *result){ + int i,j; + const SalStreamDescription *ls,*rs; - for(i=0,j=0;instreams;++i){ + for(i=0,j=0;in_total_streams;++i){ ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); - if (rs) { + if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); ++j; } else ms_warning("No matching stream for %i",i); } - result->nstreams=j; + result->n_active_streams=j; + result->n_total_streams=local_offer->n_total_streams; result->bandwidth=remote_answer->bandwidth; strcpy(result->addr,remote_answer->addr); return 0; @@ -294,12 +296,13 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, * The returned media description is an answer and should be sent to the offerer. **/ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, - const SalMediaDescription *remote_offer, - SalMediaDescription *result, bool_t one_matching_codec){ + const SalMediaDescription *remote_offer, + SalMediaDescription *result, bool_t one_matching_codec){ int i; const SalStreamDescription *ls=NULL,*rs; - - for(i=0;instreams;++i){ + + result->n_active_streams=0; + for(i=0;in_total_streams;++i){ rs=&remote_offer->streams[i]; if (rs->proto!=SalProtoUnknown){ ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); @@ -310,6 +313,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); + result->n_active_streams++; } else { /* create an inactive stream for the answer, as there where no matching stream a local capability */ @@ -322,7 +326,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities } } } - result->nstreams=i; + result->n_total_streams=i; strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); result->bandwidth=local_capabilities->bandwidth; diff --git a/coreapi/sal.c b/coreapi/sal.c index 2b09212aa..05d03499d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -76,7 +76,7 @@ void sal_media_description_unref(SalMediaDescription *md){ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; - for(i=0;instreams;++i){ + for(i=0;in_active_streams;++i){ SalStreamDescription *ss=&md->streams[i]; if (ss->proto==proto && ss->type==type) return ss; } @@ -84,17 +84,13 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, } bool_t sal_media_description_empty(const SalMediaDescription *md){ - int i; - for(i=0;instreams;++i){ - const SalStreamDescription *ss=&md->streams[i]; - if (ss->rtp_port!=0) return FALSE; - } + if (md->n_active_streams > 0) return FALSE; return TRUE; } void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ int i; - for(i=0;instreams;++i){ + for(i=0;in_active_streams;++i){ SalStreamDescription *ss=&md->streams[i]; ss->dir=stream_dir; } @@ -110,7 +106,7 @@ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ int i; /* we are looking for at least one stream with requested direction, inactive streams are ignored*/ - for(i=0;instreams;++i){ + for(i=0;in_active_streams;++i){ const SalStreamDescription *ss=&md->streams[i]; if (ss->dir==stream_dir) return TRUE; /*compatibility check for phones that only used the null address and no attributes */ @@ -224,9 +220,9 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD int i; 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->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - for(i = 0; i < md1->nstreams; ++i){ + for(i = 0; i < md1->n_total_streams; ++i){ result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } return result; diff --git a/coreapi/sal.h b/coreapi/sal.h index ba6daa221..6baae97ae 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -178,7 +178,8 @@ typedef struct SalMediaDescription{ int refcount; char addr[64]; char username[64]; - int nstreams; + int n_active_streams; + int n_total_streams; int bandwidth; unsigned int session_ver; unsigned int session_id; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index d8332621d..1cbecb638 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -589,18 +589,15 @@ static void sdp_process(SalOp *h){ strcpy(h->result->addr,h->base.remote_media->addr); h->result->bandwidth=h->base.remote_media->bandwidth; - for(i=0;iresult->nstreams;++i){ - if (h->result->streams[i].rtp_port>0){ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - - if (h->result->streams[i].proto == SalProtoRtpSavp) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } + for(i=0;iresult->n_active_streams;++i){ + strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); + strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); + h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; + h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; + h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; + h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; + if (h->result->streams[i].proto == SalProtoRtpSavp) { + h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; } } } diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 4aad14863..9297077e6 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -394,7 +394,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ int i; sdp_message_t *msg=create_generic_sdp(desc); - for(i=0;instreams;++i){ + for(i=0;in_total_streams;++i){ add_line(msg,i,&desc->streams[i]); } return msg; @@ -463,6 +463,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ } } + desc->n_active_streams = 0; + /* for each m= line */ for (i=0; !sdp_message_endof_media (msg, i) && irtp_addr,rtp_addr,sizeof(stream->rtp_addr)); if (rtp_port) stream->rtp_port=atoi(rtp_port); + if (stream->rtp_port > 0) + desc->n_active_streams++; stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ @@ -609,6 +613,6 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ } } } - desc->nstreams=i; + desc->n_total_streams=i; return 0; }