diff --git a/src/media/media_recorder.cpp b/src/media/media_recorder.cpp
index 2fcd94d94bbe5e6b56336dfcdab5396298b36ff2..82dc9e55714aac8183d3b8b52b741782c0b5a186 100644
--- a/src/media/media_recorder.cpp
+++ b/src/media/media_recorder.cpp
@@ -121,7 +121,8 @@ MediaRecorder::startRecording()
     encoder_.reset(new MediaEncoder);
 
     RING_DBG() << "Start recording '" << getPath() << "'";
-    isRecording_ = true;
+    if (initRecord() >= 0)
+        isRecording_ = true;
     return 0;
 }
 
@@ -141,37 +142,44 @@ MediaRecorder::stopRecording()
 void
 MediaRecorder::update(Observable<std::shared_ptr<AudioFrame>>* ob, const std::shared_ptr<AudioFrame>& a)
 {
-    MediaStream ms;
+    std::string name;
     if (dynamic_cast<AudioReceiveThread*>(ob))
-        ms.name = "a:remote";
+        name = "a:remote";
     else // ob is of type AudioInput*
-        ms.name = "a:local";
-    ms.isVideo = false;
-    ms.update(a->pointer());
-    ms.firstTimestamp = a->pointer()->pts;
-    recordData(a->pointer(), ms);
+        name = "a:local";
+    recordData(a->pointer(), streams_[name]);
 }
 
-void MediaRecorder::attached(Observable<std::shared_ptr<AudioFrame>>* /*ob*/)
+void MediaRecorder::attached(Observable<std::shared_ptr<AudioFrame>>* ob)
 {
-    ++nbExpectedStreams_;
+    MediaStream ms;
+    if (auto receiver = dynamic_cast<AudioReceiveThread*>(ob))
+        ms = receiver->getInfo();
+    else if (auto input = dynamic_cast<AudioInput*>(ob))
+        ms = input->getInfo();
+    if (addStream(ms) >= 0)
+        hasAudio_ = true;
 }
 
 void MediaRecorder::update(Observable<std::shared_ptr<VideoFrame>>* ob, const std::shared_ptr<VideoFrame>& v)
 {
-    MediaStream ms;
-    if (auto receiver = dynamic_cast<video::VideoReceiveThread*>(ob)) {
-        ms = receiver->getInfo();
-    } else if (auto input = dynamic_cast<video::VideoInput*>(ob)) {
-        ms = input->getInfo();
-    }
-    ms.firstTimestamp = v->pointer()->pts;
-    recordData(v->pointer(), ms);
+    std::string name;
+    if (dynamic_cast<video::VideoReceiveThread*>(ob))
+        name = "v:remote";
+    else // ob is of type VideoInput*
+        name = "v:local";
+    recordData(v->pointer(), streams_[name]);
 }
 
-void MediaRecorder::attached(Observable<std::shared_ptr<VideoFrame>>* /*ob*/)
+void MediaRecorder::attached(Observable<std::shared_ptr<VideoFrame>>* ob)
 {
-    ++nbExpectedStreams_;
+    MediaStream ms;
+    if (auto receiver = dynamic_cast<video::VideoReceiveThread*>(ob))
+        ms = receiver->getInfo();
+    else if (auto input = dynamic_cast<video::VideoInput*>(ob))
+        ms = input->getInfo();
+    if (addStream(ms) >= 0)
+        hasVideo_ = true;
 }
 
 int
@@ -183,24 +191,12 @@ MediaRecorder::addStream(const MediaStream& ms)
     }
 
     if (streams_.insert(std::make_pair(ms.name, ms)).second) {
-        RING_DBG() << "Recorder input #" << (nbReceivedAudioStreams_ + nbReceivedVideoStreams_) << ": " << ms;
+        RING_DBG() << "Recorder input #" << streams_.size() << ": " << ms;
+        return 0;
     } else {
         RING_ERR() << "Could not add stream '" << ms.name << "' to record";
         return -1;
     }
-
-    std::lock_guard<std::mutex> lk(mutex_);
-
-    if (ms.isVideo)
-        ++nbReceivedVideoStreams_;
-    else
-        ++nbReceivedAudioStreams_;
-
-    // wait until all streams are ready before writing to the file
-    if (nbExpectedStreams_ != nbReceivedAudioStreams_ + nbReceivedVideoStreams_)
-        return 0;
-    else
-        return initRecord();
 }
 
 int
@@ -264,7 +260,7 @@ MediaRecorder::initRecord()
     encoderOptions["description"] = description_;
 
     videoFilter_.reset();
-    if (nbReceivedVideoStreams_ > 0) {
+    if (hasVideo_) {
         const MediaStream& videoStream = setupVideoOutput();
         if (videoStream.format < 0) {
             RING_ERR() << "Could not retrieve video recorder stream properties";
@@ -278,7 +274,7 @@ MediaRecorder::initRecord()
     }
 
     audioFilter_.reset();
-    if (nbReceivedAudioStreams_ > 0) {
+    if (hasAudio_) {
         const MediaStream& audioStream = setupAudioOutput();
         if (audioStream.format < 0) {
             RING_ERR() << "Could not retrieve audio recorder stream properties";
@@ -290,7 +286,7 @@ MediaRecorder::initRecord()
 
     encoder_->openFileOutput(getPath(), encoderOptions);
 
-    if (nbReceivedVideoStreams_ > 0) {
+    if (hasVideo_) {
         auto videoCodec = std::static_pointer_cast<ring::SystemVideoCodecInfo>(
             getSystemCodecContainer()->searchCodecByName("VP8", ring::MEDIA_VIDEO));
         videoIdx_ = encoder_->addStream(*videoCodec.get());
@@ -300,7 +296,7 @@ MediaRecorder::initRecord()
         }
     }
 
-    if (nbReceivedAudioStreams_ > 0) {
+    if (hasAudio_) {
         auto audioCodec = std::static_pointer_cast<ring::SystemAudioCodecInfo>(
             getSystemCodecContainer()->searchCodecByName("opus", ring::MEDIA_AUDIO));
         audioIdx_ = encoder_->addStream(*audioCodec.get());
@@ -311,8 +307,8 @@ MediaRecorder::initRecord()
     }
 
     // ready to start recording if audio stream index and video stream index are valid
-    bool audioIsReady = nbReceivedAudioStreams_ == 0 || (nbReceivedAudioStreams_ > 0 && audioIdx_ >= 0);
-    bool videoIsReady = (audioOnly_ && nbReceivedVideoStreams_ == 0) || (nbReceivedVideoStreams_ > 0 && videoIdx_ >= 0);
+    bool audioIsReady = hasAudio_ && audioIdx_ >= 0;
+    bool videoIsReady = !audioOnly_ && hasVideo_ && videoIdx_ >= 0;
     isReady_ = audioIsReady && videoIsReady;
 
     if (isReady_) {
@@ -330,7 +326,7 @@ MediaRecorder::initRecord()
         RING_DBG() << "Recording initialized";
         return 0;
     } else {
-        RING_ERR() << "Something went wrong when initializing the recorder";
+        RING_ERR() << "Failed to initialize recorder";
         return -1;
     }
 }
@@ -358,8 +354,8 @@ MediaRecorder::setupVideoOutput()
     // vp8 supports only yuv420p
     videoFilter_.reset(new MediaFilter);
     int ret = -1;
-
-    switch (nbReceivedVideoStreams_) {
+    int streams = peer.isValid() + local.isValid();
+    switch (streams) {
     case 1:
     {
         auto inputStream = peer.isValid() ? peer : local;
@@ -444,8 +440,8 @@ MediaRecorder::setupAudioOutput()
     // resample to common audio format, so any player can play the file
     audioFilter_.reset(new MediaFilter);
     int ret = -1;
-
-    switch (nbReceivedAudioStreams_) {
+    int streams = peer.isValid() + local.isValid();
+    switch (streams) {
     case 1:
     {
         auto inputStream = peer.isValid() ? peer : local;
@@ -535,8 +531,6 @@ MediaRecorder::resetToDefaults()
 {
     streams_.clear();
     videoIdx_ = audioIdx_ = -1;
-    nbExpectedStreams_ = 0;
-    nbReceivedVideoStreams_ = nbReceivedAudioStreams_ = 0;
     isRecording_ = false;
     isReady_ = false;
     audioOnly_ = false;
diff --git a/src/media/media_recorder.h b/src/media/media_recorder.h
index b3fbba002b9c3dcbfd813d5958cc088428677755..4c0b0c0d3c71fbabcd68b840fdc4a698accaea8e 100644
--- a/src/media/media_recorder.h
+++ b/src/media/media_recorder.h
@@ -111,9 +111,8 @@ private:
     std::string dir_;
     std::string filename_;
 
-    unsigned nbExpectedStreams_ = 0;
-    unsigned nbReceivedVideoStreams_ = 0;
-    unsigned nbReceivedAudioStreams_ = 0;
+    bool hasAudio_ {false};
+    bool hasVideo_ {false};
     int videoIdx_ = -1;
     int audioIdx_ = -1;
     bool isRecording_ = false;
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index c08533fe805007d800bc01ddd93c816423f2e7d9..7160c5715739bcb8e1cc0f18a64a92636d7727a1 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -1187,8 +1187,8 @@ SIPCall::getDetails() const
 bool
 SIPCall::toggleRecording()
 {
-    const bool startRecording = Call::toggleRecording();
-    if (startRecording) {
+    // add streams to recorder before starting the record
+    if (not Call::isRecording()) {
         std::stringstream ss;
         ss << "Conversation at %TIMESTAMP between "
             << getSIPAccount().getUserUri() << " and " << peerUri_;
@@ -1207,7 +1207,7 @@ SIPCall::toggleRecording()
             videortp_->deinitRecorder(recorder_);
 #endif
     }
-    return startRecording;
+    return Call::toggleRecording();
 }
 
 void