From ad64b94401f02d2d9fc308430391c05ce9948d9d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 30 May 2014 14:25:51 +0200 Subject: [PATCH] Parse rtcp-fb attributes contained in SDP. --- coreapi/bellesip_sal/sal_sdp.c | 136 ++++++++++++++++++++++++++++----- coreapi/linphonecore.c | 5 +- coreapi/linphonecore.h | 7 ++ coreapi/offeranswer.c | 8 +- coreapi/proxy.c | 4 + 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 31341fd21..628fc6974 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -76,28 +76,34 @@ static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); } -static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream, int nb_avpf_pt) { +static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream) { MSList *pt_it; PayloadType *pt; + PayloadTypeAvpfParams avpf_params; belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, -1); belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, md->avpf_rr_interval); belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); - if ((stream->type == SalVideo) && (nb_avpf_pt > 0)) { - if (nb_avpf_pt == ms_list_size(stream->payloads)) { - add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_PLI); - add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_SLI); - add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_RPSI); - } else { - for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { - pt = (PayloadType *) pt_it->data; - if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); - } - } + + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + + /* AVPF/SAVPF profile is used so enable AVPF for all paylad types. */ + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params = payload_type_get_avpf_params(pt); + avpf_params.trr_interval = md->avpf_rr_interval; + + /* Add rtcp-fb attributes according to the AVPF features of the payload types. */ + if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_SLI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); } } } @@ -134,13 +140,12 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session int rtp_port; int rtcp_port; bool_t different_rtp_and_rtcp_addr; - int nb_avpf_pt = 0; - + rtp_addr=stream->rtp_addr; rtcp_addr=stream->rtcp_addr; rtp_port=stream->rtp_port; rtcp_port=stream->rtcp_port; - + media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream) ,stream->rtp_port ,1 @@ -149,7 +154,6 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if (stream->payloads) { for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { pt= ( PayloadType* ) pt_it->data; - if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) nb_avpf_pt++; mime_param= belle_sdp_mime_parameter_create ( pt->mime_type , payload_type_get_number ( pt ) , pt->clock_rate @@ -175,7 +179,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session }else inet6=FALSE; belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr)); } - + if ( stream->bandwidth>0 ) belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); @@ -238,7 +242,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session } if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { - add_rtcp_fb_attributes(media_desc, md, stream, nb_avpf_pt); + add_rtcp_fb_attributes(media_desc, md, stream); } if (stream->rtcp_xr.enabled == TRUE) { @@ -324,9 +328,11 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { PayloadType *pt; + PayloadTypeAvpfParams avpf_params; belle_sip_list_t* mime_param_it=NULL; belle_sdp_mime_parameter_t* mime_param; belle_sip_list_t* mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); + memset(&avpf_params, 0, sizeof(avpf_params)); for ( mime_param_it=mime_params ; mime_param_it!=NULL ; mime_param_it=mime_param_it->next ) { @@ -338,6 +344,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) ); pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param ); payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) ); + payload_type_set_avpf_params(pt, avpf_params); stream->payloads=ms_list_append ( stream->payloads,pt ); stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, @@ -441,6 +448,87 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_ } } +static void enable_avpf_for_stream(SalStreamDescription *stream) { + MSList *pt_it; + PayloadType *pt; + PayloadTypeAvpfParams avpf_params; + + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + avpf_params = payload_type_get_avpf_params(pt); + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + avpf_params.trr_interval = 0; + payload_type_set_avpf_params(pt, avpf_params); + } +} + +static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb_attribute, PayloadType *pt) { + PayloadTypeAvpfParams avpf_params = payload_type_get_avpf_params(pt); + switch (belle_sdp_rtcp_fb_attribute_get_type(fb_attribute)) { + case BELLE_SDP_RTCP_FB_NACK: + switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) { + case BELLE_SDP_RTCP_FB_PLI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI; + break; + case BELLE_SDP_RTCP_FB_SLI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_SLI; + break; + case BELLE_SDP_RTCP_FB_RPSI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_RPSI; + break; + default: + break; + } + break; + case BELLE_SDP_RTCP_FB_TRR_INT: + avpf_params.trr_interval = (unsigned char)belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute); + break; + case BELLE_SDP_RTCP_FB_ACK: + default: + break; + } + payload_type_set_avpf_params(pt, avpf_params); +} + +static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *it; + belle_sdp_attribute_t *attribute; + belle_sdp_rtcp_fb_attribute_t *fb_attribute; + MSList *pt_it; + PayloadType *pt; + int8_t pt_num; + + /* Handle rtcp-fb attributes that concern all payload types. */ + for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { + attribute = BELLE_SDP_ATTRIBUTE(it->data); + if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) { + fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute); + if (belle_sdp_rtcp_fb_attribute_get_id(fb_attribute) == -1) { + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + apply_rtcp_fb_attribute_to_payload(fb_attribute, pt); + } + } + } + } + + /* Handle rtcp-fb attributes that are specefic to a payload type. */ + for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { + attribute = BELLE_SDP_ATTRIBUTE(it->data); + if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) { + fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute); + pt_num = belle_sdp_rtcp_fb_attribute_get_id(fb_attribute); + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + if (payload_type_get_number(pt) == (int)pt_num) { + apply_rtcp_fb_attribute_to_payload(fb_attribute, pt); + } + } + } + } +} + static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) { config->enabled = FALSE; config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; @@ -583,6 +671,12 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, /* Get ICE candidate attributes if any */ sdp_parse_media_ice_parameters(media_desc, stream); + /* Get RTCP-FB attributes if any */ + if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { + enable_avpf_for_stream(stream); + sdp_parse_rtcp_fb_parameters(media_desc, stream); + } + /* Get RTCP-XR attributes if any */ stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 65b18e6e8..d593a1dbd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2840,8 +2840,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); - cp->avpf_enabled = proxy->avpf_enabled; - cp->avpf_rr_interval = proxy->avpf_rr_interval; + cp->avpf_enabled = linphone_proxy_config_is_avpf_enabled(proxy); + cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy); } /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -6438,6 +6438,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; params->privacy=LinphonePrivacyDefault; + params->avpf_enabled=TRUE; } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b9a199519..b21ebc7ca 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -936,6 +936,13 @@ LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const Linp */ LINPHONE_PUBLIC void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable); +/** + * Indicates whether AVPF/SAVPF is being used for calls using this proxy config. + * @param[in] cfg #LinphoneProxyConfig object + * @return True if AVPF/SAVPF is enabled, false otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_proxy_config_is_avpf_enabled(LinphoneProxyConfig *cfg); + /** * Set the interval between regular RTCP reports when using AVPF/SAVPF. * @param[in] cfg #LinphoneProxyConfig object diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index be8998168..7b38aaed7 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -324,9 +324,11 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c } /*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) || (local==SalProtoRtpAvpf) || (local==SalProtoRtpSavpf))) +static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) { + if (local == remote) return TRUE; + if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) + return TRUE; + if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpAvpf) || (local == SalProtoRtpSavpf))) return TRUE; return FALSE; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 278fd9be6..c85cc33dd 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1551,6 +1551,10 @@ void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable) cfg->avpf_enabled = enable; } +bool_t linphone_proxy_config_is_avpf_enabled(LinphoneProxyConfig *cfg) { + return cfg->avpf_enabled; +} + void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval) { if (interval > 5) interval = 5; cfg->avpf_rr_interval = interval;