Commit 22e9270a authored by Simon Morlat's avatar Simon Morlat
Browse files

Add RTP bundle mode support.

This work required a major internal refactoring of how streams (audio, video, text, maybe others in the future) are handled by liblinphone.
This refactoring introduces a new design, where a streams are managed through a common base class named 'Stream', by a new class StreamsGroup that has the responsability of coordinating streams together.
In addition, these classes are provided with an OfferAnswerContext, that contains a representation of SDP local parameters, remote parameters, and agreed parameters.

The IceAgent has been redesigned too, renamed as IceService. It is now invoked by the StreamsGroup, and given the same OfferAnswerContext.
The IceService now supports handling of several IP addresses, using getifaddrs() (linux, android, iOS, Mac), windows to be done. The new code is more compact.

The internal function sal_stream_description_active() has been removed as its name was confusing.
Instead sal_stream_description_active() can be used to know if a stream is active (i...
parent 68f64b37
# Change Log
# Changelog
All notable changes to this project will be documented in this file.
Group changes to describe their impact on the project, as follows:
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Added for new features.
Changed for changes in existing functionality.
Deprecated for once-stable features removed in upcoming releases.
Removed for deprecated features removed in this release.
Fixed for any bug fixes.
Security to invite users to upgrade in case of vulnerabilities.
# Preamble
This changelog file was started on October 2019. Previous changes were more or less tracked in the *NEWS* file.
## [Unreleased]
### Added
- RTP bundle mode feature according to https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54 .
### Changed
- Big internal refactoring of how streams are managed within offer/answer exchanges.
- ICE now uses all IP addresses detected on the host.
- Better handling of parameter changes in streams during the session, which avoids unecessary restarts.
### Fixed
- Internal refactoring of management of locally played tones, in order to fix race conditions.
## [4.3.0] - 2019-10-14
### Added
......
......@@ -97,6 +97,8 @@ include(CMakePushCheckState)
include(GNUInstallDirs)
include(CheckCXXCompilerFlag)
check_symbol_exists(getifaddrs "sys/types.h;ifaddrs.h" HAVE_GETIFADDRS)
if(NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
message(STATUS "Setting install rpath to ${CMAKE_INSTALL_RPATH}")
......@@ -284,10 +286,8 @@ if(MSVC)
else()
list(APPEND STRICT_OPTIONS_CPP
"-Wall"
"-Wcast-align"
"-Wconversion"
"-Werror=return-type"
"-Wfloat-equal"
"-Winit-self"
"-Wno-error=deprecated-declarations"
"-Wpointer-arith"
......
......@@ -89,7 +89,7 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc ChangeLog.md LICENSE.txt README.md
%doc CHANGELOG.md LICENSE.txt README.md
%if @ENABLE_DAEMON@ || @ENABLE_CONSOLE_UI@ || @ENABLE_TOOLS@
%{_bindir}/*
%endif
......
......@@ -50,3 +50,5 @@
#cmakedefine HAVE_ADVANCED_IM
#cmakedefine HAVE_DB_STORAGE
#cmakedefine ENABLE_UPDATE_CHECK 1
#cmakedefine HAVE_GETIFADDRS
......@@ -192,6 +192,20 @@ static belle_sdp_attribute_t * create_rtcp_xr_attribute(const OrtpRtcpXrConfigur
return BELLE_SDP_ATTRIBUTE(attribute);
}
static void add_mid_attributes(belle_sdp_media_description_t *media_desc, const SalStreamDescription *stream){
if (stream->mid[0] != '\0'){
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("mid", stream->mid));
}
if (stream->mid_rtp_ext_header_id){
char *value = bctbx_strdup_printf("%i urn:ietf:params:rtp-hdrext:sdes:mid", stream->mid_rtp_ext_header_id);
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("extmap", value));
bctbx_free(value);
}
if (stream->bundle_only){
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("bundle-only", NULL));
}
}
static void stream_description_to_sdp ( belle_sdp_session_description_t *session_desc, const SalMediaDescription *md, const SalStreamDescription *stream ) {
belle_sdp_mime_parameter_t* mime_param;
belle_sdp_media_description_t* media_desc;
......@@ -205,6 +219,7 @@ 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;
bool_t stream_enabled = sal_stream_description_enabled(stream);
rtp_addr=stream->rtp_addr;
rtcp_addr=stream->rtcp_addr;
......@@ -318,7 +333,8 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
if (stream->rtcp_mux){
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create ("rtcp-mux",NULL ) );
}
add_mid_attributes(media_desc, stream);
if (rtp_port != 0) {
different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0);
if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) {
......@@ -346,11 +362,11 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}
}
if ((rtp_port != 0) && (sal_stream_description_has_avpf(stream) || sal_stream_description_has_implicit_avpf(stream))) {
if (stream_enabled && (sal_stream_description_has_avpf(stream) || sal_stream_description_has_implicit_avpf(stream))) {
add_rtcp_fb_attributes(media_desc, md, stream);
}
if ((rtp_port != 0) && (stream->rtcp_xr.enabled == TRUE)) {
if (stream_enabled && (stream->rtcp_xr.enabled == TRUE)) {
char sastr[1024] = {0};
char mastr[1024] = {0};
size_t saoff = 0;
......@@ -391,7 +407,25 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
belle_sdp_session_description_add_media_description(session_desc, media_desc);
}
belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescription *desc ) {
static void bundles_to_sdp(const bctbx_list_t *bundles, belle_sdp_session_description_t *session_desc){
const bctbx_list_t *elem;
for (elem = bundles; elem != NULL; elem = elem->next){
SalStreamBundle *bundle = (SalStreamBundle*) elem->data;
const bctbx_list_t * id_iterator;
char *attr_value = ms_strdup("BUNDLE");
for (id_iterator = bundle->mids; id_iterator != NULL; id_iterator = id_iterator->next){
const char *mid = (const char*) id_iterator->data;
char *tmp = ms_strdup_printf("%s %s", attr_value, mid);
ms_free(attr_value);
attr_value = tmp;
}
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("group", attr_value));
bctbx_free(attr_value);
}
}
belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *desc) {
belle_sdp_session_description_t* session_desc=belle_sdp_session_description_new();
bool_t inet6;
belle_sdp_origin_t* origin;
......@@ -440,6 +474,10 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
if (desc->rtcp_xr.enabled == TRUE) {
belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr));
}
if (desc->bundles)
bundles_to_sdp(desc->bundles, session_desc);
if (desc->custom_sdp_attributes) {
belle_sdp_session_description_t *custom_desc = (belle_sdp_session_description_t *)desc->custom_sdp_attributes;
belle_sip_list_t *l = belle_sdp_session_description_get_attributes(custom_desc);
......@@ -807,6 +845,14 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
stream->rtcp_mux = belle_sdp_media_description_get_attribute(media_desc, "rtcp-mux") != NULL;
stream->bundle_only = belle_sdp_media_description_get_attribute(media_desc, "bundle-only") != NULL;
attribute = belle_sdp_media_description_get_attribute(media_desc, "mid");
if (attribute){
value = belle_sdp_attribute_get_value(attribute);
if (value)
strncpy(stream->mid, value, sizeof(stream->mid) - 1);
}
/* Get media payload types */
sdp_parse_payload_types(media_desc, stream);
......@@ -876,18 +922,45 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
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);
/* Get the custom attributes */
/* Get the custom attributes, and parse some 'extmap'*/
for (custom_attribute_it = belle_sdp_media_description_get_attributes(media_desc); custom_attribute_it != NULL; custom_attribute_it = custom_attribute_it->next) {
belle_sdp_attribute_t *attr = (belle_sdp_attribute_t *)custom_attribute_it->data;
stream->custom_sdp_attributes = sal_custom_sdp_attribute_append(stream->custom_sdp_attributes, belle_sdp_attribute_get_name(attr), belle_sdp_attribute_get_value(attr));
const char *attr_name = belle_sdp_attribute_get_name(attr);
const char *attr_value = belle_sdp_attribute_get_value(attr);
stream->custom_sdp_attributes = sal_custom_sdp_attribute_append(stream->custom_sdp_attributes, attr_name, attr_value);
if (strcasecmp(attr_name, "extmap") == 0){
char *extmap_urn = (char*)bctbx_malloc0(strlen(attr_value) + 1);
int rtp_ext_header_id = 0;
if (sscanf(attr_value, "%i %s", &rtp_ext_header_id, extmap_urn) > 0
&& strcasecmp(extmap_urn, "urn:ietf:params:rtp-hdrext:sdes:mid") == 0){
stream->mid_rtp_ext_header_id = rtp_ext_header_id;
}
bctbx_free(extmap_urn);
}
}
md->nb_streams++;
return stream;
}
static void add_bundles(SalMediaDescription *desc, const char *ids){
char *tmp = (char*)ms_malloc0(strlen(ids) + 1);
int err;
SalStreamBundle *bundle = sal_media_description_add_new_bundle(desc);
do{
int consumed = 0;
err = sscanf(ids, "%s%n", tmp, &consumed);
if (err > 0){
bundle->mids = bctbx_list_append(bundle->mids, bctbx_strdup(tmp));
ids += consumed;
}else break;
}while( *ids != '\0');
ms_free(tmp);
}
int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) {
int sdp_to_media_description( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) {
belle_sdp_connection_t* cnx;
belle_sip_list_t* media_desc_it;
belle_sdp_media_description_t* media_desc;
......@@ -954,10 +1027,17 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
/* Get session RTCP-XR attributes if any */
sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr);
/* Get the custom attributes */
/* Get the custom attributes, parse some of them that are relevant */
for (custom_attribute_it = belle_sdp_session_description_get_attributes(session_desc); custom_attribute_it != NULL; custom_attribute_it = custom_attribute_it->next) {
belle_sdp_attribute_t *attr = (belle_sdp_attribute_t *)custom_attribute_it->data;
desc->custom_sdp_attributes = sal_custom_sdp_attribute_append(desc->custom_sdp_attributes, belle_sdp_attribute_get_name(attr), belle_sdp_attribute_get_value(attr));
if (strcasecmp(belle_sdp_attribute_get_name(attr), "group") == 0){
value = belle_sdp_attribute_get_value(attr);
if (value && strncasecmp(value, "BUNDLE", strlen("BUNDLE")) == 0){
add_bundles(desc, value + strlen("BUNDLE"));
}
}
}
for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc )
......
......@@ -69,6 +69,8 @@
#include "content/content-manager.h"
#include "content/content-type.h"
#include "core/core-p.h"
#include "conference/session/media-session.h"
#include "conference/session/media-session-p.h"
// For migration purpose.
#include "address/address-p.h"
......@@ -2557,7 +2559,6 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
linphone_presence_model_set_basic_status(lc->presence_model, LinphonePresenceBasicStatusOpen);
_linphone_core_read_config(lc);
linphone_core_add_linphone_spec(lc, "ephemeral");
linphone_core_set_state(lc, LinphoneGlobalReady, "Ready");
if (automatically_start) {
......@@ -5590,48 +5591,20 @@ void * linphone_core_get_native_video_window_id(const LinphoneCore *lc){
#ifdef VIDEO_ENABLED
/*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/
LinphoneCall *call=linphone_core_get_current_call (lc);
if (call) {
VideoStream *vstream = reinterpret_cast<VideoStream *>(linphone_call_get_stream(call, LinphoneStreamTypeVideo));
if (vstream)
return video_stream_get_native_window_id(vstream);
auto ms = dynamic_pointer_cast<LinphonePrivate::MediaSession>(L_GET_PRIVATE_FROM_C_OBJECT(call)->getActiveSession());
if (ms) return ms->getNativeVideoWindowId();
}
#endif
}
return 0;
}
/* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/
static void unset_video_window_id(LinphoneCore *lc, bool_t preview, void *id){
if ((id != NULL)
#ifndef _WIN32
&& ((unsigned long)id != (unsigned long)-1)
#endif
){
ms_error("Invalid use of unset_video_window_id()");
return;
}
L_GET_PRIVATE_FROM_C_OBJECT(lc)->unsetVideoWindowId(!!preview, id);
}
void _linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id) {
if ((id == NULL)
#ifndef _WIN32
|| ((unsigned long)id == (unsigned long)-1)
#endif
){
unset_video_window_id(lc,FALSE,id);
}
L_GET_PRIVATE_FROM_C_OBJECT(lc)->setVideoWindowId(false, id);
lc->video_window_id=id;
#ifdef VIDEO_ENABLED
{
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call) {
VideoStream *vstream = reinterpret_cast<VideoStream *>(linphone_call_get_stream(call, LinphoneStreamTypeVideo));
if (vstream)
video_stream_set_native_window_id(vstream,id);
}
}
#endif
}
void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id) {
......@@ -5650,10 +5623,10 @@ void * linphone_core_get_native_preview_window_id(const LinphoneCore *lc){
/*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/
#ifdef VIDEO_ENABLED
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call) {
VideoStream *vstream = reinterpret_cast<VideoStream *>(linphone_call_get_stream(call, LinphoneStreamTypeVideo));
if (vstream)
return video_stream_get_native_preview_window_id(vstream);
auto ms = dynamic_pointer_cast<LinphonePrivate::MediaSession>(L_GET_PRIVATE_FROM_C_OBJECT(call)->getActiveSession());
if (ms) return ms->getNativePreviewVideoWindowId();
}
if (lc->previewstream)
return video_preview_get_native_window_id(lc->previewstream);
......@@ -5663,24 +5636,11 @@ void * linphone_core_get_native_preview_window_id(const LinphoneCore *lc){
}
void _linphone_core_set_native_preview_window_id(LinphoneCore *lc, void *id) {
if ((id == NULL)
#ifndef _WIN32
|| ((unsigned long)id == (unsigned long)-1)
#endif
) {
unset_video_window_id(lc,TRUE,id);
}
L_GET_PRIVATE_FROM_C_OBJECT(lc)->setVideoWindowId(true, id);
lc->preview_window_id=id;
#ifdef VIDEO_ENABLED
{
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call) {
VideoStream *vstream = reinterpret_cast<VideoStream *>(linphone_call_get_stream(call, LinphoneStreamTypeVideo));
if (vstream)
video_stream_set_native_preview_window_id(vstream,id);
}else if (lc->previewstream){
video_preview_set_native_window_id(lc->previewstream,id);
}
if (lc->previewstream){
video_preview_set_native_window_id(lc->previewstream,id);
}
#endif
}
......@@ -6132,7 +6092,11 @@ void sip_config_uninit(LinphoneCore *lc)
for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
_linphone_proxy_config_unpublish(cfg); /* to unpublish without changing the stored flag enable_publish */
_linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */
/* Do not unregister when push notifications are allowed, otherwise this clears tokens from the SIP server.*/
if (!linphone_proxy_config_is_push_notification_allowed(cfg)){
_linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */
}
}
ms_message("Unregistration started.");
......@@ -7146,7 +7110,7 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) {
}
void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) {
L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(L_GET_CPP_PTR_FROM_C_OBJECT(lc));
L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(L_GET_CPP_PTR_FROM_C_OBJECT(lc), LinphoneCallOutgoing);
}
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
......@@ -7336,6 +7300,14 @@ bool_t linphone_core_video_multicast_enabled(const LinphoneCore *lc) {
return lc->rtp_conf.video_multicast_enabled;
}
bool_t linphone_core_rtp_bundle_enabled(const LinphoneCore *lc){
return linphone_config_get_bool(lc->config, "rtp", "bundle", FALSE);
}
void linphone_core_enable_rtp_bundle(LinphoneCore *lc, bool_t value){
linphone_config_set_bool(lc->config, "rtp", "bundle", value);
}
void linphone_core_set_video_preset(LinphoneCore *lc, const char *preset) {
lp_config_set_string(lc->config, "video", "preset", preset);
}
......
......@@ -45,10 +45,6 @@
#undef snprintf
#include <mediastreamer2/stun.h>
#ifdef HAVE_GETIFADDRS
#include <net/if.h>
#include <ifaddrs.h>
#endif
#include <math.h>
#if _MSC_VER
#define snprintf _snprintf
......
......@@ -336,7 +336,7 @@ static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offere
static void initiate_outgoing(MSFactory* factory, const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
if (remote_answer->rtp_port!=0)
if (sal_stream_description_enabled(remote_answer))
result->payloads=match_payloads(factory, local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
else {
ms_message("Local stream description [%p] rejected by peer",local_offer);
......@@ -411,7 +411,18 @@ static void initiate_outgoing(MSFactory* factory, const SalStreamDescription *lo
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
}
if (remote_answer->mid[0] != '\0'){
if (local_offer->mid[0] != '\0'){
strncpy(result->mid, remote_answer->mid, sizeof(result->mid) - 1);
result->mid_rtp_ext_header_id = remote_answer->mid_rtp_ext_header_id;
result->bundle_only = remote_answer->bundle_only;
result->rtcp_mux = TRUE; /* RTCP mux must be enabled in bundle mode. */
}else{
ms_error("The remote has set a mid in an answer while we didn't offered it.");
}
}else{
result->rtcp_mux = remote_answer->rtcp_mux && local_offer->rtcp_mux;
}
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->rtp_addr,remote_answer->rtp_addr);
......@@ -422,13 +433,14 @@ static void initiate_outgoing(MSFactory* factory, const SalStreamDescription *lo
result->ptime=remote_answer->ptime;
result->maxptime=remote_answer->maxptime;
}else{
result->rtp_port=0;
sal_stream_description_disable(result);
}
if (sal_stream_description_has_srtp(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))
result->rtp_port = 0;
if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)){
sal_stream_description_disable(result);
}
}
result->rtp_ssrc=local_offer->rtp_ssrc;
strncpy(result->rtcp_cname,local_offer->rtcp_cname,sizeof(result->rtcp_cname));
......@@ -446,19 +458,19 @@ static void initiate_outgoing(MSFactory* factory, const SalStreamDescription *lo
result->dtls_fingerprint[0] = '\0';
result->dtls_role = SalDtlsRoleInvalid;
}
result->rtcp_mux = remote_answer->rtcp_mux && local_offer->rtcp_mux;
result->implicit_rtcp_fb = local_offer->implicit_rtcp_fb && remote_answer->implicit_rtcp_fb;
}
static void initiate_incoming(MSFactory *factory, const SalStreamDescription *local_cap,
const SalStreamDescription *remote_offer,
SalStreamDescription *result, bool_t one_matching_codec){
SalStreamDescription *result, bool_t one_matching_codec, const char *bundle_owner_mid){
result->payloads=match_payloads(factory, local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
result->proto=remote_offer->proto;
result->type=local_cap->type;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
if (!result->payloads || only_telephone_event(result->payloads) || remote_offer->rtp_port==0){
if (!result->payloads || only_telephone_event(result->payloads) || !sal_stream_description_enabled(remote_offer)){
result->rtp_port=0;
return;
}
......@@ -488,12 +500,28 @@ static void initiate_incoming(MSFactory *factory, const SalStreamDescription *lo
result->ptime=local_cap->ptime;
result->maxptime=local_cap->maxptime;
}
/* Handle RTP bundle negociation */
if (remote_offer->mid[0] != '\0' && bundle_owner_mid){
strncpy(result->mid, remote_offer->mid, sizeof(result->mid) - 1);
result->mid_rtp_ext_header_id = remote_offer->mid_rtp_ext_header_id;
if (strcmp(bundle_owner_mid, remote_offer->mid) != 0){
/* The stream is a secondary one part of a bundle.
* In this case it must set the bundle-only attribute, and set port to zero.*/
result->bundle_only = TRUE;
result->rtp_port = 0;
}
result->rtcp_mux = TRUE; /* RTCP mux must be enabled in bundle mode. */
}else {
result->rtcp_mux = remote_offer->rtcp_mux && local_cap->rtcp_mux;
}
if (sal_stream_description_has_srtp(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)) {
result->rtp_port = 0;
sal_stream_description_disable(result);
ms_message("No matching crypto algo for remote stream's offer [%p]",remote_offer);
}
......@@ -528,7 +556,6 @@ static void initiate_incoming(MSFactory *factory, const SalStreamDescription *lo
result->dtls_fingerprint[0] = '\0';
result->dtls_role = SalDtlsRoleInvalid;
}
result->rtcp_mux = remote_offer->rtcp_mux && local_cap->rtcp_mux;
result->implicit_rtcp_fb = local_cap->implicit_rtcp_fb && remote_offer->implicit_rtcp_fb;
}
......@@ -567,6 +594,16 @@ int offer_answer_initiate_outgoing(MSFactory *factory, const SalMediaDescription
if ((local_offer->rtcp_xr.enabled == TRUE) && (remote_answer->rtcp_xr.enabled == FALSE)) {
result->rtcp_xr.enabled = FALSE;
}
/* TODO: check that the bundle answer is compliant with our offer.
* For now, just check the presence of a bundle response. */
if (local_offer->bundles){
if (remote_answer->bundles){
/* Copy the bundle offering to the result media description. */
result->bundles = bctbx_list_copy_with_data(remote_answer->bundles, (bctbx_list_copy_func) sal_stream_bundle_clone);
}
}else if (remote_answer->bundles){
ms_error("Remote answerer is proposing bundles, which we did not offer.");
}
return 0;
}
......@@ -582,11 +619,23 @@ int offer_answer_initiate_incoming(MSFactory *factory, const SalMediaDescription
int i;
const SalStreamDescription *ls=NULL,*rs;
if (remote_offer->bundles && local_capabilities->accept_bundles){
/* Copy the bundle offering to the result media description. */
result->bundles = bctbx_list_copy_with_data(remote_offer->bundles, (bctbx_list_copy_func) sal_stream_bundle_clone);
}
for(i=0;i<remote_offer->nb_streams;++i){
rs = &remote_offer->streams[i];
ls = &local_capabilities->streams[i];
if (ls && rs->type == ls->type && rs->proto == ls->proto){
initiate_incoming(factory, ls,rs,&result->streams[i],one_matching_codec);
const char *bundle_owner_mid = NULL;
if (local_capabilities->accept_bundles){
int owner_index = sal_media_description_get_index_of_transport_owner(remote_offer, rs);
if (owner_index != -1){
bundle_owner_mid = remote_offer->streams[owner_index].mid;
}
}
initiate_incoming(factory, ls,rs,&result->streams[i],one_matching_codec, bundle_owner_mid);
// Handle global RTCP FB attributes
result->streams[i].rtcp_fb.generic_nack_enabled = rs->rtcp_fb.generic_nack_enabled;
result->streams[i].rtcp_fb.tmmbr_enabled = rs->rtcp_fb.tmmbr_enabled;
......
......@@ -240,8 +240,6 @@ LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, b
LINPHONE_PUBLIC void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev);
void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream);
LinphoneCallStats *_linphone_call_stats_new(void);
void _linphone_call_stats_uninit(LinphoneCallStats *stats);
void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src);
void _linphone_call_stats_set_ice_state (LinphoneCallStats *stats, LinphoneIceState state);
void _linphone_call_stats_set_type (LinphoneCallStats *stats, LinphoneStreamType type);
void _linphone_call_stats_set_received_rtcp (LinphoneCallStats *stats, mblk_t *m);
......
......@@ -31,8 +31,8 @@
struct _LinphoneQualityReporting{
reporting_session_report_t * reports[3]; /**Store information on audio and video media streams (RFC 6035) */
bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/
LinphoneQualityReportingReportSendCb on_report_sent;
bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/
};
struct _LinphoneCallLog{
......
......@@ -165,7 +165,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf
cfg->avpf_rr_interval = lc ? !!lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5;
cfg->publish_expires= lc ? lp_config_get_default_int(lc->config, "proxy", "publish_expires", -1) : -1;
cfg->publish = lc ? !!lp_config_get_default_int(lc->config, "proxy", "publish", FALSE) : FALSE;
cfg->push_notification_allowed = lc ? !!lp_config_get_default_int(lc->config, "proxy", "push_notification_allowed", TRUE) : TRUE;
cfg->push_notification_allowed = lc ? !!lp_config_get_default_int(lc->config, "proxy", "push_notification_allowed", FALSE) : FALSE;
cfg->refkey = refkey ? ms_strdup(refkey) : NULL;
if (nat_policy_ref) {
LinphoneNatPolicy *policy = linphone_config_create_nat_policy_from_section(lc->config,nat_policy_ref);
......@@ -589,8 +589,7 @@ static LinphoneAddress *guess_contact_for_register (LinphoneProxyConfig *cfg) {