From 971b9197714b2ed6e4033e5ea62f925296927e17 Mon Sep 17 00:00:00 2001 From: Mohamed Chibani <mohamed.chibani@savoirfairelinux.com> Date: Wed, 17 Jun 2020 12:32:11 -0400 Subject: [PATCH] ice-turn: Fixes the issue of audio loss after 5mn. Send outgoing packets to the default remote address (the address present in the 'c=' or 'a=rtcp' lines in case of RTP connections) instead of the ICE nominated address. Gitlab: #223 Change-Id: I4b17ee55ebd92292f994baf7a972514d95ae728b --- src/ice_socket.h | 1 + src/ice_transport.cpp | 57 ++++++++++++++++++++++++++- src/ice_transport.h | 2 + src/media/audio/audio_rtp_session.cpp | 7 +++- src/media/media_codec.h | 3 ++ src/media/video/video_rtp_session.cpp | 6 ++- src/sip/sdp.cpp | 12 ++++++ 7 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/ice_socket.h b/src/ice_socket.h index cd46a1a8c6..39aa813ef0 100644 --- a/src/ice_socket.h +++ b/src/ice_socket.h @@ -49,6 +49,7 @@ class IceSocket ssize_t waitForData(std::chrono::milliseconds timeout); void setOnRecv(IceRecvCb cb); uint16_t getTransportOverhead(); + void setDefaultRemoteAddress(const IpAddr& addr); }; /// ICE transport as a GenericSocket. diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp index a8b165e06d..74ea713228 100644 --- a/src/ice_transport.cpp +++ b/src/ice_transport.cpp @@ -174,6 +174,9 @@ public: */ void selectUPnPIceCandidates(); + void setDefaultRemoteAddress(int comp_id, const IpAddr& addr); + const IpAddr& getDefaultRemoteAddress(int comp_id) const; + std::unique_ptr<upnp::Controller> upnp_; std::mutex upnpMutex_; @@ -189,6 +192,9 @@ public: std::condition_variable waitDataCv_ = {}; onShutdownCb scb; + + // Default remote adresses + std::vector<IpAddr> iceDefaultRemoteAddr_; }; //============================================================================== @@ -284,6 +290,7 @@ IceTransport::Impl::Impl(const char* name, int component_count, bool master, , compIO_(component_count) , initiatorSession_(master) , thread_() + , iceDefaultRemoteAddr_(component_count) { sip_utils::register_thread(); if (options.upnpEnable) @@ -396,6 +403,9 @@ IceTransport::Impl::Impl(const char* name, int component_count, bool master, } } }); + + // Init to invalid adresses + iceDefaultRemoteAddr_.reserve(component_count); } IceTransport::Impl::~Impl() @@ -825,6 +835,25 @@ IceTransport::Impl::selectUPnPIceCandidates() } } +void +IceTransport::Impl::setDefaultRemoteAddress(int comp_id, const IpAddr& addr) +{ + // Component ID must be valid. + assert(comp_id < component_count_); + + iceDefaultRemoteAddr_[comp_id] = addr; + // The port does not matter. Set it 0 to avoid confusion. + iceDefaultRemoteAddr_[comp_id].setPort(0); +} + +const IpAddr& +IceTransport::Impl::getDefaultRemoteAddress(int comp_id) const +{ + // Component ID must be valid. + assert(comp_id < component_count_); + + return iceDefaultRemoteAddr_[comp_id]; +} void IceTransport::Impl::onReceiveData(unsigned comp_id, void *pkt, pj_size_t size) @@ -1031,6 +1060,16 @@ IceTransport::getLocalAddress(unsigned comp_id) const IpAddr IceTransport::getRemoteAddress(unsigned comp_id) const { + + // Return the default remote address if set. + // Note that the default remote addresses are the addresses + // set in the 'c=' and 'a=rtcp' lines of the received SDP. + // See pj_ice_strans_sendto2() for more details. + + if (pimpl_->getDefaultRemoteAddress(comp_id)) { + return pimpl_->getDefaultRemoteAddress(comp_id); + } + return pimpl_->getRemoteAddress(comp_id); } @@ -1047,7 +1086,6 @@ IceTransport::getLocalCandidates(unsigned comp_id) const pj_ice_sess_cand cand[PJ_ARRAY_SIZE(pimpl_->cand_)]; unsigned cand_cnt = PJ_ARRAY_SIZE(cand); - { std::lock_guard<std::mutex> lk {pimpl_->iceMutex_}; if (!pimpl_->icest_) return res; @@ -1305,6 +1343,7 @@ IceTransport::send(int comp_id, const unsigned char* buf, size_t len) { sip_utils::register_thread(); auto remote = getRemoteAddress(comp_id); + if (!remote) { JAMI_ERR("[ice:%p] can't find remote address for component %d", this, comp_id); errno = EINVAL; @@ -1440,6 +1479,12 @@ IceTransport::parse_SDP(const std::string& sdp_msg, const IceTransport& ice) return res; } +void +IceTransport::setDefaultRemoteAddress(int comp_id, const IpAddr& addr) +{ + pimpl_->setDefaultRemoteAddress(comp_id, addr); +} + //============================================================================== IceTransportFactory::IceTransportFactory() @@ -1607,8 +1652,16 @@ IceSocket::setOnRecv(IceRecvCb cb) } uint16_t -IceSocket::getTransportOverhead(){ +IceSocket::getTransportOverhead() +{ return (ice_transport_->getRemoteAddress(compId_).getFamily() == AF_INET) ? IPV4_HEADER_SIZE : IPV6_HEADER_SIZE; } +void +IceSocket::setDefaultRemoteAddress(const IpAddr& addr) +{ + if (ice_transport_) + ice_transport_->setDefaultRemoteAddress(compId_, addr); +} + } // namespace jami diff --git a/src/ice_transport.h b/src/ice_transport.h index 7ac2f2a40f..3b9ce36453 100644 --- a/src/ice_transport.h +++ b/src/ice_transport.h @@ -229,6 +229,8 @@ public: static ICESDP parse_SDP(const std::string& sdp_msg, const IceTransport& ice); + void setDefaultRemoteAddress(int comp_id, const IpAddr& addr); + private: class Impl; std::unique_ptr<Impl> pimpl_; diff --git a/src/media/audio/audio_rtp_session.cpp b/src/media/audio/audio_rtp_session.cpp index c53a717588..f6325c46a7 100644 --- a/src/media/audio/audio_rtp_session.cpp +++ b/src/media/audio/audio_rtp_session.cpp @@ -149,8 +149,13 @@ AudioRtpSession::start(std::unique_ptr<IceSocket> rtp_sock, std::unique_ptr<IceS } try { - if (rtp_sock and rtcp_sock) + if (rtp_sock and rtcp_sock) { + + rtp_sock->setDefaultRemoteAddress(send_.addr); + rtcp_sock->setDefaultRemoteAddress(send_.rtcp_addr); + socketPair_.reset(new SocketPair(std::move(rtp_sock), std::move(rtcp_sock))); + } else socketPair_.reset(new SocketPair(getRemoteRtpUri().c_str(), receive_.addr.getPort())); diff --git a/src/media/media_codec.h b/src/media/media_codec.h index 6068ef3377..38034abf0f 100644 --- a/src/media/media_codec.h +++ b/src/media/media_codec.h @@ -272,6 +272,9 @@ struct MediaDescription { /** Endpoint socket address */ IpAddr addr {}; + /** RTCP socket address */ + IpAddr rtcp_addr {}; + /** RTP */ std::shared_ptr<AccountCodecInfo> codec {}; unsigned payload_type {}; diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index f242d9f093..2d50cb0791 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -208,8 +208,12 @@ void VideoRtpSession::start(std::unique_ptr<IceSocket> rtp_sock, } try { - if (rtp_sock and rtcp_sock) + if (rtp_sock and rtcp_sock) { + rtp_sock->setDefaultRemoteAddress(send_.addr); + rtcp_sock->setDefaultRemoteAddress(send_.rtcp_addr); + socketPair_.reset(new SocketPair(std::move(rtp_sock), std::move(rtcp_sock))); + } else socketPair_.reset(new SocketPair(getRemoteRtpUri().c_str(), receive_.addr.getPort())); diff --git a/src/sip/sdp.cpp b/src/sip/sdp.cpp index acfa2bac82..b57a5efbe3 100644 --- a/src/sip/sdp.cpp +++ b/src/sip/sdp.cpp @@ -597,6 +597,18 @@ Sdp::getMediaSlots(const pjmedia_sdp_session* session, bool remote) const descr.addr = std::string(conn->addr.ptr, conn->addr.slen); descr.addr.setPort(media->desc.port); + // Get the "rtcp" address from the SDP if present. Otherwise, + // infere it from endpoint (RTP) address. + auto attr = pjmedia_sdp_attr_find2(media->attr_count, media->attr, "rtcp", NULL); + if (attr) { + pjmedia_sdp_rtcp_attr rtcp; + auto status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp); + if (status == PJ_SUCCESS && rtcp.addr.slen) { + descr.rtcp_addr = std::string(rtcp.addr.ptr, rtcp.addr.slen); + descr.rtcp_addr.setPort(rtcp.port); + } + } + descr.holding = pjmedia_sdp_attr_find2(media->attr_count, media->attr, "sendonly", nullptr) || pjmedia_sdp_attr_find2(media->attr_count, media->attr, "inactive", nullptr); -- GitLab