Commit 39bbe265 authored by Ghislain MARY's avatar Ghislain MARY
Browse files

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.
parent 83ea53b5
......@@ -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; 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));
}
......
......@@ -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; 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;
......
......@@ -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;i<md->nstreams;i++){
for(i=0;i<md->n_active_streams;i++){
SalStreamDescription *sd=&md->streams[i];
if (sd->proto!=SalProtoRtpSavp){
return TRUE;
......
......@@ -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;
......
......@@ -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;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;
......@@ -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;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);
......@@ -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;
......
......@@ -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;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;
}
......@@ -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;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;
}
......@@ -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;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 */
......@@ -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;
......
......@@ -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;
......
......@@ -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;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];
}
}
}
......
......@@ -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;i<desc->nstreams;++i){
for(i=0;i<desc->n_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) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
{
......@@ -486,6 +488,8 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
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){
......@@ -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;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment