diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp
index 9c3dfa2d894c89e9a1d0523f3135e62b1e61c3c7..b450b6def35c2fd14db053560522477eb4cf26f1 100644
--- a/src/media/media_decoder.cpp
+++ b/src/media/media_decoder.cpp
@@ -295,16 +295,17 @@ MediaDecoder::decode(VideoFrame& result)
             static_cast<AVRounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
 
         if (auto rec = recorder_.lock()) {
+            bool fromPeer = (inputCtx_->iformat->name == std::string("sdp"));
             if (!recordingStarted_) {
                 auto ms = MediaStream("", decoderCtx_, frame->pts);
                 ms.format = frame->format; // might not match avStream_ if accel is used
-                if (rec->addStream(true, true, ms) >= 0)
+                if (rec->addStream(true, fromPeer, ms) >= 0)
                     recordingStarted_ = true;
                 else
                     recorder_ = std::weak_ptr<MediaRecorder>();
             }
             if (recordingStarted_)
-                rec->recordData(frame, true, true);
+                rec->recordData(frame, true, fromPeer);
         }
 
         if (emulateRate_ and packetTimestamp != AV_NOPTS_VALUE) {
diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index 029d566af82862949798dd49f12d2bd02cf9a489..44034e5b89001396589bab16e3e1c7d9a51b7745 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -443,6 +443,18 @@ int MediaEncoder::encode_audio(const AudioBuffer &buffer)
         nb_frames -= frame->nb_samples;
         offset_ptr += frame->nb_samples * buffer.channels();
 
+        if (auto rec = recorder_.lock()) {
+            if (!recordingStarted_) {
+                auto ms = MediaStream("", encoders_[currentStreamIdx_], frame->pts);
+                if (rec->addStream(false, false, ms) >= 0)
+                    recordingStarted_ = true;
+                else
+                    recorder_ = std::weak_ptr<MediaRecorder>();
+            }
+            if (recordingStarted_)
+                rec->recordData(frame, false, false);
+        }
+
         encode(frame, currentStreamIdx_);
         av_frame_free(&frame);
     }
@@ -460,19 +472,6 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx)
     pkt.data = nullptr; // packet data will be allocated by the encoder
     pkt.size = 0;
 
-    if (auto rec = recorder_.lock()) {
-        bool isVideo = encoderCtx->codec_type == AVMEDIA_TYPE_VIDEO;
-        if (!recordingStarted_) {
-            auto ms = MediaStream("", encoderCtx, frame->pts);
-            if (rec->addStream(isVideo, false, ms) >= 0)
-                recordingStarted_ = true;
-            else
-                recorder_ = std::weak_ptr<MediaRecorder>();
-        }
-        if (recordingStarted_)
-            rec->recordData(frame, isVideo, false);
-    }
-
     ret = avcodec_send_frame(encoderCtx, frame);
     if (ret < 0)
         return -1;
diff --git a/src/media/video/video_input.cpp b/src/media/video/video_input.cpp
index 5853697e5d4e8fffce7e5efa530f8e5d91e2b599..367c1c6984d49b99b98900f7b1f775c410b75be0 100644
--- a/src/media/video/video_input.cpp
+++ b/src/media/video/video_input.cpp
@@ -587,4 +587,11 @@ VideoInput::foundDecOpts(const DeviceParams& params)
     }
 }
 
+void
+VideoInput::startRecorder(std::shared_ptr<MediaRecorder>& rec)
+{
+    if (decoder_)
+        decoder_->startRecorder(rec);
+}
+
 }} // namespace ring::video
diff --git a/src/media/video/video_input.h b/src/media/video/video_input.h
index f6a4c0b44f0033acafa19419bb45072f44f7f8fa..4ddcc81ade7cbeb70896dc20b86f650e18bcdf43 100644
--- a/src/media/video/video_input.h
+++ b/src/media/video/video_input.h
@@ -42,6 +42,7 @@
 
 namespace ring {
 class MediaDecoder;
+class MediaRecorder;
 }
 
 namespace ring { namespace video {
@@ -88,6 +89,8 @@ public:
     void releaseFrame(void *frame);
 #endif
 
+    void startRecorder(std::shared_ptr<MediaRecorder>& rec);
+
 private:
     NON_COPYABLE(VideoInput);
 
diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp
index 6818967188c2f5a988232d9da86de1b11732bf18..50d7f8a2456c68764ff63ea763fde5843f773152 100644
--- a/src/media/video/video_rtp_session.cpp
+++ b/src/media/video/video_rtp_session.cpp
@@ -571,14 +571,12 @@ VideoRtpSession::startRecorder(std::shared_ptr<MediaRecorder>& rec)
     const constexpr int keyframes = 3;
     if (receiveThread_)
         receiveThread_->startRecorder(rec);
-    if (sender_)
-        sender_->startRecorder(rec);
-    for (int i = 0; i < keyframes; ++i) {
+    if (auto vidInput = std::static_pointer_cast<VideoInput>(videoLocal_))
+        vidInput->startRecorder(rec);
+    for (int i = 0; i < keyframes; ++i)
         if (receiveThread_)
             receiveThread_->triggerKeyFrameRequest();
-        if (sender_)
-            sender_->forceKeyFrame();
-    }
+    // TODO trigger keyframes for local video
 }
 
 }} // namespace ring::video
diff --git a/src/media/video/video_sender.cpp b/src/media/video/video_sender.cpp
index ca58aae12926939ebbfd9658acf6116e67d0b3d9..8fb9916e0e68b682bcc65aa8adf90727f99faa55 100644
--- a/src/media/video/video_sender.cpp
+++ b/src/media/video/video_sender.cpp
@@ -106,11 +106,4 @@ VideoSender::useCodec(const ring::AccountVideoCodecInfo* codec) const
     return videoEncoder_->useCodec(codec);
 }
 
-void
-VideoSender::startRecorder(std::shared_ptr<MediaRecorder>& rec)
-{
-    if (videoEncoder_)
-        videoEncoder_->startRecorder(rec);
-}
-
 }} // namespace ring::video
diff --git a/src/media/video/video_sender.h b/src/media/video/video_sender.h
index 875b17fa2ff7318c33fb6d4c945d448596ea052b..322aa618926aa648144a6846f03df951d6553fcf 100644
--- a/src/media/video/video_sender.h
+++ b/src/media/video/video_sender.h
@@ -35,7 +35,6 @@
 namespace ring {
 class SocketPair;
 struct AccountVideoCodecInfo;
-class MediaRecorder;
 }
 
 namespace ring { namespace video {
@@ -63,8 +62,6 @@ public:
 
     bool useCodec(const AccountVideoCodecInfo* codec) const;
 
-    void startRecorder(std::shared_ptr<MediaRecorder>& rec);
-
 private:
     static constexpr int KEYFRAMES_AT_START {4}; // Number of keyframes to enforce at stream startup
     static constexpr unsigned KEY_FRAME_PERIOD {0}; // seconds before forcing a keyframe