diff --git a/src/call.h b/src/call.h index 54c264a698d25a09a3977976d92b29b0bcfeb30b..5eb618fcf38a84b0da3b204875d1dc75025ef04d 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 7474886ae5e03b773fafe8c6ba42c36bb117b8b0..f0bf91a6109328603552e2fc05d230191e5e2306 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 8259d36714163087101860b30dada1b7b2c1f231..add163b1d2a21079c6c3dc6c7747a5166229b29f 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 d939b99a49e961e5f32127a4cd8c820be2924de3..959e41aca745230dda30782da152a5dc6e94dab5 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 fa22ab2b2d4755f8ef5c3766bbdf846ce45243a4..6340f3a916856d34691b1765be7e30ac7f4c7295 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 d70c4b00f501224fa460276eba9490e8ee52fc2e..def4987967c2649542c100a25d7af97e3af084cd 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 286f781e2ef18a0492339948f42f9faf0a414f20..e3ab0bd55928141264642df5c77317e496453b6d 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 a8a3f3ccfc1a29992d3714b57bf322567f01f7fa..57d1032de879e4b0be4317a010b66d3e624a8890 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 40d5f0ab74e01e2a4c557ab1001d5fafb6eba491..077dff5363b47b167e80a4c888adf6674137ae68 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 4b303651de78485e8c66adb7115eaa9de1e4cafa..407b5da78cc340cbe0262a15a72066ac13d1b9c0 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 d7b10818737d9e8166f12dca4274eefb06b58e5b..f234be540b5420d940e2c327e3f8b14e88b3d34a 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 74f35b1980ecc77737ea681ef3a7b883e47335d3..2448dba06e3351aa7e1343adc38943b59de012b7 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;