Commits

Ghislain MARY  committed 39bbe26

Keep the total number of streams and the number of active streams in the media description.

This is to respect section 8 of RFC 3264 ("Modifying the Session"). The
number of streams in the SDP MUST NOT decrease.

  • Participants
  • Parent commits 83ea53b

Comments (0)

Files changed (9)

File coreapi/callbacks.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) {
 					if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){
 						/* clear SRTP local params */
 						call->params.media_encryption = LinphoneMediaEncryptionNone;
-						for(i=0; i<call->localdesc->nstreams; i++) {
+						for(i=0; i<call->localdesc->n_active_streams; i++) {
 							call->localdesc->streams[i].proto = SalProtoRtpAvp;
 							memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
 						}

File coreapi/linphonecall.c

 	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;
 			}
 			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){
 	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));
 	
 		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; i<md->nstreams; 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; 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;

File coreapi/linphonecore.c

 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;i<md->nstreams;i++){
+		for(i=0;i<md->n_active_streams;i++){
 			SalStreamDescription *sd=&md->streams[i];
 			if (sd->proto!=SalProtoRtpSavp){
 				return TRUE;

File coreapi/misc.c

 	}
 	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;
 			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)) {
 			}
 			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')) {
 		}
 
 		/* 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) {
 				}
 			}
 		}
-		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);
 {
 	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;

File coreapi/offeranswer.c

 
 #include "sal.h"
 #include "offeranswer.h"
+#include "private.h"
 
 static bool_t only_telephone_event(const MSList *l){
 	for(;l!=NULL;l=l->next){
  * 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;i<local_offer->nstreams;++i){
+	for(i=0,j=0;i<local_offer->n_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;
  * 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;i<remote_offer->nstreams;++i){
+
+	result->n_active_streams=0;
+	for(i=0;i<remote_offer->n_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);
 		}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 */
 			}
 		}
 	}
-	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;

File coreapi/sal.c

 SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
     SalMediaProto proto, SalStreamType type){
 	int i;
-	for(i=0;i<md->nstreams;++i){
+	for(i=0;i<md->n_active_streams;++i){
 		SalStreamDescription *ss=&md->streams[i];
 		if (ss->proto==proto && ss->type==type) return ss;
 	}
 }
 
 bool_t sal_media_description_empty(const SalMediaDescription *md){
-	int i;
-	for(i=0;i<md->nstreams;++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;i<md->nstreams;++i){
+	for(i=0;i<md->n_active_streams;++i){
 		SalStreamDescription *ss=&md->streams[i];
 		ss->dir=stream_dir;
 	}
 	int i;
 
 	/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
-	for(i=0;i<md->nstreams;++i){
+	for(i=0;i<md->n_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 */
 	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;

File coreapi/sal.h

 	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;

File coreapi/sal_eXosip2.c

 		strcpy(h->result->addr,h->base.remote_media->addr);
 		h->result->bandwidth=h->base.remote_media->bandwidth;
 		
-		for(i=0;i<h->result->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;i<h->result->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];
 			}
 		}
 	}

File coreapi/sal_eXosip2_sdp.c

 sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
 	int i;
 	sdp_message_t *msg=create_generic_sdp(desc);
-	for(i=0;i<desc->nstreams;++i){
+	for(i=0;i<desc->n_total_streams;++i){
 		add_line(msg,i,&desc->streams[i]);
 	}
 	return msg;
 		}
 	}
 
+	desc->n_active_streams = 0;
+
 	/* for each m= line */
 	for (i=0; !sdp_message_endof_media (msg, i) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
 	{
 			strncpy(stream->rtp_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){
 			}
 		}
 	}
-	desc->nstreams=i;
+	desc->n_total_streams=i;
 	return 0;
 }