diff --git a/daemon/src/call.h b/daemon/src/call.h
index eae06627d809466fb6025db30419ad8cae4191b1..1d6f231a8f64bb8b59691b5609fefb621bffcc7a 100644
--- a/daemon/src/call.h
+++ b/daemon/src/call.h
@@ -239,6 +239,12 @@ class Call : public Recordable {
 
         virtual VoIPLink* getVoIPLink() const = 0;
 
+        /**
+         * Hang up the call
+         * @param reason
+         */
+        virtual void hangup(int reason) = 0;
+
     private:
         bool validTransition(CallState newState);
 
diff --git a/daemon/src/iax/iaxcall.cpp b/daemon/src/iax/iaxcall.cpp
index be14b9c58bdf88f167cff4a27ad48421a8d021ab..0dc26e6cd130a27c93d67fa61ce4dc5a45f2edab 100644
--- a/daemon/src/iax/iaxcall.cpp
+++ b/daemon/src/iax/iaxcall.cpp
@@ -132,3 +132,15 @@ void IAXCall::answer()
 VoIPLink*
 IAXCall::getVoIPLink() const
 { return link_; }
+
+void
+IAXCall::hangup(int reason UNUSED)
+{
+    Manager::instance().getMainBuffer().unBindAll(getCallId());
+
+    std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
+    iax_hangup(session, (char*) "Dumped Call");
+    session = nullptr;
+
+    link_->removeIaxCall(getCallId());
+}
diff --git a/daemon/src/iax/iaxcall.h b/daemon/src/iax/iaxcall.h
index dd4be39ba755137cf84d6833ee0bbe9e19c904b8..f8969f1a7961ac787d807f4f7f7a518e5f6efa7a 100644
--- a/daemon/src/iax/iaxcall.h
+++ b/daemon/src/iax/iaxcall.h
@@ -80,6 +80,8 @@ class IAXCall : public Call {
 
         VoIPLink* getVoIPLink() const;
 
+        void hangup(int reason);
+
     private:
         void answer();
 
diff --git a/daemon/src/iax/iaxvoiplink.cpp b/daemon/src/iax/iaxvoiplink.cpp
index f4cf4abed4d634e4e2e89ca759619cb10ddb084a..ec3d3184bea794b06240e51e89397d32170efc21 100644
--- a/daemon/src/iax/iaxvoiplink.cpp
+++ b/daemon/src/iax/iaxvoiplink.cpp
@@ -330,27 +330,6 @@ IAXVoIPLink::answer(Call *call)
     Manager::instance().getMainBuffer().flushAllBuffers();
 }
 
-void
-IAXVoIPLink::hangup(const std::string& id, int reason UNUSED)
-{
-    Manager::instance().getMainBuffer().unBindAll(id);
-
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        auto call = getIAXCall(id);
-        if (!call)
-            throw VoipLinkException("Could not find call");
-
-        {
-            std::lock_guard<std::mutex> lock(mutexIAX);
-            iax_hangup(call->session, (char*) "Dumped Call");
-        }
-        call->session = NULL;
-    }
-
-    removeIaxCall(id);
-}
-
 
 void
 IAXVoIPLink::peerHungup(const std::string& id)
diff --git a/daemon/src/iax/iaxvoiplink.h b/daemon/src/iax/iaxvoiplink.h
index 76defcdd28af31dd8ecdc806a07e32f3c50824b0..533c01d2b910d98d270bea774c0152c1e0bd51c5 100644
--- a/daemon/src/iax/iaxvoiplink.h
+++ b/daemon/src/iax/iaxvoiplink.h
@@ -127,12 +127,6 @@ class IAXVoIPLink : public VoIPLink {
          */
         virtual void answer(Call *c);
 
-        /**
-         * Hangup a call
-         * @param id The ID of the call
-         */
-        virtual void hangup(const std::string& id, int reason);
-
         /**
          * Peer Hungup a call
          * @param id The ID of the call
diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp
index fe6a112c58e53ca6138e0435c66f8c34b9421b43..ff0a253c470be0367ddb1e0af575a0e7d3d8caaf 100644
--- a/daemon/src/managerimpl.cpp
+++ b/daemon/src/managerimpl.cpp
@@ -487,7 +487,7 @@ bool ManagerImpl::hangupCall(const std::string& callId)
     try {
         if (auto call = getCallFromCallID(callId)) {
             history_.addCall(call.get(), preferences.getHistoryLimit());
-            call->getVoIPLink()->hangup(callId, 0);
+            call->hangup(0);
             checkAudio();
             saveHistory();
         }
diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp
index ec383d602f78d9b224f949a60a97fae161b56666..1a4d4d564efbd49141d30a5d365f808685d770da 100644
--- a/daemon/src/sip/sipcall.cpp
+++ b/daemon/src/sip/sipcall.cpp
@@ -225,3 +225,63 @@ SIPCall::onhold()
 VoIPLink*
 SIPCall::getVoIPLink() const
 { return &SIPVoIPLink::instance(); }
+
+void
+SIPCall::hangup(int reason)
+{
+    const std::string account_id(getAccountId());
+
+    SIPAccount *account = Manager::instance().getSipAccount(account_id);
+    if (not account)
+        throw VoipLinkException("Could not find account for this call");
+
+    if (not inv)
+        throw VoipLinkException("No invite session for this call");
+
+    pjsip_route_hdr *route = inv->dlg->route_set.next;
+    while (route and route != &inv->dlg->route_set) {
+        char buf[1024];
+        int printed = pjsip_hdr_print_on(route, buf, sizeof(buf));
+
+        if (printed >= 0) {
+            buf[printed] = '\0';
+            DEBUG("Route header %s", buf);
+        }
+
+        route = route->next;
+    }
+
+    pjsip_tx_data *tdata = NULL;
+
+    const int status = reason ? reason :
+                       inv->state <= PJSIP_INV_STATE_EARLY and inv->role != PJSIP_ROLE_UAC ?
+                       PJSIP_SC_CALL_TSX_DOES_NOT_EXIST :
+                       inv->state >= PJSIP_INV_STATE_DISCONNECTED ? PJSIP_SC_DECLINE :
+                       0;
+
+    // User hangup current call. Notify peer
+    if (pjsip_inv_end_session(inv, status, NULL, &tdata) != PJ_SUCCESS || !tdata)
+        return;
+
+    // contactStr must stay in scope as long as tdata
+    const pj_str_t contactStr(account->getContactHeader());
+    sip_utils::addContactHeader(&contactStr, tdata);
+
+    if (pjsip_inv_send_msg(inv, tdata) != PJ_SUCCESS)
+        return;
+
+    auto& siplink = SIPVoIPLink::instance();
+
+    // Make sure user data is NULL in callbacks
+    inv->mod_data[siplink.getMod()->id] = NULL;
+
+    // Stop all RTP streams
+    if (Manager::instance().isCurrentCall(getCallId())) {
+        getAudioRtp().stop();
+#ifdef SFL_VIDEO
+        getVideoRtp().stop();
+#endif
+    }
+
+    siplink.removeSipCall(getCallId());
+}
diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h
index 2d7d9590e1ea25fe9992bf03852b44f402c1bccd..558aa39985c9dc3e6e69283030ea1448ed1438e9 100644
--- a/daemon/src/sip/sipcall.h
+++ b/daemon/src/sip/sipcall.h
@@ -117,6 +117,8 @@ class SIPCall : public Call {
 
         VoIPLink* getVoIPLink() const;
 
+        void hangup(int reason);
+
     private:
 
         // override of Call::createHistoryEntry
diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index e40b404d1da6b6465537796de70b0b9104bcb96c..09814478831fd7e1e5742c7423ccf5fbe9f662a7 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -1059,64 +1059,6 @@ stopRtpIfCurrent(const std::string &id, SIPCall &call)
     }
 }
 
-void
-SIPVoIPLink::hangup(const std::string& id, int reason)
-{
-    auto call = getSipCall(id);
-    if (!call)
-        return;
-
-    std::string account_id(call->getAccountId());
-    SIPAccount *account = Manager::instance().getSipAccount(account_id);
-
-    if (account == NULL)
-        throw VoipLinkException("Could not find account for this call");
-
-    pjsip_inv_session *inv = call->inv;
-
-    if (inv == NULL)
-        throw VoipLinkException("No invite session for this call");
-
-    pjsip_route_hdr *route = inv->dlg->route_set.next;
-
-    while (route and route != &inv->dlg->route_set) {
-        char buf[1024];
-        int printed = pjsip_hdr_print_on(route, buf, sizeof(buf));
-
-        if (printed >= 0) {
-            buf[printed] = '\0';
-            DEBUG("Route header %s", buf);
-        }
-
-        route = route->next;
-    }
-
-    pjsip_tx_data *tdata = NULL;
-
-    const int status = reason ? reason :
-                       inv->state <= PJSIP_INV_STATE_EARLY and inv->role != PJSIP_ROLE_UAC ?
-                       PJSIP_SC_CALL_TSX_DOES_NOT_EXIST :
-                       inv->state >= PJSIP_INV_STATE_DISCONNECTED ? PJSIP_SC_DECLINE :
-                       0;
-
-    // User hangup current call. Notify peer
-    if (pjsip_inv_end_session(inv, status, NULL, &tdata) != PJ_SUCCESS || !tdata)
-        return;
-
-    // contactStr must stay in scope as long as tdata
-    const pj_str_t contactStr(account->getContactHeader());
-    sip_utils::addContactHeader(&contactStr, tdata);
-
-    if (pjsip_inv_send_msg(inv, tdata) != PJ_SUCCESS)
-        return;
-
-    // Make sure user data is NULL in callbacks
-    inv->mod_data[mod_ua_.id] = NULL;
-
-    stopRtpIfCurrent(id, *call);
-    removeSipCall(id);
-}
-
 void
 SIPVoIPLink::peerHungup(const std::string& id)
 {
@@ -1806,9 +1748,9 @@ sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status)
 
         WARN("Could not negotiate offer");
         const std::string callID(call->getCallId());
-        SIPVoIPLink::instance().hangup(callID, reason);
-        // call is now a dangling pointer after calling hangup
-        call = 0;
+        call->hangup(reason);
+        // This will probably invoke call's destructor
+        call = nullptr;
         Manager::instance().callFailure(callID);
         return;
     }
diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h
index 0e6687ccc7931ca798064a613bff0d460fbf0d38..97364130900f53c0356cee812e5ef5994b3a6f1e 100644
--- a/daemon/src/sip/sipvoiplink.h
+++ b/daemon/src/sip/sipvoiplink.h
@@ -165,12 +165,6 @@ class SIPVoIPLink : public VoIPLink {
          */
         virtual void answer(Call *c);
 
-        /**
-         * Hang up the call
-         * @param id The call identifier
-         */
-        virtual void hangup(const std::string& id, int reason);
-
         /**
          * Hang up the call
          * @param id The call identifier
diff --git a/daemon/src/voiplink.h b/daemon/src/voiplink.h
index afdc9a965426098aeac475a1ab2f556c2083e195..acdb080a8b0fe8f446b66cb261a0d5af70a65217 100644
--- a/daemon/src/voiplink.h
+++ b/daemon/src/voiplink.h
@@ -99,12 +99,6 @@ class VoIPLink {
          */
         virtual void answer(Call *c) = 0;
 
-        /**
-         * Hang up a call
-         * @param id The call identifier
-         */
-        virtual void hangup(const std::string &id, int reason) = 0;
-
         /**
         * Peer Hung up a call
         * @param id The call identifier