diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index ece2c7324a7b84bcdac5fb2a259bc39e15377e98..4571f79062900e7b76b93b66da0fd95249995326 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -424,7 +424,10 @@ JamiAccount::newOutgoingCall(std::string_view toUrl, if (not call) return {}; - newOutgoingCallHelper(call, toUrl); + getIceOptions([=](auto&& opts) { + call->initIceMediaTransport(true, std::forward<IceTransportOptions>(opts)); + newOutgoingCallHelper(call, toUrl); + }); return call; } @@ -442,7 +445,10 @@ JamiAccount::newOutgoingCall(std::string_view toUrl, const std::vector<DRing::Me if (not call) return {}; - newOutgoingCallHelper(call, toUrl); + getIceOptions([=](auto&& opts) { + call->initIceMediaTransport(true, std::forward<IceTransportOptions>(opts)); + newOutgoingCallHelper(call, toUrl); + }); return call; } @@ -491,7 +497,6 @@ std::shared_ptr<SIPCall> JamiAccount::createSubCall(const std::shared_ptr<SIPCall>& mainCall) { auto mediaList = MediaAttribute::mediaAttributesToMediaMaps(mainCall->getMediaAttributeList()); - if (not mediaList.empty()) { return Manager::instance().callFactory.newSipCall(shared(), Call::CallType::OUTGOING, @@ -567,6 +572,7 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: auto dummyCall = createSubCall(call); call->addSubCall(*dummyCall); + dummyCall->setIceMedia(call->getIceMedia()); auto sendRequest = [this, wCall, toUri, dummyCall = std::move(dummyCall)](const DeviceId& deviceId, bool eraseDummy) { @@ -596,6 +602,7 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: } }); call->addSubCall(*dev_call); + dev_call->setIceMedia(call->getIceMedia()); { std::lock_guard<std::mutex> lk(pendingCallsMutex_); pendingCalls_[deviceId].emplace_back(dev_call); @@ -634,6 +641,8 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: dev_call->setTransport(transport); call->addSubCall(*dev_call); + dev_call->setIceMedia(call->getIceMedia()); + // Set the call in PROGRESSING State because the ICE session // is already ready. Note that this line should be after // addSubcall() to change the state of the main call @@ -654,9 +663,9 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: } }); - auto remoted_address = ice->getRemoteAddress(ICE_COMP_ID_SIP_TRANSPORT); + auto remote_address = ice->getRemoteAddress(ICE_COMP_ID_SIP_TRANSPORT); try { - onConnectedOutgoingCall(dev_call, toUri, remoted_address); + onConnectedOutgoingCall(dev_call, toUri, remote_address); } catch (const VoipLinkException&) { // In this case, the main scenario is that SIPStartCall failed because // the ICE is dead and the TLS session didn't send any packet on that dead @@ -708,70 +717,55 @@ JamiAccount::onConnectedOutgoingCall(const std::shared_ptr<SIPCall>& call, return; JAMI_DBG("[call:%s] outgoing call connected to %s", call->getCallId().c_str(), to_id.c_str()); - getIceOptions([=](auto&& opts) { - opts.onInitDone = [w = weak(), target = std::move(target), call](bool ok) { - if (!ok) { - JAMI_ERR("ICE medias are not initialized"); - return; - } - auto shared = w.lock(); - if (!shared or !call) - return; - - const auto localAddress = ip_utils::getInterfaceAddr(shared->getLocalInterface(), - target.getFamily()); + const auto localAddress = ip_utils::getInterfaceAddr(getLocalInterface(), target.getFamily()); - IpAddr addrSdp = shared->getPublishedSameasLocal() - ? localAddress - : shared->getPublishedIpAddress(target.getFamily()); + IpAddr addrSdp = getPublishedSameasLocal() ? localAddress + : getPublishedIpAddress(target.getFamily()); - // fallback on local address - if (not addrSdp) - addrSdp = localAddress; + // fallback on local address + if (not addrSdp) + addrSdp = localAddress; - // Initialize the session using ULAW as default codec in case of early media - // The session should be ready to receive media once the first INVITE is sent, before - // the session initialization is completed - if (!getSystemCodecContainer()->searchCodecByName("PCMA", jami::MEDIA_AUDIO)) - JAMI_WARN("Could not instantiate codec for early media"); + // Initialize the session using ULAW as default codec in case of early media + // The session should be ready to receive media once the first INVITE is sent, before + // the session initialization is completed + if (!getSystemCodecContainer()->searchCodecByName("PCMA", jami::MEDIA_AUDIO)) + JAMI_WARN("Could not instantiate codec for early media"); - // Building the local SDP offer - auto& sdp = call->getSDP(); + // Building the local SDP offer + auto& sdp = call->getSDP(); - sdp.setPublishedIP(addrSdp); + sdp.setPublishedIP(addrSdp); - auto mediaAttrList = call->getMediaAttributeList(); + auto mediaAttrList = call->getMediaAttributeList(); - if (mediaAttrList.empty()) { - JAMI_ERR("Call [%s] has no media. Abort!", call->getCallId().c_str()); - return; - } + if (mediaAttrList.empty()) { + JAMI_ERR("Call [%s] has no media. Abort!", call->getCallId().c_str()); + return; + } - if (not sdp.createOffer(mediaAttrList)) { - JAMI_ERR("Could not send outgoing INVITE request for new call"); - return; - } + if (not sdp.createOffer(mediaAttrList)) { + JAMI_ERR("Could not send outgoing INVITE request for new call"); + return; + } - // Note: pj_ice_strans_create can call onComplete in the same thread - // This means that iceMutex_ in IceTransport can be locked when onInitDone is called - // So, we need to run the call creation in the main thread - // Also, we do not directly call SIPStartCall before receiving onInitDone, because - // there is an inside waitForInitialization that can block the thread. - // Note: avoid runMainThread as SIPStartCall use transportMutex - dht::ThreadPool::io().run( - [w = std::move(w), target = std::move(target), call = std::move(call)] { - auto shared = w.lock(); - if (!shared) - return; + call->setIPToIP(true); + call->setPeerNumber(to_id); + + // Note: pj_ice_strans_create can call onComplete in the same thread + // This means that iceMutex_ in IceTransport can be locked when onInitDone is called + // So, we need to run the call creation in the main thread + // Also, we do not directly call SIPStartCall before receiving onInitDone, because + // there is an inside waitForInitialization that can block the thread. + // Note: avoid runMainThread as SIPStartCall use transportMutex + dht::ThreadPool::io().run([w = weak(), call = std::move(call), target] { + auto account = w.lock(); + if (not account) + return; - if (not shared->SIPStartCall(*call, target)) { - JAMI_ERR("Could not send outgoing INVITE request for new call"); - } - }); - }; - call->setIPToIP(true); - call->setPeerNumber(to_id); - call->initIceMediaTransport(true, std::move(opts)); + if (not account->SIPStartCall(*call, target)) { + JAMI_ERR("Could not send outgoing INVITE request for new call"); + } }); } @@ -780,7 +774,7 @@ JamiAccount::SIPStartCall(SIPCall& call, const IpAddr& target) { JAMI_DBG("Start SIP call [%s]", call.getCallId().c_str()); - if (call.isIceEnabled()) + if (call.getIceMedia()) call.addLocalIceAttributes(); std::string toUri(getToUri(call.getPeerNumber() + "@" diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index d036d89ea101d910ac8079768b170c2f5a6c99e2..8419220002148a0e5b1cd72f3b7ab96ac4ce4174 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -2998,12 +2998,6 @@ SIPCall::merge(Call& call) pj_strcpy(&contactHeader_, &subcall.contactHeader_); localAudioPort_ = subcall.localAudioPort_; localVideoPort_ = subcall.localVideoPort_; - { - std::lock_guard<std::mutex> lk(transportMtx_); - resetTransport(std::move(mediaTransport_)); - mediaTransport_ = std::move(subcall.mediaTransport_); - } - peerUserAgent_ = subcall.peerUserAgent_; peerSupportMultiStream_ = subcall.peerSupportMultiStream_; @@ -3034,6 +3028,17 @@ SIPCall::remoteHasValidIceAttributes() return true; } +void SIPCall::setIceMedia(std::shared_ptr<IceTransport> ice) +{ + JAMI_DBG("[call:%s] Setting ICE session [%p]", getCallId().c_str(), ice.get()); + + std::lock_guard<std::mutex> lk(transportMtx_); + if (not isSubcall()) { + JAMI_ERR("[call:%s] The call is expected to be a sub-call", getCallId().c_str()); + } + mediaTransport_ = std::move(ice); +} + void SIPCall::setupIceResponse() { @@ -3056,12 +3061,13 @@ SIPCall::setupIceResponse() // Try to use the discovered public address. If not available, // fallback on local address. opt.accountPublicAddr = account->getPublishedIpAddress(); - if (opt.accountPublicAddr) { + if (opt.accountLocalAddr) { opt.accountLocalAddr = ip_utils::getInterfaceAddr(account->getLocalInterface(), opt.accountPublicAddr.getFamily()); } else { - opt.accountLocalAddr = ip_utils::getInterfaceAddr(account->getLocalInterface(), - pj_AF_INET()); + // Just set the local address for both, most likely the account is not + // registered. + opt.accountLocalAddr = ip_utils::getInterfaceAddr(account->getLocalInterface(), AF_INET); opt.accountPublicAddr = opt.accountLocalAddr; } diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index 6cb5c817bb29627c54859e9b7b5e343f06523c7f..59647726ce342a5023868ff18b7fa378dcceb91d 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -236,6 +236,17 @@ public: bool remoteHasValidIceAttributes(); void addLocalIceAttributes(); + std::shared_ptr<IceTransport> getIceMedia() const + { + std::lock_guard<std::mutex> lk(transportMtx_); + return mediaTransport_; + }; + + /** + * Set ICE instance. Must be called only for sub-calls + */ + void setIceMedia(std::shared_ptr<IceTransport> ice); + /** * Setup ICE locally to answer to an ICE offer. The ICE session has * the controlled role (slave)