diff --git a/configure.ac b/configure.ac
index 2106d59bebeed2f0bd1d553c0dc737de3a94ae56..3e42a4ecfd68e304c58cf66848374369aea20d07 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Jami - configure.ac
 
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ([2.69])
-AC_INIT([Jami Daemon],[13.2.0],[jami@gnu.org],[jami])
+AC_INIT([Jami Daemon],[13.4.0],[jami@gnu.org],[jami])
 
 dnl Clear the implicit flags that default to '-g -O2', otherwise they
 dnl take precedence over the values we set via the
diff --git a/meson.build b/meson.build
index f9d2c3f59c21c6d7400e1d2de852603f7c27b64a..79b32ad8d4eefd1794e0aa1760913f40cd285643 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
 project('jami-daemon', ['c', 'cpp'],
-        version: '13.2.0',
+        version: '13.4.0',
         license: 'GPL3+',
         default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'],
         meson_version:'>= 0.56'
diff --git a/src/call.h b/src/call.h
index c74ac8ceb9190e807071492a9c9cf000c315be2c..1bd5512ae728179371b62f60eba7afd82d728759 100644
--- a/src/call.h
+++ b/src/call.h
@@ -259,8 +259,11 @@ public:
      * list means the media update request was not accepted, meaning the
      * call continue with the current media. It's up to the implementation
      * to determine wether an answer will be sent to the peer.
+     * @param isRemote      True if the media list is from the remote peer
      */
-    virtual void answerMediaChangeRequest(const std::vector<DRing::MediaMap>& mediaList) = 0;
+    virtual void answerMediaChangeRequest(const std::vector<DRing::MediaMap>& mediaList,
+                                          bool isRemote = false)
+        = 0;
     /**
      * Hang up the call
      * @param reason
diff --git a/src/fileutils.cpp b/src/fileutils.cpp
index d3e2dad6cf67e7fbee31fc382852c8d63f01cac2..324e26b2d2fe6a59969c1e12cfaf3b5442c9a8bc 100644
--- a/src/fileutils.cpp
+++ b/src/fileutils.cpp
@@ -325,7 +325,9 @@ writeTime(const std::string& path)
 #endif
 }
 
-bool createSymlink(const std::string& linkFile, const std::string& target) {
+bool
+createSymlink(const std::string& linkFile, const std::string& target)
+{
 #if !USE_STD_FILESYSTEM
     if (symlink(target.c_str(), linkFile.c_str())) {
         JAMI_ERR("Couldn't create soft link: %s", strerror(errno));
@@ -342,7 +344,9 @@ bool createSymlink(const std::string& linkFile, const std::string& target) {
     return true;
 }
 
-bool createHardlink(const std::string& linkFile, const std::string& target) {
+bool
+createHardlink(const std::string& linkFile, const std::string& target)
+{
 #if !USE_STD_FILESYSTEM
     if (link(target.c_str(), linkFile.c_str())) {
         JAMI_ERR("Couldn't create hard link: %s", strerror(errno));
@@ -567,7 +571,6 @@ readArchive(const std::string& path, const std::string& pwd)
         throw e;
     }
 
-
     if (isUnencryptedGzip(data)) {
         if (!pwd.empty())
             JAMI_WARN() << "A gunzip in a gunzip is detected. A webserver may have a bad config";
diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index 43822c9ebb376fee099af79622778bbfe8c843ca..3773bb460dc434fbe850a739be14eb46f2903e8f 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -168,10 +168,12 @@ void
 MediaEncoder::openOutput(const std::string& filename, const std::string& format)
 {
     avformat_free_context(outputCtx_);
-    if (format.empty())
-        avformat_alloc_output_context2(&outputCtx_, nullptr, nullptr, filename.c_str());
-    else
-        avformat_alloc_output_context2(&outputCtx_, nullptr, format.c_str(), filename.c_str());
+    int result = avformat_alloc_output_context2(&outputCtx_,
+                                                nullptr,
+                                                format.empty() ? nullptr : format.c_str(),
+                                                filename.c_str());
+    if (result < 0)
+        JAMI_ERR() << "Cannot open " << filename << ": " << libav_utils::getError(-result);
 }
 
 int
diff --git a/src/sip/sdp.cpp b/src/sip/sdp.cpp
index 268f20f2bd0676fc6869ce2b305328ff3b0b7924..7f900a97329c0c798821ed9acf5dbaa738378eb6 100644
--- a/src/sip/sdp.cpp
+++ b/src/sip/sdp.cpp
@@ -91,7 +91,8 @@ Sdp::findCodecBySpec(std::string_view codec, const unsigned clockrate) const
     // TODO : only manage a list?
     for (const auto& accountCodec : audio_codec_list_) {
         auto audioCodecInfo = std::static_pointer_cast<AccountAudioCodecInfo>(accountCodec);
-        auto& sysCodecInfo = *static_cast<const SystemAudioCodecInfo*>(&audioCodecInfo->systemCodecInfo);
+        auto& sysCodecInfo = *static_cast<const SystemAudioCodecInfo*>(
+            &audioCodecInfo->systemCodecInfo);
         if (sysCodecInfo.name == codec
             and (audioCodecInfo->isPCMG722() ? (clockrate == 8000)
                                              : (sysCodecInfo.audioformat.sample_rate == clockrate)))
@@ -850,7 +851,7 @@ Sdp::getMediaDescriptions(const pjmedia_sdp_session* session, bool remote) const
             descr.rtp_clockrate = rtpmap.clock_rate;
             descr.codec = findCodecBySpec(codec_raw, rtpmap.clock_rate);
             if (not descr.codec) {
-                JAMI_ERR("Could not find codec %.*s", (int)codec_raw.size(), codec_raw.data());
+                JAMI_ERR("Could not find codec %.*s", (int) codec_raw.size(), codec_raw.data());
                 descr.enabled = false;
                 continue;
             }
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index 381cd81a02af622d5f2469c8e1567f338c48b3e6..3d3bea0e220900b426037c04d9b657961e989de1 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -899,7 +899,7 @@ SIPCall::answer(const std::vector<DRing::MediaMap>& mediaList)
 }
 
 void
-SIPCall::answerMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMediaList)
+SIPCall::answerMediaChangeRequest(const std::vector<DRing::MediaMap>& mediaList, bool isRemote)
 {
     std::lock_guard<std::recursive_mutex> lk {callMutex_};
 
@@ -909,20 +909,19 @@ SIPCall::answerMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMedi
         return;
     }
 
-    auto remoteMediaAttrList = MediaAttribute::buildMediaAttributesList(remoteMediaList,
-                                                                        isSrtpEnabled());
+    auto mediaAttrList = MediaAttribute::buildMediaAttributesList(mediaList, isSrtpEnabled());
 
     // TODO. is the right place?
     // Disable video if disabled in the account.
     if (not account->isVideoEnabled()) {
-        for (auto& mediaAttr : remoteMediaAttrList) {
+        for (auto& mediaAttr : mediaAttrList) {
             if (mediaAttr.type_ == MediaType::MEDIA_VIDEO) {
                 mediaAttr.enabled_ = false;
             }
         }
     }
 
-    if (remoteMediaAttrList.empty()) {
+    if (mediaAttrList.empty()) {
         JAMI_WARN("[call:%s] Media list is empty. Ignoring the media change request",
                   getCallId().c_str());
         return;
@@ -944,17 +943,17 @@ SIPCall::answerMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMedi
 
     JAMI_DBG("[call:%s] Answering to media change request with new media", getCallId().c_str());
     idx = 0;
-    for (auto const& newMediaAttr : remoteMediaAttrList) {
+    for (auto const& newMediaAttr : mediaAttrList) {
         JAMI_DBG("[call:%s] Media @%u: %s",
                  getCallId().c_str(),
                  idx++,
                  newMediaAttr.toString(true).c_str());
     }
 
-    if (!updateAllMediaStreams(remoteMediaAttrList, true))
+    if (!updateAllMediaStreams(mediaAttrList, isRemote))
         return;
 
-    if (not sdp_->processIncomingOffer(remoteMediaAttrList)) {
+    if (not sdp_->processIncomingOffer(mediaAttrList)) {
         JAMI_WARN("[call:%s] Could not process the new offer, ignoring", getCallId().c_str());
         return;
     }
@@ -2689,8 +2688,8 @@ SIPCall::handleMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMedi
     // If the offered media does not differ from the current local media, the
     // request is answered using the current local media.
     if (not checkMediaChangeRequest(remoteMediaList)) {
-        answerMediaChangeRequest(
-            MediaAttribute::mediaAttributesToMediaMaps(getMediaAttributeList()));
+        answerMediaChangeRequest(MediaAttribute::mediaAttributesToMediaMaps(getMediaAttributeList()),
+                                 true);
         return;
     }
 
@@ -2714,7 +2713,7 @@ SIPCall::handleMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMedi
                 newMediaList.emplace_back(remoteMediaList[idx]);
             }
         }
-        answerMediaChangeRequest(newMediaList);
+        answerMediaChangeRequest(newMediaList, true);
         return;
     }
 
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index 6ebbfbf24bf4f5eb0fc3c2a263e69b6a11a721c4..ad164eef36c6bd08c714fc582ac2dccc1dc9e723 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -122,7 +122,8 @@ public:
     void answer(const std::vector<DRing::MediaMap>& mediaList) override;
     bool checkMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMediaList) override;
     void handleMediaChangeRequest(const std::vector<DRing::MediaMap>& remoteMediaList) override;
-    void answerMediaChangeRequest(const std::vector<DRing::MediaMap>& mediaList) override;
+    void answerMediaChangeRequest(const std::vector<DRing::MediaMap>& mediaList,
+                                  bool isRemote = false) override;
     void hangup(int reason) override;
     void refuse() override;
     void transfer(const std::string& to) override;
diff --git a/test/unitTest/call/conference.cpp b/test/unitTest/call/conference.cpp
index 1672abc41bb8603c210114afe01195f29b97d9e1..a8fad525f3f94d442ad1bb46d5185965953837a5 100644
--- a/test/unitTest/call/conference.cpp
+++ b/test/unitTest/call/conference.cpp
@@ -873,7 +873,7 @@ ConferenceTest::testParticipantAddRmSecondVideo()
     // Bob removes his second video
     pInfos_.clear();
     mediaList.pop_back();
-    DRing::requestMediaChange(bobId, confId, mediaList);
+    DRing::requestMediaChange(bobId, bobCall.callId, mediaList);
 
     // Check that bob has ont video attached to the conference
     CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return bobVideos() == 1; }));
diff --git a/test/unitTest/call/recorder.cpp b/test/unitTest/call/recorder.cpp
index 1f259bc77327d411361e8fd8a4896d73965b85c8..6ec837d2b9d2e537fe5ea2c8af9c8529bfdec934 100644
--- a/test/unitTest/call/recorder.cpp
+++ b/test/unitTest/call/recorder.cpp
@@ -75,6 +75,8 @@ public:
 
     std::string aliceId;
     std::string bobId;
+    std::string recordDir;
+    std::string recordedFile;
     CallData bobCall {};
 
     std::mutex mtx;
@@ -101,19 +103,24 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(RecorderTest, RecorderTest::name());
 void
 RecorderTest::setUp()
 {
+    // Generate a temporary directory with a file inside
+    recordDir = "records";
+    fileutils::recursive_mkdir(recordDir.c_str());
+    CPPUNIT_ASSERT(fileutils::isDirectory(recordDir));
+
     auto actors = load_actors_and_wait_for_announcement("actors/alice-bob.yml");
     aliceId = actors["alice"];
     bobId = actors["bob"];
     bobCall.reset();
 
-    fileutils::recursive_mkdir("records");
-    DRing::setRecordPath("records");
+    DRing::setRecordPath(recordDir);
 }
 
 void
 RecorderTest::tearDown()
 {
-    fileutils::removeAll("records");
+    DRing::setIsAlwaysRecording(false);
+    fileutils::removeAll(recordDir);
 
     wait_for_removal_of({aliceId, bobId});
 }
@@ -159,7 +166,11 @@ RecorderTest::registerSignalHandlers()
                 bobCall.mediaStatus = event;
             cv.notify_one();
         }));
-
+    confHandlers.insert(DRing::exportable_callback<DRing::CallSignal::RecordPlaybackStopped>(
+        [&](const std::string& path) {
+            recordedFile = path;
+            cv.notify_one();
+        }));
     DRing::registerSignalHandlers(confHandlers);
 }
 
@@ -183,18 +194,16 @@ RecorderTest::testRecordCall()
 
     // Start recorder
     CPPUNIT_ASSERT(!DRing::getIsRecording(aliceId, callId));
-    auto files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 0);
     DRing::toggleRecording(aliceId, callId);
 
     // Stop recorder after a few seconds
     std::this_thread::sleep_for(5s);
     CPPUNIT_ASSERT(DRing::getIsRecording(aliceId, callId));
+    recordedFile.clear();
     DRing::toggleRecording(aliceId, callId);
     CPPUNIT_ASSERT(!DRing::getIsRecording(aliceId, callId));
 
-    files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 1);
+    CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !recordedFile.empty(); }));
 
     Manager::instance().hangupCall(aliceId, callId);
     CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
@@ -226,18 +235,18 @@ RecorderTest::testRecordAudioOnlyCall()
     }));
 
     // Start recorder
-    auto files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 0);
     DRing::toggleRecording(aliceId, callId);
 
     // Stop recorder
     std::this_thread::sleep_for(5s);
     CPPUNIT_ASSERT(DRing::getIsRecording(aliceId, callId));
+    recordedFile.clear();
     DRing::toggleRecording(aliceId, callId);
     CPPUNIT_ASSERT(!DRing::getIsRecording(aliceId, callId));
 
-    files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 1);
+    CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
+        return !recordedFile.empty() && recordedFile.find(".ogg") != std::string::npos;
+    }));
 
     Manager::instance().hangupCall(aliceId, callId);
     CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
@@ -262,17 +271,14 @@ RecorderTest::testStopCallWhileRecording()
     }));
 
     // Start recorder
-    auto files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 0);
     DRing::toggleRecording(aliceId, callId);
 
     // Hangup call
     std::this_thread::sleep_for(5s);
+    recordedFile.clear();
     Manager::instance().hangupCall(aliceId, callId);
-    CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
-
-    files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 1);
+    CPPUNIT_ASSERT(
+        cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER" && !recordedFile.empty(); }));
 }
 
 void
@@ -298,10 +304,10 @@ RecorderTest::testDaemonPreference()
     // Let record some seconds
     std::this_thread::sleep_for(5s);
 
+    recordedFile.clear();
     Manager::instance().hangupCall(aliceId, callId);
-    CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
-    auto files = fileutils::readDirectory("records");
-    CPPUNIT_ASSERT(files.size() == 1);
+    CPPUNIT_ASSERT(
+        cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER" && !recordedFile.empty(); }));
 }
 
 } // namespace test
diff --git a/test/unitTest/conversation/conversation.cpp b/test/unitTest/conversation/conversation.cpp
index 409d1f96c16a0f7d3d9e7d087bd3ae80a2c9a065..2d5925898839533ca7db5769a74127657e37cdad 100644
--- a/test/unitTest/conversation/conversation.cpp
+++ b/test/unitTest/conversation/conversation.cpp
@@ -2702,7 +2702,6 @@ ConversationTest::testRemoveReaddMultipleDevice()
             [&](const std::string& accountId,
                 const std::string& conversationId,
                 std::map<std::string, std::string> /*metadatas*/) {
-                JAMI_ERR("@@@@ INCOMING: %s %s", accountId.c_str(), conversationId.c_str());
                 if (accountId == bobId)
                     requestReceived = true;
                 else if (accountId == bob2Id)
diff --git a/test/unitTest/media_negotiation/auto_answer.cpp b/test/unitTest/media_negotiation/auto_answer.cpp
index 496c602771bf88797b5308e54dc7c28f3dc18bfe..0501bfcbb8103ed33730e7b7f4524de1c277f262 100644
--- a/test/unitTest/media_negotiation/auto_answer.cpp
+++ b/test/unitTest/media_negotiation/auto_answer.cpp
@@ -925,7 +925,6 @@ AutoAnswerMediaNegoTest::audio_only_then_caller_add_video()
     scenario.offerUpdate_.emplace_back(video);
     scenario.answerUpdate_.emplace_back(audio);
     scenario.answerUpdate_.emplace_back(video);
-    scenario.expectMediaRenegotiation_ = true;
 
     testWithScenario(aliceData_, bobData_, scenario);