From f6c3205d65f9873353b662759249bf685a24cdfe Mon Sep 17 00:00:00 2001 From: Philippe Gorley <gorley.philippe@gmail.com> Date: Mon, 26 Sep 2016 14:52:59 -0400 Subject: [PATCH] video: fallback from hardware to software decoding This patch also implements a way for the Call object to restart the media receiver Change-Id: I1090575f14425d383eb5471a388c4c9e8d888b0e (cherry picked from commit 660bc3404d949947c9e521786381560a970959a3) --- src/call.h | 2 ++ src/media/audio/audio_rtp_session.cpp | 11 ++++++++ src/media/audio/audio_rtp_session.h | 1 + src/media/media_decoder.cpp | 2 +- src/media/media_decoder.h | 3 +- src/media/rtp_session.h | 1 + src/media/video/video_receive_thread.cpp | 15 ++++++++-- src/media/video/video_receive_thread.h | 5 +++- src/media/video/video_rtp_session.cpp | 36 ++++++++++++++++++++++-- src/media/video/video_rtp_session.h | 2 ++ src/sip/sipcall.cpp | 10 +++++++ src/sip/sipcall.h | 2 ++ 12 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/call.h b/src/call.h index 54c264a698..5eb618fcf3 100644 --- a/src/call.h +++ b/src/call.h @@ -331,6 +331,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { virtual void restartMediaSender() = 0; + virtual void restartMediaReceiver() = 0; + protected: /** * Constructor of a call diff --git a/src/media/audio/audio_rtp_session.cpp b/src/media/audio/audio_rtp_session.cpp index 7474886ae5..f0bf91a610 100644 --- a/src/media/audio/audio_rtp_session.cpp +++ b/src/media/audio/audio_rtp_session.cpp @@ -422,6 +422,17 @@ AudioRtpSession::startReceiver() receiveThread_->startLoop(); } +void +AudioRtpSession::restartReceiver() +{ + std::lock_guard<std::recursive_mutex> lock(mutex_); + // ensure that start has been called before restart + if (not socketPair_) + return; + + startReceiver(); +} + void AudioRtpSession::start(std::unique_ptr<IceSocket> rtp_sock, std::unique_ptr<IceSocket> rtcp_sock) { diff --git a/src/media/audio/audio_rtp_session.h b/src/media/audio/audio_rtp_session.h index 8259d36714..add163b1d2 100644 --- a/src/media/audio/audio_rtp_session.h +++ b/src/media/audio/audio_rtp_session.h @@ -44,6 +44,7 @@ class AudioRtpSession : public RtpSession { void start(std::unique_ptr<IceSocket> rtp_sock = nullptr, std::unique_ptr<IceSocket> rtcp_sock = nullptr) override; void restartSender() override; + void restartReceiver() override; void stop() override; void setMuted(bool isMuted); diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index d939b99a49..959e41aca7 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -340,7 +340,7 @@ MediaDecoder::decode(VideoFrame& result) if (!accel_->hasFailed()) accel_->extractData(decoderCtx_, result); else - return Status::DecodeError; + return Status::RestartRequired; } #endif // RING_ACCEL if (emulateRate_ and frame->pkt_pts != AV_NOPTS_VALUE) { diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h index fa22ab2b2d..6340f3a916 100644 --- a/src/media/media_decoder.h +++ b/src/media/media_decoder.h @@ -64,7 +64,8 @@ class MediaDecoder { FrameFinished, EOFError, ReadError, - DecodeError + DecodeError, + RestartRequired }; MediaDecoder(); diff --git a/src/media/rtp_session.h b/src/media/rtp_session.h index d70c4b00f5..def4987967 100644 --- a/src/media/rtp_session.h +++ b/src/media/rtp_session.h @@ -39,6 +39,7 @@ public: virtual void start(std::unique_ptr<IceSocket> rtp_sock = nullptr, std::unique_ptr<IceSocket> rtcp_sock = nullptr) = 0; virtual void restartSender() = 0; + virtual void restartReceiver() = 0; virtual void stop() = 0; virtual void updateMedia(const MediaDescription& send, diff --git a/src/media/video/video_receive_thread.cpp b/src/media/video/video_receive_thread.cpp index 286f781e2e..e3ab0bd559 100644 --- a/src/media/video/video_receive_thread.cpp +++ b/src/media/video/video_receive_thread.cpp @@ -37,13 +37,15 @@ namespace ring { namespace video { using std::string; VideoReceiveThread::VideoReceiveThread(const std::string& id, - const std::string &sdp) : + const std::string &sdp, + const DeviceParams& args) : VideoGenerator::VideoGenerator() - , args_() + , args_(args) , dstWidth_(0) , dstHeight_(0) , id_(id) , stream_(sdp) + , restartDecoder_(false) , sdpContext_(stream_.str().size(), false, &readFunction, 0, 0, this) , sink_ {Manager::instance().createSinkClient(id)} , requestKeyFrameCallback_(0) @@ -175,6 +177,11 @@ bool VideoReceiveThread::decodeFrame() case MediaDecoder::Status::ReadError: RING_ERR("fatal error, read failed"); loop_.stop(); + break; + + case MediaDecoder::Status::RestartRequired: + restartDecoder_ = true; + break; case MediaDecoder::Status::Success: case MediaDecoder::Status::EOFError: @@ -216,4 +223,8 @@ int VideoReceiveThread::getHeight() const int VideoReceiveThread::getPixelFormat() const { return videoDecoder_->getPixelFormat(); } +bool +VideoReceiveThread::restartDecoder() const +{ return restartDecoder_.load(); } + }} // namespace ring::video diff --git a/src/media/video/video_receive_thread.h b/src/media/video/video_receive_thread.h index a8a3f3ccfc..57d1032de8 100644 --- a/src/media/video/video_receive_thread.h +++ b/src/media/video/video_receive_thread.h @@ -34,6 +34,7 @@ #include <climits> #include <sstream> #include <memory> +#include <atomic> namespace ring { class SocketPair; @@ -46,7 +47,7 @@ class SinkClient; class VideoReceiveThread : public VideoGenerator { public: - VideoReceiveThread(const std::string &id, const std::string &sdp); + VideoReceiveThread(const std::string &id, const std::string &sdp, const DeviceParams& args); ~VideoReceiveThread(); void startLoop(); @@ -59,6 +60,7 @@ public: int getWidth() const; int getHeight() const; int getPixelFormat() const; + bool restartDecoder() const; private: NON_COPYABLE(VideoReceiveThread); @@ -76,6 +78,7 @@ private: MediaIOHandle sdpContext_; std::unique_ptr<MediaIOHandle> demuxContext_; std::shared_ptr<SinkClient> sink_; + std::atomic_bool restartDecoder_; void (*requestKeyFrameCallback_)(const std::string &); void openDecoder(); bool decodeFrame(); diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 40d5f0ab74..077dff5363 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -129,10 +129,13 @@ VideoRtpSession::restartSender() void VideoRtpSession::startReceiver() { if (receive_.enabled and not receive_.holding) { - if (receiveThread_) - RING_WARN("restarting video receiver"); + DeviceParams receiverArgs = {}; + if (receiveThread_) { + RING_WARN("Restarting video receiver"); + receiverArgs.enableAccel = "0"; // most likely cause of this restart + } receiveThread_.reset( - new VideoReceiveThread(callID_, receive_.receiving_sdp) + new VideoReceiveThread(callID_, receive_.receiving_sdp, receiverArgs) ); /* ebail: keyframe requests can lead to timeout if they are not answered. * we decided so to disable them for the moment @@ -147,6 +150,19 @@ void VideoRtpSession::startReceiver() receiveThread_.reset(); } } + +void +VideoRtpSession::restartReceiver() +{ + std::lock_guard<std::recursive_mutex> lock(mutex_); + + // ensure that start has been called before restart + if (not socketPair_) + return; + + startReceiver(); // disable accel +} + void VideoRtpSession::start(std::unique_ptr<IceSocket> rtp_sock, std::unique_ptr<IceSocket> rtcp_sock) { @@ -526,9 +542,23 @@ VideoRtpSession::setupRtcpChecker() return true; } +void +VideoRtpSession::checkReceiver() +{ + if (receiveThread_ && receiveThread_->restartDecoder()) { + const auto& cid = callID_; + runOnMainThread([cid]{ + if (auto call = Manager::instance().callFactory.getCall(cid)) { + call->restartMediaReceiver(); + } + }); + } +} + void VideoRtpSession::processRtcpChecker() { + checkReceiver(); adaptQualityAndBitrate(); rtcpCheckerThread_.wait_for(std::chrono::seconds(RTCP_CHECKING_INTERVAL)); } diff --git a/src/media/video/video_rtp_session.h b/src/media/video/video_rtp_session.h index 4b303651de..407b5da78c 100644 --- a/src/media/video/video_rtp_session.h +++ b/src/media/video/video_rtp_session.h @@ -62,6 +62,7 @@ public: void start(std::unique_ptr<IceSocket> rtp_sock = nullptr, std::unique_ptr<IceSocket> rtcp_sock = nullptr) override; void restartSender() override; + void restartReceiver() override; void stop() override; void forceKeyFrame(); @@ -100,6 +101,7 @@ private: void adaptQualityAndBitrate(); void storeVideoBitrateInfo(); void getVideoBitrateInfo(); + void checkReceiver(); // interval in seconds between RTCP checkings diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index d7b1081873..f234be540b 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -889,6 +889,16 @@ SIPCall::restartMediaSender() #endif } +void +SIPCall::restartMediaReceiver() +{ + RING_DBG("[call:%s] restarting RX media streams", getCallId().c_str()); + avformatrtp_->restartReceiver(); +#ifdef RING_VIDEO + videortp_.restartReceiver(); +#endif +} + void SIPCall::stopAllMedia() { diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index 74f35b1980..2448dba06e 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -203,6 +203,8 @@ class SIPCall : public Call void restartMediaSender() override; + void restartMediaReceiver() override; + bool useVideoCodec(const AccountVideoCodecInfo* codec) const override; virtual std::map<std::string, std::string> getDetails() const override; -- GitLab