From 2c7f03af0d5e12551649d515dd6b6e892b9a0d6d Mon Sep 17 00:00:00 2001
From: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
Date: Thu, 25 Jun 2015 16:07:22 -0400
Subject: [PATCH] deamon: check on/off hold state change success

Do not emit HOLD state change if it did not succeed
in the daemon.

Refs #76232

Change-Id: Ib7c95b934d03152db5592706fdea953d56b6e280
---
 src/call.cpp        |  7 +++++--
 src/call.h          |  4 ++--
 src/iax/iaxcall.cpp | 13 ++++++++-----
 src/iax/iaxcall.h   |  4 ++--
 src/manager.cpp     | 21 ++++++++++++---------
 src/sip/sipcall.cpp | 22 +++++++++++++++-------
 src/sip/sipcall.h   |  6 +++---
 7 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/src/call.cpp b/src/call.cpp
index de068038d2..47cedd596a 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -124,10 +124,13 @@ Call::validTransition(CallState newState)
 bool
 Call::setState(CallState state)
 {
+
     std::lock_guard<std::mutex> lock(callMutex_);
     if (not validTransition(state)) {
-        assert((int)callState_ < enum_class_size<CallState>() && (int)state < enum_class_size<CallState>());
-        //RING_ERR("Invalid call state transition from %s to %s", states[callState_], states[state]);
+        assert((int)callState_ < enum_class_size<CallState>()
+               && (int)state < enum_class_size<CallState>());
+        RING_ERR("Invalid attempted call state transition from %d to %d",
+                 callState_, state);
         return false;
     }
 
diff --git a/src/call.h b/src/call.h
index 88f90323b6..767950a243 100644
--- a/src/call.h
+++ b/src/call.h
@@ -271,13 +271,13 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
          * Put a call on hold
          * @return bool True on success
          */
-        virtual void onhold() = 0;
+        virtual bool onhold() = 0;
 
         /**
          * Resume a call from hold state
          * @return bool True on success
          */
-        virtual void offhold() = 0;
+        virtual bool offhold() = 0;
 
         /**
          * mute/unmute a media of a call
diff --git a/src/iax/iaxcall.cpp b/src/iax/iaxcall.cpp
index 7332f36e8f..38fb846ba4 100644
--- a/src/iax/iaxcall.cpp
+++ b/src/iax/iaxcall.cpp
@@ -194,7 +194,7 @@ IAXCall::attendedTransfer(const std::string& /*targetID*/)
     return false; // TODO
 }
 
-void
+bool
 IAXCall::onhold()
 {
     Manager::instance().getRingBufferPool().unBindAll(getCallId());
@@ -204,12 +204,14 @@ IAXCall::onhold()
         iax_quelch_moh(session, true);
     }
 
-    setState(Call::CallState::HOLD);
+    return setState(Call::CallState::HOLD);
 }
 
-void
+bool
 IAXCall::offhold()
 {
+    bool success = false;
+
     Manager::instance().addStream(*this);
 
     {
@@ -217,9 +219,10 @@ IAXCall::offhold()
         iax_unquelch(session);
     }
 
-    setState(Call::CallState::ACTIVE);
+    if (success = setState(Call::CallState::ACTIVE))
+        Manager::instance().startAudioDriverStream();
 
-    Manager::instance().startAudioDriverStream();
+    return success;
 }
 
 void
diff --git a/src/iax/iaxcall.h b/src/iax/iaxcall.h
index a84599aef8..1ace687369 100644
--- a/src/iax/iaxcall.h
+++ b/src/iax/iaxcall.h
@@ -127,9 +127,9 @@ class IAXCall : public Call
 
         bool attendedTransfer(const std::string& to);
 
-        void onhold();
+        bool onhold();
 
-        void offhold();
+        bool offhold();
 
         //TODO: implement mute for IAX
         void muteMedia(const std::string& mediaType, bool isMuted) {}
diff --git a/src/manager.cpp b/src/manager.cpp
index 802a07c247..d686c6eeff 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -628,26 +628,29 @@ Manager::onHoldCall(const std::string& callId)
 
     if (auto call = getCallFromCallID(callId)) {
         try {
-            call->onhold();
-            removeStream(*call); // Unbind calls in main buffer
+            if (result = call->onhold())
+                removeStream(*call); // Unbind calls in main buffer
         } catch (const VoipLinkException &e) {
             RING_ERR("%s", e.what());
             result = false;
         }
+
     } else {
         RING_DBG("CallID %s doesn't exist in call onHold", callId.c_str());
         return false;
     }
 
-    // Remove call from teh queue if it was still there
-    removeWaitingCall(callId);
+    if (result) {
+        // Remove call from the queue if it was still there
+        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)
-        unsetCurrentCall();
+        // 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)
+            unsetCurrentCall();
 
-    emitSignal<DRing::CallSignal::StateChange>(callId, "HOLD", 0);
+        emitSignal<DRing::CallSignal::StateChange>(callId, "HOLD", 0);
+    }
 
     return result;
 }
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index 4f099f6a3e..efcd8dcb53 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -585,11 +585,11 @@ SIPCall::attendedTransfer(const std::string& to)
     return transferCommon(&dst);
 }
 
-void
+bool
 SIPCall::onhold()
 {
     if (not setState(CallState::HOLD))
-        return;
+        return false;
 
     stopAllMedia();
 
@@ -597,30 +597,35 @@ SIPCall::onhold()
         if (SIPSessionReinvite() != PJ_SUCCESS)
             RING_WARN("Reinvite failed");
     }
+
+    return true;
 }
 
-void
+bool
 SIPCall::offhold()
 {
+    bool success = false;
     auto& account = getSIPAccount();
 
     try {
         if (account.isStunEnabled())
-            internalOffHold([&] { updateSDPFromSTUN(); });
+            success = internalOffHold([&] { updateSDPFromSTUN(); });
         else
-            internalOffHold([] {});
+            success = internalOffHold([] {});
 
     } catch (const SdpException &e) {
         RING_ERR("%s", e.what());
         throw VoipLinkException("SDP issue in offhold");
     }
+
+    return success;
 }
 
-void
+bool
 SIPCall::internalOffHold(const std::function<void()>& sdp_cb)
 {
     if (not setState(CallState::ACTIVE))
-        return;
+        return false;
 
     sdp_cb();
 
@@ -628,8 +633,11 @@ SIPCall::internalOffHold(const std::function<void()>& sdp_cb)
         if (SIPSessionReinvite() != PJ_SUCCESS) {
             RING_WARN("Reinvite failed, resuming hold");
             onhold();
+            return false;
         }
     }
+
+    return true;
 }
 
 void
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index 46b05b2920..06ac8cbf3c 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -152,9 +152,9 @@ class SIPCall : public Call
 
         bool attendedTransfer(const std::string& to);
 
-        void onhold();
+        bool onhold();
 
-        void offhold();
+        bool offhold();
 
         void switchInput(const std::string& resource);
 
@@ -221,7 +221,7 @@ class SIPCall : public Call
          */
         bool transferCommon(pj_str_t *dst);
 
-        void internalOffHold(const std::function<void()> &SDPUpdateFunc);
+        bool internalOffHold(const std::function<void()> &SDPUpdateFunc);
 
         int SIPSessionReinvite();
 
-- 
GitLab