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;