diff --git a/src/call.cpp b/src/call.cpp index 5721aeea30e77fd071e0d7704a81ba8917cac0ae..db4bee11e6ef09590979b5533fa9948da2640ce4 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -212,7 +212,7 @@ Call::setState(CallState call_state, ConnectionState cnx_state, signed code) l(callState_, connectionState_, code); if (old_client_state != new_client_state) { - if (not parent_.load()) { + if (not parent_) { RING_DBG("[call:%s] emit client call state change %s, code %d", id_.c_str(), new_client_state.c_str(), code); emitSignal<DRing::CallSignal::StateChange>(id_, new_client_state, code); @@ -342,10 +342,14 @@ Call::getNullDetails() void Call::onTextMessage(std::map<std::string, std::string>&& messages) { - if (parent_.load()) - pendingInMessages_.emplace_back(std::move(messages), ""); - else - Manager::instance().incomingMessage(getCallId(), getPeerNumber(), messages); + { + std::lock_guard<std::recursive_mutex> lk {callMutex_}; + if (parent_) { + pendingInMessages_.emplace_back(std::move(messages), ""); + return; + } + } + Manager::instance().incomingMessage(getCallId(), getPeerNumber(), messages); } void @@ -376,18 +380,15 @@ Call::addSubCall(Call& subcall) } RING_DBG("[call:%s] add subcall %s", getCallId().c_str(), subcall.getCallId().c_str()); - subcall.parent_ = this; + subcall.parent_ = getPtr(*this); for (const auto& msg : pendingOutMessages_) subcall.sendTextMessage(msg.first, msg.second); subcall.addStateListener( - [&subcall](Call::CallState new_state, - Call::ConnectionState new_cstate, - UNUSED int code) { - auto ptr = getPtr(subcall); // keep the subcall valid (subcallStateChanged may remove it) - auto parent = subcall.parent_.load(); - assert(parent != nullptr); + [&subcall](Call::CallState new_state, Call::ConnectionState new_cstate, UNUSED int code) { + auto parent = subcall.parent_; + assert(parent != nullptr); // subcall cannot be "un-parented" parent->subcallStateChanged(subcall, new_state, new_cstate); }); } @@ -494,7 +495,7 @@ Call::checkPendingIM() auto state = getStateStr(); // Let parent call handles IM after the merge - if (not parent_.load()) { + if (not parent_) { if (state == DRing::Call::StateEvent::CURRENT) { for (const auto& msg : pendingInMessages_) Manager::instance().incomingMessage(getCallId(), getPeerNumber(), msg.first); diff --git a/src/call.h b/src/call.h index 6c7c4dfeb9274e0e0472d296f48c5e8c824770d8..dd885138e9e588b4078cad8fa75dc92e91ca2338 100644 --- a/src/call.h +++ b/src/call.h @@ -40,7 +40,6 @@ #include <condition_variable> #include <set> #include <list> -#include <atomic> namespace ring { @@ -262,7 +261,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { /// Return true if this call instance is a subcall (internal call for multi-device handling) /// bool isSubcall() const { - return parent_.load() != nullptr; + std::lock_guard<std::recursive_mutex> lk {callMutex_}; + return parent_ != nullptr; } public: // media management @@ -318,8 +318,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { bool isAudioMuted_{false}; bool isVideoMuted_{false}; - ///< MultiDevice: parent call, nullptr otherwise. - std::atomic<Call*> parent_ {nullptr}; + ///< MultiDevice: parent call, nullptr otherwise. Access protected by callMutex_. + mutable std::shared_ptr<Call> parent_; ///< MultiDevice: list of attached subcall SubcallSet subcalls_; diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index 6dc1572e4a611d230cea52f65b1eed9507ed3e02..4033bbd922786bb55bfdd2750bf20cbf284a469d 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -712,7 +712,7 @@ SIPCall::onAnswered() RING_WARN("[call:%s] onAnswered()", getCallId().c_str()); if (getConnectionState() != ConnectionState::CONNECTED) { setState(CallState::ACTIVE, ConnectionState::CONNECTED); - if (not parent_.load()) + if (not isSubcall()) Manager::instance().peerAnsweredCall(*this); } } @@ -882,7 +882,7 @@ SIPCall::startAllMedia() } } - if (not parent_.load() and peerHolding_ != peer_holding) { + if (not isSubcall() and peerHolding_ != peer_holding) { peerHolding_ = peer_holding; emitSignal<DRing::CallSignal::PeerHold>(getCallId(), peerHolding_); } @@ -928,7 +928,7 @@ SIPCall::muteMedia(const std::string& mediaType, bool mute) isVideoMuted_ = mute; videoInput_ = isVideoMuted_ ? "" : Manager::instance().getVideoManager().videoDeviceMonitor.getMRLForDefaultDevice(); DRing::switchInput(getCallId(), videoInput_); - if (not parent_.load()) + if (not isSubcall()) emitSignal<DRing::CallSignal::VideoMuted>(getCallId(), isVideoMuted_); #endif } else if (mediaType.compare(DRing::Media::Details::MEDIA_TYPE_AUDIO) == 0) { @@ -936,7 +936,7 @@ SIPCall::muteMedia(const std::string& mediaType, bool mute) RING_WARN("[call:%s] audio muting %s", getCallId().c_str(), bool_to_str(mute)); isAudioMuted_ = mute; avformatrtp_->setMuted(isAudioMuted_); - if (not parent_.load()) + if (not isSubcall()) emitSignal<DRing::CallSignal::AudioMuted>(getCallId(), isAudioMuted_); } } @@ -961,8 +961,9 @@ SIPCall::onMediaUpdate() return; } - // If we are a subcall let the parent manage it after merge operation - if (not parent_.load()) + // Main call (no subcalls) must wait for ICE now, the rest of code needs to access + // to a negotiated transport. + if (not isSubcall()) waitForIceAndStartMedia(); }