diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index d9e288f950d3af97f89ff7a2a28d591815f02322..5d66871b290d8df3e8b56d87bd4fa82cca610658 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -285,8 +285,10 @@ MediaEncoder::encode(VideoFrame& input, bool is_keyframe, if (is_keyframe) { frame->pict_type = AV_PICTURE_TYPE_I; + frame->key_frame = 1; } else { frame->pict_type = AV_PICTURE_TYPE_NONE; + frame->key_frame = 0; } AVPacket pkt; diff --git a/src/media/rtp_session.h b/src/media/rtp_session.h index 2a80154ccdc6942be6e1c71069a84d559c56daa2..7f17dc9560627a3e98dbaa943fc28c297ca8c4fa 100644 --- a/src/media/rtp_session.h +++ b/src/media/rtp_session.h @@ -57,7 +57,7 @@ public: protected: std::recursive_mutex mutex_; - std::unique_ptr<SocketPair> socketPair_; + std::shared_ptr<SocketPair> socketPair_; const std::string callID_; MediaDescription send_; diff --git a/src/media/video/video_receive_thread.cpp b/src/media/video/video_receive_thread.cpp index f9397beef142dda2beb95fe766cfb73e4465d483..b40fed421a6b299b41e4696467a5838196a3b9b1 100644 --- a/src/media/video/video_receive_thread.cpp +++ b/src/media/video/video_receive_thread.cpp @@ -36,6 +36,8 @@ namespace ring { namespace video { using std::string; +static constexpr uint32_t RTCP_RR_FRACTION_MASK = 0xFF000000; + VideoReceiveThread::VideoReceiveThread(const std::string& id, const std::string &sdp, const bool isReset, @@ -162,15 +164,27 @@ int VideoReceiveThread::readFunction(void *opaque, uint8_t *buf, int buf_size) return is.gcount(); } -void VideoReceiveThread::addIOContext(SocketPair &socketPair) +void VideoReceiveThread::addIOContext(std::shared_ptr<SocketPair> socketPair) { - demuxContext_.reset(socketPair.createIOContext(mtu_)); + demuxContext_.reset(socketPair->createIOContext(mtu_)); + socketPair_ = socketPair; } bool VideoReceiveThread::decodeFrame() { const auto ret = videoDecoder_->decode(getNewFrame()); + if (requestKeyFrameCallback_) { + auto rtcpPackets = socketPair_->getRtcpInfo(); + if (rtcpPackets.size() != 0) { + // recent packet loss detected, ask for keyframe + if (ntohl(rtcpPackets.back().fraction_lost) & RTCP_RR_FRACTION_MASK) { + RING_DBG("Sending keyframe request"); + requestKeyFrameCallback_(id_); + } + } + } + switch (ret) { case MediaDecoder::Status::FrameFinished: publishFrame(); diff --git a/src/media/video/video_receive_thread.h b/src/media/video/video_receive_thread.h index 5b2253023a53fb494338f7c8dd9a278cbb8a3827..08d84cdaaa07a66af6ebeae9feb1c720917611d4 100644 --- a/src/media/video/video_receive_thread.h +++ b/src/media/video/video_receive_thread.h @@ -51,7 +51,7 @@ public: ~VideoReceiveThread(); void startLoop(); - void addIOContext(SocketPair &socketPair); + void addIOContext(std::shared_ptr<SocketPair> socketPair); void setRequestKeyFrameCallback(void (*)(const std::string &)); void enterConference(); void exitConference(); @@ -81,6 +81,7 @@ private: std::atomic_bool restartDecoder_; bool isReset_; uint16_t mtu_; + std::shared_ptr<SocketPair> socketPair_; void (*requestKeyFrameCallback_)(const std::string &); void openDecoder(); diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index db9cad6ddf586dd01ef62a06ab8c0b4f418961dc..5d35eb901801ae7fad10b911274fc025e58d141a 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -154,12 +154,10 @@ void VideoRtpSession::startReceiver() new VideoReceiveThread(callID_, receive_.receiving_sdp, isReset, mtu_) ); - /* ebail: keyframe requests can lead to timeout if they are not answered. - * we decided so to disable them for the moment + // XXX keyframe requests can timeout if unanswered receiveThread_->setRequestKeyFrameCallback(&SIPVoIPLink::enqueueKeyframeRequest); - */ receiverRestartThread_.start(); - receiveThread_->addIOContext(*socketPair_); + receiveThread_->addIOContext(socketPair_); receiveThread_->startLoop(); } else { RING_DBG("Video receiving disabled"); diff --git a/src/media/video/video_sender.cpp b/src/media/video/video_sender.cpp index c8246c29f4ab941510fc73fcf8eb241dd2982e8a..b0c3bae15739081a9cfcb5faa6a066fb74df016c 100644 --- a/src/media/video/video_sender.cpp +++ b/src/media/video/video_sender.cpp @@ -61,7 +61,7 @@ VideoSender::~VideoSender() void VideoSender::encodeAndSendVideo(VideoFrame& input_frame) { - bool is_keyframe = forceKeyFrame_ > 0 \ + bool is_keyframe = forceKeyFrame_ > 0 or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0); if (is_keyframe) @@ -84,7 +84,7 @@ VideoSender::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/, void VideoSender::forceKeyFrame() { - RING_DBG("keyframe requested"); + RING_DBG("Peer has requested a key frame"); ++forceKeyFrame_; } diff --git a/src/media/video/video_sender.h b/src/media/video/video_sender.h index 42562e6c0bfdbb7733a72b10d9cda93f9a1aba0b..01419a65d1e03030e0347c1ba88d45dcbf92d281 100644 --- a/src/media/video/video_sender.h +++ b/src/media/video/video_sender.h @@ -64,7 +64,7 @@ public: private: static constexpr int KEYFRAMES_AT_START {4}; // Number of keyframes to enforce at stream startup - static constexpr unsigned KEY_FRAME_PERIOD {5}; // seconds before forcing a keyframe + static constexpr unsigned KEY_FRAME_PERIOD {0}; // seconds before forcing a keyframe NON_COPYABLE(VideoSender); @@ -74,6 +74,7 @@ private: std::unique_ptr<MediaIOHandle> muxContext_ = nullptr; std::unique_ptr<MediaEncoder> videoEncoder_ = nullptr; + // XXX forceKeyFrame_ is always at -1, incremented to 0 when a keyframe is requested (still works though) std::atomic<int> forceKeyFrame_ {KEYFRAMES_AT_START}; int keyFrameFreq_ {0}; // Set keyframe rate, 0 to disable auto-keyframe. Computed in constructor int64_t frameNumber_ = 0;