From a126eb69cbd8c0cc7b92bef61df6f5e3798da0ab Mon Sep 17 00:00:00 2001
From: agsantos <aline.gondimsantos@savoirfairelinux.com>
Date: Fri, 15 Oct 2021 11:34:17 -0400
Subject: [PATCH] videoInput: use new api

 - VideoSettings OK
 - PhotoBooth OK
 - Calls - mostly ok, have to test camera unplugin/replugin/multiplecameras
   -> seems to leak, client freezing in calls/conferences
 - Recording - OK

Change-Id: I49362900979d48abf2507ab89fcb261808423445
---
 src/avadapter.cpp                             |  33 +----
 src/avadapter.h                               |   3 -
 src/calladapter.cpp                           |  14 ++-
 src/calladapter.h                             |   3 +-
 src/commoncomponents/PhotoboothView.qml       |   8 +-
 src/distantrenderer.cpp                       |  19 ++-
 src/distantrenderer.h                         |   3 +-
 src/mainview/components/OngoingCallPage.qml   |  25 ++++
 src/mainview/components/RecordBox.qml         |  11 +-
 src/previewrenderer.cpp                       | 119 +++++++++---------
 src/previewrenderer.h                         |   5 +-
 src/rendermanager.cpp                         |  92 +++++---------
 src/rendermanager.h                           |  44 ++-----
 src/settingsview/SettingsView.qml             |   3 -
 src/settingsview/components/VideoSettings.qml |  11 +-
 src/videodevices.cpp                          |  63 +++++++++-
 src/videodevices.h                            |   5 +
 17 files changed, 248 insertions(+), 213 deletions(-)

diff --git a/src/avadapter.cpp b/src/avadapter.cpp
index 9ba43dd7e..541216c33 100644
--- a/src/avadapter.cpp
+++ b/src/avadapter.cpp
@@ -36,18 +36,15 @@
 AvAdapter::AvAdapter(LRCInstance* instance, QObject* parent)
     : QmlAdapterBase(instance, parent)
 {
-    connect(lrcInstance_->renderer(), &RenderManager::previewFrameStarted, [this]() {
-        // TODO: listen to the correct signals that are needed to be added in daemon or lrc
-        auto callId = lrcInstance_->getCurrentCallId();
-        if (!callId.isEmpty())
-            set_currentRenderingDeviceType(
-                lrcInstance_->avModel().getCurrentRenderedDevice(callId).type);
-    });
-
     connect(&lrcInstance_->avModel(),
             &lrc::api::AVModel::audioDeviceEvent,
             this,
             &AvAdapter::onAudioDeviceEvent);
+    connect(&lrcInstance_->avModel(), &lrc::api::AVModel::rendererStarted, [this](const QString&) {
+        auto callId = lrcInstance_->getCurrentCallId();
+        set_currentRenderingDeviceType(
+            lrcInstance_->getCurrentCallModel()->getCurrentRenderedDevice(callId).type);
+    });
 }
 
 // The top left corner of primary screen is (0, 0).
@@ -327,23 +324,3 @@ AvAdapter::setHardwareAcceleration(bool accelerate)
 {
     lrcInstance_->avModel().setHardwareAcceleration(accelerate);
 }
-
-void
-AvAdapter::startPreviewing(bool force)
-{
-    lrcInstance_->renderer()->startPreviewing(force);
-}
-
-void
-AvAdapter::stopPreviewing()
-{
-    if (!lrcInstance_->hasActiveCall(true)) {
-        lrcInstance_->renderer()->stopPreviewing();
-    }
-}
-
-bool
-AvAdapter::isPreviewing()
-{
-    return lrcInstance_->renderer()->isPreviewing();
-}
\ No newline at end of file
diff --git a/src/avadapter.h b/src/avadapter.h
index b4e623411..68e3a893d 100644
--- a/src/avadapter.h
+++ b/src/avadapter.h
@@ -77,9 +77,6 @@ protected:
     // TODO: to be removed
     Q_INVOKABLE bool getHardwareAcceleration();
     Q_INVOKABLE void setHardwareAcceleration(bool accelerate);
-    Q_INVOKABLE bool isPreviewing();
-    Q_INVOKABLE void startPreviewing(bool force = false);
-    Q_INVOKABLE void stopPreviewing();
 
 private Q_SLOTS:
     void onAudioDeviceEvent();
diff --git a/src/calladapter.cpp b/src/calladapter.cpp
index 0ba242ec7..153b7b40d 100644
--- a/src/calladapter.cpp
+++ b/src/calladapter.cpp
@@ -654,6 +654,17 @@ CallAdapter::updateCallOverlay(const lrc::api::conversation::Info& convInfo)
     bool isConferenceCall = !convInfo.confId.isEmpty()
                             || (convInfo.confId.isEmpty() && call->participantsInfos.size() != 0);
     bool isGrid = call->layout == lrc::api::call::Layout::GRID;
+    QString previewId {};
+    if (!isAudioOnly && !isVideoMuted && call->status == lrc::api::call::Status::IN_PROGRESS) {
+        for (const auto& media : call->mediaList) {
+            if (media["MEDIA_TYPE"] == "MEDIA_TYPE_VIDEO") {
+                if (media["ENABLED"] == "true" && media["MUTED"] == "false") {
+                    previewId = media["SOURCE"];
+                    break;
+                }
+            }
+        }
+    }
 
     Q_EMIT updateOverlay(isPaused,
                          isAudioOnly,
@@ -661,7 +672,8 @@ CallAdapter::updateCallOverlay(const lrc::api::conversation::Info& convInfo)
                          isVideoMuted,
                          accInfo.profileInfo.type == lrc::api::profile::Type::SIP,
                          isConferenceCall,
-                         isGrid);
+                         isGrid,
+                         previewId);
 }
 
 void
diff --git a/src/calladapter.h b/src/calladapter.h
index e9f39ba9c..e7ba606a8 100644
--- a/src/calladapter.h
+++ b/src/calladapter.h
@@ -101,7 +101,8 @@ Q_SIGNALS:
                        bool isVideoMuted,
                        bool isSIP,
                        bool isConferenceCall,
-                       bool isGrid);
+                       bool isGrid,
+                       const QString& previewId);
     void remoteRecordingChanged(const QStringList& peers, bool state);
     void eraseRemoteRecording();
 
diff --git a/src/commoncomponents/PhotoboothView.qml b/src/commoncomponents/PhotoboothView.qml
index 80faca19f..bee3ea5cc 100644
--- a/src/commoncomponents/PhotoboothView.qml
+++ b/src/commoncomponents/PhotoboothView.qml
@@ -39,13 +39,14 @@ Item {
     height: boothLayout.height
 
     function startBooth() {
-        AvAdapter.startPreviewing(false)
+        preview.deviceId = VideoDevices.getDefaultDevice()
+        preview.rendererId = VideoDevices.startDevice(preview.deviceId)
         isPreviewing = true
     }
 
     function stopBooth(){
         if (!AccountAdapter.hasVideoCall()) {
-            AvAdapter.stopPreviewing()
+        VideoDevices.stopDevice(preview.deviceId)
         }
         isPreviewing = false
     }
@@ -135,6 +136,9 @@ Item {
                 anchors.fill: parent
                 anchors.margins: 1
 
+                property string deviceId: VideoDevices.getDefaultDevice()
+                rendererId: ""
+
                 visible: isPreviewing
                 lrcInstance: LRCInstance
 
diff --git a/src/distantrenderer.cpp b/src/distantrenderer.cpp
index 8e9e4c250..78f04862b 100644
--- a/src/distantrenderer.cpp
+++ b/src/distantrenderer.cpp
@@ -34,14 +34,14 @@ DistantRenderer::DistantRenderer(QQuickItem* parent)
             connect(lrcInstance_->renderer(),
                     &RenderManager::distantFrameUpdated,
                     [this](const QString& id) {
-                        if (distantRenderId_ == id)
+                        if (rendererId_ == id)
                             update(QRect(0, 0, width(), height()));
                     });
 
             connect(lrcInstance_->renderer(),
                     &RenderManager::distantRenderingStopped,
                     [this](const QString& id) {
-                        if (distantRenderId_ == id)
+                        if (rendererId_ == id)
                             update(QRect(0, 0, width(), height()));
                     });
         }
@@ -53,7 +53,7 @@ DistantRenderer::~DistantRenderer() {}
 void
 DistantRenderer::setRendererId(const QString& id)
 {
-    distantRenderId_ = id;
+    rendererId_ = id;
     // Note: Force a paint to update frame as we change the renderer
     update(QRect(0, 0, width(), height()));
 }
@@ -61,7 +61,16 @@ DistantRenderer::setRendererId(const QString& id)
 QString
 DistantRenderer::rendererId()
 {
-    return distantRenderId_;
+    return rendererId_;
+}
+
+QString
+DistantRenderer::takePhoto(int size)
+{
+    if (auto previewImage = lrcInstance_->renderer()->getPreviewFrame(rendererId_)) {
+        return Utils::byteArrayToBase64String(Utils::QImageToByteArray(previewImage->copy()));
+    }
+    return {};
 }
 
 int
@@ -91,7 +100,7 @@ DistantRenderer::getScaledHeight() const
 void
 DistantRenderer::paint(QPainter* painter)
 {
-    lrcInstance_->renderer()->drawFrame(distantRenderId_, [this, painter](QImage* distantImage) {
+    lrcInstance_->renderer()->drawFrame(rendererId_, [this, painter](QImage* distantImage) {
         if (distantImage) {
             painter->setRenderHint(QPainter::Antialiasing);
             painter->setRenderHint(QPainter::SmoothPixmapTransform);
diff --git a/src/distantrenderer.h b/src/distantrenderer.h
index fef749b3e..ee81afa1b 100644
--- a/src/distantrenderer.h
+++ b/src/distantrenderer.h
@@ -43,6 +43,7 @@ public:
     Q_INVOKABLE int getYOffset() const;
     Q_INVOKABLE double getScaledWidth() const;
     Q_INVOKABLE double getScaledHeight() const;
+    Q_INVOKABLE QString takePhoto(int size);
 
 Q_SIGNALS:
     void offsetChanged();
@@ -58,7 +59,7 @@ private:
     /*
      * Unique DistantRenderId for each call.
      */
-    QString distantRenderId_;
+    QString rendererId_;
     int xOffset_ {0};
     int yOffset_ {0};
     double scaledWidth_ {0};
diff --git a/src/mainview/components/OngoingCallPage.qml b/src/mainview/components/OngoingCallPage.qml
index e3664b299..76b448747 100644
--- a/src/mainview/components/OngoingCallPage.qml
+++ b/src/mainview/components/OngoingCallPage.qml
@@ -42,6 +42,15 @@ Rectangle {
     property bool isAudioOnly: false
     property alias callId: distantRenderer.rendererId
     property var linkedWebview: null
+    property string callPreviewId: ""
+
+    onCallPreviewIdChanged: {
+        testLog("\n\n CHANGING CALLPREVIEWID" + root.callPreviewId + " " + previewRenderer.rendererId + " \n\n")
+    }
+
+    function testLog(txt) {
+        console.log(this, txt)
+    }
 
     color: "black"
 
@@ -182,6 +191,14 @@ Rectangle {
                     visible: !callOverlay.isAudioOnly && !callOverlay.isConferenceCall && !callOverlay.isVideoMuted && !callOverlay.isPaused &&
                              ((VideoDevices.listSize !== 0 && AvAdapter.currentRenderingDeviceType === Video.DeviceType.CAMERA) || AvAdapter.currentRenderingDeviceType !== Video.DeviceType.CAMERA )
 
+                    rendererId: root.callPreviewId
+
+                    onVisibleChanged: {
+                        if (!visible) {
+                            VideoDevices.stopDevice(rendererId, true)
+                        }
+                    }
+
                     width: Math.max(callPageMainRect.width / 5, JamiTheme.minimumPreviewWidth)
                     x: callPageMainRect.width - previewRenderer.width - previewMargin
                     y: previewMarginYTop
@@ -274,6 +291,14 @@ Rectangle {
 
                         function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted,
                                                  isSIP, isConferenceCall, isGrid, previewId) {
+                            if (previewId != "") {
+                                if (root.callPreviewId != previewId)
+                                    VideoDevices.stopDevice(root.callPreviewId, true)
+                                VideoDevices.startDevice(previewId)
+                            } else {
+                                VideoDevices.stopDevice(root.callPreviewId, true)
+                            }
+                            root.callPreviewId = previewId
                             callOverlay.showOnHoldImage(isPaused)
                             root.isAudioOnly = isAudioOnly
                             audioCallPageRectCentralRect.visible = !isPaused && root.isAudioOnly
diff --git a/src/mainview/components/RecordBox.qml b/src/mainview/components/RecordBox.qml
index 9db8100b9..452e1ce87 100644
--- a/src/mainview/components/RecordBox.qml
+++ b/src/mainview/components/RecordBox.qml
@@ -59,7 +59,8 @@ Rectangle {
         updateState(RecordBox.States.INIT)
 
         if (isVideo) {
-            AvAdapter.startPreviewing(false)
+            previewWidget.deviceId = VideoDevices.getDefaultDevice()
+            previewWidget.rendererId = VideoDevices.startDevice(previewWidget.deviceId)
             previewAvailable = true
         }
     }
@@ -79,8 +80,8 @@ Rectangle {
     }
 
     function closeRecorder() {
-        if (isVideo && AvAdapter.isPreviewing()) {
-            AvAdapter.stopPreviewing()
+        if (isVideo) {
+            VideoDevices.stopDevice(previewWidget.deviceId)
         }
         stopRecording()
         visible = false
@@ -104,7 +105,7 @@ Rectangle {
 
     function startRecording() {
         timer.start()
-        pathRecorder = AVModel.startLocalRecorder(!isVideo)
+        pathRecorder = AVModel.startLocalMediaRecorder(VideoDevices.getDefaultDevice())
         if (pathRecorder == "") {
             timer.stop()
         }
@@ -251,6 +252,8 @@ Rectangle {
 
             anchors.fill: rectBox
             anchors.centerIn: rectBox
+            property string deviceId: VideoDevices.getDefaultDevice()
+            rendererId: VideoDevices.getDefaultDevice()
 
             lrcInstance: LRCInstance
 
diff --git a/src/previewrenderer.cpp b/src/previewrenderer.cpp
index 4faad9fa7..34452a1dd 100644
--- a/src/previewrenderer.cpp
+++ b/src/previewrenderer.cpp
@@ -19,8 +19,6 @@
 
 #include "previewrenderer.h"
 
-#include "lrcinstance.h"
-
 PreviewRenderer::PreviewRenderer(QQuickItem* parent)
     : QQuickPaintedItem(parent)
 {
@@ -32,9 +30,9 @@ PreviewRenderer::PreviewRenderer(QQuickItem* parent)
     connect(this, &PreviewRenderer::lrcInstanceChanged, [this] {
         if (lrcInstance_)
             previewFrameUpdatedConnection_ = connect(lrcInstance_->renderer(),
-                                                     &RenderManager::previewFrameUpdated,
-                                                     [this]() {
-                                                         if (isVisible())
+                                                     &RenderManager::distantFrameUpdated,
+                                                     [this](const QString& id) {
+                                                         if (rendererId_ == id && isVisible())
                                                              update(QRect(0, 0, width(), height()));
                                                      });
     });
@@ -48,39 +46,38 @@ PreviewRenderer::~PreviewRenderer()
 void
 PreviewRenderer::paint(QPainter* painter)
 {
-    lrcInstance_->renderer()
-        ->drawFrame(lrc::api::video::PREVIEW_RENDERER_ID, [this, painter](QImage* previewImage) {
-            if (previewImage) {
-                painter->setRenderHint(QPainter::Antialiasing);
-                painter->setRenderHint(QPainter::SmoothPixmapTransform);
-
-                auto aspectRatio = static_cast<qreal>(previewImage->width())
-                                   / static_cast<qreal>(previewImage->height());
-                auto previewHeight = height();
-                auto previewWidth = previewHeight * aspectRatio;
-
-                /* Instead of setting fixed size, we could get an x offset for the preview
-                 * but this would render the horizontal spacers in the parent widget useless.
-                 * e.g.
-                 * auto parent = qobject_cast<QWidget*>(this->parent());
-                 * auto xPos = (parent->width() - previewWidth) / 2;
-                 * setGeometry(QRect(QPoint(xPos, this->pos().y()),
-                 *             QSize(previewWidth, previewHeight)));
-                 */
-                setWidth(previewWidth);
-                setHeight(previewHeight);
-
-                // If the given size is empty, this function returns a null image.
-                QImage scaledPreview;
-                scaledPreview = previewImage->scaled(size().toSize(),
-                                                     Qt::KeepAspectRatio,
-                                                     Qt::SmoothTransformation);
-                painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
-                                   scaledPreview);
-            } else {
-                paintBackground(painter);
-            }
-        });
+    lrcInstance_->renderer()->drawFrame(rendererId_, [this, painter](QImage* previewImage) {
+        if (previewImage) {
+            painter->setRenderHint(QPainter::Antialiasing);
+            painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
+            auto aspectRatio = static_cast<qreal>(previewImage->width())
+                               / static_cast<qreal>(previewImage->height());
+            auto previewHeight = height();
+            auto previewWidth = previewHeight * aspectRatio;
+
+            /* Instead of setting fixed size, we could get an x offset for the preview
+             * but this would render the horizontal spacers in the parent widget useless.
+             * e.g.
+             * auto parent = qobject_cast<QWidget*>(this->parent());
+             * auto xPos = (parent->width() - previewWidth) / 2;
+             * setGeometry(QRect(QPoint(xPos, this->pos().y()),
+             *             QSize(previewWidth, previewHeight)));
+             */
+            setWidth(previewWidth);
+            setHeight(previewHeight);
+
+            // If the given size is empty, this function returns a null image.
+            QImage scaledPreview;
+            scaledPreview = previewImage->scaled(size().toSize(),
+                                                 Qt::KeepAspectRatio,
+                                                 Qt::SmoothTransformation);
+            painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
+                               scaledPreview);
+        } else {
+            paintBackground(painter);
+        }
+    });
 }
 
 void
@@ -103,18 +100,17 @@ VideoCallPreviewRenderer::~VideoCallPreviewRenderer() {}
 void
 VideoCallPreviewRenderer::paint(QPainter* painter)
 {
-    lrcInstance_->renderer()
-        ->drawFrame(lrc::api::video::PREVIEW_RENDERER_ID, [this, painter](QImage* previewImage) {
-            if (previewImage) {
-                auto scalingFactor = static_cast<qreal>(previewImage->height())
-                                     / static_cast<qreal>(previewImage->width());
-                setProperty("previewImageScalingFactor", scalingFactor);
-                QImage scaledPreview;
-                scaledPreview = previewImage->scaled(size().toSize(), Qt::KeepAspectRatio);
-                painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
-                                   scaledPreview);
-            }
-        });
+    lrcInstance_->renderer()->drawFrame(get_rendererId(), [this, painter](QImage* previewImage) {
+        if (previewImage) {
+            auto scalingFactor = static_cast<qreal>(previewImage->height())
+                                 / static_cast<qreal>(previewImage->width());
+            setProperty("previewImageScalingFactor", scalingFactor);
+            QImage scaledPreview;
+            scaledPreview = previewImage->scaled(size().toSize(), Qt::KeepAspectRatio);
+            painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
+                               scaledPreview);
+        }
+    });
 }
 
 PhotoboothPreviewRender::PhotoboothPreviewRender(QQuickItem* parent)
@@ -123,7 +119,7 @@ PhotoboothPreviewRender::PhotoboothPreviewRender(QQuickItem* parent)
     connect(this, &PreviewRenderer::lrcInstanceChanged, [this] {
         if (lrcInstance_)
             connect(lrcInstance_->renderer(),
-                    &RenderManager::previewRenderingStopped,
+                    &RenderManager::distantRenderingStopped,
                     this,
                     &PhotoboothPreviewRender::renderingStopped,
                     Qt::UniqueConnection);
@@ -133,7 +129,7 @@ PhotoboothPreviewRender::PhotoboothPreviewRender(QQuickItem* parent)
 QString
 PhotoboothPreviewRender::takePhoto(int size)
 {
-    if (auto previewImage = lrcInstance_->renderer()->getPreviewFrame()) {
+    if (auto previewImage = lrcInstance_->renderer()->getPreviewFrame(get_rendererId())) {
         return Utils::byteArrayToBase64String(Utils::QImageToByteArray(previewImage->copy()));
     }
     return {};
@@ -144,14 +140,13 @@ PhotoboothPreviewRender::paint(QPainter* painter)
 {
     painter->setRenderHint(QPainter::Antialiasing, true);
 
-    lrcInstance_->renderer()
-        ->drawFrame(lrc::api::video::PREVIEW_RENDERER_ID, [this, painter](QImage* previewImage) {
-            if (previewImage) {
-                QImage scaledPreview;
-                scaledPreview = Utils::getCirclePhoto(*previewImage,
-                                                      height() <= width() ? height() : width());
-                painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
-                                   scaledPreview);
-            }
-        });
+    lrcInstance_->renderer()->drawFrame(get_rendererId(), [this, painter](QImage* previewImage) {
+        if (previewImage) {
+            QImage scaledPreview;
+            scaledPreview = Utils::getCirclePhoto(*previewImage,
+                                                  height() <= width() ? height() : width());
+            painter->drawImage(QRect(0, 0, scaledPreview.width(), scaledPreview.height()),
+                               scaledPreview);
+        }
+    });
 }
diff --git a/src/previewrenderer.h b/src/previewrenderer.h
index d5d91c9c0..e79551d5b 100644
--- a/src/previewrenderer.h
+++ b/src/previewrenderer.h
@@ -21,7 +21,7 @@
 
 #include <QtQuick>
 
-class LRCInstance;
+#include "lrcinstance.h"
 
 /*
  * Use QQuickPaintedItem so that QPainter apis can be used.
@@ -31,6 +31,7 @@ class PreviewRenderer : public QQuickPaintedItem
 {
     Q_OBJECT
     Q_PROPERTY(LRCInstance* lrcInstance MEMBER lrcInstance_ NOTIFY lrcInstanceChanged)
+    QML_PROPERTY(QString, rendererId);
 
 public:
     explicit PreviewRenderer(QQuickItem* parent = nullptr);
@@ -78,7 +79,7 @@ public:
     Q_INVOKABLE QString takePhoto(int size);
 
 Q_SIGNALS:
-    void renderingStopped();
+    void renderingStopped(const QString id);
 
 private:
     void paint(QPainter* painter) override final;
diff --git a/src/rendermanager.cpp b/src/rendermanager.cpp
index c483c786c..87ce91c75 100644
--- a/src/rendermanager.cpp
+++ b/src/rendermanager.cpp
@@ -31,9 +31,7 @@ FrameWrapper::FrameWrapper(AVModel& avModel, const QString& id)
 
 FrameWrapper::~FrameWrapper()
 {
-    if (id_ == video::PREVIEW_RENDERER_ID) {
-        avModel_.stopPreview();
-    }
+    avModel_.stopPreview(id_);
 }
 
 void
@@ -194,65 +192,40 @@ FrameWrapper::slotRenderingStopped(const QString& id)
 
 RenderManager::RenderManager(AVModel& avModel)
     : avModel_(avModel)
-{
-    previewFrameWrapper_ = std::make_unique<FrameWrapper>(avModel_);
-
-    QObject::connect(previewFrameWrapper_.get(),
-                     &FrameWrapper::renderingStarted,
-                     [this](const QString& id) {
-                         Q_UNUSED(id);
-                         Q_EMIT previewFrameStarted();
-                     });
-
-    QObject::connect(previewFrameWrapper_.get(),
-                     &FrameWrapper::frameUpdated,
-                     [this](const QString& id) {
-                         Q_UNUSED(id);
-                         Q_EMIT previewFrameUpdated();
-                     });
-    QObject::connect(previewFrameWrapper_.get(),
-                     &FrameWrapper::renderingStopped,
-                     [this](const QString& id) {
-                         Q_UNUSED(id);
-                         Q_EMIT previewRenderingStopped();
-                     });
-
-    previewFrameWrapper_->connectStartRendering();
-}
+{}
 
 RenderManager::~RenderManager()
 {
-    previewFrameWrapper_.reset();
-
     for (auto& dfw : distantFrameWrapperMap_) {
         dfw.second.reset();
     }
 }
 
-bool
-RenderManager::isPreviewing()
-{
-    return previewFrameWrapper_->isRendering();
-}
-
 void
-RenderManager::stopPreviewing()
+RenderManager::stopPreviewing(const QString& id)
 {
-    previewFrameWrapper_->stopRendering();
-    avModel_.stopPreview();
+    auto dfwIt = distantFrameWrapperMap_.find(id);
+    if (dfwIt != distantFrameWrapperMap_.end()) {
+        dfwIt->second->stopRendering();
+        avModel_.stopPreview(id);
+    }
 }
 
-void
-RenderManager::startPreviewing(bool force)
+const QString
+RenderManager::startPreviewing(const QString& id, bool force)
 {
-    if (previewFrameWrapper_->isRendering() && !force) {
-        return;
-    }
+    auto dfwIt = distantFrameWrapperMap_.find(id);
+    if (dfwIt != distantFrameWrapperMap_.end()) {
+        if (dfwIt->second->isRendering() && !force) {
+            return dfwIt->second->getId();
+        }
 
-    if (previewFrameWrapper_->isRendering()) {
-        avModel_.stopPreview();
+        if (dfwIt->second->isRendering()) {
+            avModel_.stopPreview(id);
+        }
+        return avModel_.startPreview(id);
     }
-    avModel_.startPreview();
+    return "";
 }
 
 void
@@ -328,24 +301,21 @@ RenderManager::removeDistantRenderer(const QString& id)
 void
 RenderManager::drawFrame(const QString& id, DrawFrameCallback cb)
 {
-    if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
-        if (previewFrameWrapper_->frameMutexTryLock()) {
-            cb(previewFrameWrapper_->getFrame());
-            previewFrameWrapper_->frameMutexUnlock();
-        }
-    } else {
-        auto dfwIt = distantFrameWrapperMap_.find(id);
-        if (dfwIt != distantFrameWrapperMap_.end()) {
-            if (dfwIt->second->frameMutexTryLock()) {
-                cb(dfwIt->second->getFrame());
-                dfwIt->second->frameMutexUnlock();
-            }
+    auto dfwIt = distantFrameWrapperMap_.find(id);
+    if (dfwIt != distantFrameWrapperMap_.end()) {
+        if (dfwIt->second->frameMutexTryLock()) {
+            cb(dfwIt->second->getFrame());
+            dfwIt->second->frameMutexUnlock();
         }
     }
 }
 
 QImage*
-RenderManager::getPreviewFrame()
+RenderManager::getPreviewFrame(const QString& id)
 {
-    return previewFrameWrapper_->getFrame();
+    auto dfwIt = distantFrameWrapperMap_.find(id);
+    if (dfwIt != distantFrameWrapperMap_.end()) {
+        return dfwIt->second->getFrame();
+    }
+    return {};
 }
diff --git a/src/rendermanager.h b/src/rendermanager.h
index a4bf076e4..2c8dc669b 100644
--- a/src/rendermanager.h
+++ b/src/rendermanager.h
@@ -46,7 +46,7 @@ class FrameWrapper final : public QObject
     Q_OBJECT;
 
 public:
-    FrameWrapper(AVModel& avModel, const QString& id = video::PREVIEW_RENDERER_ID);
+    FrameWrapper(AVModel& avModel, const QString& id);
     ~FrameWrapper();
 
     /*
@@ -81,6 +81,11 @@ public:
 
     void frameMutexUnlock();
 
+    const QString getId()
+    {
+        return id_;
+    }
+
 Q_SIGNALS:
     /*
      * Emitted once in slotRenderingStarted.
@@ -103,17 +108,17 @@ public Q_SLOTS:
      * Used to listen to AVModel::rendererStarted.
      * @param id of the renderer
      */
-    void slotRenderingStarted(const QString& id = video::PREVIEW_RENDERER_ID);
+    void slotRenderingStarted(const QString& id);
     /*
      * Used to listen to AVModel::frameUpdated.
      * @param id of the renderer
      */
-    void slotFrameUpdated(const QString& id = video::PREVIEW_RENDERER_ID);
+    void slotFrameUpdated(const QString& id);
     /*
      * Used to listen to AVModel::renderingStopped.
      * @param id of the renderer
      */
-    void slotRenderingStopped(const QString& id = video::PREVIEW_RENDERER_ID);
+    void slotRenderingStopped(const QString& id);
 
 private:
     /*
@@ -179,19 +184,15 @@ public:
 
     using DrawFrameCallback = std::function<void(QImage*)>;
 
-    /*
-     * Check if the preview is active.
-     */
-    bool isPreviewing();
     /*
      * Start capturing and rendering preview frames.
      * @param force if the capture device should be started
      */
-    void startPreviewing(bool force = false);
+    const QString startPreviewing(const QString& id, bool force = false);
     /*
      * Stop capturing.
      */
-    void stopPreviewing();
+    void stopPreviewing(const QString& id);
     /*
      * Add and connect a distant renderer for a given id
      * to a FrameWrapper object
@@ -215,25 +216,9 @@ public:
      * Get the most recently rendered preview frame as a QImage (none thread safe).
      * @return the rendered preview image
      */
-    QImage* getPreviewFrame();
+    QImage* getPreviewFrame(const QString& id = "");
 
 Q_SIGNALS:
-
-    /*
-     * Emitted when the preview the preview is started.
-     */
-    void previewFrameStarted();
-
-    /*
-     * Emitted when the preview has a new frame ready.
-     */
-    void previewFrameUpdated();
-
-    /*
-     * Emitted when the preview is stopped.
-     */
-    void previewRenderingStopped();
-
     /*
      * Emitted when a distant renderer has a new frame ready for a given id.
      */
@@ -245,11 +230,6 @@ Q_SIGNALS:
     void distantRenderingStopped(const QString& id);
 
 private:
-    /*
-     * One preview frame.
-     */
-    std::unique_ptr<FrameWrapper> previewFrameWrapper_;
-
     /*
      * Distant for each call/conf/conversation.
      */
diff --git a/src/settingsview/SettingsView.qml b/src/settingsview/SettingsView.qml
index 152a3aa76..d89b61cec 100644
--- a/src/settingsview/SettingsView.qml
+++ b/src/settingsview/SettingsView.qml
@@ -41,8 +41,6 @@ Rectangle {
     onVisibleChanged: {
         if(visible){
             setSelected(selectedMenu,true)
-        } else {
-            AvAdapter.stopPreviewing()
         }
     }
 
@@ -69,7 +67,6 @@ Rectangle {
 
     // slots
     function leaveSettingsSlot(showMainView) {
-        AvAdapter.stopPreviewing()
         settingsViewRect.stopBooth()
         if (showMainView)
             settingsViewNeedToShowMainView()
diff --git a/src/settingsview/components/VideoSettings.qml b/src/settingsview/components/VideoSettings.qml
index 34076e66f..19afe5ef0 100644
--- a/src/settingsview/components/VideoSettings.qml
+++ b/src/settingsview/components/VideoSettings.qml
@@ -37,7 +37,8 @@ ColumnLayout {
 
     function startPreviewing(force = false) {
         if (root.visible) {
-            AvAdapter.startPreviewing(force)
+            previewWidget.deviceId = VideoDevices.getDefaultDevice()
+            previewWidget.rendererId = VideoDevices.startDevice(previewWidget.deviceId, force)
             previewAvailable = true
         }
     }
@@ -63,7 +64,7 @@ ColumnLayout {
             if (previewWidget.visible)
                 startPreviewing(true)
         } else {
-            AvAdapter.stopPreviewing()
+            VideoDevices.stopDevice(previewWidget.deviceId)
         }
     }
 
@@ -134,7 +135,7 @@ ColumnLayout {
 
         onActivated: {
             // TODO: start and stop preview logic in here should be in LRC
-            AvAdapter.stopPreviewing()
+            VideoDevices.stopDevice(previewWidget.deviceId)
             VideoDevices.setDefaultDevice(modelIndex)
             startPreviewing()
         }
@@ -215,10 +216,12 @@ ColumnLayout {
 
         color: JamiTheme.primaryForegroundColor
 
-        PreviewRenderer {
+        DistantRenderer {
             id: previewWidget
 
             anchors.fill: rectBox
+            property string deviceId: VideoDevices.getDefaultDevice()
+            rendererId: VideoDevices.getDefaultDevice()
 
             lrcInstance: LRCInstance
 
diff --git a/src/videodevices.cpp b/src/videodevices.cpp
index e4d1d5dd5..9cdccbed0 100644
--- a/src/videodevices.cpp
+++ b/src/videodevices.cpp
@@ -278,6 +278,40 @@ VideoDevices::setDefaultDevice(int index, bool useSourceModel)
     updateData();
 }
 
+const QString
+VideoDevices::getDefaultDevice()
+{
+    auto idx = devicesSourceModel_->getCurrentIndex();
+    auto rendererId = QString("camera://")
+                      + devicesSourceModel_
+                            ->data(devicesSourceModel_->index(idx, 0),
+                                   VideoInputDeviceModel::DeviceId)
+                            .toString();
+    return rendererId;
+}
+
+#pragma optimize("", off)
+QString
+VideoDevices::startDevice(const QString& deviceId, bool force)
+{
+    if (deviceId.isEmpty())
+        return {};
+    lrcInstance_->renderer()->addDistantRenderer(deviceId);
+    deviceOpen_ = true;
+    return lrcInstance_->renderer()->startPreviewing(deviceId, force);
+}
+
+void
+VideoDevices::stopDevice(const QString& deviceId, bool force)
+{
+    if (!deviceId.isEmpty() && (!lrcInstance_->hasActiveCall(true) || force)) {
+        lrcInstance_->renderer()->stopPreviewing(deviceId);
+        lrcInstance_->renderer()->removeDistantRenderer(deviceId);
+        deviceOpen_ = false;
+    }
+}
+#pragma optimize("", on)
+
 void
 VideoDevices::setDefaultDeviceRes(int index)
 {
@@ -349,6 +383,24 @@ VideoDevices::updateData()
             }
         }
 
+        if (deviceOpen_ && defaultId_ != defaultDeviceSettings.id) {
+            auto callId = lrcInstance_->getCurrentCallId();
+            if (!callId.isEmpty()) {
+                auto callId = lrcInstance_->getCurrentCallId();
+                auto callInfos = lrcInstance_->getCallInfo(callId,
+                                                           lrcInstance_->get_currentAccountId());
+                for (const auto& media : callInfos->mediaList) {
+                    if (media["MUTED"] == "false" && media["ENABLED"] == "true"
+                        && media["SOURCE"] == getDefaultDevice()) {
+                        /*lrcInstance_->avModel().switchInputTo("camera://" +
+                           defaultDeviceSettings.id, callId);*/
+                        // startDevice("camera://" + defaultDeviceSettings.id);
+                        break;
+                    }
+                }
+            }
+        }
+
         set_defaultChannel(defaultDeviceSettings.channel);
         set_defaultId(defaultDeviceSettings.id);
         set_defaultName(defaultDeviceSettings.name);
@@ -405,7 +457,7 @@ VideoDevices::onVideoDeviceEvent()
         auto& avModel = lrcInstance_->avModel();
         if (currentDeviceListSize == 0) {
             avModel.switchInputTo({}, callId);
-            avModel.stopPreview();
+            avModel.stopPreview(this->getDefaultDevice());
         } else if (deviceEvent == DeviceEvent::Removed) {
             avModel.switchInputTo(defaultDevice, callId);
         }
@@ -427,15 +479,18 @@ VideoDevices::onVideoDeviceEvent()
         }
 
         Q_EMIT deviceListChanged(currentDeviceListSize);
-    } else if (lrcInstance_->renderer()->isPreviewing()) {
+    } else if (deviceOpen_) {
         updateData();
 
         // Use QueuedConnection to make sure that it happens at the event loop of current device
         Utils::oneShotConnect(
             lrcInstance_->renderer(),
-            &RenderManager::previewRenderingStopped,
+            &RenderManager::distantRenderingStopped,
             this,
-            [cb] { cb(); },
+            [this, cb](const QString& id) {
+                if (this->getDefaultDevice() == id)
+                    cb();
+            },
             Qt::QueuedConnection);
     } else {
         cb();
diff --git a/src/videodevices.h b/src/videodevices.h
index 3ac428491..6322a6e5e 100644
--- a/src/videodevices.h
+++ b/src/videodevices.h
@@ -170,6 +170,9 @@ public:
     Q_INVOKABLE QVariant getScreenSharingFpsModel();
 
     Q_INVOKABLE void setDefaultDevice(int index, bool useSourceModel = false);
+    Q_INVOKABLE const QString getDefaultDevice();
+    Q_INVOKABLE QString startDevice(const QString& deviceId, bool force = false);
+    Q_INVOKABLE void stopDevice(const QString& deviceId, bool force = false);
     Q_INVOKABLE void setDefaultDeviceRes(int index);
     Q_INVOKABLE void setDefaultDeviceFps(int index);
     Q_INVOKABLE void setDisplayFPS(const QString& fps);
@@ -209,4 +212,6 @@ private:
 
     constexpr static const char DEVICE_DESKTOP[] = "desktop";
     constexpr static const char CHANNEL_DEFAULT[] = "default";
+
+    bool deviceOpen_ {false};
 };
-- 
GitLab