diff --git a/src/api/newvideo.h b/src/api/newvideo.h
index 7af16f7f4f21879848e2d84d2c26b0b40651a44a..fc0f3a7f9a10303e79d8a54d20d20aae7be65a8c 100644
--- a/src/api/newvideo.h
+++ b/src/api/newvideo.h
@@ -105,20 +105,12 @@ public:
              const bool useAVFrame = false);
     ~Renderer();
 
-    /**
-     * Start the renderer in its own thread
-     */
-    void initThread();
     /**
      * Update size and shmPath of a renderer
      * @param res new resolution "wxh"
      * @param shmPath new shmPath
      */
     void update(const QString& res, const QString& shmPath);
-    /**
-     * Stop renderer and thread
-     */
-    void quit();
 
     // Getters
     /**
@@ -147,14 +139,6 @@ public:
     QSize size() const; // TODO convert into std format!
 
     // Utils
-    /**
-     * Start rendering
-     */
-    void startRendering();
-    /**
-     * Stop rendering
-     */
-    void stopRendering();
     /**
      * set to true to receive AVFrames from render
      */
@@ -166,6 +150,17 @@ Q_SIGNALS:
      * @param id
      */
     void frameUpdated(const QString& id);
+    void started(const QString& id);
+    void stopped(const QString& id);
+
+    /**
+     * Start rendering
+     */
+    void startRendering();
+    /**
+     * Stop rendering
+     */
+    void stopRendering();
 
 private:
     std::unique_ptr<RendererPimpl> pimpl_;
diff --git a/src/avmodel.cpp b/src/avmodel.cpp
index 29ca1d60c94eebc3ecf36df5c2f765493df746e6..d27e50484e98275d5474576c55f8d0e1f6f902fc 100644
--- a/src/avmodel.cpp
+++ b/src/avmodel.cpp
@@ -62,8 +62,6 @@ public:
 
     std::mutex renderers_mtx_;
     std::map<QString, std::unique_ptr<video::Renderer>> renderers_;
-    // store if a renderers is for a finished call
-    std::map<QString, bool> finishedRenderers_;
     bool useAVFrame_ = false;
     QString currentVideoCaptureDevice_ {};
 
@@ -81,6 +79,20 @@ public:
      */
     QString getDevice(int type) const;
 
+    /**
+     * Add video::Renderer to renderers_ and start it
+     * @param id
+     * @param settings
+     * @param shmPath
+     */
+    void addRenderer(const QString& id, video::Settings settings, const QString& shmPath = {});
+
+    /**
+     * Remove renderer from renderers_
+     * @param id
+     */
+    void removeRenderer(const QString& id);
+
 public Q_SLOTS:
     /**
      * Listen from CallbacksHandler when a renderer starts
@@ -96,13 +108,6 @@ public Q_SLOTS:
      * @param shmPath
      */
     void stoppedDecoding(const QString& id, const QString& shmPath);
-    /**
-     * Listen from CallbacksHandler when a call got a new state
-     * @param id
-     * @param state the new state
-     * @param code unused
-     */
-    void slotCallStateChanged(const QString& id, const QString& state, int code);
     /**
      * Detect when the current frame is updated
      * @param id
@@ -145,8 +150,8 @@ AVModel::AVModel(const CallbacksHandler& callbacksHandler)
 AVModel::~AVModel()
 {
     std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_);
-    for (auto r = pimpl_->renderers_.cbegin(); r != pimpl_->renderers_.cend(); ++r) {
-        (*r).second->quit();
+    for (auto r = pimpl_->renderers_.begin(); r != pimpl_->renderers_.end(); ++r) {
+        (*r).second.reset();
     }
 }
 
@@ -508,36 +513,13 @@ AVModel::useAVFrame(bool useAVFrame)
 void
 AVModel::startPreview()
 {
-    std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_);
-    auto search = pimpl_->renderers_.find(video::PREVIEW_RENDERER_ID);
-    if (search == pimpl_->renderers_.end() || !pimpl_->renderers_[video::PREVIEW_RENDERER_ID]) {
-        qWarning() << "Can't find preview renderer!";
-        return;
-    }
     VideoManager::instance().startCamera();
-    pimpl_->renderers_[video::PREVIEW_RENDERER_ID]->startRendering();
 }
 
 void
 AVModel::stopPreview()
 {
-    std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_);
-    auto search = pimpl_->renderers_.find(video::PREVIEW_RENDERER_ID);
-    if (search == pimpl_->renderers_.end() || !pimpl_->renderers_[video::PREVIEW_RENDERER_ID]) {
-        qWarning() << "Can't find preview renderer!";
-        return;
-    }
-    // If an active call does not have video muted, don't stop the camera
-    // stopCamera() calls switchInput(""), which disables the camera
-    bool previewShouldBeStopped = true;
-    for (auto it = pimpl_->renderers_.cbegin(); it != pimpl_->renderers_.cend(); ++it) {
-        if (it->second->getId() != video::PREVIEW_RENDERER_ID)
-            // If rendering, don't stop preview
-            previewShouldBeStopped &= !it->second->isRendering();
-    }
-    if (previewShouldBeStopped)
-        VideoManager::instance().stopCamera();
-    pimpl_->renderers_[video::PREVIEW_RENDERER_ID]->stopRendering();
+    VideoManager::instance().stopCamera();
 }
 
 const video::Renderer&
@@ -653,27 +635,21 @@ AVModel::clearCurrentVideoCaptureDevice()
 }
 
 AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHandler)
-    : linked_(linked)
-    , callbacksHandler(callbacksHandler)
+    : callbacksHandler(callbacksHandler)
+    , linked_(linked)
 {
     std::srand(std::time(nullptr));
-    // add preview renderer
-    try {
-        renderers_.insert(
-            std::make_pair(video::PREVIEW_RENDERER_ID,
-                           std::make_unique<video::Renderer>(video::PREVIEW_RENDERER_ID,
-                                                             linked_.getDeviceSettings(
-                                                                 linked_.getDefaultDevice()),
-                                                             "",
-                                                             useAVFrame_)));
-    } catch (const std::out_of_range& e) {
-        qWarning() << "Couldn't setup video input renderer: " << e.what();
-    }
 #ifndef ENABLE_LIBWRAP
     SIZE_RENDERER = renderers_.size();
 #endif
     connect(&callbacksHandler, &CallbacksHandler::deviceEvent, this, &AVModelPimpl::slotDeviceEvent);
     connect(&callbacksHandler, &CallbacksHandler::audioMeter, this, &AVModelPimpl::slotAudioMeter);
+    connect(&callbacksHandler,
+            &CallbacksHandler::recordPlaybackStopped,
+            this,
+            &AVModelPimpl::slotRecordPlaybackStopped);
+
+    // render connections
     connect(&callbacksHandler,
             &CallbacksHandler::startedDecoding,
             this,
@@ -682,18 +658,6 @@ AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHan
             &CallbacksHandler::stoppedDecoding,
             this,
             &AVModelPimpl::stoppedDecoding);
-    connect(&callbacksHandler,
-            &CallbacksHandler::callStateChanged,
-            this,
-            &AVModelPimpl::slotCallStateChanged);
-    connect(&*renderers_[video::PREVIEW_RENDERER_ID],
-            &api::video::Renderer::frameUpdated,
-            this,
-            &AVModelPimpl::slotFrameUpdated);
-    connect(&callbacksHandler,
-            &CallbacksHandler::recordPlaybackStopped,
-            this,
-            &AVModelPimpl::slotRecordPlaybackStopped);
 
     auto startedPreview = false;
     auto restartRenderers = [&](const QStringList& callList) {
@@ -712,6 +676,7 @@ AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHan
     restartRenderers(CallManager::instance().getConferenceList());
     if (startedPreview)
         restartRenderers({"local"});
+    currentVideoCaptureDevice_ = VideoManager::instance().getDefaultDevice();
 }
 
 QString
@@ -744,99 +709,16 @@ AVModelPimpl::getRecordingPath() const
 void
 AVModelPimpl::startedDecoding(const QString& id, const QString& shmPath, int width, int height)
 {
-    const QString res = toQString(width) + "x" + toQString(height);
-    {
-        std::lock_guard<std::mutex> lk(renderers_mtx_);
-        auto search = renderers_.find(id);
-
-        if (search == renderers_.end()) {
-            video::Settings settings;
-            settings.size = res;
-            renderers_.insert(std::make_pair(id,
-                                             std::make_unique<video::Renderer>(id,
-                                                                               settings,
-                                                                               shmPath,
-                                                                               useAVFrame_)));
-            finishedRenderers_.insert(std::make_pair(id, false));
-#ifndef ENABLE_LIBWRAP
-            SIZE_RENDERER = renderers_.size();
-#endif
-            renderers_.at(id)->initThread();
-            connect(&*renderers_[id],
-                    &api::video::Renderer::frameUpdated,
-                    this,
-                    &AVModelPimpl::slotFrameUpdated);
-        } else {
-            (*search).second->update(res, shmPath);
-        }
-        renderers_.at(id)->startRendering();
-    }
-    emit linked_.rendererStarted(id);
+    video::Settings settings;
+    settings.size = toQString(width) + "x" + toQString(height);
+    addRenderer(id, settings, shmPath);
 }
 
 void
 AVModelPimpl::stoppedDecoding(const QString& id, const QString& shmPath)
 {
     Q_UNUSED(shmPath)
-    {
-        std::lock_guard<std::mutex> lk(renderers_mtx_);
-        auto search = renderers_.find(id);
-        if (search == renderers_.end()) {
-            qWarning() << "Cannot stop decoding, renderer " << id << "not found";
-            return; // nothing to do
-        }
-
-        (*search).second->stopRendering();
-        qDebug() << "Video stopped for call" << id;
-        (*search).second->quit();
-        if (id != video::PREVIEW_RENDERER_ID) {
-            auto searchFinished = finishedRenderers_.find(id);
-            if (searchFinished == finishedRenderers_.end()) {
-                qWarning() << "Finished flag: " << id << " not found";
-                return; // nothing to do
-            }
-            if (searchFinished->second) {
-                disconnect(&*search->second,
-                           &api::video::Renderer::frameUpdated,
-                           this,
-                           &AVModelPimpl::slotFrameUpdated);
-                renderers_.erase(search);
-#ifndef ENABLE_LIBWRAP
-                SIZE_RENDERER = renderers_.size();
-#endif
-                finishedRenderers_.erase(id);
-            }
-        }
-    }
-    emit linked_.rendererStopped(id);
-}
-
-void
-AVModelPimpl::slotCallStateChanged(const QString& id, const QString& state, int code)
-{
-    Q_UNUSED(code)
-    if (call::to_status(state) != call::Status::ENDED)
-        return;
-    std::lock_guard<std::mutex> lk(renderers_mtx_);
-    auto search = renderers_.find(id);
-    auto searchFinished = finishedRenderers_.find(id);
-    if (search == renderers_.end() || searchFinished == finishedRenderers_.end()) {
-        qWarning() << "Renderer " << id << "not found";
-        return; // nothing to do
-    }
-    if (!search->second->isRendering()) {
-        disconnect(&*search->second,
-                   &api::video::Renderer::frameUpdated,
-                   this,
-                   &AVModelPimpl::slotFrameUpdated);
-        renderers_.erase(search);
-#ifndef ENABLE_LIBWRAP
-        SIZE_RENDERER = renderers_.size();
-#endif
-        finishedRenderers_.erase(id);
-    } else {
-        finishedRenderers_.at(id) = true;
-    }
+    removeRenderer(id);
 }
 
 #ifndef ENABLE_LIBWRAP
@@ -906,6 +788,65 @@ AVModelPimpl::getDevice(int type) const
     return result;
 }
 
+void
+AVModelPimpl::addRenderer(const QString& id, video::Settings settings, const QString& shmPath)
+{
+    {
+        std::lock_guard<std::mutex> lk(renderers_mtx_);
+        auto search = renderers_.find(id);
+        if (search == renderers_.end()) {
+            renderers_
+                .emplace(id, std::make_unique<video::Renderer>(id, settings, shmPath, useAVFrame_));
+            renderers_.at(id)->startRendering();
+        } else {
+            if (search->second) {
+                search->second->update(settings.size, shmPath);
+            } else {
+                search->second.reset(new video::Renderer(id, settings, shmPath, useAVFrame_));
+                renderers_.at(id)->startRendering();
+            }
+        }
+        connect(
+            renderers_.at(id).get(),
+            &video::Renderer::started,
+            this,
+            [this](const QString& id) { emit linked_.rendererStarted(id); },
+            Qt::UniqueConnection);
+        connect(renderers_.at(id).get(),
+                &video::Renderer::frameUpdated,
+                this,
+                &AVModelPimpl::slotFrameUpdated,
+                Qt::UniqueConnection);
+    }
+}
+
+void
+AVModelPimpl::removeRenderer(const QString& id)
+{
+    {
+        std::lock_guard<std::mutex> lk(renderers_mtx_);
+        auto search = renderers_.find(id);
+        if (search == renderers_.end()) {
+            qWarning() << "Cannot remove renderer. " << id << "not found";
+            return;
+        }
+        disconnect(search->second.get(),
+                   &video::Renderer::frameUpdated,
+                   this,
+                   &AVModelPimpl::slotFrameUpdated);
+        connect(
+            search->second.get(),
+            &video::Renderer::stopped,
+            this,
+            [this](const QString& id) {
+                renderers_.erase(id);
+                emit linked_.rendererStopped(id);
+            },
+            Qt::DirectConnection);
+        search->second.reset();
+    }
+}
+
 void
 AVModelPimpl::slotFrameUpdated(const QString& id)
 {
diff --git a/src/directrenderer.cpp b/src/directrenderer.cpp
index c7a421949d8f75579bdf02820cd5f1e0d5d57fd0..a47d6b0ee677c0eb171e679bb46456a9bcd25617 100644
--- a/src/directrenderer.cpp
+++ b/src/directrenderer.cpp
@@ -87,7 +87,12 @@ Video::DirectRenderer::DirectRenderer(const QString& id, const QSize& res, bool
 }
 
 /// Destructor
-Video::DirectRenderer::~DirectRenderer() {}
+Video::DirectRenderer::~DirectRenderer()
+{
+    stopRendering();
+
+    d_ptr.reset();
+}
 
 void
 Video::DirectRenderer::startRendering()
diff --git a/src/newvideo.cpp b/src/newvideo.cpp
index 2c94ef74e80a02d8f4217d70f29c39c4a20bc571..32c08aaf03dabe4f743f3d4e770a13b30820dacd 100644
--- a/src/newvideo.cpp
+++ b/src/newvideo.cpp
@@ -16,8 +16,8 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
  ***************************************************************************/
 
-// LRC
 #include "api/newvideo.h"
+
 #include "dbus/videomanager.h"
 #ifdef ENABLE_LIBWRAP
 #include "directrenderer.h"
@@ -25,12 +25,10 @@
 #include "shmrenderer.h"
 #endif
 
-// std
-#include <mutex>
-
-// Qt
 #include <QSize>
 
+#include <mutex>
+
 namespace lrc {
 
 using namespace api::video;
@@ -45,7 +43,7 @@ public:
                   const bool useAVFrame);
     ~RendererPimpl();
 
-    Renderer& linked;
+    Renderer& linked_;
 
     QString id_;
     Settings videoSettings_;
@@ -53,14 +51,12 @@ public:
     bool usingAVFrame_;
 
     /**
-     * Convert a string (wxh) to a QSize
+     * Convert a string (WxH) to a QSize
      * @param res the string to convert
      * @return the QSize object
      */
     static QSize stringToQSize(const QString& res);
 
-    std::mutex rendering_mtx_;
-
 #ifdef ENABLE_LIBWRAP
     std::unique_ptr<Video::DirectRenderer> renderer;
 #else
@@ -87,23 +83,15 @@ Renderer::Renderer(const QString& id,
 
 Renderer::~Renderer()
 {
-    stopRendering();
-}
-
-void
-Renderer::initThread()
-{
-    if (!pimpl_->renderer)
-        return;
 #ifdef ENABLE_LIBWRAP
     if (pimpl_->usingAVFrame_) {
-        VideoManager::instance().registerAVSinkTarget(pimpl_->id_, pimpl_->renderer->avTarget());
+        VideoManager::instance().registerAVSinkTarget(pimpl_->id_, {});
     } else {
-        VideoManager::instance().registerSinkTarget(pimpl_->id_, pimpl_->renderer->target());
+        VideoManager::instance().registerSinkTarget(pimpl_->id_, {});
     }
-#endif
-    if (!pimpl_->thread_.isRunning())
-        pimpl_->thread_.start();
+#endif // ENABLE_LIBWRAP
+
+    pimpl_.reset();
 }
 
 void
@@ -130,7 +118,6 @@ Renderer::update(const QString& res, const QString& shmPath)
 bool
 Renderer::isRendering() const
 {
-    std::lock_guard<std::mutex> lk(pimpl_->rendering_mtx_);
     if (pimpl_->renderer)
         return pimpl_->renderer->isRendering();
     return false;
@@ -176,36 +163,7 @@ Renderer::currentAVFrame() const
 QSize
 Renderer::size() const
 {
-    if (pimpl_->renderer)
-        return pimpl_->renderer->size();
-    return QSize();
-}
-
-void
-Renderer::quit()
-{
-    pimpl_->thread_.quit();
-    pimpl_->thread_.wait();
-}
-
-void
-Renderer::startRendering()
-{
-    if (pimpl_->renderer) {
-        std::lock_guard<std::mutex> lk(pimpl_->rendering_mtx_);
-        if (pimpl_->renderer->isRendering())
-            return;
-        pimpl_->renderer->startRendering();
-    }
-}
-
-void
-Renderer::stopRendering()
-{
-    if (pimpl_->renderer) {
-        std::lock_guard<std::mutex> lk(pimpl_->rendering_mtx_);
-        pimpl_->renderer->stopRendering();
-    }
+    return pimpl_->renderer->size();
 }
 
 } // namespace video
@@ -216,7 +174,7 @@ RendererPimpl::RendererPimpl(Renderer& linked,
                              Settings videoSettings,
                              const QString& shmPath,
                              bool useAVFrame)
-    : linked(linked)
+    : linked_(linked)
     , id_(id)
     , videoSettings_(videoSettings)
     , usingAVFrame_(useAVFrame)
@@ -229,10 +187,47 @@ RendererPimpl::RendererPimpl(Renderer& linked,
 #endif
     renderer->moveToThread(&thread_);
 
-    connect(&*renderer, &Video::Renderer::frameUpdated, this, &RendererPimpl::slotFrameUpdated);
+    connect(&thread_, &QThread::finished, [this] { renderer.reset(); });
+
+    connect(&linked,
+            &Renderer::startRendering,
+            renderer.get(),
+            &Video::Renderer::startRendering,
+            Qt::QueuedConnection);
+
+    connect(renderer.get(), &Video::Renderer::frameUpdated, [this] {
+        emit linked_.frameUpdated(id_);
+    });
+
+    connect(
+        renderer.get(),
+        &Video::Renderer::started,
+        this,
+        [this] { emit linked_.started(id_); },
+        Qt::DirectConnection);
+    connect(
+        renderer.get(),
+        &Video::Renderer::stopped,
+        this,
+        [this] { emit linked_.stopped(id_); },
+        Qt::DirectConnection);
+
+#ifdef ENABLE_LIBWRAP
+    if (usingAVFrame_) {
+        VideoManager::instance().registerAVSinkTarget(id_, renderer->avTarget());
+    } else {
+        VideoManager::instance().registerSinkTarget(id_, renderer->target());
+    }
+#endif
+
+    thread_.start();
 }
 
-RendererPimpl::~RendererPimpl() {}
+RendererPimpl::~RendererPimpl()
+{
+    thread_.quit();
+    thread_.wait();
+}
 
 QSize
 RendererPimpl::stringToQSize(const QString& res)
@@ -246,12 +241,6 @@ RendererPimpl::stringToQSize(const QString& res)
     return QSize(width, height);
 }
 
-void
-RendererPimpl::slotFrameUpdated()
-{
-    emit linked.frameUpdated(id_);
-}
-
 } // end of namespace lrc
 
 #include "api/moc_newvideo.cpp"
diff --git a/src/shmrenderer.cpp b/src/shmrenderer.cpp
index c2dc7e364ce0941b4a381048959c37857c313bef..d4bb282dc74dbffdf085188c3b27b5b524126314 100644
--- a/src/shmrenderer.cpp
+++ b/src/shmrenderer.cpp
@@ -135,10 +135,6 @@ ShmRenderer::ShmRenderer(const QString& id, const QString& shmPath, const QSize&
 /// Destructor
 ShmRenderer::~ShmRenderer()
 {
-    if (d_ptr->m_pTimer) {
-        d_ptr->m_pTimer->stop();
-        d_ptr->m_pTimer = nullptr;
-    }
     stopShm();
 }
 
@@ -274,18 +270,23 @@ ShmRenderer::stopShm()
     if (d_ptr->m_fd < 0)
         return;
 
+    Video::Renderer::d_ptr->m_isRendering = false;
+
     if (d_ptr->m_pTimer) {
         d_ptr->m_pTimer->stop();
         d_ptr->m_pTimer = nullptr;
     }
 
-    // reset the frame so it doesn't point to an old value
-    Video::Renderer::d_ptr->m_pFrame.reset();
-
     // Emit the signal before closing the file, this lower the risk of invalid
     // memory access
     emit stopped();
 
+    {
+        QMutexLocker lk {mutex()};
+        // reset the frame so it doesn't point to an old value
+        Video::Renderer::d_ptr->m_pFrame.reset();
+    }
+
     ::close(d_ptr->m_fd);
     d_ptr->m_fd = -1;
 
@@ -323,7 +324,7 @@ ShmRenderer::startRendering()
 {
     QMutexLocker locker {mutex()};
 
-    if (!startShm())
+    if (!startShm() || Video::Renderer::d_ptr->m_isRendering)
         return;
 
     Video::Renderer::d_ptr->m_isRendering = true;
@@ -339,20 +340,10 @@ ShmRenderer::startRendering()
     emit started();
 }
 
-/// Stop the rendering loop
+/// Done on destroy instead
 void
 ShmRenderer::stopRendering()
-{
-    QMutexLocker locker {mutex()};
-    Video::Renderer::d_ptr->m_isRendering = false;
-
-    if (d_ptr->m_pTimer) {
-        d_ptr->m_pTimer->stop();
-        d_ptr->m_pTimer = nullptr;
-    }
-
-    stopShm();
-}
+{}
 
 /*****************************************************************************
  *                                                                           *
diff --git a/src/shmrenderer.h b/src/shmrenderer.h
index 6f3b4d1f5f56fa0b98450671aaf0da633ca5ed8d..05ed9b893e54359715baa963146d7808a75a115d 100644
--- a/src/shmrenderer.h
+++ b/src/shmrenderer.h
@@ -64,7 +64,7 @@ private:
 
 public Q_SLOTS:
     void startRendering() override;
-    void stopRendering() override;
+    void stopRendering() override; // Unused
 };
 
 } // namespace Video
diff --git a/src/video/renderer.h b/src/video/renderer.h
index 67505c42fdf2e621a982069f1907fb66334bd69c..f562dcd2342e68edb4db3fccc20314866b713878 100644
--- a/src/video/renderer.h
+++ b/src/video/renderer.h
@@ -74,7 +74,6 @@ class LIB_EXPORT Renderer : public QObject
     friend class Video::ShmRenderer;
     friend class Video::DirectRendererPrivate;
     friend class Video::DirectRenderer;
-    friend class VideoRendererManagerPrivate;
 
 public:
     /**