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;