Commit f8ae4884 authored by Sylvain Berfini's avatar Sylvain Berfini 🎩
Browse files

Merge branch 'release/4.5' into master

parents 338bf5f2 c347156d
......@@ -10,23 +10,41 @@ This changelog file was started on October 2019. Previous changes were more or l
## [Unreleased]
## [4.5.0] 2021-03-29
### Added
- EnterForeground and enterBackground automatically for ios and anroid.
- Audio routes API to choose which device use to capture & play audio on Android & iOS.
- Handling push notifications, activity monitor and Core iterate automatically in Core for Android.
- Auto acquire and release of audio focus for Android.
- Audio conference API improved: distribution of participant list over RFC4575 SUBSCRIBE/NOTIFY.
- Automatic handling of some mobile OS behaviours
* enterForeground() and enterBackground() automatically called (iOS and Android).
* auto acquire and release of audio focus for Android.
* Core.iterate() is being called automatically internally for Android, it is no longer needed to create a timer in the application to call it.
- New audio routes API to choose which device use to capture & play audio (Android & iOS). The application can manage
audio route changes (bluetooth, speaker, earpiece) throug liblinphone's API.
- Added API to play user's ringtone instead of default ringtone for Android.
- New method linphone_core_audio_route_changed(), to fix audio issues when switching audio to some low sample rate Bluetooth devices.
- Added callback to notify a message is about to be sent.
- iOS: added linphone_core_configure_audio_session() to be called when used with Callkit
see specific documentation here: https://wiki.linphone.org/xwiki/wiki/public/view/Lib/Getting%20started/iOS/#HCallKitintegration
- client-based video conference in active speaker switching mode (beta feature).
### Changed
- Warning: some function parameters have been renamed for consistency, which modified the Swift API (where parameter names are part of the ABI).
As a result, adjustements in applications are expected when migrating a swift app based on liblinphone from 4.4 to 4.5.
- Improved Android network manager.
- to make it consistent with other liblinphone's object, linphone_core_create_subscribe(), linphone_core_create_subscribe2(),
- To make it consistent with other liblinphone's object, linphone_core_create_subscribe(), linphone_core_create_subscribe2(),
linphone_core_create_publish() now give ownership of the returned LinphoneEvent, which means that it is no longer need to call
linphone_event_ref() after calling these functions. As a consequence, an application not using linphone_event_ref() should now
use linphone_event_unref() when the LinphoneEvent is no longer used, otherwise it will create a memory leak.
- Real time text related function linphone_chat_message_get_char() now will always return the new line character,
which wasn't the case before if the getChar() was done after the composing callback was triggered for this character.
which wasn't the case before if the get_char() was done after the composing callback was triggered for this character.
- linphone_core_interpret_url() will unescape characters first if possible if only a username is given as input parameter.
- linphone_chat_message_cancel_file_transfer() no longer deletes the file for outgoing messages.
- magic search result created from filter now applies the international prefix of the default proxy config if possible.
- To improve performance file transfer progress callback will be at most notified 100 times.
- Deprecate linphone_core_audio_route_changed() that was introduced in 4.4, to fix audio issues
when switching audio to some low sample rate Bluetooth devices. It is now handled internally.
### Fixed
- Internal refactoring of management of locally played tones, in order to fix race conditions.
......@@ -34,6 +52,8 @@ This changelog file was started on October 2019. Previous changes were more or l
- Error IMDN in LIME chat rooms not properly sent.
- Chat message lost during attachment auto download if Core stopped during the process.
- Windows tests.
- Name of MediaCodec encoder and decoder filters in H264Helper Java class.
- Both FileContent and FileTransferContent being present in linphone_chat_message_get_contents() list until upload is finished.
## [4.4.0] 2020-06-16
......
......@@ -21,7 +21,7 @@
############################################################################
cmake_minimum_required(VERSION 3.1)
project(linphone VERSION 4.5.0 LANGUAGES C CXX)
project(linphone VERSION 5.0.0 LANGUAGES C CXX)
set(LINPHONE_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
......@@ -187,7 +187,7 @@ if(ENABLE_LIME)
set(HAVE_LIME 1)
endif()
if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER OR ENABLE_SWIFT_WRAPPER OR ENABLE_DOC)
find_package(PythonInterp REQUIRED)
find_package(PythonInterp 3 REQUIRED)
check_python_module(pystache)
check_python_module(six)
if(ENABLE_DOC)
......
......@@ -128,3 +128,290 @@ void sdp_parse_media_rtcp_xr_parameters(const belle_sdp_media_description_t *med
sdp_parse_rtcp_xr_parameters(attribute, config);
}
static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) {
SalStreamDescription *stream;
belle_sdp_connection_t* cnx;
belle_sdp_media_t* media;
belle_sdp_attribute_t* attribute;
belle_sip_list_t *custom_attribute_it;
const char* value;
const char *mtype,*proto;
bool_t has_avpf_attributes;
stream=&md->streams[md->nb_streams];
media=belle_sdp_media_description_get_media ( media_desc );
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/AVPF") == 0) {
stream->proto = SalProtoRtpAvpf;
} else if (strcasecmp(proto, "RTP/SAVPF") == 0) {
stream->proto = SalProtoRtpSavpf;
} else if (strcasecmp(proto, "UDP/TLS/RTP/SAVP") == 0) {
stream->proto = SalProtoUdpTlsRtpSavp;
} else if (strcasecmp(proto, "UDP/TLS/RTP/SAVPF") == 0) {
stream->proto = SalProtoUdpTlsRtpSavpf;
} else {
strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1);
}
}
if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 );
stream->ttl=belle_sdp_connection_get_ttl(cnx);
}
stream->rtp_port=belle_sdp_media_get_media_port ( media );
mtype = belle_sdp_media_get_media_type ( media );
if ( strcasecmp ( "audio", mtype ) == 0 ) {
stream->type=SalAudio;
} else if ( strcasecmp ( "video", mtype ) == 0 ) {
stream->type=SalVideo;
} else if ( strcasecmp ( "text", mtype ) == 0 ) {
stream->type=SalText;
} else {
stream->type=SalOther;
strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 );
}
if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) {
stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" );
}
if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) {
stream->dir=SalStreamSendRecv;
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) {
stream->dir=SalStreamSendOnly;
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) {
stream->dir=SalStreamRecvOnly;
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) {
stream->dir=SalStreamInactive;
} else {
stream->dir=md->dir; /*takes default value if not present*/
}
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);
/* Get media specific RTCP attribute */
stream->rtcp_port = stream->rtp_port + 1;
strncpy(stream->rtcp_addr, stream->rtp_addr, sizeof(stream->rtcp_addr) - 1);
attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
char *tmp = (char *)ms_malloc0(strlen(value));
int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp);
if (nb == 1) {
/* SDP rtcp attribute only contains the port */
} else if (nb == 2) {
strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr));
stream->rtcp_addr[sizeof(stream->rtcp_addr) - 1] = '\0';
} else {
ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb);
}
ms_free(tmp);
}
/* Read DTLS specific attributes : check is some are found in the stream description otherwise copy the session description one(which are at least set to Invalid) */
if (((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp))) {
attribute=belle_sdp_media_description_get_attribute(media_desc,"setup");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
if (strncmp(value, "actpass", 7) == 0) {
stream->dtls_role = SalDtlsRoleUnset;
} else if (strncmp(value, "active", 6) == 0) {
stream->dtls_role = SalDtlsRoleIsClient;
} else if (strncmp(value, "passive", 7) == 0) {
stream->dtls_role = SalDtlsRoleIsServer;
}
}
if (stream->dtls_role != SalDtlsRoleInvalid && (attribute=belle_sdp_media_description_get_attribute(media_desc,"fingerprint"))) {
strncpy(stream->dtls_fingerprint, belle_sdp_attribute_get_value(attribute),sizeof(stream->dtls_fingerprint));
}
}
/* Read crypto lines if any */
if (sal_stream_description_has_srtp(stream)) {
sdp_parse_media_crypto_parameters(media_desc, stream);
}
/* Read zrtp-hash attribute */
if ((attribute=belle_sdp_media_description_get_attribute(media_desc,"zrtp-hash"))!=NULL) {
if ((value=belle_sdp_attribute_get_value(attribute))!=NULL) {
strncpy((char *)(stream->zrtphash), belle_sdp_attribute_get_value(attribute),sizeof(stream->zrtphash));
stream->haveZrtpHash = 1;
}
}
/* Get ICE candidate attributes if any */
sdp_parse_media_ice_parameters(media_desc, stream);
has_avpf_attributes = sdp_parse_rtcp_fb_parameters(media_desc, stream);
/* Get RTCP-FB attributes if any */
if (sal_stream_description_has_avpf(stream)) {
enable_avpf_for_stream(stream);
}else if (has_avpf_attributes ){
enable_avpf_for_stream(stream);
stream->implicit_rtcp_fb = TRUE;
}
/* 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);
/* 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;
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 ) {
belle_sdp_connection_t* cnx;
belle_sip_list_t* media_desc_it;
belle_sdp_media_description_t* media_desc;
belle_sdp_session_name_t *sname;
belle_sip_list_t *custom_attribute_it;
const char* value;
SalDtlsRole session_role=SalDtlsRoleInvalid;
int i;
desc->nb_streams = 0;
desc->dir = SalStreamSendRecv;
if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 );
}
if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){
strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1);
}
if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) {
desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" );
}
belle_sdp_origin_t *origin = belle_sdp_session_description_get_origin(session_desc);
desc->session_id = belle_sdp_origin_get_session_id(origin);
desc->session_ver = belle_sdp_origin_get_session_version(origin);
/*in some very rare case, session attribute may set stream dir*/
if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) {
desc->dir=SalStreamSendRecv;
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) {
desc->dir=SalStreamSendOnly;
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) {
desc->dir=SalStreamRecvOnly;
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) {
desc->dir=SalStreamInactive;
}
/*DTLS attributes can be defined at session level.*/
value=belle_sdp_session_description_get_attribute_value(session_desc,"setup");
if (value){
if (strncmp(value, "actpass", 7) == 0) {
session_role = SalDtlsRoleUnset;
} else if (strncmp(value, "active", 6) == 0) {
session_role = SalDtlsRoleIsClient;
} else if (strncmp(value, "passive", 7) == 0) {
session_role = SalDtlsRoleIsServer;
}
}
value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint");
/*copy dtls attributes to every streams, might be overwritten stream by stream*/
for (i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++) {
if (value)
strncpy(desc->streams[i].dtls_fingerprint, value, sizeof(desc->streams[i].dtls_fingerprint));
desc->streams[i].dtls_role=session_role; /*set or reset value*/
}
/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag");
if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1);
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd");
if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1);
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite");
if (value) desc->ice_lite = TRUE;
/* Get session RTCP-XR attributes if any */
sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr);
/* Do we have Lime Ik attribute */
value = belle_sdp_session_description_get_attribute_value(session_desc,"Ik");
if (value) desc->haveLimeIk = TRUE;
/* get ready to parse also lime-Ik */
value = belle_sdp_session_description_get_attribute_value(session_desc,"lime-Ik");
if (value) desc->haveLimeIk = TRUE;
/* 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 )
; media_desc_it!=NULL
; media_desc_it=media_desc_it->next ) {
if (desc->nb_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){
ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->nb_streams);
break;
}
media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data );
sdp_to_stream_description(desc, media_desc);
}
return 0;
}
......@@ -140,7 +140,8 @@ LinphoneChatRoom *linphone_core_create_chat_room_6(LinphoneCore *lc, const Linph
bool withGruu = chatRoomParams ? chatRoomParams->getChatRoomBackend() == LinphonePrivate::ChatRoomParams::ChatRoomBackend::FlexisipChat : false;
LinphonePrivate::IdentityAddress identityAddress = localAddr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) : L_GET_PRIVATE_FROM_C_OBJECT(lc)->getDefaultLocalAddress(nullptr, withGruu);
shared_ptr<LinphonePrivate::AbstractChatRoom> room = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createChatRoom(chatRoomParams, identityAddress, participantsList);
return L_GET_C_BACK_PTR(room);
if (room) return L_GET_C_BACK_PTR(room);
return NULL;
}
LinphoneChatRoom *linphone_core_search_chat_room(const LinphoneCore *lc, const LinphoneChatRoomParams *params, const LinphoneAddress *localAddr, const LinphoneAddress *remoteAddr, const bctbx_list_t *participants) {
......@@ -152,7 +153,8 @@ LinphoneChatRoom *linphone_core_search_chat_room(const LinphoneCore *lc, const L
LinphonePrivate::IdentityAddress identityAddress = localAddr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(localAddr)) : L_GET_PRIVATE_FROM_C_OBJECT(lc)->getDefaultLocalAddress(nullptr, withGruu);
LinphonePrivate::IdentityAddress remoteAddress = remoteAddr ? LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(remoteAddr)) : LinphonePrivate::IdentityAddress();
shared_ptr<LinphonePrivate::AbstractChatRoom> room = L_GET_PRIVATE_FROM_C_OBJECT(lc)->searchChatRoom(chatRoomParams, identityAddress, remoteAddress, participantsList);
return L_GET_C_BACK_PTR(room);
if (room) return L_GET_C_BACK_PTR(room);
return NULL;
}
LinphoneChatRoomParams *linphone_core_create_default_chat_room_params(LinphoneCore *lc) {
......
......@@ -152,7 +152,7 @@ bool Conference::addParticipantDevice(std::shared_ptr<LinphonePrivate::Call> cal
const Address * remoteContact = static_pointer_cast<MediaSession>(call->getActiveSession())->getRemoteContactAddress();
if (remoteContact) {
// If device is not found, then add it
if (p->findDevice(*remoteContact) == nullptr) {
if (p->findDevice(*remoteContact, false) == nullptr) {
lInfo() << "Adding device with address " << remoteContact->asString() << " to participant " << p.get();
shared_ptr<ParticipantDevice> device = p->addDevice(*remoteContact);
_linphone_call_set_conf_ref(call->toC(), toC());
......@@ -656,6 +656,11 @@ int LocalConference::removeParticipant (const std::shared_ptr<LinphonePrivate::C
// This is the default behaviour
err = static_pointer_cast<LinphonePrivate::MediaSession>(session)->terminate();
}
if (call) {
call->setConference(nullptr);
}
}
}
......@@ -710,6 +715,13 @@ int LocalConference::removeParticipant (const std::shared_ptr<LinphonePrivate::C
/* invoke removeParticipant() recursively to remove this last participant. */
bool success = Conference::removeParticipant(remainingParticipant);
mMixerSession->unjoinStreamsGroup(session->getStreamsGroup());
// Detach call from conference
shared_ptr<Call> lastSessionCall = getCore()->getCallByRemoteAddress (*session->getRemoteAddress());
if (lastSessionCall) {
lastSessionCall->setConference(nullptr);
}
return success;
}
}
......@@ -803,6 +815,7 @@ void LocalConference::removeLocalEndpoint () {
void LocalConference::leave () {
if (isIn()) {
lInfo() << getMe()->getAddress() << " is leaving conference " << getConferenceAddress();
confParams->enableLocalParticipant(false);
removeLocalEndpoint();
}
......@@ -1214,13 +1227,14 @@ void RemoteConference::leave () {
LinphoneCallState callState = static_cast<LinphoneCallState>(m_focusCall->getState());
switch (callState) {
case LinphoneCallPaused:
lInfo() << getMe()->getAddress() << " is leaving conference " << getConferenceAddress() << " while focus call is paused.";
break;
case LinphoneCallStreamsRunning:
lInfo() << getMe()->getAddress() << " is leaving conference " << getConferenceAddress() << ". Focus call is going to be paused.";
m_focusCall->pause();
break;
default:
ms_error("Could not leave the conference: bad focus call state (%s)",
linphone_call_state_to_string(callState));
lError() << getMe()->getAddress() << " cannot leave conference " << getConferenceAddress() << " because focus call is in state " << linphone_call_state_to_string(callState);
}
}
......
......@@ -228,7 +228,7 @@ TAB_SIZE = 8
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
ALIASES = bctbx_list{1}="A list of \ref \1 objects. \xmlonly <bctbxlist>\1</bctbxlist> \endxmlonly"
ALIASES = bctbx_list{1}="\xmlonly<bctbxlist>\1</bctbxlist>\endxmlonly"
ALIASES += donotwrap="\xmlonly <donotwrap /> \endxmlonly"
ALIASES += maybenil="\xmlonly <maybenil /> \endxmlonly"
ALIASES += notnil="\xmlonly <notnil /> \endxmlonly"
......
......@@ -15,7 +15,7 @@
* - C++ (https://linphone.org/@LINPHONE_STATE@/docs/liblinphone/@LINPHONE_VERSION@/c++)
* - Swift (https://linphone.org/@LINPHONE_STATE@/docs/liblinphone/@LINPHONE_VERSION@/swift)
* - Java (https://linphone.org/@LINPHONE_STATE@/docs/liblinphone/@LINPHONE_VERSION@/java)
* - C# (coming soon)
* - C# (https://linphone.org/@LINPHONE_STATE@/docs/liblinphone/@LINPHONE_VERSION@/cs)
* - Python (coming soon)
*
* Liblinphone is distributed under GPLv3 (https://www.gnu.org/licenses/gpl-3.0.html). Please understand the licencing details before using it!
......
......@@ -155,7 +155,6 @@ static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable);
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_zrtp_cache_close(LinphoneCore *lc);
void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName);
static void _linphone_core_stop_async_end(LinphoneCore *lc);
static LinphoneStatus _linphone_core_set_sip_transports(LinphoneCore *lc, const LinphoneSipTransports * tr_config, bool_t applyIt);
bool_t linphone_core_sound_resources_need_locking(LinphoneCore *lc, const LinphoneCallParams *params);
......@@ -294,6 +293,14 @@ void linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs *cbs, LinphoneCoreCb
cbs->vtable->call_log_updated = cb;
}
LinphoneCoreCbsCallIdUpdatedCb linphone_core_cbs_get_call_id_updated(LinphoneCoreCbs *cbs) {
return cbs->vtable->call_id_updated;
}
void linphone_core_cbs_set_call_id_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallIdUpdatedCb cb) {
cbs->vtable->call_id_updated = cb;
}
LinphoneCoreCbsChatRoomReadCb linphone_core_cbs_get_chat_room_read(LinphoneCoreCbs *cbs) {
return cbs->vtable->chat_room_read;
}
......@@ -1291,7 +1298,6 @@ static void build_sound_devices_table(LinphoneCore *lc){
if (old!=NULL) ms_free((void *)old);
L_GET_PRIVATE_FROM_C_OBJECT(lc)->computeAudioDevicesList();
linphone_core_notify_audio_devices_list_updated(lc);
}
static string get_default_local_ring(LinphoneCore * lc) {
......@@ -1363,6 +1369,10 @@ static void sound_config_read(LinphoneCore *lc) {
devid = linphone_config_get_string(lc->config, "sound", "media_dev_id", NULL);
linphone_core_set_media_device(lc, devid);
// Wait to have restored previous sound cards to notify list has been updated
// Otherwise app won't be able to change audio device in callback
linphone_core_notify_audio_devices_list_updated(lc);
/*
tmp=linphone_config_get_int(lc->config,"sound","play_lev",80);
linphone_core_set_play_level(lc,tmp);
......@@ -2482,11 +2492,15 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve
#ifdef HAVE_ADVANCED_IM
const LinphoneAddress *resource = linphone_event_get_resource(lev);
char *resourceAddrStr = linphone_address_as_string_uri_only(resource);
const char *factoryUri = linphone_proxy_config_get_conference_factory_uri(linphone_core_get_default_proxy_config(lc));
if (factoryUri && (strcmp(resourceAddrStr, factoryUri) == 0)) {
bctbx_free(resourceAddrStr);
L_GET_PRIVATE_FROM_C_OBJECT(lc)->remoteListEventHandler->notifyReceived(L_GET_CPP_PTR_FROM_C_OBJECT(body));
return;
const bctbx_list_t * elem;
for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next) {
LinphoneProxyConfig *proxy = (LinphoneProxyConfig*) elem->data;
const char *factoryUri = linphone_proxy_config_get_conference_factory_uri(proxy);
if (factoryUri && (strcmp(resourceAddrStr, factoryUri) == 0)) {
bctbx_free(resourceAddrStr);
L_GET_PRIVATE_FROM_C_OBJECT(lc)->remoteListEventHandler->notifyReceived(L_GET_CPP_PTR_FROM_C_OBJECT(body));
return;
}
}
bctbx_free(resourceAddrStr);
......@@ -2814,7 +2828,10 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
if (system_context) {
lc->system_context = system_context;
}
lc->platform_helper = LinphonePrivate::createIosPlatformHelpers(lc->cppPtr, lc->system_context);
if (lc->platform_helper == NULL) {
lc->platform_helper = LinphonePrivate::createIosPlatformHelpers(lc->cppPtr, lc->system_context);
}
getPlatformHelpers(lc)->start(lc->cppPtr);
#endif
if (lc->platform_helper == NULL)
lc->platform_helper = new LinphonePrivate::GenericPlatformHelpers(lc->cppPtr);
......@@ -2869,7 +2886,12 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
* If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip.
* ipv6 config value is read later in fonction sip_config_read*/
int use_ipv6_for_sip = linphone_config_get_int(lc->config,"sip","use_ipv6",TRUE);
lc->http_provider = belle_sip_stack_create_http_provider(reinterpret_cast<belle_sip_stack_t *>(lc->sal->getStackImpl()), (use_ipv6_for_sip?"::0":"0.0.0.0"));
/* TLS transports is always enabled, TCP can be disabled using the https_only flag in the configuration */
uint8_t transports = BELLE_SIP_HTTP_TRANSPORT_TLS;
if (linphone_config_get_bool(lc->config,"sip","https_only",FALSE) == FALSE) {
transports |= BELLE_SIP_HTTP_TRANSPORT_TCP;
}
lc->http_provider = belle_sip_stack_create_http_provider_with_transports(reinterpret_cast<belle_sip_stack_t *>(lc->sal->getStackImpl()), (use_ipv6_for_sip?"::0":"0.0.0.0"), transports);
lc->http_crypto_config = belle_tls_crypto_config_new();
belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config);
......@@ -2905,20 +2927,38 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
LinphoneStatus linphone_core_start (LinphoneCore *lc) {
try {
if (lc->state == LinphoneGlobalOn) {
bctbx_warning("Core is already started, skipping...");
return -1;
} else if (lc->state == LinphoneGlobalShutdown) {
bctbx_error("Can't start a Core that is stopping, wait for Off state");
return -1;
} else if (lc->state == LinphoneGlobalOff) {
bctbx_warning("Core was stopped, before starting it again we need to init it");
linphone_core_init(lc, NULL, lc->config, lc->data, NULL, FALSE);
if (lc->state == LinphoneGlobalShutdown) {
//Force change of status to LinphoneGlobalOff, otherwise restarting it will fail
bctbx_warning("Core was shutDown, forcing to off");
_linphone_core_stop_async_end(lc);
}