Commit 2110281d authored by Ghislain MARY's avatar Ghislain MARY
Browse files

Handle AVPF and SAVPF profiles.

parent 92b20e62
......@@ -70,7 +70,7 @@ static void sdp_process(SalOp *h){
strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
if (h->result->streams[i].proto == SalProtoRtpSavp) {
if ((h->result->streams[i].proto == SalProtoRtpSavpf) || (h->result->streams[i].proto == SalProtoRtpSavp)) {
h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
}
}
......
......@@ -143,7 +143,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
if ( stream->bandwidth>0 )
belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth );
if ( stream->proto == SalProtoRtpSavp ) {
if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) {
/* add crypto lines */
for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) {
MSCryptoSuiteNameParams desc;
......@@ -469,11 +469,15 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
proto = belle_sdp_media_get_protocol ( media );
stream->proto=SalProtoOther;
if ( proto ) {
if ( strcasecmp ( proto,"RTP/AVP" ) ==0 )
stream->proto=SalProtoRtpAvp;
else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) {
stream->proto=SalProtoRtpSavp;
}else{
if (strcasecmp(proto, "RTP/AVP") == 0) {
stream->proto = SalProtoRtpAvp;
} else if (strcasecmp(proto, "RTP/SAVP") == 0) {
stream->proto = SalProtoRtpSavp;
} else if (strcasecmp(proto, "RTP/AVPF") == 0) {
stream->proto = SalProtoRtpAvpf;
} else if (strcasecmp(proto, "RTP/SAVPF") == 0) {
stream->proto = SalProtoRtpSavpf;
} else {
strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1);
}
}
......@@ -532,7 +536,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
/* Read crypto lines if any */
if ( stream->proto == SalProtoRtpSavp ) {
if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) {
sdp_parse_media_crypto_parameters(media_desc, stream);
}
......
......@@ -670,24 +670,32 @@ static void call_failure(SalOp *op){
break;
case SalReasonUnsupportedContent: /*<this is for compatibility: linphone sent 415 because of SDP offer answer failure*/
case SalReasonNotAcceptable:
//media_encryption_mandatory
if (call->params.media_encryption == LinphoneMediaEncryptionSRTP &&
!linphone_core_is_media_encryption_mandatory(lc)) {
ms_message("Outgoing call [%p] failed with SRTP and/or AVPF enabled", call);
if ((call->state == LinphoneCallOutgoingInit)
|| (call->state == LinphoneCallOutgoingProgress)
|| (call->state == LinphoneCallOutgoingRinging) /* Push notification case */
|| (call->state == LinphoneCallOutgoingEarlyMedia)) {
int i;
ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
if (call->state==LinphoneCallOutgoingInit
|| call->state==LinphoneCallOutgoingProgress
|| call->state==LinphoneCallOutgoingRinging /*push case*/
|| call->state==LinphoneCallOutgoingEarlyMedia){
ms_message("Retrying call [%p] with AVP",call);
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
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));
for (i = 0; i < call->localdesc->n_active_streams; i++) {
if (call->params.media_encryption == LinphoneMediaEncryptionSRTP) {
if (call->params.avpf_enabled == TRUE) {
if (i == 0) ms_message("Retrying call [%p] with SAVP", call);
call->params.avpf_enabled = FALSE;
linphone_core_restart_invite(lc, call);
return;
} else if (!linphone_core_is_media_encryption_mandatory(lc)) {
if (i == 0) ms_message("Retrying call [%p] with AVP", call);
call->params.media_encryption = LinphoneMediaEncryptionNone;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
linphone_core_restart_invite(lc, call);
return;
}
} else if (call->params.avpf_enabled == TRUE) {
if (i == 0) ms_message("Retrying call [%p] with AVP", call);
call->params.avpf_enabled = FALSE;
linphone_core_restart_invite(lc, call);
return;
}
linphone_core_restart_invite(lc, call);
return;
}
}
msg=_("Incompatible media parameters.");
......
......@@ -265,8 +265,8 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1);
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){
if (is_encryption_active(&md->streams[i]) == TRUE) {
if (keep_srtp_keys && old_md && is_encryption_active(&old_md->streams[i]) == TRUE){
int j;
ms_message("Keeping same crypto keys.");
for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
......@@ -311,6 +311,13 @@ void linphone_call_increment_local_media_description(LinphoneCall *call){
md->session_ver++;
}
static SalMediaProto get_proto_from_call_params(LinphoneCallParams *params) {
if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp;
if (params->avpf_enabled) return SalProtoRtpAvpf;
return SalProtoRtpAvp;
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
MSList *l;
PayloadType *pt;
......@@ -349,8 +356,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
md->streams[0].rtp_port=call->media_ports[0].rtp_port;
md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].proto=get_proto_from_call_params(&call->params);
md->streams[0].type=SalAudio;
if (call->params.down_ptime)
md->streams[0].ptime=call->params.down_ptime;
......@@ -961,10 +967,6 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
return &call->current_params;
}
static bool_t is_video_active(const SalStreamDescription *sd){
return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
}
/**
* Returns call parameters proposed by remote.
*
......@@ -976,19 +978,20 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
memset(cp,0,sizeof(*cp));
if (call->op){
SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
if (md){
SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
if (secure_vsd){
cp->has_video=is_video_active(secure_vsd);
if (secure_asd || asd==NULL)
cp->media_encryption=LinphoneMediaEncryptionSRTP;
}else if (vsd){
cp->has_video=is_video_active(vsd);
if (md) {
SalStreamDescription *sd;
unsigned int i;
unsigned int nb_audio_streams = sal_media_description_nb_active_streams_of_type(md, SalAudio);
unsigned int nb_video_streams = sal_media_description_nb_active_streams_of_type(md, SalVideo);
for (i = 0; i < nb_video_streams; i++) {
sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i);
if (is_video_active(sd) == TRUE) cp->has_video = TRUE;
if (is_encryption_active(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
}
for (i = 0; i < nb_audio_streams; i++) {
sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i);
if (is_encryption_active(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
}
if (!cp->has_video){
if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
......@@ -1861,12 +1864,10 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca
const SalStreamDescription *localstream;
const SalStreamDescription *remotestream;
localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, type);
if (!localstream) localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpAvp, type);
localstream = sal_media_description_find_best_stream(call->localdesc, type);
if (!localstream) return;
localconfig = &localstream->rtcp_xr;
remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpSavp, type);
if (!remotestream) remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpAvp, type);
remotestream = sal_media_description_find_best_stream(sal_call_get_remote_media_description(call->op), type);
if (!remotestream) return;
remoteconfig = &remotestream->rtcp_xr;
......@@ -1902,14 +1903,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
int crypto_idx;
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
/* look for savp stream first */
stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpSavp,SalAudio);
/* no savp audio stream, use avp */
if (!stream)
stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio);
if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
......@@ -1965,8 +1960,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
call->current_params.record_file=ms_strdup(call->params.record_file);
}
/* valid local tags are > 0 */
if (stream->proto == SalProtoRtpSavp) {
local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio);
if (is_encryption_active(stream) == TRUE) {
local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio);
crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
......@@ -2020,17 +2015,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
/* look for savp stream first */
const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpSavp,SalVideo);
char rtcp_tool[128]={0};
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
const SalStreamDescription *vstream;
/* no savp audio stream, use avp */
if (!vstream)
vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
/* shutdown preview */
if (lc->previewstream!=NULL) {
......@@ -2038,6 +2026,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
lc->previewstream=NULL;
}
vstream = sal_media_description_find_best_stream(call->resultdesc, SalVideo);
if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
......@@ -2088,7 +2077,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
cam=get_nowebcam_device();
}
if (!is_inactive){
if (vstream->proto == SalProtoRtpSavp) {
if (is_encryption_active(vstream) == TRUE) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key);
......@@ -2121,8 +2110,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
char *cname;
bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
#ifdef VIDEO_ENABLED
const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo);
#endif
call->current_params.audio_codec = NULL;
......@@ -2209,17 +2197,17 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript
SalStreamDescription *new_stream;
const SalStreamDescription *local_st_desc;
local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalAudio);
old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalAudio);
new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalAudio);
if (call->audiostream && local_st_desc && old_stream && new_stream &&
update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){
}
#ifdef VIDEO_ENABLED
local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalVideo);
old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalVideo);
new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalVideo);
if (call->videostream && local_st_desc && old_stream && new_stream &&
update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){
}
......
......@@ -2972,7 +2972,7 @@ bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){
for(i=0;i<md->n_active_streams;i++){
const SalStreamDescription *sd=&md->streams[i];
if (sd->proto!=SalProtoRtpSavp){
if (is_encryption_active(sd) != TRUE){
return FALSE;
}
}
......
......@@ -1520,3 +1520,10 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){
return result;
}
bool_t is_video_active(const SalStreamDescription *sd) {
return (sd->rtp_port != 0) && (sd->dir != SalStreamInactive);
}
bool_t is_encryption_active(const SalStreamDescription *sd) {
return ((sd->proto == SalProtoRtpSavpf) || (sd->proto == SalProtoRtpSavp));
}
......@@ -233,7 +233,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
}else{
result->rtp_port=0;
}
if (result->proto == SalProtoRtpSavp) {
if (is_encryption_active(result) == TRUE) {
/* verify crypto algo */
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE))
......@@ -259,7 +259,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
}else{
result->rtp_port=0;
}
if (result->proto == SalProtoRtpSavp) {
if (is_encryption_active(result) == TRUE) {
/* select crypto algo */
memset(result->crypto, 0, sizeof(result->crypto));
if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE))
......@@ -323,10 +323,11 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c
return TRUE;
}
/*in answering mode, we consider that if we are able to make SAVP, then we can do AVP as well*/
/*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){
if (local==remote) return TRUE;
if (remote==SalProtoRtpAvp && local==SalProtoRtpSavp) return TRUE;
if ((remote==SalProtoRtpAvp) && ((local==SalProtoRtpSavp) || (local==SalProtoRtpAvpf) || (local==SalProtoRtpSavpf)))
return TRUE;
return FALSE;
}
......
......@@ -95,6 +95,7 @@ struct _LinphoneCallParams{
char *session_name;
SalCustomHeader *custom_headers;
bool_t has_video;
bool_t avpf_enabled; /* RTCP feedback messages are enabled */
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t in_conference; /*in conference mode */
bool_t low_bandwidth;
......@@ -389,6 +390,8 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
LinphoneCall * is_a_linphone_call(void *user_pointer);
LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer);
bool_t is_video_active(const SalStreamDescription *sd);
bool_t is_encryption_active(const SalStreamDescription *sd);
void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description);
......
......@@ -91,6 +91,39 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
return NULL;
}
unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) {
unsigned int i;
unsigned int nb = 0;
for (i = 0; i < md->n_active_streams; ++i) {
if (md->streams[i].type == type) nb++;
}
return nb;
}
SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) {
unsigned int i;
for (i = 0; i < md->n_active_streams; ++i) {
if (md->streams[i].type == type) {
if (idx-- == 0) return &md->streams[i];
}
}
return NULL;
}
SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) {
SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
return desc;
}
SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) {
SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type);
return desc;
}
bool_t sal_media_description_empty(const SalMediaDescription *md){
if (md->n_active_streams > 0) return FALSE;
return TRUE;
......@@ -515,6 +548,8 @@ const char* sal_media_proto_to_string(SalMediaProto type) {
switch (type) {
case SalProtoRtpAvp:return "RTP/AVP";
case SalProtoRtpSavp:return "RTP/SAVP";
case SalProtoRtpAvpf:return "RTP/AVPF";
case SalProtoRtpSavpf:return "RTP/SAVPF";
default: return "unknown";
}
}
......
......@@ -123,6 +123,8 @@ const char* sal_stream_type_to_string(SalStreamType type);
typedef enum{
SalProtoRtpAvp,
SalProtoRtpSavp,
SalProtoRtpAvpf,
SalProtoRtpSavpf,
SalProtoOther
}SalMediaProto;
const char* sal_media_proto_to_string(SalMediaProto type);
......@@ -251,6 +253,10 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir);
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type);
SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx);
SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type);
SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type);
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir);
......
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