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);