diff --git a/src/libclient/avmodel.cpp b/src/libclient/avmodel.cpp index 50a6b330f58ab1153f75179a79560a354ff4d901..b6712b73dfeec698462cec71c666329c273b2b1f 100644 --- a/src/libclient/avmodel.cpp +++ b/src/libclient/avmodel.cpp @@ -38,6 +38,7 @@ #include <QtCore/QDir> #include <QUrl> #include <QSize> +#include <QReadWriteLock> #include <algorithm> // std::sort #include <chrono> @@ -75,7 +76,7 @@ public: static const QString recorderSavesSubdir; AVModel& linked_; - std::mutex renderers_mtx_; + QReadWriteLock renderersMutex_; std::map<QString, std::unique_ptr<Renderer>> renderers_; QString currentVideoCaptureDevice_ {}; @@ -166,7 +167,7 @@ AVModel::AVModel(const CallbacksHandler& callbacksHandler) AVModel::~AVModel() { - std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); + QWriteLocker lk(&pimpl_->renderersMutex_); for (auto r = pimpl_->renderers_.begin(); r != pimpl_->renderers_.end(); ++r) { (*r).second.reset(); } @@ -176,7 +177,7 @@ QList<MapStringString> AVModel::getRenderersInfo(QString id) { QList<MapStringString> infoList; - std::lock_guard<std::mutex> lk(pimpl_->renderers_mtx_); + QReadLocker lk(&pimpl_->renderersMutex_); for (auto r = pimpl_->renderers_.begin(); r != pimpl_->renderers_.end(); r++) { MapStringString qmap; auto& rend = r->second; @@ -195,14 +196,17 @@ AVModel::getRenderersInfo(QString id) void AVModel::updateRenderersFPSInfo(QString rendererId) { - std::unique_lock<std::mutex> lk(pimpl_->renderers_mtx_); + QReadLocker lk(&pimpl_->renderersMutex_); auto it = std::find_if(pimpl_->renderers_.begin(), pimpl_->renderers_.end(), [&rendererId](const auto& c) { return rendererId == c.second->getInfos()["RENDERER_ID"]; }); - if (it != pimpl_->renderers_.end()) - Q_EMIT onRendererFpsChange(qMakePair(rendererId, it->second->getInfos()["FPS"])); + if (it != pimpl_->renderers_.end()) { + auto fpsInfo = qMakePair(rendererId, it->second->getInfos()["FPS"]); + lk.unlock(); + Q_EMIT onRendererFpsChange(fpsInfo); + } } bool @@ -333,7 +337,7 @@ AVModel::setDeviceSettings(video::Settings& settings) // If the preview is running, reload it // doing this during a call will cause re-invite, this is unwanted - std::unique_lock<std::mutex> lk(pimpl_->renderers_mtx_); + QReadLocker lk(&pimpl_->renderersMutex_); auto it = pimpl_->renderers_.find(video::PREVIEW_RENDERER_ID); if (it != pimpl_->renderers_.end() && it->second && pimpl_->renderers_.size() == 1) { lk.unlock(); @@ -942,54 +946,63 @@ createRenderer(const QString& id, const QSize& res, const QString& shmPath = {}) void AVModelPimpl::addRenderer(const QString& id, const QSize& res, const QString& shmPath) { + // Remove the renderer if it already exists. + removeRenderer(id); // Will write-lock renderersMutex_. + { - std::lock_guard<std::mutex> lk(renderers_mtx_); + QWriteLocker lk(&renderersMutex_); renderers_[id] = createRenderer(id, res, shmPath); } - auto& r = renderers_[id]; - - // Listen and forward id-bound signals upwards. - connect( - r.get(), - &Renderer::fpsChanged, - this, - [this, id](void) { linked_.updateRenderersFPSInfo(id); }, - Qt::QueuedConnection); - connect( - r.get(), - &Renderer::started, - this, - [this, id](const QSize& size) { Q_EMIT linked_.rendererStarted(id, size); }, - Qt::DirectConnection); + QReadLocker lk(&renderersMutex_); + auto it = renderers_.find(id); + if (it == renderers_.end()) { + qWarning() << Q_FUNC_INFO << "Renderer not found for id:" << id; + return; + } + + if (auto* renderer = it->second.get()) { + connect( + renderer, + &Renderer::fpsChanged, + this, + [this, id](void) { linked_.updateRenderersFPSInfo(id); }, + Qt::QueuedConnection); + connect( + renderer, + &Renderer::started, + this, + [this, id](const QSize& size) { Q_EMIT linked_.rendererStarted(id, size); }, + Qt::DirectConnection); #ifdef ENABLE_LIBWRAP - connect( - r.get(), - &Renderer::frameBufferRequested, - this, - [this, id](AVFrame* frame) { Q_EMIT linked_.frameBufferRequested(id, frame); }, - Qt::DirectConnection); + connect( + renderer, + &Renderer::frameBufferRequested, + this, + [this, id](AVFrame* frame) { Q_EMIT linked_.frameBufferRequested(id, frame); }, + Qt::DirectConnection); #endif - connect( - r.get(), - &Renderer::frameUpdated, - this, - [this, id] { Q_EMIT linked_.frameUpdated(id); }, - Qt::DirectConnection); - connect( - r.get(), - &Renderer::stopped, - this, - [this, id] { Q_EMIT linked_.rendererStopped(id); }, - Qt::DirectConnection); - - r->startRendering(); + connect( + renderer, + &Renderer::frameUpdated, + this, + [this, id] { Q_EMIT linked_.frameUpdated(id); }, + Qt::DirectConnection); + connect( + renderer, + &Renderer::stopped, + this, + [this, id] { Q_EMIT linked_.rendererStopped(id); }, + Qt::DirectConnection); + + renderer->startRendering(); + } } void AVModelPimpl::removeRenderer(const QString& id) { - std::lock_guard<std::mutex> lk(renderers_mtx_); + QWriteLocker lk(&renderersMutex_); auto it = renderers_.find(id); if (it == renderers_.end()) { qWarning() << "Cannot remove renderer. " << id << "not found"; @@ -1001,14 +1014,14 @@ AVModelPimpl::removeRenderer(const QString& id) bool AVModelPimpl::hasRenderer(const QString& id) { - std::lock_guard<std::mutex> lk(renderers_mtx_); + QReadLocker lk(&renderersMutex_); return renderers_.find(id) != renderers_.end(); } QSize AVModelPimpl::getRendererSize(const QString& id) { - std::lock_guard<std::mutex> lk(renderers_mtx_); + QReadLocker lk(&renderersMutex_); auto it = renderers_.find(id); if (it != renderers_.end()) { return it->second->size(); @@ -1019,7 +1032,7 @@ AVModelPimpl::getRendererSize(const QString& id) Frame AVModelPimpl::getRendererFrame(const QString& id) { - std::lock_guard<std::mutex> lk(renderers_mtx_); + QReadLocker lk(&renderersMutex_); auto it = renderers_.find(id); if (it != renderers_.end()) { return it->second->currentFrame();