diff --git a/src/call.h b/src/call.h index 02b2c8c4f66fa73bdc66424075e25974efd2296a..658a61b0558c5310b8e37f65849036f97a1cbaa3 100644 --- a/src/call.h +++ b/src/call.h @@ -59,6 +59,7 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { public: using SubcallSet = std::set<std::shared_ptr<Call>, std::owner_less<std::shared_ptr<Call>>>; using OnNeedFallbackCb = std::function<void()>; + using OnReadyCb = std::function<void(bool)>; static const char * const DEFAULT_ID; @@ -229,15 +230,17 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { /** * Put a call on hold - * @return bool True on success + * @param cb On hold can be queued if waiting for ICE. This callback will be called when ready + * @return bool True on success, False if failed or pending */ - virtual bool onhold() = 0; + virtual bool onhold(OnReadyCb&& cb) = 0; /** * Resume a call from hold state - * @return bool True on success + * @param cb On hold can be queued if waiting for ICE. This callback will be called when ready + * @return bool True on success, False if failed or pending */ - virtual bool offhold() = 0; + virtual bool offhold(OnReadyCb&& cb) = 0; virtual void sendKeyframe() = 0; diff --git a/src/manager.cpp b/src/manager.cpp index 0e976aa7556474e945b9a24ee45696db88060cab..dcace10ef557ed00538ed4b17f94ef78da0f7fd1 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -1064,29 +1064,29 @@ Manager::onHoldCall(const std::string& callId) if (auto call = getCallFromCallID(callId)) { try { - result = call->onhold(); - if (result) + result = call->onhold([=](bool ok) { + if (!ok) { + JAMI_ERR("hold failed for call %s", callId.c_str()); + return; + } removeAudio(*call); // Unbind calls in main buffer + // Remove call from the queue if it was still there + pimpl_->removeWaitingCall(callId); + + // keeps current call id if the action is not holding this call + // or a new outgoing call. This could happen in case of a conference + if (current_call_id == callId) + pimpl_->unsetCurrentCall(); + }); } catch (const VoipLinkException &e) { JAMI_ERR("%s", e.what()); result = false; } - } else { JAMI_DBG("CallID %s doesn't exist in call onHold", callId.c_str()); return false; } - if (result) { - // Remove call from the queue if it was still there - pimpl_->removeWaitingCall(callId); - - // keeps current call id if the action is not holding this call - // or a new outgoing call. This could happen in case of a conference - if (current_call_id == callId) - pimpl_->unsetCurrentCall(); - } - return result; } @@ -1103,21 +1103,24 @@ Manager::offHoldCall(const std::string& callId) return false; try { - result = call->offhold(); + result = call->offhold([=](bool ok) { + if (!ok) { + JAMI_ERR("off hold failed for call %s", callId.c_str()); + return; + } + + if (isConferenceParticipant(callId)) + pimpl_->switchCall(call->getConfId()); + else + pimpl_->switchCall(call); + + addAudio(*call); + }); } catch (const VoipLinkException &e) { JAMI_ERR("%s", e.what()); return false; } - if (result) { - if (isConferenceParticipant(callId)) - pimpl_->switchCall(call->getConfId()); - else - pimpl_->switchCall(call); - - addAudio(*call); - } - return result; } diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index f90d5488b96529694a3535c378cb241fac1ec4ad..238189e7187c5959df6c55b541c91c56e4659ac0 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -582,13 +582,26 @@ SIPCall::attendedTransfer(const std::string& to) } bool -SIPCall::onhold() +SIPCall::onhold(OnReadyCb&& cb) { // If ICE is currently negotiating, we must wait before hold the call if (isWaitingForIceAndMedia_) { + holdCb_ = std::move(cb); remainingRequest_ = Request::HoldingOn; return false; } + + auto result = hold(); + + if (cb) + cb(result); + + return result; +} + +bool +SIPCall::hold() +{ if (not setState(CallState::HOLD)) return false; @@ -602,22 +615,33 @@ SIPCall::onhold() } isWaitingForIceAndMedia_ = true; - return true; } bool -SIPCall::offhold() +SIPCall::offhold(OnReadyCb&& cb) { - bool success = false; // If ICE is currently negotiating, we must wait before unhold the call if (isWaitingForIceAndMedia_) { + offHoldCb_ = std::move(cb); remainingRequest_ = Request::HoldingOff; return false; } + auto result = unhold(); + + if (cb) + cb(result); + + return result; +} + +bool +SIPCall::unhold() +{ auto& account = getSIPAccount(); + bool success = false; try { if (account.isStunEnabled()) success = internalOffHold([&] { updateSDPFromSTUN(); }); @@ -645,7 +669,11 @@ SIPCall::internalOffHold(const std::function<void()>& sdp_cb) if (getConnectionState() == ConnectionState::CONNECTED) { if (SIPSessionReinvite() != PJ_SUCCESS) { JAMI_WARN("[call:%s] resuming hold", getCallId().c_str()); - onhold(); + if (isWaitingForIceAndMedia_) { + remainingRequest_ = Request::HoldingOn; + } else { + hold(); + } return false; } } @@ -1023,12 +1051,21 @@ SIPCall::startAllMedia() // Media is restarted, we can process the last holding request. isWaitingForIceAndMedia_ = false; if (remainingRequest_ != Request::NoRequest) { + bool result = true; switch (remainingRequest_) { case Request::HoldingOn: - onhold(); + result = hold(); + if (holdCb_) { + holdCb_(result); + holdCb_ = nullptr; + } break; case Request::HoldingOff: - offhold(); + result = unhold(); + if (offHoldCb_) { + offHoldCb_(result); + offHoldCb_ = nullptr; + } break; case Request::SwitchInput: SIPSessionReinvite(); diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index 8fb180d9b83e27434dbff46c21c90653cc0f0bab..c84440637ba7e04374d72ace4dcf47f97a9121d6 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -94,8 +94,8 @@ public: // overridden void refuse() override; void transfer(const std::string& to) override; bool attendedTransfer(const std::string& to) override; - bool onhold() override; - bool offhold() override; + bool onhold(OnReadyCb&& cb) override; + bool offhold(OnReadyCb&& cb) override; void switchInput(const std::string& resource) override; void peerHungup() override; void carryingDTMFdigits(char code) override; @@ -264,6 +264,10 @@ private: bool internalOffHold(const std::function<void()> &SDPUpdateFunc); + bool hold(); + + bool unhold(); + int SIPSessionReinvite(); std::vector<IceCandidate> getAllRemoteCandidates(); @@ -343,6 +347,9 @@ private: bool pendingRecord_ {false}; time_point lastKeyFrameReq_ {time_point::min()}; + + OnReadyCb holdCb_ {}; + OnReadyCb offHoldCb_ {}; }; // Helpers