From 382c22a80f547f6f5460820376e546bc651126a3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Dec 2017 14:50:51 +0100 Subject: [PATCH] Convert call transfer handling to C++. --- coreapi/callbacks.c | 79 ++++------ coreapi/linphonecore.c | 42 +---- coreapi/private_functions.h | 2 - src/c-wrapper/api/c-call-params.cpp | 13 +- src/c-wrapper/api/c-call.cpp | 93 +++-------- src/call/call-p.h | 4 + src/call/call.cpp | 144 ++++++++++++++---- src/call/call.h | 7 + src/conference/params/call-session-params-p.h | 8 +- .../session/call-session-listener.h | 2 + src/conference/session/call-session-p.h | 12 +- src/conference/session/call-session.cpp | 109 +++++++++---- src/conference/session/call-session.h | 7 + src/conference/session/media-session-p.h | 5 + src/conference/session/media-session.cpp | 63 ++++++-- src/sal/call-op.cpp | 2 +- 16 files changed, 361 insertions(+), 231 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 3345e6588..2b90953a8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -181,12 +181,6 @@ static void call_ringing(SalOp *h) { L_GET_PRIVATE(session)->remoteRinging(); } -#if 0 -static void start_pending_refer(LinphoneCall *call){ - linphone_core_start_refered_call(call->core, call,NULL); -} -#endif - /* * could be reach : * - when the call is accepted @@ -363,30 +357,20 @@ static void dtmf_received(SalOp *op, char dtmf) { L_GET_PRIVATE(mediaSession)->dtmfReceived(dtmf); } -static void call_refer_received(SalOp *op, const SalAddress *referto){ -#if 0 - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - LinphoneAddress *refer_to_addr = linphone_address_new(referto); - char method[20] = ""; - - if(refer_to_addr) { - const char *tmp = linphone_address_get_method_param(refer_to_addr); - if(tmp) strncpy(method, tmp, sizeof(method)); - linphone_address_unref(refer_to_addr); +static void call_refer_received(SalOp *op, const SalAddress *referTo) { + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); + char *addrStr = sal_address_as_string_uri_only(referTo); + Address referToAddr(addrStr); + string method; + if (referToAddr.isValid()) + method = referToAddr.getMethodParam(); + if (session && (method.empty() || (method == "INVITE"))) { + L_GET_PRIVATE(session)->referred(referToAddr); + } else { + LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); + linphone_core_notify_refer_received(lc, addrStr); } - if (call && (strlen(method) == 0 || strcmp(method, "INVITE") == 0)) { - if (call->refer_to!=NULL){ - ms_free(call->refer_to); - } - call->refer_to=ms_strdup(referto); - call->refer_pending=TRUE; - linphone_call_set_state(call,LinphoneCallRefered,"Refered"); - if (call->refer_pending) linphone_core_start_refered_call(lc,call,NULL); - }else { - linphone_core_notify_refer_received(lc,referto); - } -#endif + bctbx_free(addrStr); } static void message_received(SalOp *op, const SalMessage *msg){ @@ -534,31 +518,30 @@ static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { } } -static void notify_refer(SalOp *op, SalReferStatus status){ - LinphoneCall *call=(LinphoneCall*) op->get_user_pointer(); +static void notify_refer(SalOp *op, SalReferStatus status) { + LinphonePrivate::CallSession *session = reinterpret_cast(op->get_user_pointer()); + if (!session) { + ms_warning("Receiving notify_refer for unknown CallSession"); + return; + } LinphoneCallState cstate; - if (call==NULL) { - ms_warning("Receiving notify_refer for unknown call."); - return ; - } - switch(status){ + switch (status) { case SalReferTrying: - cstate=LinphoneCallOutgoingProgress; - break; + cstate = LinphoneCallOutgoingProgress; + break; case SalReferSuccess: - cstate=LinphoneCallConnected; - break; + cstate = LinphoneCallConnected; + break; case SalReferFailed: - cstate=LinphoneCallError; - break; + cstate = LinphoneCallError; + break; default: - cstate=LinphoneCallError; - } - linphone_call_set_transfer_state(call, cstate); - if (cstate==LinphoneCallConnected){ - /*automatically terminate the call as the transfer is complete.*/ - linphone_call_terminate(call); + cstate = LinphoneCallError; + break; } + L_GET_PRIVATE(session)->setTransferState(cstate); + if (cstate == LinphoneCallConnected) + session->terminate(); // Automatically terminate the call as the transfer is complete } static LinphoneChatMessageState chatStatusSal2Linphone(SalMessageDeliveryStatus status){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4d22aec51..d669975c6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3372,42 +3372,10 @@ const char * linphone_core_get_route(LinphoneCore *lc){ return route; } -LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ -#if 0 - LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_call_params(lc, NULL); - LinphoneCall *newcall; - - if (call->state!=LinphoneCallPaused){ - ms_message("Automatically pausing current call to accept transfer."); - _linphone_call_pause(call); - call->was_automatically_paused=TRUE; - } - - if (!params){ - linphone_call_params_enable_audio(cp, linphone_call_params_audio_enabled(call->current_params)); - linphone_call_params_enable_video(cp, linphone_call_params_video_enabled(call->current_params)); /*start the call to refer-target with video enabled if original call had video*/ - } - linphone_call_params_set_referer(cp, call); - ms_message("Starting new call to refered address %s",call->refer_to); - call->refer_pending=FALSE; - newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); - linphone_call_params_unref(cp); - if (newcall) { - call->transfer_target=linphone_call_ref(newcall); - linphone_core_notify_refer_state(lc,call,newcall); - } - return newcall; -#else - return nullptr; -#endif -} - -void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){ -#if 0 - if (referer->op!=NULL){ - sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL); - } -#endif +LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) { + shared_ptr referredCall = L_GET_PRIVATE_FROM_C_OBJECT(call)->startReferredCall(params + ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); + return L_GET_C_BACK_PTR(referredCall); } /* @@ -3786,7 +3754,7 @@ int linphone_core_preempt_sound_resources(LinphoneCore *lc){ current_call=linphone_core_get_current_call(lc); if(current_call != NULL){ ms_message("Pausing automatically the current call."); - err = _linphone_call_pause(current_call); + err = L_GET_CPP_PTR_FROM_C_OBJECT(current_call)->pause(); } if (lc->ringstream){ linphone_core_stop_ringing(lc); diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index 81e5ddf78..ff7340167 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -51,7 +51,6 @@ LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const Linpho void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress * to); -void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state); LinphonePlayer *linphone_call_build_player(LinphoneCall*call); LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call); @@ -327,7 +326,6 @@ int _linphone_call_pause(LinphoneCall *call); /*conferencing subsystem*/ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted); bool_t linphone_core_sound_resources_available(LinphoneCore *lc); -void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall); LINPHONE_PUBLIC unsigned int linphone_core_get_audio_features(LinphoneCore *lc); void _linphone_core_codec_config_write(LinphoneCore *lc); diff --git a/src/c-wrapper/api/c-call-params.cpp b/src/c-wrapper/api/c-call-params.cpp index 062f5ee2c..e0c322106 100644 --- a/src/c-wrapper/api/c-call-params.cpp +++ b/src/c-wrapper/api/c-call-params.cpp @@ -18,9 +18,11 @@ */ #include "c-wrapper/c-wrapper.h" +#include "call/call-p.h" #include "core/core.h" #include "conference/params/call-session-params-p.h" #include "conference/params/media-session-params-p.h" +#include "conference/session/call-session.h" #include "linphone/call_params.h" @@ -437,11 +439,18 @@ SalCustomSdpAttribute *linphone_call_params_get_custom_sdp_media_attributes (con } LinphoneCall *linphone_call_params_get_referer (const LinphoneCallParams *params) { - return L_GET_PRIVATE_FROM_C_OBJECT(params)->getReferer(); + shared_ptr session = L_GET_PRIVATE_FROM_C_OBJECT(params)->getReferer(); + if (!session) + return nullptr; + for (const auto &call : session->getCore()->getCalls()) { + if (L_GET_PRIVATE(call)->getActiveSession() == session) + return L_GET_C_BACK_PTR(call); + } + return nullptr; } void linphone_call_params_set_referer (LinphoneCallParams *params, LinphoneCall *referer) { - L_GET_PRIVATE_FROM_C_OBJECT(params)->setReferer(referer); + L_GET_PRIVATE_FROM_C_OBJECT(params)->setReferer(L_GET_PRIVATE_FROM_C_OBJECT(referer)->getActiveSession()); } bool_t linphone_call_params_get_update_call_when_ice_completed (const LinphoneCallParams *params) { diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index a7630a752..c70b2ea50 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -48,6 +48,7 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, LinphoneAddress *diversionAddressCache; LinphoneAddress *remoteAddressCache; LinphoneAddress *toAddressCache; + mutable char *referToCache; char *remoteContactCache; char *remoteUserAgentCache; mutable char *toHeaderCache; @@ -56,12 +57,10 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call, LinphonePrivate::SalOp *op; LinphoneCallState transfer_state; /*idle if no transfer*/ MSAudioEndpoint *endpoint; /*used for conferencing*/ - char *refer_to; LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ LinphoneChatRoom *chat_room; LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ - bool_t refer_pending; ) static void _linphone_call_constructor (LinphoneCall *call) { @@ -86,6 +85,8 @@ static void _linphone_call_destructor (LinphoneCall *call) { linphone_address_unref(call->remoteAddressCache); if (call->toAddressCache) linphone_address_unref(call->toAddressCache); + if (call->referToCache) + bctbx_free(call->referToCache); if (call->remoteContactCache) bctbx_free(call->remoteContactCache); if (call->remoteUserAgentCache) @@ -97,10 +98,6 @@ static void _linphone_call_destructor (LinphoneCall *call) { call->op->release(); call->op=nullptr; } - if (call->refer_to){ - ms_free(call->refer_to); - call->refer_to=nullptr; - } if (call->referer){ linphone_call_unref(call->referer); call->referer=nullptr; @@ -142,18 +139,6 @@ static bool_t linphone_call_sound_resources_available (LinphoneCall *call) { void linphone_call_stop_media_streams (LinphoneCall *call) {} -void linphone_call_set_transfer_state (LinphoneCall *call, LinphoneCallState state) { -#if 0 - if (state != call->transfer_state) { - ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call - ,linphone_call_state_to_string(call->transfer_state) - ,linphone_call_state_to_string(state)); - call->transfer_state = state; - linphone_call_notify_transfer_state_changed(call, state); - } -#endif -} - /* Internal version that does not play tone indication*/ int _linphone_call_pause (LinphoneCall *call) { return 0; @@ -299,35 +284,31 @@ LinphoneCallLog *linphone_call_get_call_log (const LinphoneCall *call) { } const char *linphone_call_get_refer_to (const LinphoneCall *call) { -#if 0 - return call->refer_to; -#else - return nullptr; -#endif + string referTo = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getReferTo(); + if (referTo.empty()) + return nullptr; + if (call->referToCache) + bctbx_free(call->referToCache); + call->referToCache = bctbx_strdup(referTo.c_str()); + return call->referToCache; } bool_t linphone_call_has_transfer_pending (const LinphoneCall *call) { -#if 0 - return call->refer_pending; -#else - return FALSE; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->hasTransferPending(); } LinphoneCall *linphone_call_get_transferer_call (const LinphoneCall *call) { -#if 0 - return call->referer; -#else - return nullptr; -#endif + shared_ptr referer = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getReferer(); + if (!referer) + return nullptr; + return L_GET_C_BACK_PTR(referer); } LinphoneCall *linphone_call_get_transfer_target_call (const LinphoneCall *call) { -#if 0 - return call->transfer_target; -#else - return nullptr; -#endif + shared_ptr transferTarget = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getTransferTarget(); + if (!transferTarget) + return nullptr; + return L_GET_C_BACK_PTR(transferTarget); } LinphoneCall *linphone_call_get_replaced_call (LinphoneCall *call) { @@ -430,11 +411,7 @@ void linphone_call_set_next_video_frame_decoded_callback (LinphoneCall *call, Li } LinphoneCallState linphone_call_get_transfer_state (LinphoneCall *call) { -#if 0 - return call->transfer_state; -#else - return LinphoneCallIdle; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getTransferState(); } void linphone_call_zoom_video (LinphoneCall* call, float zoom_factor, float* cx, float* cy) { @@ -559,36 +536,12 @@ LinphoneStatus linphone_call_accept_update (LinphoneCall *call, const LinphoneCa return L_GET_CPP_PTR_FROM_C_OBJECT(call)->acceptUpdate(params ? L_GET_CPP_PTR_FROM_C_OBJECT(params) : nullptr); } -LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *refer_to) { -#if 0 - char *real_url = nullptr; - LinphoneCore *lc = linphone_call_get_core(call); - LinphoneAddress *real_parsed_url = linphone_core_interpret_url(lc, refer_to); - - if (!real_parsed_url) { - /* bad url */ - return -1; - } - //lc->call = nullptr; // Do not do that you will lose the call afterward... - real_url = linphone_address_as_string(real_parsed_url); - sal_call_refer(call->op, real_url); - ms_free(real_url); - linphone_address_unref(real_parsed_url); - linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); - return 0; -#else - return 0; -#endif +LinphoneStatus linphone_call_transfer (LinphoneCall *call, const char *referTo) { + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->transfer(referTo); } LinphoneStatus linphone_call_transfer_to_another (LinphoneCall *call, LinphoneCall *dest) { -#if 0 - int result = sal_call_refer_with_replaces (call->op, dest->op); - linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit); - return result; -#else - return 0; -#endif + return L_GET_CPP_PTR_FROM_C_OBJECT(call)->transfer(L_GET_CPP_PTR_FROM_C_OBJECT(dest)); } void *linphone_call_get_native_video_window_id (const LinphoneCall *call) { diff --git a/src/call/call-p.h b/src/call/call-p.h index 4840044e0..a6c0d1b98 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -44,7 +44,9 @@ public: void iterate (time_t currentRealTime, bool oneSecondElapsed); void startIncomingNotification (); + void pauseForTransfer (); int startInvite (const Address *destination); + std::shared_ptr startReferredCall (const MediaSessionParams *params); virtual std::shared_ptr getActiveSession () const { return nullptr; } bool getAudioMuted () const; @@ -71,7 +73,9 @@ private: bool onCallSessionAccepted (const std::shared_ptr &session) override; void onCallSessionSetReleased (const std::shared_ptr &session) override; void onCallSessionSetTerminated (const std::shared_ptr &session) override; + void onCallSessionStartReferred (const std::shared_ptr &session) override; void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; + void onCallSessionTransferStateChanged (const std::shared_ptr &session, LinphoneCallState state) override; void onCheckForAcceptation (const std::shared_ptr &session) override; void onDtmfReceived (const std::shared_ptr &session, char dtmf) override; void onIncomingCallSessionNotified (const std::shared_ptr &session) override; diff --git a/src/call/call.cpp b/src/call/call.cpp index d15850465..ca11eba11 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -19,6 +19,7 @@ #include "c-wrapper/c-wrapper.h" #include "call-p.h" +#include "conference/params/media-session-params-p.h" #include "conference/session/call-session-p.h" #include "conference/session/media-session-p.h" #include "core/core-p.h" @@ -76,10 +77,39 @@ void CallPrivate::startIncomingNotification () { getActiveSession()->startIncomingNotification(); } +void CallPrivate::pauseForTransfer () { + static_pointer_cast(getActiveSession())->getPrivate()->pauseForTransfer(); +} + int CallPrivate::startInvite (const Address *destination) { return getActiveSession()->startInvite(destination, ""); } +shared_ptr CallPrivate::startReferredCall (const MediaSessionParams *params) { + L_Q(); + if (q->getState() != LinphoneCallPaused) { + pauseForTransfer(); + } + MediaSessionParams msp; + if (params) + msp = *params; + else { + msp.initDefault(q->getCore()); + msp.enableAudio(q->getCurrentParams()->audioEnabled()); + msp.enableVideo(q->getCurrentParams()->videoEnabled()); + } + lInfo() << "Starting new call to referred address " << q->getReferTo(); + L_GET_PRIVATE(&msp)->setReferer(getActiveSession()); + L_GET_PRIVATE(getActiveSession())->setReferPending(false); + LinphoneCall *newCall = linphone_core_invite_with_params( + q->getCore()->getCCore(), q->getReferTo().c_str(), L_GET_C_BACK_PTR(&msp)); + if (newCall) { + getActiveSession()->getPrivate()->setTransferTarget(L_GET_PRIVATE_FROM_C_OBJECT(newCall)->getActiveSession()); + L_GET_PRIVATE_FROM_C_OBJECT(newCall)->getActiveSession()->getPrivate()->notifyReferState(); + } + return L_GET_CPP_PTR_FROM_C_OBJECT(newCall); +} + // ----------------------------------------------------------------------------- void CallPrivate::createPlayer () const { @@ -125,28 +155,28 @@ void CallPrivate::terminateBecauseOfLostMedia () { // ----------------------------------------------------------------------------- -void CallPrivate::onAckBeingSent (const std::shared_ptr &session, LinphoneHeaders *headers) { +void CallPrivate::onAckBeingSent (const shared_ptr &session, LinphoneHeaders *headers) { L_Q(); linphone_call_notify_ack_processing(L_GET_C_BACK_PTR(q), headers, false); } -void CallPrivate::onAckReceived (const std::shared_ptr &session, LinphoneHeaders *headers) { +void CallPrivate::onAckReceived (const shared_ptr &session, LinphoneHeaders *headers) { L_Q(); linphone_call_notify_ack_processing(L_GET_C_BACK_PTR(q), headers, true); } -void CallPrivate::onBackgroundTaskToBeStarted (const std::shared_ptr &session) { +void CallPrivate::onBackgroundTaskToBeStarted (const shared_ptr &session) { backgroundTaskId = sal_begin_background_task("liblinphone call notification", nullptr, nullptr); } -void CallPrivate::onBackgroundTaskToBeStopped (const std::shared_ptr &session) { +void CallPrivate::onBackgroundTaskToBeStopped (const shared_ptr &session) { if (backgroundTaskId != 0) { sal_end_background_task(backgroundTaskId); backgroundTaskId = 0; } } -bool CallPrivate::onCallSessionAccepted (const std::shared_ptr &session) { +bool CallPrivate::onCallSessionAccepted (const shared_ptr &session) { L_Q(); LinphoneCore *lc = q->getCore()->getCCore(); bool wasRinging = false; @@ -167,12 +197,12 @@ bool CallPrivate::onCallSessionAccepted (const std::shared_ptr &session) { +void CallPrivate::onCallSessionSetReleased (const shared_ptr &session) { L_Q(); linphone_call_unref(L_GET_C_BACK_PTR(q)); } -void CallPrivate::onCallSessionSetTerminated (const std::shared_ptr &session) { +void CallPrivate::onCallSessionSetTerminated (const shared_ptr &session) { L_Q(); LinphoneCore *core = q->getCore()->getCCore(); if (q->getSharedFromThis() == q->getCore()->getCurrentCall()) { @@ -197,12 +227,21 @@ void CallPrivate::onCallSessionSetTerminated (const std::shared_ptrbw_controller); } -void CallPrivate::onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const string &message) { +void CallPrivate::onCallSessionStartReferred (const shared_ptr &session) { + startReferredCall(nullptr); +} + +void CallPrivate::onCallSessionStateChanged (const shared_ptr &session, LinphoneCallState state, const string &message) { L_Q(); linphone_call_notify_state_changed(L_GET_C_BACK_PTR(q), state, message.c_str()); } -void CallPrivate::onCheckForAcceptation (const std::shared_ptr &session) { +void CallPrivate::onCallSessionTransferStateChanged (const shared_ptr &session, LinphoneCallState state) { + L_Q(); + linphone_call_notify_transfer_state_changed(L_GET_C_BACK_PTR(q), state); +} + +void CallPrivate::onCheckForAcceptation (const shared_ptr &session) { L_Q(); LinphoneCall *lcall = L_GET_C_BACK_PTR(q); bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(q->getCore()->getCCore())); @@ -225,23 +264,23 @@ void CallPrivate::onCheckForAcceptation (const std::shared_ptr &session, char dtmf) { +void CallPrivate::onDtmfReceived (const shared_ptr &session, char dtmf) { L_Q(); linphone_call_notify_dtmf_received(L_GET_C_BACK_PTR(q), dtmf); } -void CallPrivate::onIncomingCallSessionNotified (const std::shared_ptr &session) { +void CallPrivate::onIncomingCallSessionNotified (const shared_ptr &session) { L_Q(); /* The call is acceptable so we can now add it to our list */ q->getCore()->getPrivate()->addCall(q->getSharedFromThis()); } -void CallPrivate::onIncomingCallSessionStarted (const std::shared_ptr &session) { +void CallPrivate::onIncomingCallSessionStarted (const shared_ptr &session) { L_Q(); linphone_core_notify_incoming_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); } -void CallPrivate::onIncomingCallSessionTimeoutCheck (const std::shared_ptr &session, int elapsed, bool oneSecondElapsed) { +void CallPrivate::onIncomingCallSessionTimeoutCheck (const shared_ptr &session, int elapsed, bool oneSecondElapsed) { L_Q(); if (oneSecondElapsed) lInfo() << "Incoming call ringing for " << elapsed << " seconds"; @@ -253,12 +292,12 @@ void CallPrivate::onIncomingCallSessionTimeoutCheck (const std::shared_ptr &session, const LinphoneInfoMessage *im) { +void CallPrivate::onInfoReceived (const shared_ptr &session, const LinphoneInfoMessage *im) { L_Q(); linphone_call_notify_info_message_received(L_GET_C_BACK_PTR(q), im); } -void CallPrivate::onNoMediaTimeoutCheck (const std::shared_ptr &session, bool oneSecondElapsed) { +void CallPrivate::onNoMediaTimeoutCheck (const shared_ptr &session, bool oneSecondElapsed) { L_Q(); int disconnectTimeout = linphone_core_get_nortp_timeout(q->getCore()->getCCore()); bool disconnected = false; @@ -270,27 +309,27 @@ void CallPrivate::onNoMediaTimeoutCheck (const std::shared_ptr &session, bool activated, const string &authToken) { +void CallPrivate::onEncryptionChanged (const shared_ptr &session, bool activated, const string &authToken) { L_Q(); linphone_call_notify_encryption_changed(L_GET_C_BACK_PTR(q), activated, authToken.empty() ? nullptr : authToken.c_str()); } -void CallPrivate::onStatsUpdated (const std::shared_ptr &session, const LinphoneCallStats *stats) { +void CallPrivate::onStatsUpdated (const shared_ptr &session, const LinphoneCallStats *stats) { L_Q(); linphone_call_notify_stats_updated(L_GET_C_BACK_PTR(q), stats); } -void CallPrivate::onResetCurrentSession (const std::shared_ptr &session) { +void CallPrivate::onResetCurrentSession (const shared_ptr &session) { L_Q(); q->getCore()->getPrivate()->setCurrentCall(nullptr); } -void CallPrivate::onSetCurrentSession (const std::shared_ptr &session) { +void CallPrivate::onSetCurrentSession (const shared_ptr &session) { L_Q(); q->getCore()->getPrivate()->setCurrentCall(q->getSharedFromThis()); } -void CallPrivate::onFirstVideoFrameDecoded (const std::shared_ptr &session) { +void CallPrivate::onFirstVideoFrameDecoded (const shared_ptr &session) { L_Q(); if (nextVideoFrameDecoded._func) { nextVideoFrameDecoded._func(L_GET_C_BACK_PTR(q), nextVideoFrameDecoded._user_data); @@ -299,16 +338,16 @@ void CallPrivate::onFirstVideoFrameDecoded (const std::shared_ptr &session) { +void CallPrivate::onResetFirstVideoFrameDecoded (const shared_ptr &session) { resetFirstVideoFrameDecoded(); } -void CallPrivate::onPlayErrorTone (const std::shared_ptr &session, LinphoneReason reason) { +void CallPrivate::onPlayErrorTone (const shared_ptr &session, LinphoneReason reason) { L_Q(); linphone_core_play_call_error_tone(q->getCore()->getCCore(), reason); } -void CallPrivate::onRingbackToneRequested (const std::shared_ptr &session, bool requested) { +void CallPrivate::onRingbackToneRequested (const shared_ptr &session, bool requested) { L_Q(); if (requested && linphone_core_get_remote_ringback_tone(q->getCore()->getCCore())) playingRingbackTone = true; @@ -316,7 +355,7 @@ void CallPrivate::onRingbackToneRequested (const std::shared_ptr &session) { +void CallPrivate::onStartRinging (const shared_ptr &session) { L_Q(); LinphoneCore *lc = q->getCore()->getCCore(); if (lc->ringstream) @@ -324,12 +363,12 @@ void CallPrivate::onStartRinging (const std::shared_ptr &sess startRemoteRing(); } -void CallPrivate::onStopRinging (const std::shared_ptr &session) { +void CallPrivate::onStopRinging (const shared_ptr &session) { L_Q(); linphone_core_stop_ringing(q->getCore()->getCCore()); } -void CallPrivate::onStopRingingIfInCall (const std::shared_ptr &session) { +void CallPrivate::onStopRingingIfInCall (const shared_ptr &session) { L_Q(); LinphoneCore *lc = q->getCore()->getCCore(); // We stop the ring only if we have this current call or if we are in call @@ -338,7 +377,7 @@ void CallPrivate::onStopRingingIfInCall (const std::shared_ptr &session) { +void CallPrivate::onStopRingingIfNeeded (const shared_ptr &session) { L_Q(); LinphoneCore *lc = q->getCore()->getCCore(); bool stopRinging = true; @@ -354,7 +393,7 @@ void CallPrivate::onStopRingingIfNeeded (const std::shared_ptr &session) { +bool CallPrivate::isPlayingRingbackTone (const shared_ptr &session) { return playingRingbackTone; } @@ -403,6 +442,11 @@ LinphoneStatus Call::deferUpdate () { return d->getActiveSession()->deferUpdate(); } +bool Call::hasTransferPending () const { + L_D(); + return d->getActiveSession()->hasTransferPending(); +} + void Call::oglRender () const { L_D(); static_pointer_cast(d->getActiveSession())->getPrivate()->oglRender(); @@ -463,6 +507,16 @@ LinphoneStatus Call::terminate (const LinphoneErrorInfo *ei) { return d->getActiveSession()->terminate(ei); } +LinphoneStatus Call::transfer (const shared_ptr &dest) { + L_D(); + return d->getActiveSession()->transfer(dest->getPrivate()->getActiveSession()); +} + +LinphoneStatus Call::transfer (const string &dest) { + L_D(); + return d->getActiveSession()->transfer(dest); +} + LinphoneStatus Call::update (const MediaSessionParams *msp) { L_D(); return static_pointer_cast(d->getActiveSession())->update(msp); @@ -616,6 +670,23 @@ float Call::getRecordVolume () const { return static_pointer_cast(d->getActiveSession())->getRecordVolume(); } +shared_ptr Call::getReferer () const { + L_D(); + shared_ptr referer = d->getActiveSession()->getReferer(); + if (!referer) + return nullptr; + for (const auto &call : getCore()->getCalls()) { + if (call->getPrivate()->getActiveSession() == referer) + return call; + } + return nullptr; +} + +string Call::getReferTo () const { + L_D(); + return d->getActiveSession()->getReferTo(); +} + const Address &Call::getRemoteAddress () const { L_D(); return d->getActiveSession()->getRemoteAddress(); @@ -681,6 +752,23 @@ string Call::getToHeader (const std::string &name) const { return d->getActiveSession()->getToHeader(name); } +LinphoneCallState Call::getTransferState () const { + L_D(); + return d->getActiveSession()->getTransferState(); +} + +shared_ptr Call::getTransferTarget () const { + L_D(); + shared_ptr transferTarget = d->getActiveSession()->getTransferTarget(); + if (!transferTarget) + return nullptr; + for (const auto &call : getCore()->getCalls()) { + if (call->getPrivate()->getActiveSession() == transferTarget) + return call; + } + return nullptr; +} + LinphoneCallStats *Call::getVideoStats () const { L_D(); return static_pointer_cast(d->getActiveSession())->getVideoStats(); diff --git a/src/call/call.h b/src/call/call.h index 164bc02cd..d15447805 100644 --- a/src/call/call.h +++ b/src/call/call.h @@ -48,6 +48,7 @@ public: LinphoneStatus decline (LinphoneReason reason); LinphoneStatus decline (const LinphoneErrorInfo *ei); LinphoneStatus deferUpdate (); + bool hasTransferPending () const; void oglRender () const; LinphoneStatus pause (); LinphoneStatus redirect (const std::string &redirectUri); @@ -60,6 +61,8 @@ public: LinphoneStatus takePreviewSnapshot (const std::string &file); LinphoneStatus takeVideoSnapshot (const std::string &file); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); + LinphoneStatus transfer (const std::shared_ptr &dest); + LinphoneStatus transfer (const std::string &dest); LinphoneStatus update (const MediaSessionParams *msp = nullptr); void zoomVideo (float zoomFactor, float *cx, float *cy); void zoomVideo (float zoomFactor, float cx, float cy); @@ -91,6 +94,8 @@ public: float getPlayVolume () const; LinphoneReason getReason () const; float getRecordVolume () const; + std::shared_ptr getReferer () const; + std::string getReferTo () const; const Address &getRemoteAddress () const; std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; @@ -104,6 +109,8 @@ public: LinphoneCallStats *getTextStats () const; const Address &getToAddress () const; std::string getToHeader (const std::string &name) const; + LinphoneCallState getTransferState () const; + std::shared_ptr getTransferTarget () const; LinphoneCallStats *getVideoStats () const; bool mediaInProgress () const; void setAudioRoute (LinphoneAudioRoute route); diff --git a/src/conference/params/call-session-params-p.h b/src/conference/params/call-session-params-p.h index b07fc90d6..3d63c8233 100644 --- a/src/conference/params/call-session-params-p.h +++ b/src/conference/params/call-session-params-p.h @@ -30,6 +30,8 @@ LINPHONE_BEGIN_NAMESPACE +class CallSession; + class CallSessionParamsPrivate : public ClonableObjectPrivate { public: CallSessionParamsPrivate () = default; @@ -48,8 +50,8 @@ public: const std::unordered_map &getCustomContactParameters () const { return customContactParameters; } - LinphoneCall *getReferer () const { return referer; } - void setReferer (LinphoneCall *call) { referer = call; } + std::shared_ptr getReferer () const { return referer; } + void setReferer (std::shared_ptr session) { referer = session; } public: std::string sessionName; @@ -62,7 +64,7 @@ private: bool noUserConsent = false; /* When set to true an UPDATE request will be used instead of reINVITE */ SalCustomHeader *customHeaders = nullptr; std::unordered_map customContactParameters; - LinphoneCall *referer = nullptr; /* In case call creation is consecutive to an incoming transfer, this points to the original call */ + std::shared_ptr referer; /* In case call creation is consecutive to an incoming transfer, this points to the original call */ L_DECLARE_PUBLIC(CallSessionParams); }; diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index 918cdb692..0f6b2d6fe 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -37,7 +37,9 @@ public: virtual bool onCallSessionAccepted (const std::shared_ptr &session) { return false; } virtual void onCallSessionSetReleased (const std::shared_ptr &session) {} virtual void onCallSessionSetTerminated (const std::shared_ptr &session) {} + virtual void onCallSessionStartReferred (const std::shared_ptr &session) {} virtual void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) {} + virtual void onCallSessionTransferStateChanged (const std::shared_ptr &session, LinphoneCallState state) {} virtual void onCheckForAcceptation (const std::shared_ptr &session) {} virtual void onDtmfReceived (const std::shared_ptr &session, char dtmf) {} virtual void onIncomingCallSessionNotified (const std::shared_ptr &session) {} diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 6d9828163..38e9a696b 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -35,7 +35,9 @@ public: int computeDuration () const; virtual void initializeParamsAccordingToIncomingCallParams (); + void notifyReferState (); virtual void setState (LinphoneCallState newState, const std::string &message); + void setTransferState (LinphoneCallState newState); void startIncomingNotification (); bool startPing (); void setPingTime (int value) { pingTime = value; } @@ -45,6 +47,8 @@ public: SalCallOp * getOp () const { return op; } bool isBroken () const { return broken; } void setParams (CallSessionParams *csp); + void setReferPending (bool value) { referPending = value; } + void setTransferTarget (std::shared_ptr session) { transferTarget = session; } virtual void abort (const std::string &errorMsg); virtual void accepted (); @@ -54,6 +58,7 @@ public: virtual bool failure (); void infoReceived (SalBodyHandler *bodyHandler); void pingReply (); + void referred (const Address &referToAddr); virtual void remoteRinging (); void replaceOp (SalCallOp *newOp); virtual void terminated (); @@ -109,10 +114,11 @@ protected: LinphoneCallDir direction = LinphoneCallOutgoing; LinphoneCallState state = LinphoneCallIdle; LinphoneCallState prevState = LinphoneCallIdle; - //LinphoneCallState transferState = LinphoneCallIdle; + LinphoneCallState transferState = LinphoneCallIdle; LinphoneProxyConfig *destProxy = nullptr; LinphoneErrorInfo *ei = nullptr; LinphoneCallLog *log = nullptr; + std::string referTo; SalCallOp *op = nullptr; @@ -120,11 +126,15 @@ protected: bool pingReplied = false; int pingTime = 0; + std::shared_ptr referer; + std::shared_ptr transferTarget; + bool broken = false; bool deferIncomingNotification = false; bool deferUpdate = false; bool needLocalIpRefresh = false; bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */ + bool referPending = false; bool reinviteOnCancelResponseRequested = false; private: diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index 6ca45ebeb..1b89299e7 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -54,6 +54,12 @@ void CallSessionPrivate::initializeParamsAccordingToIncomingCallParams () { currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy()); } +void CallSessionPrivate::notifyReferState () { + SalCallOp *refererOp = referer->getPrivate()->getOp(); + if (refererOp) + refererOp->notify_refer_state(op); +} + void CallSessionPrivate::setState(LinphoneCallState newState, const string &message) { L_Q(); if (state != newState){ @@ -137,12 +143,23 @@ void CallSessionPrivate::setState(LinphoneCallState newState, const string &mess linphone_call_state_to_string(prevState) << " to " << linphone_call_state_to_string(state) << ")"; } if (listener) - listener->onCallSessionStateChanged(q->getSharedFromThis(), state, message); + listener->onCallSessionStateChanged(q->getSharedFromThis(), newState, message); if (newState == LinphoneCallReleased) setReleased(); /* Shall be performed after app notification */ } } +void CallSessionPrivate::setTransferState (LinphoneCallState newState) { + L_Q(); + if (newState == transferState) + return; + lInfo() << "Transfer state for CallSession [" << q << "] changed from [" + << linphone_call_state_to_string(transferState) << "] to [" << linphone_call_state_to_string(newState) << "]"; + transferState = newState; + if (listener) + listener->onCallSessionTransferStateChanged(q->getSharedFromThis(), newState); +} + void CallSessionPrivate::startIncomingNotification () { L_Q(); if (listener) @@ -286,15 +303,10 @@ bool CallSessionPrivate::failure () { if ((ei->reason != SalReasonNone) && listener) listener->onPlayErrorTone(q->getSharedFromThis(), linphone_reason_from_sal(ei->reason)); } -#if 0 - LinphoneCall *referer=call->referer; - if (referer){ - /*notify referer of the failure*/ - linphone_core_notify_refer_state(lc,referer,call); - /*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/ - linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer"); + if (referer) { + // Notify referer of the failure + notifyReferState(); } -#endif return false; } @@ -321,6 +333,15 @@ void CallSessionPrivate::pingReply () { } } +void CallSessionPrivate::referred (const Address &referToAddr) { + L_Q(); + referTo = referToAddr.asString(); + referPending = true; + setState(LinphoneCallRefered, "Referred"); + if (referPending && listener) + listener->onCallSessionStartReferred(q->getSharedFromThis()); +} + void CallSessionPrivate::remoteRinging () { L_Q(); /* Set privacy */ @@ -389,10 +410,8 @@ void CallSessionPrivate::terminated () { default: break; } -#if 0 - if (call->refer_pending) - linphone_core_start_refered_call(lc,call,NULL); -#endif + if (referPending && listener) + listener->onCallSessionStartReferred(q->getSharedFromThis()); if (listener) listener->onStopRingingIfInCall(q->getSharedFromThis()); setState(LinphoneCallEnd, "Call ended"); @@ -587,16 +606,9 @@ void CallSessionPrivate::setReleased () { op->release(); op = nullptr; } + referer = nullptr; + transferTarget = nullptr; #if 0 - /* It is necessary to reset pointers to other call to prevent circular references that would result in memory never freed */ - if (call->referer){ - linphone_call_unref(call->referer); - call->referer=NULL; - } - if (call->transfer_target){ - linphone_call_unref(call->transfer_target); - call->transfer_target=NULL; - } if (call->chat_room){ linphone_chat_room_unref(call->chat_room); call->chat_room = NULL; @@ -731,10 +743,8 @@ void CallSessionPrivate::createOpTo (const LinphoneAddress *to) { op->release(); op = new SalCallOp(q->getCore()->getCCore()->sal); op->set_user_pointer(q); -#if 0 - if (linphone_call_params_get_referer(call->params)) - sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op); -#endif + if (params->getPrivate()->getReferer()) + op->set_referer(params->getPrivate()->getReferer()->getPrivate()->getOp()); linphone_configure_op(q->getCore()->getCCore(), op, to, q->getParams()->getPrivate()->getCustomHeaders(), false); if (q->getParams()->getPrivacy() != LinphonePrivacyDefault) op->set_privacy((SalPrivacyMask)q->getParams()->getPrivacy()); @@ -932,6 +942,8 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg } if (direction == LinphoneCallOutgoing) { + if (d->params->getPrivate()->getReferer()) + d->referer = d->params->getPrivate()->getReferer(); d->startPing(); } else if (direction == LinphoneCallIncoming) { d->setParams(new CallSessionParams()); @@ -987,6 +999,11 @@ LinphoneStatus CallSession::deferUpdate () { return 0; } +bool CallSession::hasTransferPending () { + L_D(); + return d->referPending; +} + void CallSession::initiateIncoming () {} bool CallSession::initiateOutgoing () { @@ -1134,6 +1151,26 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) { return 0; } +LinphoneStatus CallSession::transfer (const shared_ptr &dest) { + L_D(); + int result = d->op->refer_with_replaces(dest->getPrivate()->op); + d->setTransferState(LinphoneCallOutgoingInit); + return result; +} + +LinphoneStatus CallSession::transfer (const string &dest) { + L_D(); + LinphoneAddress *destAddr = linphone_core_interpret_url(getCore()->getCCore(), dest.c_str()); + if (!destAddr) + return -1; + char *addrStr = linphone_address_as_string(destAddr); + d->op->refer(addrStr); + bctbx_free(addrStr); + linphone_address_unref(destAddr); + d->setTransferState(LinphoneCallOutgoingInit); + return 0; +} + LinphoneStatus CallSession::update (const CallSessionParams *csp, const string &subject, const Content *content) { L_D(); LinphoneCallState nextState; @@ -1200,6 +1237,16 @@ LinphoneReason CallSession::getReason () const { return linphone_error_info_get_reason(getErrorInfo()); } +shared_ptr CallSession::getReferer () const { + L_D(); + return d->referer; +} + +string CallSession::getReferTo () const { + L_D(); + return d->referTo; +} + const Address& CallSession::getRemoteAddress () const { L_D(); return *L_GET_CPP_PTR_FROM_C_OBJECT((d->direction == LinphoneCallIncoming) @@ -1256,6 +1303,16 @@ const Address& CallSession::getToAddress () const { return d->toAddress; } +LinphoneCallState CallSession::getTransferState () const { + L_D(); + return d->transferState; +} + +shared_ptr CallSession::getTransferTarget () const { + L_D(); + return d->transferTarget; +} + string CallSession::getToHeader (const string &name) const { L_D(); return L_C_TO_STRING(sal_custom_header_find(d->op->get_recv_custom_header(), name.c_str())); diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 466e9a141..20d305f71 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -59,6 +59,7 @@ public: LinphoneStatus decline (const LinphoneErrorInfo *ei); LinphoneStatus declineNotAnswered (LinphoneReason reason); virtual LinphoneStatus deferUpdate (); + bool hasTransferPending (); virtual void initiateIncoming (); virtual bool initiateOutgoing (); virtual void iterate (time_t currentRealTime, bool oneSecondElapsed); @@ -67,6 +68,8 @@ public: virtual void startIncomingNotification (); virtual int startInvite (const Address *destination, const std::string &subject = "", const Content *content = nullptr); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); + LinphoneStatus transfer (const std::shared_ptr &dest); + LinphoneStatus transfer (const std::string &dest); LinphoneStatus update (const CallSessionParams *csp, const std::string &subject = "", const Content *content = nullptr); CallSessionParams *getCurrentParams () const; @@ -77,6 +80,8 @@ public: LinphoneCallLog * getLog () const; virtual const CallSessionParams *getParams () const; LinphoneReason getReason () const; + std::shared_ptr getReferer () const; + std::string getReferTo () const; const Address& getRemoteAddress () const; std::string getRemoteAddressAsString () const; std::string getRemoteContact () const; @@ -85,6 +90,8 @@ public: std::string getRemoteUserAgent () const; LinphoneCallState getState () const; const Address& getToAddress () const; + LinphoneCallState getTransferState () const; + std::shared_ptr getTransferTarget () const; std::string getToHeader (const std::string &name) const; protected: diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 24e840f4f..1efd7af61 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -40,15 +40,20 @@ public: MediaSessionPrivate () = default; public: + static int resumeAfterFailedTransfer (void *userData, unsigned int); + static bool_t startPendingRefer (void *userData); static void stunAuthRequestedCb (void *userData, const char *realm, const char *nonce, const char **username, const char **password, const char **ha1); void accepted () override; void ackReceived (LinphoneHeaders *headers) override; void dtmfReceived (char dtmf); bool failure () override; + void pauseForTransfer (); void pausedByRemote (); void remoteRinging () override; + int resumeAfterFailedTransfer (); void resumed (); + void startPendingRefer (); void telephoneEventReceived (int event); void terminated () override; void updated (bool isUpdate); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 19a54983d..aac0f68ac 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -102,10 +102,8 @@ void MediaSessionPrivate::accepted () { switch (state) { case LinphoneCallResuming: case LinphoneCallConnected: -#if 0 - if (call->referer) - linphone_core_notify_refer_state(lc,call->referer,call); -#endif + if (referer) + notifyReferState(); BCTBX_NO_BREAK; /* Intentional no break */ case LinphoneCallUpdating: case LinphoneCallUpdatedByRemote: @@ -129,10 +127,8 @@ void MediaSessionPrivate::accepted () { * Our streams are all send-only (with music), soundcard and camera are never used. */ nextState = LinphoneCallPaused; nextStateMsg = "Call paused"; -#if 0 - if (call->refer_pending) - linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call); -#endif + if (referPending) + linphone_task_list_add(&tl, &MediaSessionPrivate::startPendingRefer, q); break; default: lError() << "accepted(): don't know what to do in state [" << linphone_call_state_to_string(state) << "]"; @@ -249,12 +245,26 @@ bool MediaSessionPrivate::failure () { if (stop) return true; + if (referer) { + // Schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests + linphone_core_queue_task(q->getCore()->getCCore(), + &MediaSessionPrivate::resumeAfterFailedTransfer, referer.get(), + "Automatic CallSession resuming after failed transfer"); + } + if (listener) listener->onStopRingingIfNeeded(q->getSharedFromThis()); stopStreams(); return false; } +void MediaSessionPrivate::pauseForTransfer () { + L_Q(); + lInfo() << "Automatically pausing current MediaSession to accept transfer"; + q->pause(); + automaticallyPaused = true; +} + void MediaSessionPrivate::pausedByRemote () { L_Q(); MediaSessionParams *newParams = new MediaSessionParams(*getParams()); @@ -308,10 +318,31 @@ void MediaSessionPrivate::remoteRinging () { } } +int MediaSessionPrivate::resumeAfterFailedTransfer () { + L_Q(); + if (automaticallyPaused && (state == LinphoneCallPausing)) + return BELLE_SIP_CONTINUE; // Was still in pausing state + if (automaticallyPaused && (state == LinphoneCallPaused)) { + if (op->is_idle()) + q->resume(); + else { + lInfo() << "MediaSessionPrivate::resumeAfterFailedTransfer(), op was busy"; + return BELLE_SIP_CONTINUE; + } + } + return BELLE_SIP_STOP; +} + void MediaSessionPrivate::resumed () { acceptUpdate(nullptr, LinphoneCallStreamsRunning, "Connected (streams running)"); } +void MediaSessionPrivate::startPendingRefer () { + L_Q(); + if (listener) + listener->onCallSessionStartReferred(q->getSharedFromThis()); +} + void MediaSessionPrivate::telephoneEventReceived (int event) { static char dtmfTab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'A', 'B', 'C', 'D' }; if ((event < 0) || (event > 15)) { @@ -4035,6 +4066,17 @@ int MediaSessionPrivate::sendDtmf () { // ----------------------------------------------------------------------------- +int MediaSessionPrivate::resumeAfterFailedTransfer (void *userData, unsigned int) { + MediaSession *session = reinterpret_cast(userData); + return session->getPrivate()->resumeAfterFailedTransfer(); +} + +bool_t MediaSessionPrivate::startPendingRefer (void *userData) { + MediaSession *session = reinterpret_cast(userData); + session->getPrivate()->startPendingRefer(); + return TRUE; +} + void MediaSessionPrivate::stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1) { L_Q(); /* Get the username from the nat policy or the proxy config */ @@ -4209,11 +4251,6 @@ void MediaSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cf d->iceAgent->checkSession(IR_Controlling, false); d->runStunTestsIfNeeded(); d->discoverMtu(to); -#if 0 - if (linphone_call_params_get_referer(params)){ - call->referer=linphone_call_ref(linphone_call_params_get_referer(params)); - } -#endif } else if (direction == LinphoneCallIncoming) { d->selectIncomingIpVersion(); /* Note that the choice of IP version for streams is later refined by setCompatibleIncomingCallParams() when examining the diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 43e2179d3..a5a8749b9 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -1415,7 +1415,7 @@ int SalCallOp::notify_refer_state(SalCallOp *newcall) { if(belle_sip_dialog_get_state(this->dialog) == BELLE_SIP_DIALOG_TERMINATED){ return 0; } - state = this->dialog?belle_sip_dialog_get_state(this->dialog):BELLE_SIP_DIALOG_NULL; + state = newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; switch(state) { case BELLE_SIP_DIALOG_EARLY: send_notify_for_refer(100, "Trying");