From 0a96e391cc0aad8aa4d7fcad5eed2dbb60e88ac1 Mon Sep 17 00:00:00 2001 From: Pierre Lespagnol <pierre.lespagnol@savoirfairelinux.com> Date: Thu, 22 Aug 2019 16:34:59 -0400 Subject: [PATCH] video_rtp_session: send key frame request when we missed a video RTP packet Limit key frame request to one per second Change-Id: Id32c710ac44c017bc222dffb21f79b6e61af2534 --- src/media/socket_pair.cpp | 9 ++++++ src/media/socket_pair.h | 6 +++- src/media/video/video_rtp_session.cpp | 5 ++- src/sip/sipcall.cpp | 45 +++++++++++++++------------ src/sip/sipcall.h | 5 +++ 5 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/media/socket_pair.cpp b/src/media/socket_pair.cpp index 04234e36e7..3f6cb1555c 100644 --- a/src/media/socket_pair.cpp +++ b/src/media/socket_pair.cpp @@ -457,6 +457,9 @@ SocketPair::readCallback(uint8_t* buf, int buf_size) // SRTP decrypt if (not fromRTCP and srtpContext_ and srtpContext_->srtp_in.aes) { auto err = ff_srtp_decrypt(&srtpContext_->srtp_in, buf, &len); + if(packetLossCallback_ and (buf[2] << 8 | buf[3]) != lastSeqNum_+1) + packetLossCallback_(); + lastSeqNum_ = buf[2] << 8 | buf[3]; if (err < 0) JAMI_WARN("decrypt error %d", err); } @@ -581,4 +584,10 @@ SocketPair::getLastLatency() return -1; } +void +SocketPair::setPacketLossCallback(std::function<void(void)> cb) +{ + packetLossCallback_ = std::move(cb); +} + } // namespace jami diff --git a/src/media/socket_pair.h b/src/media/socket_pair.h index e620202e9f..593996cd97 100644 --- a/src/media/socket_pair.h +++ b/src/media/socket_pair.h @@ -45,7 +45,7 @@ using socklen_t = int; #include <list> #include <vector> #include <condition_variable> - +#include <functional> namespace jami { @@ -136,6 +136,8 @@ class SocketPair { bool waitForRTCP(std::chrono::seconds interval); double getLastLatency(); + void setPacketLossCallback(std::function<void (void)> cb); + private: NON_COPYABLE(SocketPair); @@ -163,6 +165,7 @@ class SocketPair { std::atomic_bool interrupted_ {false}; std::atomic_bool noWrite_ {false}; std::unique_ptr<SRTPProtoContext> srtpContext_; + std::function<void(void)> packetLossCallback_; std::list<rtcpRRHeader> listRtcpHeader_; std::mutex rtcpInfo_mutex_; @@ -176,6 +179,7 @@ class SocketPair { std::list<double> histoLatency_; std::chrono::steady_clock::time_point lastRR_time; + uint16_t lastSeqNum_ {0}; }; diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 8ae0146f6a..2a28e1b52f 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -75,7 +75,10 @@ VideoRtpSession::updateMedia(const MediaDescription& send, const MediaDescriptio void VideoRtpSession::setRequestKeyFrameCallback(std::function<void(void)> cb) { - requestKeyFrameCallback_ = std::move(cb); + if(socketPair_) + socketPair_->setPacketLossCallback(std::move(cb)); + else + JAMI_ERR("No socket pair, keyframe request callback not possible"); } void VideoRtpSession::startSender() diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index f9ac13590e..71e5dccc19 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -69,6 +69,7 @@ getVideoSettings() static constexpr std::chrono::seconds DEFAULT_ICE_INIT_TIMEOUT {35}; // seconds static constexpr std::chrono::seconds DEFAULT_ICE_NEGO_TIMEOUT {60}; // seconds +static constexpr std::chrono::milliseconds MS_BETWEEN_2_KEYFRAME_REQUEST {1000}; // SDP media Ids static constexpr int SDP_AUDIO_MEDIA_ID {0}; @@ -271,18 +272,22 @@ SIPCall::sendSIPInfo(const char *const body, const char *const subtype) void SIPCall::requestKeyframe() { - constexpr const char * const BODY = - "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" - "<media_control><vc_primitive><to_encoder>" - "<picture_fast_update/>" - "</to_encoder></vc_primitive></media_control>"; + auto now = clock::now(); + if ((now - lastKeyFrameReq_) < MS_BETWEEN_2_KEYFRAME_REQUEST and lastKeyFrameReq_ != time_point::min()) + return; + constexpr const char * const BODY = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "<media_control><vc_primitive><to_encoder>" + "<picture_fast_update/>" + "</to_encoder></vc_primitive></media_control>"; JAMI_DBG("Sending video keyframe request via SIP INFO"); try { sendSIPInfo(BODY, "media_control+xml"); } catch (const std::exception& e) { JAMI_ERR("Error sending video keyframe request: %s", e.what()); } + lastKeyFrameReq_ = now; } void @@ -907,21 +912,6 @@ SIPCall::startAllMedia() bool peer_holding {true}; int slotN = -1; -#ifdef ENABLE_VIDEO - videortp_->setRequestKeyFrameCallback([wthis = weak()] { - runOnMainThread([wthis] { - if (auto this_ = wthis.lock()) - this_->requestKeyframe(); - }); - }); - videortp_->setChangeOrientationCallback([wthis = weak()] (int angle) { - runOnMainThread([wthis, angle] { - if (auto this_ = wthis.lock()) - this_->setVideoOrientation(angle); - }); - }); -#endif - for (const auto& slot : slots) { ++slotN; const auto& local = slot.first; @@ -1001,6 +991,21 @@ SIPCall::startAllMedia() } } +#ifdef ENABLE_VIDEO + videortp_->setRequestKeyFrameCallback([wthis = weak()] { + runOnMainThread([wthis] { + if (auto this_ = wthis.lock()) + this_->requestKeyframe(); + }); + }); + videortp_->setChangeOrientationCallback([wthis = weak()] (int angle) { + runOnMainThread([wthis, angle] { + if (auto this_ = wthis.lock()) + this_->setVideoOrientation(angle); + }); + }); +#endif + if (not isSubcall() and peerHolding_ != peer_holding) { peerHolding_ = peer_holding; emitSignal<DRing::CallSignal::PeerHold>(getCallId(), peerHolding_); diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index ab44cab6d8..44a4ef82c0 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -246,6 +246,9 @@ public: // NOT SIP RELATED (good candidates to be moved elsewhere) void rtpSetupSuccess(MediaType type); private: + using clock = std::chrono::steady_clock; + using time_point = clock::time_point; + NON_COPYABLE(SIPCall); void setCallMediaLocal(); @@ -338,6 +341,8 @@ private: bool readyToRecord_ {false}; bool pendingRecord_ {false}; + + time_point lastKeyFrameReq_ {time_point::min()}; }; // Helpers -- GitLab