From 23ecb71e03d237e45dd02b69d3792d638953b8d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Tue, 3 Oct 2023 05:40:30 -0400
Subject: [PATCH] jamiaccount: use current media list when answering a swarm
 call

Else, the mute state is ignored, causing the new member to be able
to listen from the host even if the host muted itself.

https://git.jami.net/savoirfairelinux/jami-client-android/-/issues/1351
Change-Id: Ic0e4f7ac99fd945847f47c9e2e4573fa1d6a1b1a
---
 src/jamidht/jamiaccount.cpp         | 21 +++++----
 test/unitTest/conversation/call.cpp | 68 +++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 8 deletions(-)

diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 6ac8625236..830a6abc9b 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -521,7 +521,18 @@ JamiAccount::handleIncomingConversationCall(const std::string& callId,
         Manager::instance().hangupCall(getAccountID(), callId);
         return;
     }
-    Manager::instance().answerCall(*call);
+
+    std::shared_ptr<Conference> conf;
+    std::vector<libjami::MediaMap> currentMediaList;
+    if (!isNotHosting) {
+        conf = getConference(confId);
+        if (!conf) {
+            JAMI_ERR("Conference %s not found", confId.c_str());
+            return;
+        }
+        currentMediaList = conf->currentMediaList();
+    }
+    Manager::instance().answerCall(*call, currentMediaList);
 
     if (isNotHosting) {
         // Create conference and host it.
@@ -529,12 +540,6 @@ JamiAccount::handleIncomingConversationCall(const std::string& callId,
         if (auto conf = getConference(confId))
             conf->detachLocalParticipant();
     } else {
-        auto conf = getConference(confId);
-        if (!conf) {
-            JAMI_ERR("Conference %s not found", confId.c_str());
-            return;
-        }
-
         Manager::instance().addParticipant(*call, *conf);
         emitSignal<libjami::CallSignal::ConferenceChanged>(getAccountID(),
                                                            conf->getConfId(),
@@ -3860,7 +3865,7 @@ JamiAccount::cacheSIPConnection(std::shared_ptr<dhtnet::ChannelSocket>&& socket,
             shared->convModule()->syncConversations(peerId, deviceId.toString());
         }
     });
-    
+
     // Retry messages
     messageEngine_.onPeerOnline(peerId);
     messageEngine_.onPeerOnline(peerId, true, deviceId.toString());
diff --git a/test/unitTest/conversation/call.cpp b/test/unitTest/conversation/call.cpp
index 3f03711a9c..79f81843da 100644
--- a/test/unitTest/conversation/call.cpp
+++ b/test/unitTest/conversation/call.cpp
@@ -30,6 +30,7 @@
 #include "conversation/conversationcommon.h"
 #include "manager.h"
 #include "media_const.h"
+#include "sip/sipcall.h"
 
 using namespace std::literals::chrono_literals;
 
@@ -85,6 +86,7 @@ private:
     void testCallSelfIfDefaultHost();
     void testNeedsHost();
     void testAudioOnly();
+    void testJoinAfterMuteHost();
 
     CPPUNIT_TEST_SUITE(ConversationCallTest);
     CPPUNIT_TEST(testActiveCalls);
@@ -98,6 +100,7 @@ private:
     CPPUNIT_TEST(testCallSelfIfDefaultHost);
     CPPUNIT_TEST(testNeedsHost);
     CPPUNIT_TEST(testAudioOnly);
+    CPPUNIT_TEST(testJoinAfterMuteHost);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -1009,6 +1012,71 @@ ConversationCallTest::testAudioOnly()
     CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0);
 }
 
+void
+ConversationCallTest::testJoinAfterMuteHost()
+{
+    connectSignals();
+
+    auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
+    auto aliceUri = aliceAccount->getUsername();
+    auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
+    auto bobUri = bobAccount->getUsername();
+    // Start conversation
+    libjami::startConversation(aliceId);
+    CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData_.id.empty(); }));
+
+    libjami::addConversationMember(aliceId, aliceData_.id, bobUri);
+    CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() {
+        return bobData_.requestReceived;
+    }));
+
+    aliceData_.messages.clear();
+    libjami::acceptConversationRequest(bobId, aliceData_.id);
+    CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
+        return !bobData_.id.empty() && !aliceData_.messages.empty();
+    }));
+
+    // start call
+    aliceData_.messages.clear();
+    bobData_.messages.clear();
+    carlaData_.messages.clear();
+    auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {});
+    auto lastCommitIsCall = [&](const auto& data) {
+        return !data.messages.empty()
+               && data.messages.rbegin()->at("type") == "application/call-history+json";
+    };
+    // should get message
+    CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
+        return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_) && !pInfos_.empty();
+    }));
+    auto confId = bobData_.messages.rbegin()->at("confId");
+
+    // Mute host
+    auto call = std::dynamic_pointer_cast<SIPCall>(aliceAccount->getCall(callId));
+    auto proposedList = call->currentMediaList();
+    for (auto& media : proposedList)
+        if (media["LABEL"] == "audio_0")
+            media["MUTED"] = "true";
+    libjami::requestMediaChange(aliceId, confId, proposedList);
+
+    // Bob join, alice must stay muted
+    auto destination = fmt::format("rdv:{}/{}/{}/{}",
+                                   bobData_.id,
+                                   bobData_.messages.rbegin()->at("uri"),
+                                   bobData_.messages.rbegin()->at("device"),
+                                   confId);
+
+    aliceData_.conferenceChanged = false;
+    pInfos_.clear();
+    auto bobCall = libjami::placeCallWithMedia(bobId, destination, {});
+    CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
+        return aliceData_.conferenceChanged && bobData_.hostState == "CURRENT"  && bobData_.state == "CURRENT" && pInfos_.size() == 2;
+    }));
+    // Audio of the host is still muted
+    CPPUNIT_ASSERT(pInfos_[0]["audioLocalMuted"] == "true");
+
+}
+
 } // namespace test
 } // namespace jami
 
-- 
GitLab