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