diff --git a/CMakeLists.txt b/CMakeLists.txt
index 277dd7e987118894bfd4b9e8b053cfd26585a6b5..b640c2c792cf69d204c780eb6ffa326337baf2d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -221,7 +221,7 @@ set(COMMON_SOURCES
   ${APP_SRC_DIR}/callparticipantsmodel.cpp
   ${APP_SRC_DIR}/tipsmodel.cpp
   ${APP_SRC_DIR}/positioning.cpp
-)
+  ${APP_SRC_DIR}/currentcall.cpp)
 
 set(COMMON_HEADERS
   ${APP_SRC_DIR}/avatarimageprovider.h
@@ -280,7 +280,8 @@ set(COMMON_HEADERS
   ${APP_SRC_DIR}/videoprovider.h
   ${APP_SRC_DIR}/callparticipantsmodel.h
   ${APP_SRC_DIR}/tipsmodel.h
-  ${APP_SRC_DIR}/positioning.h)
+  ${APP_SRC_DIR}/positioning.h
+  ${APP_SRC_DIR}/currentcall.h)
 
 if(WITH_WEBENGINE)
   list(APPEND COMMON_SOURCES
diff --git a/extras/packaging/update/sparkle/Sparkle b/extras/packaging/update/sparkle/Sparkle
deleted file mode 160000
index 2195ee0883efc92828a0cf33b830f43f9bd7e01b..0000000000000000000000000000000000000000
--- a/extras/packaging/update/sparkle/Sparkle
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 2195ee0883efc92828a0cf33b830f43f9bd7e01b
diff --git a/src/app/calladapter.cpp b/src/app/calladapter.cpp
index be21ec2d8eb0b88ed5bd0f043f6028fbbdc28d8d..fe6f7d4cc2567f3db7739608f7848cea91f20539 100644
--- a/src/app/calladapter.cpp
+++ b/src/app/calladapter.cpp
@@ -238,7 +238,6 @@ CallAdapter::onCallStatusChanged(const QString& callId, int code)
         const auto& convInfo = lrcInstance_->getConversationFromCallId(callId);
         if (!convInfo.uid.isEmpty()) {
             Q_EMIT callStatusChanged(static_cast<int>(call.status), accountId_, convInfo.uid);
-            updateCallOverlay(convInfo);
         }
 
         switch (call.status) {
@@ -330,25 +329,11 @@ CallAdapter::onCallInfosChanged(const QString& accountId, const QString& callId)
             }
             Q_EMIT callInfosChanged(call.isAudioOnly, accountId, convInfo.uid);
             participantsModel_->setConferenceLayout(static_cast<int>(call.layout), callId);
-            updateCallOverlay(convInfo);
         }
     } catch (...) {
     }
 }
 
-void
-CallAdapter::onRemoteRecordingChanged(const QString& callId,
-                                      const QSet<QString>& peerRec,
-                                      bool state)
-{
-    Q_UNUSED(peerRec)
-    Q_UNUSED(state)
-    const auto currentCallId
-        = lrcInstance_->getCallIdForConversationUid(lrcInstance_->get_selectedConvUid(), accountId_);
-    if (callId == currentCallId)
-        updateRecordingPeers();
-}
-
 void
 CallAdapter::onCallAddedToConference(const QString& callId, const QString& confId)
 {
@@ -511,8 +496,6 @@ CallAdapter::updateCall(const QString& convUid, const QString& accountId, bool f
         }
     }
 
-    updateCallOverlay(convInfo);
-    updateRecordingPeers(true);
     participantsModel_->setParticipants(call->id, getConferencesInfos());
     participantsModel_->setConferenceLayout(static_cast<int>(call->layout), call->id);
 }
@@ -569,7 +552,6 @@ CallAdapter::getConferencesInfos() const
                                           .getAccountInfo(accountId_)
                                           .callModel.get()
                                           ->getParticipantsInfos(callId);
-            int index = 0;
             for (int index = 0; index < participantsModel.getParticipants().size(); index++) {
                 auto participant = participantsModel.toQJsonObject(index);
                 fillParticipantData(participant);
@@ -642,12 +624,6 @@ CallAdapter::connectCallModel(const QString& accountId)
             QOverload<const QString&, int>::of(&CallAdapter::onCallStatusChanged),
             Qt::UniqueConnection);
 
-    connect(accInfo.callModel.get(),
-            &CallModel::remoteRecordingChanged,
-            this,
-            &CallAdapter::onRemoteRecordingChanged,
-            Qt::UniqueConnection);
-
     connect(accInfo.callModel.get(),
             &CallModel::callAddedToConference,
             this,
@@ -660,32 +636,6 @@ CallAdapter::connectCallModel(const QString& accountId)
             QOverload<const QString&, const QString&>::of(&CallAdapter::onCallInfosChanged));
 }
 
-void
-CallAdapter::updateRecordingPeers(bool eraseLabelOnEmpty)
-{
-    const auto& convInfo = lrcInstance_->getConversationFromConvUid(
-        lrcInstance_->get_selectedConvUid());
-    auto* call = lrcInstance_->getCallInfoForConversation(convInfo);
-    if (!call) {
-        return;
-    }
-
-    const auto& accInfo = lrcInstance_->getCurrentAccountInfo();
-    QStringList peers {};
-    for (const auto& uri : call->peerRec) {
-        auto bestName = accInfo.contactModel->bestNameForContact(uri);
-        if (!bestName.isEmpty()) {
-            peers.append(bestName);
-        }
-    }
-    if (!peers.isEmpty())
-        Q_EMIT remoteRecordingChanged(peers, true);
-    else if (eraseLabelOnEmpty)
-        Q_EMIT eraseRemoteRecording();
-    else
-        Q_EMIT remoteRecordingChanged(peers, false);
-}
-
 void
 CallAdapter::sipInputPanelPlayDTMF(const QString& key)
 {
@@ -698,49 +648,6 @@ CallAdapter::sipInputPanelPlayDTMF(const QString& key)
     lrcInstance_->getCurrentCallModel()->playDTMF(callId, key);
 }
 
-/*
- * For Call Overlay
- */
-void
-CallAdapter::updateCallOverlay(const lrc::api::conversation::Info& convInfo)
-{
-    auto& accInfo = lrcInstance_->accountModel().getAccountInfo(accountId_);
-    auto* callModel = accInfo.callModel.get();
-
-    const auto* callInfo = lrcInstance_->getCallInfoForConversation(convInfo);
-    const auto currentCallId = lrcInstance_->getCurrentCallId();
-    if (!callInfo || callInfo->id != currentCallId)
-        return;
-
-    bool isPaused = callInfo->status == lrc::api::call::Status::PAUSED;
-    bool isAudioOnly = callInfo->isAudioOnly && !isPaused;
-    bool isAudioMuted = callInfo->status == lrc::api::call::Status::PAUSED;
-    bool isGrid = callInfo->layout == lrc::api::call::Layout::GRID;
-    QString previewId {};
-    if (callInfo->status != lrc::api::call::Status::ENDED) {
-        for (const auto& media : callInfo->mediaList) {
-            if (media[libjami::Media::MediaAttributeKey::MEDIA_TYPE]
-                == libjami::Media::Details::MEDIA_TYPE_VIDEO) {
-                if (media[libjami::Media::MediaAttributeKey::ENABLED] == TRUE_STR
-                    && media[libjami::Media::MediaAttributeKey::MUTED] == FALSE_STR) {
-                    if (previewId.isEmpty()) {
-                        previewId = media[libjami::Media::MediaAttributeKey::SOURCE];
-                    }
-                }
-            } else if (media[libjami::Media::MediaAttributeKey::LABEL] == "audio_0") {
-                isAudioMuted |= media[libjami::Media::MediaAttributeKey::MUTED] == TRUE_STR;
-            }
-        }
-    }
-
-    Q_EMIT updateOverlay(isPaused,
-                         isAudioOnly,
-                         isAudioMuted,
-                         accInfo.profileInfo.type == lrc::api::profile::Type::SIP,
-                         isGrid,
-                         previewId);
-}
-
 void
 CallAdapter::saveConferenceSubcalls()
 {
@@ -1075,7 +982,6 @@ CallAdapter::holdThisCallToggle()
     if (callModel->hasCall(callId)) {
         callModel->togglePause(callId);
     }
-    Q_EMIT showOnHoldLabel(true);
 }
 
 void
diff --git a/src/app/calladapter.h b/src/app/calladapter.h
index 88e375cb14d0839218f3be37b92b687adc61f484..cf6d3eec91f8950981df30bda97af1100b1b3f56 100644
--- a/src/app/calladapter.h
+++ b/src/app/calladapter.h
@@ -100,15 +100,6 @@ Q_SIGNALS:
 
     // For Call Overlay
     void updateTimeText(const QString& time);
-    void showOnHoldLabel(bool isPaused);
-    void updateOverlay(bool isPaused,
-                       bool isAudioOnly,
-                       bool isAudioMuted,
-                       bool isSIP,
-                       bool isGrid,
-                       const QString& previewId);
-    void remoteRecordingChanged(const QStringList& peers, bool state);
-    void eraseRemoteRecording();
 
 public Q_SLOTS:
     void onShowIncomingCallView(const QString& accountId, const QString& convUid);
@@ -117,18 +108,15 @@ public Q_SLOTS:
     void onCallStatusChanged(const QString& accountId, const QString& callId);
     void onCallInfosChanged(const QString& accountId, const QString& callId);
     void onCallStatusChanged(const QString& callId, int code);
-    void onRemoteRecordingChanged(const QString& callId, const QSet<QString>& peerRec, bool state);
     void onCallAddedToConference(const QString& callId, const QString& confId);
     void onParticipantAdded(const QString& callId, int index);
     void onParticipantRemoved(const QString& callId, int index);
     void onParticipantUpdated(const QString& callId, int index);
 
 private:
-    void updateRecordingPeers(bool eraseLabelOnEmpty = false);
     void showNotification(const QString& accountId, const QString& convUid);
     void fillParticipantData(QJsonObject& participant) const;
     void preventScreenSaver(bool state);
-    void updateCallOverlay(const lrc::api::conversation::Info& convInfo);
     void saveConferenceSubcalls();
 
     QString accountId_;
diff --git a/src/app/currentcall.cpp b/src/app/currentcall.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c3ddb64deead4011b5e893339ad2a02aba44f78
--- /dev/null
+++ b/src/app/currentcall.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "currentcall.h"
+
+#include <api/callparticipantsmodel.h>
+
+CurrentCall::CurrentCall(LRCInstance* lrcInstance, QObject* parent)
+    : QObject(parent)
+    , lrcInstance_(lrcInstance)
+{
+    connect(lrcInstance_,
+            &LRCInstance::currentAccountIdChanged,
+            this,
+            &CurrentCall::onCurrentAccountIdChanged);
+
+    connect(lrcInstance_,
+            &LRCInstance::selectedConvUidChanged,
+            this,
+            &CurrentCall::onCurrentConvIdChanged);
+
+    connectModel();
+}
+
+void
+CurrentCall::updateId(QString callId)
+{
+    auto convId = lrcInstance_->get_selectedConvUid();
+    auto optConv = lrcInstance_->getCurrentConversationModel()->getConversationForUid(convId);
+    if (!optConv.has_value()) {
+        return;
+    }
+
+    // If the optional parameter callId is empty, then we've just
+    // changed conversation selection and need to check the current
+    // conv's callId for an existing call.
+    // Otherwise, return if callId doesn't belong to this conversation.
+    if (callId.isEmpty()) {
+        callId = optConv->get().getCallId();
+    } else if (optConv->get().getCallId() != callId) {
+        return;
+    }
+
+    // Set the current id_ if there is a call.
+    auto& accInfo = lrcInstance_->getCurrentAccountInfo();
+    if (accInfo.callModel->hasCall(callId)) {
+        set_id(callId);
+    }
+}
+
+void
+CurrentCall::updateCallStatus()
+{
+    call::Status status {};
+    auto callModel = lrcInstance_->getCurrentCallModel();
+    if (callModel->hasCall(id_)) {
+        auto callInfo = callModel->getCall(id_);
+        status = callInfo.status;
+    }
+
+    set_status(status);
+    set_isActive(status_ == call::Status::CONNECTED || status_ == call::Status::IN_PROGRESS
+                 || status_ == call::Status::PAUSED);
+    set_isPaused(status_ == call::Status::PAUSED);
+}
+
+void
+CurrentCall::updateParticipants()
+{
+    auto callModel = lrcInstance_->getCurrentCallModel();
+    QStringList uris;
+    auto& participantsModel = callModel->getParticipantsInfos(id_);
+    for (int index = 0; index < participantsModel.getParticipants().size(); index++) {
+        auto participantInfo = participantsModel.toQJsonObject(index);
+        uris.append(participantInfo[ParticipantsInfosStrings::URI].toString());
+    }
+    set_uris(uris);
+    set_isConference(uris.size());
+}
+
+void
+CurrentCall::updateCallInfo()
+{
+    auto callModel = lrcInstance_->getCurrentCallModel();
+    if (!callModel->hasCall(id_)) {
+        return;
+    }
+
+    auto callInfo = callModel->getCall(id_);
+
+    set_isGrid(callInfo.layout == call::Layout::GRID);
+    set_isAudioOnly(callInfo.isAudioOnly);
+
+    bool isAudioMuted {};
+    bool isVideoMuted {};
+    bool isSharing {};
+    bool isCapturing {};
+    QString previewId {};
+    using namespace libjami::Media;
+    if (callInfo.status != lrc::api::call::Status::ENDED) {
+        for (const auto& media : callInfo.mediaList) {
+            if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_VIDEO) {
+                if (media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::DISPLAY)
+                    || media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::FILE)) {
+                    isSharing = true;
+                }
+                if (media[MediaAttributeKey::ENABLED] == TRUE_STR
+                    && media[MediaAttributeKey::MUTED] == FALSE_STR && previewId.isEmpty()) {
+                    previewId = media[libjami::Media::MediaAttributeKey::SOURCE];
+                }
+                if (media[libjami::Media::MediaAttributeKey::SOURCE].startsWith(
+                        libjami::Media::VideoProtocolPrefix::CAMERA)) {
+                    isVideoMuted |= media[MediaAttributeKey::MUTED] == TRUE_STR;
+                    isCapturing = media[MediaAttributeKey::MUTED] == FALSE_STR;
+                }
+            } else if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_AUDIO) {
+                if (media[MediaAttributeKey::LABEL] == "audio_0") {
+                    isAudioMuted |= media[libjami::Media::MediaAttributeKey::MUTED] == TRUE_STR;
+                }
+            }
+        }
+    }
+    set_previewId(previewId);
+    set_isAudioMuted(isAudioMuted);
+    set_isVideoMuted(isVideoMuted);
+    set_isSharing(isSharing);
+    set_isCapturing(isCapturing);
+    set_isHandRaised(callModel->isHandRaised(id_));
+    set_isModerator(callModel->isModerator(id_));
+}
+
+void
+CurrentCall::updateRemoteRecorders(const QStringList& recorders)
+{
+    auto& accInfo = lrcInstance_->getCurrentAccountInfo();
+    remoteRecorderNameList_.clear();
+    Q_FOREACH (const auto& uri, recorders) {
+        auto bestName = accInfo.contactModel->bestNameForContact(uri);
+        if (!bestName.isEmpty()) {
+            remoteRecorderNameList_.append(bestName);
+        }
+    }
+
+    // Convenience flag.
+    set_isRecordingRemotely(!remoteRecorderNameList_.isEmpty());
+
+    Q_EMIT remoteRecorderNameListChanged();
+}
+
+void
+CurrentCall::updateRecordingState(bool state)
+{
+    set_isRecordingLocally(state);
+}
+
+void
+CurrentCall::connectModel()
+{
+    try {
+        auto& accInfo = lrcInstance_->getCurrentAccountInfo();
+        connect(accInfo.callModel.get(),
+                &CallModel::callStatusChanged,
+                this,
+                &CurrentCall::onCallStatusChanged,
+                Qt::UniqueConnection);
+        connect(accInfo.callModel.get(),
+                &CallModel::callInfosChanged,
+                this,
+                &CurrentCall::onCallInfosChanged,
+                Qt::UniqueConnection);
+        connect(accInfo.callModel.get(),
+                &CallModel::currentCallChanged,
+                this,
+                &CurrentCall::onCurrentCallChanged,
+                Qt::UniqueConnection);
+        connect(accInfo.callModel.get(),
+                &CallModel::participantsChanged,
+                this,
+                &CurrentCall::onParticipantsChanged,
+                Qt::UniqueConnection);
+        connect(accInfo.callModel.get(),
+                &CallModel::remoteRecordersChanged,
+                this,
+                &CurrentCall::onRemoteRecordersChanged,
+                Qt::UniqueConnection);
+        connect(accInfo.callModel.get(),
+                &CallModel::recordingStateChanged,
+                this,
+                &CurrentCall::onRecordingStateChanged,
+                Qt::UniqueConnection);
+    } catch (const std::exception& e) {
+        qWarning() << "Exception getting account info." << e.what();
+    }
+}
+
+void
+CurrentCall::onCurrentConvIdChanged()
+{
+    updateId();
+    updateCallStatus();
+    updateParticipants();
+    updateCallInfo();
+
+    auto callModel = lrcInstance_->getCurrentCallModel();
+    QStringList recorders {};
+    if (callModel->hasCall(id_)) {
+        auto callInfo = callModel->getCall(id_);
+        recorders = callInfo.recordingPeers;
+    }
+    updateRecordingState(callModel->isRecording(id_));
+    updateRemoteRecorders(recorders);
+}
+
+void
+CurrentCall::onCurrentAccountIdChanged()
+{
+    try {
+        auto& accInfo = lrcInstance_->getCurrentAccountInfo();
+        set_isSIP(accInfo.profileInfo.type == profile::Type::SIP);
+    } catch (const std::exception& e) {
+        qWarning() << "Can't update current call type" << e.what();
+    }
+
+    connectModel();
+}
+
+void
+CurrentCall::onCallStatusChanged(const QString& callId, int code)
+{
+    Q_UNUSED(code)
+
+    if (id_ != callId) {
+        return;
+    }
+
+    updateCallStatus();
+}
+
+void
+CurrentCall::onCallInfosChanged(const QString& accountId, const QString& callId)
+{
+    if (id_ != callId) {
+        return;
+    }
+
+    updateCallInfo();
+}
+
+void
+CurrentCall::onCurrentCallChanged(const QString& callId)
+{
+    // If this status change's callId is not the current, it's possible that
+    // the current value of id_ is stale, and needs to be updated after checking
+    // the current conversation's getCallId(). Other slots need not do this, as the
+    // id_ is updated here.
+    if (id_ == callId) {
+        return;
+    }
+
+    updateId(callId);
+    updateCallStatus();
+    updateParticipants();
+    updateCallInfo();
+}
+
+void
+CurrentCall::onParticipantsChanged(const QString& callId)
+{
+    if (id_ != callId) {
+        return;
+    }
+
+    updateParticipants();
+}
+
+void
+CurrentCall::onRemoteRecordersChanged(const QString& callId, const QStringList& recorders)
+{
+    if (id_ != callId) {
+        return;
+    }
+
+    updateRemoteRecorders(recorders);
+}
+
+void
+CurrentCall::onRecordingStateChanged(const QString& callId, bool state)
+{
+    if (id_ != callId) {
+        return;
+    }
+
+    updateRecordingState(state);
+}
diff --git a/src/app/currentcall.h b/src/app/currentcall.h
new file mode 100644
index 0000000000000000000000000000000000000000..c04a65fc8414268875813c7e126559860e5c4487
--- /dev/null
+++ b/src/app/currentcall.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "lrcinstance.h"
+#include "qtutils.h"
+
+#include <QObject>
+#include <QString>
+
+class CurrentCall final : public QObject
+{
+    Q_OBJECT
+
+    QML_RO_PROPERTY(QString, id)
+    QML_RO_PROPERTY(QStringList, uris)
+    QML_RO_PROPERTY(bool, isAudioOnly)
+    QML_RO_PROPERTY(bool, isSIP)
+    QML_RO_PROPERTY(bool, isGrid)
+    QML_RO_PROPERTY(call::Status, status)
+    QML_RO_PROPERTY(bool, isActive)
+    QML_RO_PROPERTY(bool, isPaused)
+    QML_RO_PROPERTY(bool, isAudioMuted)
+    QML_RO_PROPERTY(bool, isCapturing)
+    QML_RO_PROPERTY(bool, isVideoMuted)
+    QML_RO_PROPERTY(QString, previewId)
+    QML_RO_PROPERTY(bool, isRecordingLocally)
+    QML_RO_PROPERTY(bool, isRecordingRemotely)
+    QML_RO_PROPERTY(QStringList, remoteRecorderNameList)
+    QML_RO_PROPERTY(bool, isSharing)
+    QML_RO_PROPERTY(bool, isHandRaised)
+    QML_RO_PROPERTY(bool, isConference)
+    QML_RO_PROPERTY(bool, isModerator)
+
+public:
+    explicit CurrentCall(LRCInstance* lrcInstance, QObject* parent = nullptr);
+    ~CurrentCall() = default;
+
+private:
+    void updateId(QString callId = {});
+    void updateCallStatus();
+    void updateParticipants();
+    void updateCallInfo();
+    void updateRemoteRecorders(const QStringList& recorders);
+    void updateRecordingState(bool state);
+    void connectModel();
+
+private Q_SLOTS:
+    void onCurrentConvIdChanged();
+    void onCurrentAccountIdChanged();
+    void onCallStatusChanged(const QString& callId, int code);
+    void onCallInfosChanged(const QString& accountId, const QString& callId);
+    void onCurrentCallChanged(const QString& callId);
+    void onParticipantsChanged(const QString& callId);
+    void onRemoteRecordersChanged(const QString& callId, const QStringList& recorders);
+    void onRecordingStateChanged(const QString& callId, bool state);
+
+private:
+    LRCInstance* lrcInstance_;
+};
diff --git a/src/app/mainview/MainView.qml b/src/app/mainview/MainView.qml
index 944788b46a2f167491171db214e95caf8379ef8d..4a19aea658163451f947702ec4504c8f9a077302 100644
--- a/src/app/mainview/MainView.qml
+++ b/src/app/mainview/MainView.qml
@@ -186,7 +186,6 @@ Rectangle {
             callStackView.setLinkedWebview(chatView)
             callStackView.responsibleAccountId = LRCInstance.currentAccountId
             callStackView.responsibleConvUid = convId
-            callStackView.isAudioOnly = item.isAudioOnly
             currentConvUID = convId
 
             if (item.callState === Call.Status.IN_PROGRESS ||
diff --git a/src/app/mainview/components/CallActionBar.qml b/src/app/mainview/components/CallActionBar.qml
index 717981b95564a78b38ff9d8cbec1c801a9e8ef61..04c8a49b8762d8e7ad2df8ce0236e9bc1a1b773f 100644
--- a/src/app/mainview/components/CallActionBar.qml
+++ b/src/app/mainview/components/CallActionBar.qml
@@ -162,7 +162,7 @@ Control {
                         layoutModel.get(index).ActiveSetting = layoutManager.isCallFullscreen
                         break
                   case JamiStrings.mosaic:
-                        if (!isGrid)
+                        if (!CurrentCall.isGrid)
                             CallAdapter.showGridConferenceLayout()
                         break
                   case JamiStrings.participantsSide:
@@ -189,10 +189,10 @@ Control {
             }
             onTriggered: {
                 layoutModel.clear()
-                if (isConference) {
+                if (CurrentCall.isConference) {
                     layoutModel.append({"Name": JamiStrings.mosaic,
                                         "IconSource": JamiResources.mosaic_black_24dp_svg,
-                                        "ActiveSetting": isGrid,
+                                        "ActiveSetting": CurrentCall.isGrid,
                                         "TopMargin": true,
                                         "BottomMargin": true,
                                         "SectionEnd": true})
@@ -223,8 +223,8 @@ Control {
                                     "ActiveSetting": layoutManager.isCallFullscreen,
                                     "TopMargin": true,
                                     "BottomMargin": true,
-                                    "SectionEnd": isConference})
-                if (isConference) {
+                                    "SectionEnd": CurrentCall.isConference})
+                if (CurrentCall.isConference) {
                     layoutModel.append({"Name": JamiStrings.hideSpectators,
                                         "IconSource": JamiResources.videocam_off_24dp_svg,
                                         "ActiveSetting": UtilsAdapter.getAppValue(Settings.HideSpectators),
@@ -263,6 +263,7 @@ Control {
                              JamiResources.micro_black_24dp_svg
             icon.color: checked ? "red" : "white"
             text: !checked ? JamiStrings.mute : JamiStrings.unmute
+            checked: CurrentCall.isAudioMuted
             property var menuAction: audioInputMenuAction
         },
         Action {
@@ -282,6 +283,7 @@ Control {
                              JamiResources.videocam_24dp_svg
             icon.color: checked ? "red" : "white"
             text: !checked ? JamiStrings.muteCamera : JamiStrings.unmuteCamera
+            checked: !CurrentCall.isCapturing
             property var menuAction: videoInputMenuAction
         }
     ]
@@ -314,11 +316,13 @@ Control {
         Action {
             id: resumePauseCallAction
             onTriggered: root.resumePauseCallClicked()
-            icon.source: isPaused ?
+            icon.source: CurrentCall.isPaused ?
                              JamiResources.play_circle_outline_24dp_svg :
                              JamiResources.pause_circle_outline_24dp_svg
             icon.color: "white"
-            text: isPaused ? JamiStrings.resumeCall : JamiStrings.pauseCall
+            text: CurrentCall.isPaused ?
+                      JamiStrings.resumeCall :
+                      JamiStrings.pauseCall
         },
         Action {
             id: inputPanelSIPAction
@@ -337,17 +341,17 @@ Control {
         Action {
             id: shareAction
             onTriggered: {
-                if (sharingActive)
+                if (CurrentCall.isSharing)
                     root.stopSharingClicked()
                 else
                     root.shareScreenClicked()
             }
-            icon.source: sharingActive ?
+            icon.source: CurrentCall.isSharing ?
                              JamiResources.share_stop_black_24dp_svg :
                              JamiResources.share_screen_black_24dp_svg
-            icon.color: sharingActive ?
+            icon.color: CurrentCall.isSharing ?
                             "red" : "white"
-            text: sharingActive ?
+            text: CurrentCall.isSharing ?
                       JamiStrings.stopSharing :
                       JamiStrings.shareScreen
             property real size: 34
@@ -362,12 +366,13 @@ Control {
             text: checked ?
                       JamiStrings.lowerHand :
                       JamiStrings.raiseHand
+            checked: CurrentCall.isHandRaised
             property real size: 34
         },
         Action {
             id: layoutAction
             onTriggered: {
-                if (!isGrid)
+                if (!CurrentCall.isGrid)
                     CallAdapter.showGridConferenceLayout()
             }
             checkable: true
@@ -386,6 +391,7 @@ Control {
             text: !checked ? JamiStrings.startRec : JamiStrings.stopRec
             property bool blinksWhenChecked: true
             property real size: 28
+            checked: CurrentCall.isRecordingLocally
             onCheckedChanged: function(checked) {
                 CallOverlayModel.setUrgentCount(recordAction,
                                                 checked ? -1 : 0)
@@ -397,27 +403,29 @@ Control {
             icon.source: JamiResources.plugins_24dp_svg
             icon.color: "white"
             text: JamiStrings.viewPlugin
-            enabled: PluginAdapter.isEnabled && PluginAdapter.callMediaHandlersListCount
+            enabled: PluginAdapter.isEnabled
+                     && PluginAdapter.callMediaHandlersListCount
         }
     ]
 
     property var overflowItemCount
 
     Connections {
-        target: callOverlay
+        target: CurrentCall
 
-        function onIsAudioOnlyChanged() { Qt.callLater(reset) }
-        function onIsSIPChanged() { Qt.callLater(reset) }
+        function onIsActiveChanged() { if (CurrentCall.isActive) reset() }
+        function onIsRecordingLocallyChanged() { Qt.callLater(reset) }
+        function onIsHandRaisedChanged() { Qt.callLater(reset) }
+        function onIsConferenceChanged() { Qt.callLater(reset) }
         function onIsModeratorChanged() { Qt.callLater(reset) }
+        function onIsSIPChanged() { Qt.callLater(reset) }
+        function onIsAudioOnlyChanged() { Qt.callLater(reset) }
         function onIsAudioMutedChanged() { Qt.callLater(reset) }
         function onIsVideoMutedChanged() { Qt.callLater(reset) }
-        function onIsRecordingChanged() { Qt.callLater(reset) }
-        function onLocalHandRaisedChanged() { Qt.callLater(reset) }
-        function onIsConferenceChanged() { Qt.callLater(reset) }
     }
+
     Connections {
         target: CurrentAccount
-
         function onVideoEnabledVideoChanged() { reset() }
     }
 
@@ -433,29 +441,24 @@ Control {
 
         // overflow controls
         CallOverlayModel.addSecondaryControl(audioOutputAction)
-        if (isConference) {
+        if (CurrentCall.isConference) {
             CallOverlayModel.addSecondaryControl(raiseHandAction)
-            raiseHandAction.checked = CallAdapter.isHandRaised()
         }
-        if (isModerator && !isSIP)
+        if (CurrentCall.isModerator && !CurrentCall.isSIP)
             CallOverlayModel.addSecondaryControl(addPersonAction)
-        if (isSIP) {
+        if (CurrentCall.isSIP) {
             CallOverlayModel.addSecondaryControl(resumePauseCallAction)
             CallOverlayModel.addSecondaryControl(inputPanelSIPAction)
             CallOverlayModel.addSecondaryControl(callTransferAction)
         }
         CallOverlayModel.addSecondaryControl(chatAction)
-        if (CurrentAccount.videoEnabled_Video)
+        if (CurrentAccount.videoEnabled_Video && !CurrentCall.isSIP)
             CallOverlayModel.addSecondaryControl(shareAction)
         CallOverlayModel.addSecondaryControl(layoutAction)
         CallOverlayModel.addSecondaryControl(recordAction)
         if (pluginsAction.enabled)
             CallOverlayModel.addSecondaryControl(pluginsAction)
         overflowItemCount = CallOverlayModel.secondaryModel().rowCount()
-
-        muteAudioAction.checked = isAudioMuted
-        recordAction.checked = CallAdapter.isRecordingThisCall()
-        muteVideoAction.checked = isAudioOnly ? true : isVideoMuted
     }
 
     Item {
diff --git a/src/app/mainview/components/CallButtonDelegate.qml b/src/app/mainview/components/CallButtonDelegate.qml
index d6650188649957799e63b63bb3b4b25e4559131c..2e72489084a747e210904194349feb39e8a48acc 100644
--- a/src/app/mainview/components/CallButtonDelegate.qml
+++ b/src/app/mainview/components/CallButtonDelegate.qml
@@ -39,6 +39,7 @@ ItemDelegate {
 
     action: ItemAction
     checkable: ItemAction.checkable
+    hoverEnabled: ItemAction.enabled
 
     // hide the action's visual elements like the blurry looking icon
     icon.source: ""
@@ -122,7 +123,11 @@ ItemDelegate {
 
         anchors.centerIn: parent
         source: ItemAction ? ItemAction.icon.source : ""
-        color: ItemAction ? ItemAction.icon.color : null
+        color: ItemAction ?
+                   (ItemAction.enabled ?
+                       ItemAction.icon.color :
+                       Qt.lighter(ItemAction.icon.color)) :
+                   null
 
         SequentialAnimation on opacity {
             loops: Animation.Infinite
@@ -172,7 +177,8 @@ ItemDelegate {
 
         indicator: null
 
-        visible: menuAction !== undefined && !UrgentCount && menuAction.enabled
+        visible: ItemAction.enabled
+                 && menuAction !== undefined && !UrgentCount && menuAction.enabled
 
         y: isVertical ? 0 : -4
         x: isVertical ? -4 : 0
diff --git a/src/app/mainview/components/CallOverlay.qml b/src/app/mainview/components/CallOverlay.qml
index ad4fab6dda30d31dc423b1139464caf3a12012f3..1a869aa110a3763db25c60c25206725d49dd5ffd 100644
--- a/src/app/mainview/components/CallOverlay.qml
+++ b/src/app/mainview/components/CallOverlay.qml
@@ -35,48 +35,11 @@ import "../../commoncomponents"
 Item {
     id: root
 
-    property bool isPaused
-    property bool isAudioOnly
-    property bool isAudioMuted
-    property bool isVideoMuted
-    property bool isRecording
-    property bool remoteRecording
-    property bool isSIP
-    property bool isModerator
-    property bool isConference
-    property bool isGrid
     property bool participantsSide: UtilsAdapter.getAppValue(Settings.ParticipantsSide)
-    property bool localHandRaised
-    property bool sharingActive: AvAdapter.isSharing()
-    property string callId: ""
 
     signal chatButtonClicked
     signal fullScreenClicked
 
-    function setRecording(localIsRecording) {
-        callViewContextMenu.localIsRecording = localIsRecording
-        mainOverlay.recordingVisible = localIsRecording
-                || callViewContextMenu.peerIsRecording
-    }
-
-    function updateUI(isPaused, isAudioOnly, isAudioMuted, isSIP, isGrid) {
-        if (isPaused !== undefined) {
-            root.isPaused = isPaused
-            root.isAudioOnly = isAudioOnly
-            root.isAudioMuted = isAudioMuted
-            callViewContextMenu.isVideoMuted = root.isVideoMuted
-            root.isSIP = isSIP
-            root.isGrid = isGrid
-            root.localHandRaised = CallAdapter.isHandRaised()
-        }
-        root.isRecording = CallAdapter.isRecordingThisCall()
-        root.isModerator = CallAdapter.isModerator()
-    }
-
-    function showOnHoldImage(visible) {
-        onHoldImage.visible = visible
-    }
-
     function closeContextMenuAndRelatedWindows() {
         ContactPickerCreation.closeContactPicker()
         sipInputPanel.close()
@@ -94,29 +57,6 @@ Item {
         callViewContextMenu.openMenu()
     }
 
-    function showRemoteRecording(peers, state) {
-        var label = ""
-        var i = 0
-        if (state) {
-            for (var p in peers) {
-                label += peers[p]
-                if (i !== (peers.length - 1))
-                    label += ", "
-                i += 1
-            }
-            label += " " + ((peers.length > 1) ? JamiStrings.areRecording : JamiStrings.isRecording)
-        }
-
-        mainOverlay.remoteRecordingLabel = state ? label : JamiStrings.peerStoppedRecording
-        root.remoteRecording = state
-        callOverlayRectMouseArea.entered()
-    }
-
-    function resetRemoteRecording() {
-        mainOverlay.remoteRecordingLabel = ""
-        root.remoteRecording = false
-    }
-
     DropArea {
         anchors.fill: parent
         onDropped: function(drop) {
@@ -158,7 +98,7 @@ Item {
         width: 200
         height: 200
 
-        visible: false
+        visible: CurrentCall.isPaused
 
         source: JamiResources.ic_pause_white_100px_svg
     }
@@ -199,17 +139,10 @@ Item {
         PluginHandlerPickerCreation.openPluginHandlerPicker()
     }
 
-    function recordClicked() {
-        CallAdapter.recordThisCallToggle()
-        updateUI()
-    }
-
     MainOverlay {
         id: mainOverlay
 
         anchors.fill: parent
-        isRecording: root.isRecording
-        remoteRecording: root.remoteRecording
 
         Connections {
             target: mainOverlay.callActionBar
@@ -222,7 +155,7 @@ Item {
             function onShareWindowClicked() { openShareWindow() }
             function onStopSharingClicked() { AvAdapter.stopSharing() }
             function onShareScreenAreaClicked() { openShareScreenArea() }
-            function onRecordCallClicked() { recordClicked() }
+            function onRecordCallClicked() { CallAdapter.recordThisCallToggle() }
             function onShareFileClicked() { jamiFileDialog.open() }
             function onPluginsClicked() { openPluginsMenu() }
             function onFullScreenClicked() { root.fullScreenClicked() }
@@ -232,13 +165,9 @@ Item {
     CallViewContextMenu {
         id: callViewContextMenu
 
-        isSIP: root.isSIP
-        isPaused: root.isPaused
-        isRecording: root.isRecording
-
         onTransferCallButtonClicked: openContactPicker(ContactList.TRANSFER)
         onPluginItemClicked: openPluginsMenu()
-        onRecordCallClicked: root.recordClicked()
+        onRecordCallClicked: CallAdapter.recordThisCallToggle()
         onOpenSelectionWindow: {
             SelectScreenWindowCreation.createSelectScreenWindowObject(appWindow)
             SelectScreenWindowCreation.showSelectScreenWindow(callPreviewId, windowSelection)
diff --git a/src/app/mainview/components/CallStackView.qml b/src/app/mainview/components/CallStackView.qml
index 98d58627d83d80c3552b78d2994401801ebeb129..b4e74bbf1683938bbb60b98ec0d8bf07591ae898 100644
--- a/src/app/mainview/components/CallStackView.qml
+++ b/src/app/mainview/components/CallStackView.qml
@@ -28,7 +28,6 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    property bool isAudioOnly: false
     property var sipKeys: [
         "1", "2", "3", "A",
         "4", "5", "6", "B",
@@ -123,13 +122,6 @@ Rectangle {
     Connections {
         target: CallAdapter
 
-        function onCallInfosChanged(audioOnly, accountId, convUid) {
-            if (callStackMainView.currentItem.stackNumber === CallStackView.OngoingPageStack
-                    && responsibleConvUid === convUid && responsibleAccountId === accountId) {
-                ongoingCallPage.isAudioOnly = audioOnly
-            }
-        }
-
         function onCallStatusChanged(status, accountId, convUid) {
             if (callStackMainView.currentItem.stackNumber === CallStackView.InitialPageStack
                     && responsibleConvUid === convUid && responsibleAccountId === accountId) {
@@ -143,8 +135,6 @@ Rectangle {
 
         property int stackNumber: CallStackView.OngoingPageStack
 
-        isAudioOnly: root.isAudioOnly
-
         visible: callStackMainView.currentItem.stackNumber === stackNumber
     }
 
@@ -153,8 +143,6 @@ Rectangle {
 
         property int stackNumber: CallStackView.InitialPageStack
 
-        isAudioOnly: root.isAudioOnly
-
         onCallAccepted: {
             CallAdapter.acceptACall(responsibleAccountId, responsibleConvUid)
             mainViewSidePanel.selectTab(SidePanelTabBar.Conversations)
diff --git a/src/app/mainview/components/CallViewContextMenu.qml b/src/app/mainview/components/CallViewContextMenu.qml
index 1b8e86c42ccb6c5f0890aab2cfc938c65fec1d3d..733178729a6be6c27cbd0346576af50f6dfc9bac 100644
--- a/src/app/mainview/components/CallViewContextMenu.qml
+++ b/src/app/mainview/components/CallViewContextMenu.qml
@@ -31,11 +31,6 @@ import "../js/screenrubberbandcreation.js" as ScreenRubberBandCreation
 ContextMenuAutoLoader {
     id: root
 
-    property bool isSIP: false
-    property bool isPaused: false
-    property bool isVideoMuted: false
-    property bool isRecording: false
-
     property bool windowSelection: false
 
     signal pluginItemClicked
@@ -47,9 +42,11 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: resumePauseCall
 
-            canTrigger: isSIP
-            itemName: isPaused ? JamiStrings.resumeCall : JamiStrings.pauseCall
-            iconSource: isPaused ?
+            canTrigger: CurrentCall.isSIP
+            itemName: CurrentCall.isPaused ?
+                          JamiStrings.resumeCall :
+                          JamiStrings.pauseCall
+            iconSource: CurrentCall.isPaused ?
                             JamiResources.play_circle_outline_24dp_svg :
                             JamiResources.pause_circle_outline_24dp_svg
             onClicked: {
@@ -59,7 +56,7 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: inputPanelSIP
 
-            canTrigger: isSIP
+            canTrigger: CurrentCall.isSIP
             itemName: JamiStrings.sipInputPanel
             iconSource: JamiResources.ic_keypad_svg
             onClicked: {
@@ -69,10 +66,10 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: callTransfer
 
-            canTrigger: isSIP
+            canTrigger: CurrentCall.isSIP
             itemName: JamiStrings.transferCall
             iconSource: JamiResources.phone_forwarded_24dp_svg
-            addMenuSeparatorAfter: isSIP
+            addMenuSeparatorAfter: CurrentCall.isSIP
             onClicked: {
                 root.transferCallButtonClicked()
             }
@@ -80,7 +77,9 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: localRecord
 
-            itemName: root.isRecording ? JamiStrings.stopRec : JamiStrings.startRec
+            itemName: CurrentCall.isRecordingLocally ?
+                          JamiStrings.stopRec :
+                          JamiStrings.startRec
             iconSource: JamiResources.fiber_manual_record_24dp_svg
             iconColor: JamiTheme.recordIconColor
             onClicked: {
@@ -103,8 +102,9 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: stopSharing
 
-            canTrigger: AvAdapter.isSharing()
-                        && !isSIP && !isVideoMuted
+            canTrigger: CurrentCall.isSharing
+                        && !CurrentCall.isSIP
+                        && !CurrentCall.isVideoMuted
             itemName: JamiStrings.stopSharing
             iconSource: JamiResources.share_stop_black_24dp_svg
             iconColor: JamiTheme.redColor
@@ -113,8 +113,9 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: shareScreen
 
-            canTrigger: CurrentAccount.videoEnabled_Video && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
-                        && !isSIP
+            canTrigger: CurrentAccount.videoEnabled_Video
+                        && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
+                        && !CurrentCall.isSIP
             itemName: JamiStrings.shareScreen
             iconSource: JamiResources.laptop_black_24dp_svg
             onClicked: {
@@ -129,8 +130,10 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: shareWindow
 
-            canTrigger: Qt.platform.os === "linux" && CurrentAccount.videoEnabled_Video && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
-                        && !isSIP
+            canTrigger: Qt.platform.os === "linux"
+                        && CurrentAccount.videoEnabled_Video
+                        && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
+                        && !CurrentCall.isSIP
             itemName: JamiStrings.shareWindow
             iconSource: JamiResources.window_black_24dp_svg
             onClicked: {
@@ -144,8 +147,9 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: shareScreenArea
 
-            canTrigger: CurrentAccount.videoEnabled_Video && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
-                        && !isSIP
+            canTrigger: CurrentAccount.videoEnabled_Video
+                        && AvAdapter.currentRenderingDeviceType !== Video.DeviceType.DISPLAY
+                        && !CurrentCall.isSIP
             itemName: JamiStrings.shareScreenArea
             iconSource: JamiResources.share_area_black_24dp_svg
             onClicked: {
@@ -160,7 +164,8 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: shareFile
 
-            canTrigger: CurrentAccount.videoEnabled_Video && !isSIP
+            canTrigger: CurrentAccount.videoEnabled_Video
+                        && !CurrentCall.isSIP
             itemName: JamiStrings.shareFile
             iconSource: JamiResources.file_black_24dp_svg
             onClicked: {
@@ -170,7 +175,8 @@ ContextMenuAutoLoader {
         GeneralMenuItem {
             id: viewPlugin
 
-            canTrigger: PluginAdapter.isEnabled && PluginAdapter.callMediaHandlersListCount
+            canTrigger: PluginAdapter.isEnabled &&
+                        PluginAdapter.callMediaHandlersListCount
             itemName: JamiStrings.viewPlugin
             iconSource: JamiResources.extension_24dp_svg
             onClicked: {
diff --git a/src/app/mainview/components/InitialCallPage.qml b/src/app/mainview/components/InitialCallPage.qml
index cf8dd9b0dbd6e0f4ccb93b1ee315be49e6d0c0e2..ca5eca44cf67307bd1419fc46889b5b1a3337a1a 100644
--- a/src/app/mainview/components/InitialCallPage.qml
+++ b/src/app/mainview/components/InitialCallPage.qml
@@ -31,7 +31,7 @@ Rectangle {
     id: root
 
     property bool isIncoming: false
-    property bool isAudioOnly: false
+    property bool isAudioOnly: CurrentCall.isAudioOnly
     property int callStatus: 0
 
     signal callCanceled
diff --git a/src/app/mainview/components/MainOverlay.qml b/src/app/mainview/components/MainOverlay.qml
index 7ecedde7c0c6f2626ff678c7d21f85e301b1b04d..78129d9af22f8ba7eaf9d1a0ecd3ad9a27034ec1 100644
--- a/src/app/mainview/components/MainOverlay.qml
+++ b/src/app/mainview/components/MainOverlay.qml
@@ -32,7 +32,21 @@ Item {
     id: root
 
     property string timeText: "00:00"
-    property string remoteRecordingLabel: ""
+    property string remoteRecordingLabel
+
+    Connections {
+        target: CurrentCall
+
+        function onIsRecordingRemotelyChanged() {
+            var label = ""
+            if (CurrentCall.isRecordingRemotely) {
+                label = CurrentCall.remoteRecorderNameList.join(", ") + " "
+                label += (CurrentCall.remoteRecorderNameList.length > 1) ?
+                            JamiStrings.areRecording : JamiStrings.isRecording
+            }
+            root.remoteRecordingLabel = label
+        }
+    }
 
     property alias callActionBar: __callActionBar
 
@@ -43,8 +57,6 @@ Item {
 
     property string muteAlertMessage: ""
     property bool muteAlertActive: false
-    property bool remoteRecording: false
-    property bool isRecording: false
 
     onMuteAlertActiveChanged: {
         if (muteAlertActive) {
@@ -117,7 +129,7 @@ Item {
             root.timeText = CallAdapter.getCallDurationTime(
                         LRCInstance.currentAccountId,
                         LRCInstance.selectedConvUid)
-            if (root.opacity === 0 && !root.remoteRecording)
+            if (root.opacity === 0 && !CurrentCall.isRecordingRemotely)
                 root.remoteRecordingLabel = ""
         }
     }
@@ -149,11 +161,11 @@ Item {
 
                 font.pointSize: JamiTheme.textFontSize
                 text: {
-                    if (!root.isAudioOnly) {
-                        if (remoteRecordingLabel === "") {
+                    if (!CurrentCall.isAudioOnly) {
+                        if (root.remoteRecordingLabel === "") {
                             return CurrentConversation.title
                         } else {
-                            return remoteRecordingLabel
+                            return root.remoteRecordingLabel
                         }
                     }
                     return ""
@@ -180,7 +192,7 @@ Item {
 
             Rectangle {
                 id: recordingRect
-                visible: root.isRecording || root.remoteRecording
+                visible: CurrentCall.isRecordingLocally || CurrentCall.isRecordingRemotely
 
                 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
                 Layout.rightMargin: JamiTheme.preferredMarginSize
diff --git a/src/app/mainview/components/OngoingCallPage.qml b/src/app/mainview/components/OngoingCallPage.qml
index 93e0b2434646bf048705b3a1fe233d824018e65c..a1adc306b8671238f369bed67b9527f89c84cf16 100644
--- a/src/app/mainview/components/OngoingCallPage.qml
+++ b/src/app/mainview/components/OngoingCallPage.qml
@@ -42,9 +42,8 @@ Rectangle {
     property int previewMarginYBottom: previewMargin + 84
     property int previewToX: 0
     property int previewToY: 0
-    property bool isAudioOnly: false
     property var linkedWebview: null
-    property string callPreviewId: ""
+    property string callPreviewId
 
     onCallPreviewIdChanged: {
         controlPreview.start()
@@ -56,8 +55,6 @@ Rectangle {
         if (accountPeerPair[0] === "" || accountPeerPair[1] === "")
             return
         contactImage.imageId = accountPeerPair[1]
-        distantRenderer.rendererId = UtilsAdapter.getCallId(accountPeerPair[0],
-                                             accountPeerPair[1])
     }
 
     function setLinkedWebview(webViewId) {
@@ -68,7 +65,6 @@ Rectangle {
                     closeInCallConversation)
     }
 
-
     Connections {
         target: UtilsAdapter
 
@@ -178,11 +174,12 @@ Rectangle {
             VideoView {
                 id: distantRenderer
 
+                rendererId: CurrentCall.id
                 anchors.centerIn: parent
                 anchors.fill: parent
                 z: -1
 
-                visible: participantsLayer.count === 0 && !root.isAudioOnly
+                visible: !CurrentCall.isConference && !CurrentCall.isAudioOnly
             }
 
             ParticipantsLayer {
@@ -190,17 +187,16 @@ Rectangle {
                 anchors.fill: parent
                 anchors.centerIn: parent
                 anchors.margins: 1
-                visible: participantsLayer.count !== 0
+                visible: CurrentCall.isConference
                 participantsSide: callOverlay.participantsSide
-
-                onCountChanged: {
-                    callOverlay.isConference = participantsLayer.count > 0
-                }
             }
 
             LocalVideo {
                 id: previewRenderer
 
+                visible: (CurrentCall.isSharing || !CurrentCall.isVideoMuted)
+                         && !CurrentCall.isConference
+
                 height: width * invAspectRatio
                 width: Math.max(callPageMainRect.width / 5, JamiTheme.minimumPreviewWidth)
                 x: callPageMainRect.width - previewRenderer.width - previewMargin
@@ -217,6 +213,7 @@ Rectangle {
                         previewRenderer.startWithId(rendId)
                     }
                 }
+
                 onVisibleChanged: {
                     controlPreview.stop()
                     if (visible) {
@@ -297,7 +294,6 @@ Rectangle {
                 id: callOverlay
 
                 anchors.fill: parent
-                isConference: participantsLayer.count > 0
 
                 function toggleConversation() {
                     if (inCallMessageWebViewStack.visible)
@@ -307,35 +303,19 @@ Rectangle {
                 }
 
                 Connections {
-                    target: CallAdapter
-
-                    function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted,
-                                             isSIP, isGrid, previewId) {
-                        root.callPreviewId = previewId
-                        callOverlay.showOnHoldImage(isPaused)
-                        root.isAudioOnly = isAudioOnly
-                        callOverlay.showOnHoldImage(isPaused)
-                        audioCallPageRectCentralRect.visible = !isPaused && root.isAudioOnly && participantsLayer.count === 0
-                        callOverlay.updateUI(isPaused, isAudioOnly,
-                                             isAudioMuted,
-                                             isSIP,
-                                             isGrid)
-                        callOverlay.isVideoMuted = !AvAdapter.isCapturing()
-                        callOverlay.sharingActive = AvAdapter.isSharing()
-                        previewRenderer.visible = (AvAdapter.isSharing() || AvAdapter.isCapturing()) && participantsLayer.count == 0
-                    }
-
-                    function onShowOnHoldLabel(isPaused) {
-                        callOverlay.showOnHoldImage(isPaused)
-                        audioCallPageRectCentralRect.visible = !isPaused && root.isAudioOnly && participantsLayer.count === 0
-                    }
-
-                    function onRemoteRecordingChanged(label, state) {
-                        callOverlay.showRemoteRecording(label, state)
-                    }
-
-                    function onEraseRemoteRecording() {
-                        callOverlay.resetRemoteRecording()
+                    target: CurrentCall
+
+                    function onPreviewIdChanged() {
+                        if (CurrentCall.previewId !== "") {
+                            if (root.callPreviewId !== "" &&
+                                    root.callPreviewId !== CurrentCall.previewId) {
+                                VideoDevices.stopDevice(root.callPreviewId)
+                            }
+                            VideoDevices.startDevice(CurrentCall.previewId)
+                        } else {
+                            VideoDevices.stopDevice(root.callPreviewId)
+                        }
+                        root.callPreviewId = CurrentCall.previewId
                     }
                 }
 
@@ -367,7 +347,9 @@ Rectangle {
                 anchors.left: parent.left
                 anchors.right: parent.right
 
-                visible: root.isAudioOnly
+                visible: !CurrentCall.isPaused &&
+                         CurrentCall.isAudioOnly &&
+                         !CurrentCall.isConference
 
                 ConversationAvatar {
                     id: contactImage
diff --git a/src/app/mainview/components/PluginHandlerPicker.qml b/src/app/mainview/components/PluginHandlerPicker.qml
index 0270d8fd92e8305c553cc6e42d36e5134d0c4205..b5f5c0170040d3256c365f5543928d2abf38bcad 100644
--- a/src/app/mainview/components/PluginHandlerPicker.qml
+++ b/src/app/mainview/components/PluginHandlerPicker.qml
@@ -58,7 +58,7 @@ Popup {
                 function onAboutToShow(visible) {
                     // Reset the model on each show.
                     if (isCall) {
-                        pluginhandlerPickerListView.model = PluginAdapter.getMediaHandlerSelectableModel(CurrentConversation.callId)
+                        pluginhandlerPickerListView.model = PluginAdapter.getMediaHandlerSelectableModel(CurrentCall.id)
                     } else {
                         var peerId = CurrentConversation.isSwarm ? CurrentConversation.id : CurrentConversation.uris[0]
                         pluginhandlerPickerListView.model = PluginAdapter.getChatHandlerSelectableModel(LRCInstance.currentAccountId, peerId)
@@ -68,8 +68,8 @@ Popup {
 
             function toggleHandlerSlot(handlerId, isLoaded) {
                 if (isCall) {
-                    PluginModel.toggleCallMediaHandler(handlerId, CurrentConversation.callId, !isLoaded)
-                    pluginhandlerPickerListView.model = PluginAdapter.getMediaHandlerSelectableModel(CurrentConversation.callId)
+                    PluginModel.toggleCallMediaHandler(handlerId, CurrentCall.id, !isLoaded)
+                    pluginhandlerPickerListView.model = PluginAdapter.getMediaHandlerSelectableModel(CurrentCall.id)
                 } else {
                     var accountId = LRCInstance.currentAccountId
                     var peerId = CurrentConversation.isSwarm ? CurrentConversation.id : CurrentConversation.uris[0]
@@ -125,7 +125,7 @@ Popup {
 
                     model: {
                         if (isCall) {
-                            return PluginAdapter.getMediaHandlerSelectableModel(CurrentConversation.callId)
+                            return PluginAdapter.getMediaHandlerSelectableModel(CurrentCall.id)
                         } else {
                             var peerId = CurrentConversation.isSwarm ? CurrentConversation.id : CurrentConversation.uris[0]
                             return PluginAdapter.getChatHandlerSelectableModel(LRCInstance.currentAccountId, peerId)
diff --git a/src/app/qmlregister.cpp b/src/app/qmlregister.cpp
index 6a57fe61c88cc043ae55d2e7256f9b02a2ffd589..2359c8014effef0f3ecbe264506eac2950db02bc 100644
--- a/src/app/qmlregister.cpp
+++ b/src/app/qmlregister.cpp
@@ -29,6 +29,7 @@
 #include "previewengine.h"
 #include "utilsadapter.h"
 #include "conversationsadapter.h"
+#include "currentcall.h"
 #include "currentconversation.h"
 #include "currentaccount.h"
 #include "videodevices.h"
@@ -118,6 +119,7 @@ registerTypes(QQmlEngine* engine,
     auto accountAdapter = new AccountAdapter(settingsManager, systemTray, lrcInstance, parent);
     auto utilsAdapter = new UtilsAdapter(settingsManager, systemTray, lrcInstance, parent);
     auto pluginAdapter = new PluginAdapter(lrcInstance, parent);
+    auto currentCall = new CurrentCall(lrcInstance, parent);
     auto currentConversation = new CurrentConversation(lrcInstance, parent);
     auto currentAccount = new CurrentAccount(lrcInstance, settingsManager, parent);
     auto tipsModel = new TipsModel(settingsManager, parent);
@@ -135,6 +137,7 @@ registerTypes(QQmlEngine* engine,
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, accountAdapter, "AccountAdapter");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, utilsAdapter, "UtilsAdapter");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, pluginAdapter, "PluginAdapter");
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentCall, "CurrentCall");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentConversation, "CurrentConversation");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, currentAccount, "CurrentAccount");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, videoDevices, "VideoDevices");
diff --git a/src/libclient/api/call.h b/src/libclient/api/call.h
index 6f117a42d2f8e27d28c9b89b4ac2eec9b4426a86..99196736f398ab478cb62dfa9e1cf4ffc6c24c40 100644
--- a/src/libclient/api/call.h
+++ b/src/libclient/api/call.h
@@ -139,7 +139,7 @@ struct Info
     bool isAudioOnly = false;
     Layout layout = Layout::GRID;
     VectorMapStringString mediaList = {};
-    QSet<QString> peerRec {};
+    QStringList recordingPeers {};
 
     bool hasMediaWithType(const QString& type, const QString& mediaType) const
     {
diff --git a/src/libclient/api/callmodel.h b/src/libclient/api/callmodel.h
index e635617e56542f9584af447227c0894779d4ec2d..2103a81611d49fddf2b56cf643a917fe16d4c1d2 100644
--- a/src/libclient/api/callmodel.h
+++ b/src/libclient/api/callmodel.h
@@ -429,7 +429,7 @@ Q_SIGNALS:
      * Emitted when the rendered image changed
      * @param confId
      */
-    void onParticipantsChanged(const QString& confId) const;
+    void participantsChanged(const QString& confId) const;
     /**
      * Emitted when a call starts
      * @param callId
@@ -469,15 +469,19 @@ Q_SIGNALS:
                          int urgentCount) const;
 
     /**
-     * Listen from CallbacksHandler when the peer start recording
+     * Provides notification of a new set of recording peers once a change has occured,
+     * in the form of a list, as QSet<QString> is not directly QML compatible.
      * @param callId
-     * @param contactId
-     * @param peerName
-     * @param state the new state
+     * @param recorders
      */
-    void remoteRecordingChanged(const QString& callId,
-                                const QSet<QString>& peerRec,
-                                bool state) const;
+    void remoteRecordersChanged(const QString& callId, const QStringList& recorders) const;
+
+    /**
+     * Provides notification of change in the local call recording state.,
+     * @param callId
+     * @param state
+     */
+    void recordingStateChanged(const QString& callId, bool state) const;
 
     /*!
      * Emitted before new pending conferences are inserted into the underlying list
@@ -504,6 +508,11 @@ Q_SIGNALS:
      */
     void callInfosChanged(const QString& accountId, const QString& callId) const;
 
+    /**
+     * Emit currentCallChanged
+     */
+    void currentCallChanged(const QString& callId) const;
+
 private:
     std::unique_ptr<CallModelPimpl> pimpl_;
 };
diff --git a/src/libclient/callbackshandler.cpp b/src/libclient/callbackshandler.cpp
index 5ef8c3e9547b90c7f6c43103a301d822abde8153..b7b29606b0d3512cee498b023e4958de701871b1 100644
--- a/src/libclient/callbackshandler.cpp
+++ b/src/libclient/callbackshandler.cpp
@@ -201,6 +201,12 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
             &CallbacksHandler::slotConferenceChanged,
             Qt::QueuedConnection);
 
+    connect(&CallManager::instance(),
+            &CallManagerInterface::recordingStateChanged,
+            this,
+            &CallbacksHandler::recordingStateChanged,
+            Qt::QueuedConnection);
+
     connect(&CallManager::instance(),
             &CallManagerInterface::incomingMessage,
             this,
@@ -572,6 +578,12 @@ CallbacksHandler::slotConferenceCreated(const QString& accountId, const QString&
     Q_EMIT conferenceCreated(accountId, callId);
 }
 
+void
+CallbacksHandler::slotConferenceRemoved(const QString& accountId, const QString& callId)
+{
+    Q_EMIT conferenceRemoved(accountId, callId);
+}
+
 void
 CallbacksHandler::slotConferenceChanged(const QString& accountId,
                                         const QString& callId,
@@ -581,12 +593,6 @@ CallbacksHandler::slotConferenceChanged(const QString& accountId,
     slotCallStateChanged(accountId, callId, state, 0);
 }
 
-void
-CallbacksHandler::slotConferenceRemoved(const QString& accountId, const QString& callId)
-{
-    Q_EMIT conferenceRemoved(accountId, callId);
-}
-
 void
 CallbacksHandler::slotAccountMessageStatusChanged(const QString& accountId,
                                                   const QString& conversationId,
diff --git a/src/libclient/callbackshandler.h b/src/libclient/callbackshandler.h
index cc6cdf3ab65478f583a2a3448fd58922c74f7fb8..72eec60b243b7e786c7a74d02ab39f676dc20908 100644
--- a/src/libclient/callbackshandler.h
+++ b/src/libclient/callbackshandler.h
@@ -377,6 +377,7 @@ Q_SIGNALS:
     void conversationPreferencesUpdated(const QString& accountId,
                                         const QString& conversationId,
                                         const MapStringString& preferences);
+    void recordingStateChanged(const QString& callId, bool state);
 
     /**
      * Emitted when a conversation receives a new position
diff --git a/src/libclient/callmodel.cpp b/src/libclient/callmodel.cpp
index 8e2de9284e4539b9971b7de3403de4b0ee846b0a..c4e454ca403fea6c4760e772e1a6abae638057ee 100644
--- a/src/libclient/callmodel.cpp
+++ b/src/libclient/callmodel.cpp
@@ -259,9 +259,16 @@ public Q_SLOTS:
     /**
      * Listen from CallbacksHandler when the peer start recording
      * @param callId
+     * @param peerUri
      * @param state the new state
      */
-    void remoteRecordingChanged(const QString& callId, const QString& peerNumber, bool state);
+    void onRemoteRecordingChanged(const QString& callId, const QString& peerUri, bool state);
+    /**
+     * Listen from CallbacksHandler when we start/stop recording
+     * @param callId
+     * @param state the new state
+     */
+    void onRecordingStateChanged(const QString& callId, bool state);
 };
 
 CallModel::CallModel(const account::Info& owner,
@@ -382,7 +389,7 @@ CallModel::createCall(const QString& uri, bool isAudioOnly, VectorMapStringStrin
     }
 #ifdef ENABLE_LIBWRAP
     auto callId = CallManager::instance().placeCallWithMedia(owner.id, uri, mediaList);
-#else  // dbus
+#else // dbus
     // do not use auto here (QDBusPendingReply<QString>)
     QString callId = CallManager::instance().placeCallWithMedia(owner.id, uri, mediaList);
 #endif // ENABLE_LIBWRAP
@@ -975,7 +982,11 @@ CallModelPimpl::CallModelPimpl(const CallModel& linked,
     connect(&callbacksHandler,
             &CallbacksHandler::remoteRecordingChanged,
             this,
-            &CallModelPimpl::remoteRecordingChanged);
+            &CallModelPimpl::onRemoteRecordingChanged);
+    connect(&callbacksHandler,
+            &CallbacksHandler::recordingStateChanged,
+            this,
+            &CallModelPimpl::onRecordingStateChanged);
 
 #ifndef ENABLE_LIBWRAP
     // Only necessary with dbus since the daemon runs separately
@@ -1140,7 +1151,7 @@ CallModel::setCurrentCall(const QString& callId) const
         }
 
         if (!lrc::api::Lrc::holdConferences) {
-            return;
+            continue;
         }
         // If the account is the host and it is attached to the conference,
         // then we should hold it.
@@ -1157,6 +1168,8 @@ CallModel::setCurrentCall(const QString& callId) const
             }
         }
     }
+
+    Q_EMIT currentCallChanged(callId);
 }
 
 void
@@ -1599,7 +1612,7 @@ CallModelPimpl::slotOnConferenceInfosUpdated(const QString& confId,
         }
     }
     Q_EMIT linked.callInfosChanged(linked.owner.id, confId);
-    Q_EMIT linked.onParticipantsChanged(confId);
+    Q_EMIT linked.participantsChanged(confId);
 }
 
 bool
@@ -1686,13 +1699,14 @@ CallModelPimpl::sendProfile(const QString& callId)
 }
 
 void
-CallModelPimpl::remoteRecordingChanged(const QString& callId, const QString& peerNumber, bool state)
+CallModelPimpl::onRemoteRecordingChanged(const QString& callId, const QString& peerUri, bool state)
 {
     auto it = calls.find(callId);
-    if (it == calls.end() or not it->second)
+    if (it == calls.end() or !it->second) {
         return;
+    }
 
-    auto uri = peerNumber;
+    auto uri = peerUri;
 
     if (uri.contains("ring:"))
         uri.remove("ring:");
@@ -1701,15 +1715,19 @@ CallModelPimpl::remoteRecordingChanged(const QString& callId, const QString& pee
     if (uri.contains("@ring.dht"))
         uri.remove("@ring.dht");
 
-    // Add peer to peerRec set
-    if (state && not it->second->peerRec.contains(uri))
-        it->second->peerRec.insert(uri);
+    // Add/remove peer to recordingPeers, preventing duplicates.
+    if (state && !it->second->recordingPeers.contains(uri))
+        it->second->recordingPeers.append(uri);
+    else if (!state && it->second->recordingPeers.contains(uri))
+        it->second->recordingPeers.removeAll(uri);
 
-    // remove peer from peerRec set
-    if (!state && it->second->peerRec.contains(uri))
-        it->second->peerRec.remove(uri);
+    Q_EMIT linked.remoteRecordersChanged(callId, it->second->recordingPeers);
+}
 
-    Q_EMIT linked.remoteRecordingChanged(callId, it->second->peerRec, state);
+void
+CallModelPimpl::onRecordingStateChanged(const QString& callId, bool state)
+{
+    Q_EMIT linked.recordingStateChanged(callId, state);
 }
 
 } // namespace lrc