From a676ad395ac8cf30d8b060b586e23ed958628984 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Fri, 2 Feb 2024 15:27:45 -0500
Subject: [PATCH] callmodel: don't turn video on when accepting a call in audio

The function which is responsible for muting the camera when accepting
a call in audio assumes that the call's mediaList has already been
initialized, but this wasn't actually the case. This caused a bug where
the 'Accept in audio' button behaved exactly like the 'Accept in video'
button.

GitLab: #1621
Change-Id: I26251f51862cf5cd9b6d4daaf15270943c0e3c4e
---
 src/app/calladapter.cpp                       |  9 +--
 src/app/calladapter.h                         |  2 +-
 .../mainview/components/InitialCallPage.qml   |  8 +--
 src/libclient/api/callmodel.h                 |  6 +-
 src/libclient/callmodel.cpp                   | 64 +++++++++++--------
 5 files changed, 45 insertions(+), 44 deletions(-)

diff --git a/src/app/calladapter.cpp b/src/app/calladapter.cpp
index 6ac9b3d55..169ba6cf7 100644
--- a/src/app/calladapter.cpp
+++ b/src/app/calladapter.cpp
@@ -389,16 +389,13 @@ CallAdapter::hangUpACall(const QString& accountId, const QString& convUid)
 }
 
 void
-CallAdapter::setCallMedia(const QString& accountId, const QString& convUid, bool video)
+CallAdapter::setCallMedia(const QString& accountId, const QString& convUid, bool videoMuted)
 {
     const auto& convInfo = lrcInstance_->getConversationFromConvUid(convUid, accountId);
     if (convInfo.uid.isEmpty())
         return;
-    try {
-        lrcInstance_->getAccountInfo(accountId).callModel->updateCallMediaList(convInfo.callId,
-                                                                               video);
-    } catch (...) {
-    }
+
+    lrcInstance_->getAccountInfo(accountId).callModel->setVideoMuted(convInfo.callId, videoMuted);
 }
 
 void
diff --git a/src/app/calladapter.h b/src/app/calladapter.h
index cefeee014..a3ebf6153 100644
--- a/src/app/calladapter.h
+++ b/src/app/calladapter.h
@@ -67,7 +67,7 @@ public:
     Q_INVOKABLE void placeAudioOnlyCall();
     Q_INVOKABLE void placeCall();
     Q_INVOKABLE void hangUpACall(const QString& accountId, const QString& convUid);
-    Q_INVOKABLE void setCallMedia(const QString& accountId, const QString& convUid, bool video);
+    Q_INVOKABLE void setCallMedia(const QString& accountId, const QString& convUid, bool videoMuted);
     Q_INVOKABLE void acceptACall(const QString& accountId, const QString& convUid);
 
     Q_INVOKABLE void connectCallModel(const QString& accountId);
diff --git a/src/app/mainview/components/InitialCallPage.qml b/src/app/mainview/components/InitialCallPage.qml
index 4c9448e99..869833366 100644
--- a/src/app/mainview/components/InitialCallPage.qml
+++ b/src/app/mainview/components/InitialCallPage.qml
@@ -213,12 +213,8 @@ Rectangle {
 
                         onClicked: {
                             if (type === "cam" || type === "mic") {
-                                var acceptVideoMedia = true;
-                                if (type === "cam")
-                                    acceptVideoMedia = true;
-                                else if (type === "mic")
-                                    acceptVideoMedia = false;
-                                CallAdapter.setCallMedia(CurrentAccount.id, CurrentConversation.id, acceptVideoMedia);
+                                var muteVideo = (type === "mic");
+                                CallAdapter.setCallMedia(CurrentAccount.id, CurrentConversation.id, muteVideo);
                                 callAccepted();
                             } else {
                                 callCanceled();
diff --git a/src/libclient/api/callmodel.h b/src/libclient/api/callmodel.h
index e0812ca61..e9a077895 100644
--- a/src/libclient/api/callmodel.h
+++ b/src/libclient/api/callmodel.h
@@ -287,12 +287,12 @@ public:
     void setCurrentCall(const QString& callId) const;
 
     /**
-     * Update call mediaList to be used in the call answering
+     * Set whether the user's video media should be muted
      *
      * @param callId
-     * @param acceptVideo
+     * @param videoMuted
      */
-    void updateCallMediaList(const QString& callId, bool acceptVideo);
+    void setVideoMuted(const QString& callId, bool videoMuted);
 
     /**
      * Change the conference layout
diff --git a/src/libclient/callmodel.cpp b/src/libclient/callmodel.cpp
index 18587c799..6b78b742d 100644
--- a/src/libclient/callmodel.cpp
+++ b/src/libclient/callmodel.cpp
@@ -348,42 +348,47 @@ CallModel::getParticipantsInfos(const QString& callId)
 }
 
 void
-CallModel::updateCallMediaList(const QString& callId, bool acceptVideo)
+CallModel::setVideoMuted(const QString& callId, bool videoMuted)
 {
-    try {
-        auto callInfos = pimpl_->calls.find(callId);
-        if (callInfos != pimpl_->calls.end()) {
-            for (auto it = callInfos->second->mediaList.begin();
-                 it != callInfos->second->mediaList.end();
-                 it++) {
-                if ((*it)[MediaAttributeKey::MEDIA_TYPE] == MediaAttributeValue::VIDEO
-                    && !acceptVideo) {
-                    (*it)[MediaAttributeKey::ENABLED] = TRUE_STR;
-                    (*it)[MediaAttributeKey::MUTED] = TRUE_STR;
-                    callInfos->second->videoMuted = !acceptVideo;
-                }
-            }
+    auto call = pimpl_->calls.find(callId);
+    if (call == pimpl_->calls.end())
+        return;
+
+    auto& callInfo = call->second;
+    callInfo->videoMuted = videoMuted;
+
+    for (auto& media : callInfo->mediaList) {
+        if (!media.contains(MediaAttributeKey::MEDIA_TYPE))
+            continue;
+
+        if (media[MediaAttributeKey::MEDIA_TYPE] == MediaAttributeValue::VIDEO) {
+            media[MediaAttributeKey::MUTED] = videoMuted ? TRUE_STR : FALSE_STR;
         }
-    } catch (...) {
     }
 }
 
+static void
+initializeMediaList(VectorMapStringString& mediaList, bool audioOnly)
+{
+    mediaList.push_back({{MediaAttributeKey::MEDIA_TYPE, MediaAttributeValue::AUDIO},
+                         {MediaAttributeKey::ENABLED, TRUE_STR},
+                         {MediaAttributeKey::MUTED, FALSE_STR},
+                         {MediaAttributeKey::SOURCE, ""},
+                         {MediaAttributeKey::LABEL, "audio_0"}});
+    if (audioOnly)
+        return;
+    mediaList.push_back({{MediaAttributeKey::MEDIA_TYPE, MediaAttributeValue::VIDEO},
+                         {MediaAttributeKey::ENABLED, TRUE_STR},
+                         {MediaAttributeKey::MUTED, FALSE_STR},
+                         {MediaAttributeKey::SOURCE, ""},
+                         {MediaAttributeKey::LABEL, "video_0"}});
+}
+
 QString
 CallModel::createCall(const QString& uri, bool isAudioOnly, VectorMapStringString mediaList)
 {
     if (mediaList.isEmpty()) {
-        MapStringString mediaAttribute = {{MediaAttributeKey::MEDIA_TYPE,
-                                           MediaAttributeValue::AUDIO},
-                                          {MediaAttributeKey::ENABLED, TRUE_STR},
-                                          {MediaAttributeKey::MUTED, FALSE_STR},
-                                          {MediaAttributeKey::SOURCE, ""},
-                                          {MediaAttributeKey::LABEL, "audio_0"}};
-        mediaList.push_back(mediaAttribute);
-        if (!isAudioOnly) {
-            mediaAttribute[MediaAttributeKey::MEDIA_TYPE] = MediaAttributeValue::VIDEO;
-            mediaAttribute[MediaAttributeKey::LABEL] = "video_0";
-            mediaList.push_back(mediaAttribute);
-        }
+        initializeMediaList(mediaList, isAudioOnly);
     }
 #ifdef ENABLE_LIBWRAP
     auto callId = CallManager::instance().placeCallWithMedia(owner.id, uri, mediaList);
@@ -1456,7 +1461,10 @@ CallModelPimpl::slotCallStateChanged(const QString& accountId,
         callInfo->type = call::Type::DIALOG;
         callInfo->isAudioOnly = details["AUDIO_ONLY"] == TRUE_STR;
         callInfo->videoMuted = details["VIDEO_MUTED"] == TRUE_STR;
-        callInfo->mediaList = {};
+        // NOTE: The CallModel::setVideoMuted function currently relies on callInfo->mediaList
+        // having been initialized. Not doing so leads to a bug where the user's camera wrongly
+        // gets turned on when they receive a call and click on "Answer in audio".
+        initializeMediaList(callInfo->mediaList, callInfo->isAudioOnly);
         calls.emplace(callId, std::move(callInfo));
 
         if (!(details["CALL_TYPE"] == "1") && !linked.owner.confProperties.allowIncoming
-- 
GitLab