diff --git a/src/media/socket_pair.cpp b/src/media/socket_pair.cpp
index 04234e36e77b28e9285075567db0a3fc349bb323..3f6cb1555cf545f1caddcb330f063170a9f6bf52 100644
--- a/src/media/socket_pair.cpp
+++ b/src/media/socket_pair.cpp
@@ -457,6 +457,9 @@ SocketPair::readCallback(uint8_t* buf, int buf_size)
     // SRTP decrypt
     if (not fromRTCP and srtpContext_ and srtpContext_->srtp_in.aes) {
         auto err = ff_srtp_decrypt(&srtpContext_->srtp_in, buf, &len);
+        if(packetLossCallback_ and (buf[2] << 8 | buf[3]) != lastSeqNum_+1)
+            packetLossCallback_();
+        lastSeqNum_ = buf[2] << 8 | buf[3];
         if (err < 0)
             JAMI_WARN("decrypt error %d", err);
     }
@@ -581,4 +584,10 @@ SocketPair::getLastLatency()
         return -1;
 }
 
+void
+SocketPair::setPacketLossCallback(std::function<void(void)> cb)
+{
+    packetLossCallback_ = std::move(cb);
+}
+
 } // namespace jami
diff --git a/src/media/socket_pair.h b/src/media/socket_pair.h
index e620202e9fd6027875d37b870c740d3363d433ad..593996cd97e4fbaef4804cf65923fa24cee56a1e 100644
--- a/src/media/socket_pair.h
+++ b/src/media/socket_pair.h
@@ -45,7 +45,7 @@ using socklen_t = int;
 #include <list>
 #include <vector>
 #include <condition_variable>
-
+#include <functional>
 
 namespace jami {
 
@@ -136,6 +136,8 @@ class SocketPair {
         bool waitForRTCP(std::chrono::seconds interval);
         double getLastLatency();
 
+        void setPacketLossCallback(std::function<void (void)> cb);
+
     private:
         NON_COPYABLE(SocketPair);
 
@@ -163,6 +165,7 @@ class SocketPair {
         std::atomic_bool interrupted_ {false};
         std::atomic_bool noWrite_ {false};
         std::unique_ptr<SRTPProtoContext> srtpContext_;
+        std::function<void(void)> packetLossCallback_;
 
         std::list<rtcpRRHeader> listRtcpHeader_;
         std::mutex rtcpInfo_mutex_;
@@ -176,6 +179,7 @@ class SocketPair {
         std::list<double> histoLatency_;
 
         std::chrono::steady_clock::time_point lastRR_time;
+        uint16_t lastSeqNum_ {0};
 };
 
 
diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp
index 8ae0146f6ac9d13c41ed8417e9b28d55bff61350..2a28e1b52fee3842b54c7848ad8a32c9741ec317 100644
--- a/src/media/video/video_rtp_session.cpp
+++ b/src/media/video/video_rtp_session.cpp
@@ -75,7 +75,10 @@ VideoRtpSession::updateMedia(const MediaDescription& send, const MediaDescriptio
 void
 VideoRtpSession::setRequestKeyFrameCallback(std::function<void(void)> cb)
 {
-    requestKeyFrameCallback_ = std::move(cb);
+    if(socketPair_)
+        socketPair_->setPacketLossCallback(std::move(cb));
+    else
+        JAMI_ERR("No socket pair, keyframe request callback not possible");
 }
 
 void VideoRtpSession::startSender()
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index f9ac13590ee7e1a07d7a1c69bf8a57bf7a4d62e9..71e5dccc19e7b8c1cc61cad4293dab2746a47318 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -69,6 +69,7 @@ getVideoSettings()
 
 static constexpr std::chrono::seconds DEFAULT_ICE_INIT_TIMEOUT {35}; // seconds
 static constexpr std::chrono::seconds DEFAULT_ICE_NEGO_TIMEOUT {60}; // seconds
+static constexpr std::chrono::milliseconds MS_BETWEEN_2_KEYFRAME_REQUEST {1000};
 
 // SDP media Ids
 static constexpr int SDP_AUDIO_MEDIA_ID {0};
@@ -271,18 +272,22 @@ SIPCall::sendSIPInfo(const char *const body, const char *const subtype)
 void
 SIPCall::requestKeyframe()
 {
-    constexpr const char * const BODY =
-        "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
-        "<media_control><vc_primitive><to_encoder>"
-        "<picture_fast_update/>"
-        "</to_encoder></vc_primitive></media_control>";
+    auto now = clock::now();
+    if ((now - lastKeyFrameReq_) < MS_BETWEEN_2_KEYFRAME_REQUEST and lastKeyFrameReq_ != time_point::min())
+        return;
 
+    constexpr const char * const BODY =
+    "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+    "<media_control><vc_primitive><to_encoder>"
+    "<picture_fast_update/>"
+    "</to_encoder></vc_primitive></media_control>";
     JAMI_DBG("Sending video keyframe request via SIP INFO");
     try {
         sendSIPInfo(BODY, "media_control+xml");
     } catch (const std::exception& e) {
         JAMI_ERR("Error sending video keyframe request: %s", e.what());
     }
+    lastKeyFrameReq_ = now;
 }
 
 void
@@ -907,21 +912,6 @@ SIPCall::startAllMedia()
     bool peer_holding {true};
     int slotN = -1;
 
-#ifdef ENABLE_VIDEO
-    videortp_->setRequestKeyFrameCallback([wthis = weak()] {
-        runOnMainThread([wthis] {
-            if (auto this_ = wthis.lock())
-                this_->requestKeyframe();
-        });
-    });
-    videortp_->setChangeOrientationCallback([wthis = weak()] (int angle) {
-        runOnMainThread([wthis, angle] {
-            if (auto this_ = wthis.lock())
-                this_->setVideoOrientation(angle);
-        });
-    });
-#endif
-
     for (const auto& slot : slots) {
         ++slotN;
         const auto& local = slot.first;
@@ -1001,6 +991,21 @@ SIPCall::startAllMedia()
         }
     }
 
+#ifdef ENABLE_VIDEO
+    videortp_->setRequestKeyFrameCallback([wthis = weak()] {
+        runOnMainThread([wthis] {
+            if (auto this_ = wthis.lock())
+                this_->requestKeyframe();
+        });
+    });
+    videortp_->setChangeOrientationCallback([wthis = weak()] (int angle) {
+        runOnMainThread([wthis, angle] {
+            if (auto this_ = wthis.lock())
+                this_->setVideoOrientation(angle);
+        });
+    });
+#endif
+
     if (not isSubcall() and peerHolding_ != peer_holding) {
         peerHolding_ = peer_holding;
         emitSignal<DRing::CallSignal::PeerHold>(getCallId(), peerHolding_);
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index ab44cab6d88170da15d4a05820f6c156c8dc7c17..44a4ef82c05fc3bdbb14533a39cf2717e07be9c2 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -246,6 +246,9 @@ public: // NOT SIP RELATED (good candidates to be moved elsewhere)
     void rtpSetupSuccess(MediaType type);
 
 private:
+    using clock = std::chrono::steady_clock;
+    using time_point = clock::time_point;
+
     NON_COPYABLE(SIPCall);
 
     void setCallMediaLocal();
@@ -338,6 +341,8 @@ private:
 
     bool readyToRecord_ {false};
     bool pendingRecord_ {false};
+
+    time_point lastKeyFrameReq_ {time_point::min()};
 };
 
 // Helpers