diff options
author | Jøger Hansegård <joger.hansegard@qt.io> | 2024-01-29 20:31:00 +0100 |
---|---|---|
committer | Jøger Hansegård <joger.hansegard@qt.io> | 2024-02-28 00:17:50 +0100 |
commit | 5fcfa339bc45460cfadb645620f0fa1e3f32ed20 (patch) | |
tree | a8c0c1cb890228a87fb2dd58ecc15ecd0e938c6e /src/multimedia | |
parent | a8757116f014f465b643ca9446cea8f82af8e8da (diff) |
Move ownership of media devices to platform media integration
This change removes the PlatformMediaDevices singleton instance, and
moves ownership to the platform integration layer. This makes it easier
to reason around object lifetimes during destruction, and will later
allow us to fix issues on the Windows Platform related to
uninitialization of the Windows Media Foundation. This uninitialization
must be done before static destruction takes place.
As a side effect, we no longer need hooks to mock media devices in unit
tests.
If no media backend is available, we use a fallback media integration
that provides basic support needed by QMediaDevices, QAudioDevice,
QSoundEffect, QAudioSink, and QAudioSource. Therefore we don't need
applications that only rely on basic services to ship a full multimedia
backend.
Reimplements a6bb5f743dd404bce3734ad0c81449b8c4bf7b29
Task-number: QTBUG-120198
Pick-to: 6.7 6.6 6.5
Change-Id: If7ee7a4892e2d84e1af71b5f867cc24d950749c2
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
Diffstat (limited to 'src/multimedia')
-rw-r--r-- | src/multimedia/android/qandroidmediadevices.cpp | 4 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiosink.cpp | 2 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiosource.cpp | 2 | ||||
-rw-r--r-- | src/multimedia/audio/qsoundeffect.cpp | 2 | ||||
-rw-r--r-- | src/multimedia/platform/qplatformmediadevices.cpp | 71 | ||||
-rw-r--r-- | src/multimedia/platform/qplatformmediadevices_p.h | 4 | ||||
-rw-r--r-- | src/multimedia/platform/qplatformmediaintegration.cpp | 53 | ||||
-rw-r--r-- | src/multimedia/platform/qplatformmediaintegration_p.h | 10 | ||||
-rw-r--r-- | src/multimedia/platform/qplatformmediaplayer.cpp | 3 | ||||
-rw-r--r-- | src/multimedia/qmediadevices.cpp | 10 | ||||
-rw-r--r-- | src/multimedia/wasm/qwasmmediadevices.cpp | 4 |
11 files changed, 76 insertions, 89 deletions
diff --git a/src/multimedia/android/qandroidmediadevices.cpp b/src/multimedia/android/qandroidmediadevices.cpp index cd6548ac3..55533621c 100644 --- a/src/multimedia/android/qandroidmediadevices.cpp +++ b/src/multimedia/android/qandroidmediadevices.cpp @@ -72,12 +72,12 @@ void QAndroidMediaDevices::forwardAudioInputsChanged() static void onAudioInputDevicesUpdated(JNIEnv */*env*/, jobject /*thiz*/) { - static_cast<QAndroidMediaDevices*>(QPlatformMediaDevices::instance())->forwardAudioInputsChanged(); + static_cast<QAndroidMediaDevices*>(QPlatformMediaIntegration::instance()->mediaDevices())->forwardAudioInputsChanged(); } static void onAudioOutputDevicesUpdated(JNIEnv */*env*/, jobject /*thiz*/) { - static_cast<QAndroidMediaDevices*>(QPlatformMediaDevices::instance())->forwardAudioOutputsChanged(); + static_cast<QAndroidMediaDevices*>(QPlatformMediaIntegration::instance()->mediaDevices())->forwardAudioOutputsChanged(); } Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/) diff --git a/src/multimedia/audio/qaudiosink.cpp b/src/multimedia/audio/qaudiosink.cpp index cb99f384e..aac96c342 100644 --- a/src/multimedia/audio/qaudiosink.cpp +++ b/src/multimedia/audio/qaudiosink.cpp @@ -87,7 +87,7 @@ QAudioSink::QAudioSink(const QAudioFormat &format, QObject *parent) QAudioSink::QAudioSink(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent): QObject(parent) { - d = QPlatformMediaDevices::instance()->audioOutputDevice(format, audioDevice, parent); + d = QPlatformMediaIntegration::instance()->mediaDevices()->audioOutputDevice(format, audioDevice, parent); if (d) connect(d, &QPlatformAudioSink::stateChanged, this, [this](QAudio::State state) { // if the signal has been emitted from another thread, diff --git a/src/multimedia/audio/qaudiosource.cpp b/src/multimedia/audio/qaudiosource.cpp index c92205c22..5e59a4798 100644 --- a/src/multimedia/audio/qaudiosource.cpp +++ b/src/multimedia/audio/qaudiosource.cpp @@ -96,7 +96,7 @@ QAudioSource::QAudioSource(const QAudioFormat &format, QObject *parent) QAudioSource::QAudioSource(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent): QObject(parent) { - d = QPlatformMediaDevices::instance()->audioInputDevice(format, audioDevice, parent); + d = QPlatformMediaIntegration::instance()->mediaDevices()->audioInputDevice(format, audioDevice, parent); if (d) { connect(d, &QPlatformAudioSource::stateChanged, this, [this](QAudio::State state) { // if the signal has been emitted from another thread, diff --git a/src/multimedia/audio/qsoundeffect.cpp b/src/multimedia/audio/qsoundeffect.cpp index 1ffe4b800..c793cf36b 100644 --- a/src/multimedia/audio/qsoundeffect.cpp +++ b/src/multimedia/audio/qsoundeffect.cpp @@ -99,7 +99,7 @@ QSoundEffectPrivate::QSoundEffectPrivate(QSoundEffect *q, const QAudioDevice &au { open(QIODevice::ReadOnly); - QPlatformMediaDevices::instance()->prepareAudio(); + QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio(); } void QSoundEffectPrivate::sampleReady() diff --git a/src/multimedia/platform/qplatformmediadevices.cpp b/src/multimedia/platform/qplatformmediadevices.cpp index 069b3012b..484886f44 100644 --- a/src/multimedia/platform/qplatformmediadevices.cpp +++ b/src/multimedia/platform/qplatformmediadevices.cpp @@ -3,17 +3,11 @@ #include "qplatformmediadevices_p.h" #include "qplatformmediaintegration_p.h" -#include "qmediadevices.h" -#include "qaudiodevice.h" #include "qcameradevice.h" #include "qaudiosystem_p.h" #include "qaudiodevice.h" #include "qplatformvideodevices_p.h" -#include <qmutex.h> -#include <qloggingcategory.h> -#include <QtCore/qcoreapplication.h> - #if defined(Q_OS_ANDROID) #include <qandroidmediadevices_p.h> #elif defined(Q_OS_DARWIN) @@ -33,69 +27,27 @@ QT_BEGIN_NAMESPACE -namespace { - -struct DevicesHolder +std::unique_ptr<QPlatformMediaDevices> QPlatformMediaDevices::create() { - ~DevicesHolder() { reset(); } - - void reset() - { - QMutexLocker locker(&mutex); - - delete nativeInstance; - nativeInstance = nullptr; - instance = nullptr; - } - - QBasicMutex mutex; - QPlatformMediaDevices *instance = nullptr; - QPlatformMediaDevices *nativeInstance = nullptr; -}; - -Q_GLOBAL_STATIC(DevicesHolder, devicesHolder); - -} - -QPlatformMediaDevices *QPlatformMediaDevices::instance() -{ - QMutexLocker locker(&devicesHolder->mutex); - if (devicesHolder->instance) - return devicesHolder->instance; - #ifdef Q_OS_DARWIN - devicesHolder->nativeInstance = new QDarwinMediaDevices; + return std::make_unique<QDarwinMediaDevices>(); #elif defined(Q_OS_WINDOWS) - devicesHolder->nativeInstance = new QWindowsMediaDevices; + return std::make_unique<QWindowsMediaDevices>(); #elif defined(Q_OS_ANDROID) - devicesHolder->nativeInstance = new QAndroidMediaDevices; + return std::make_unique<QAndroidMediaDevices>(); #elif QT_CONFIG(alsa) - devicesHolder->nativeInstance = new QAlsaMediaDevices; + return std::make_unique<QAlsaMediaDevices>(); #elif QT_CONFIG(pulseaudio) - devicesHolder->nativeInstance = new QPulseAudioMediaDevices; + return std::make_unique<QPulseAudioMediaDevices>(); #elif defined(Q_OS_QNX) - devicesHolder->nativeInstance = new QQnxMediaDevices; + return std::make_unique<QQnxMediaDevices>(); #elif defined(Q_OS_WASM) - devicesHolder->nativeInstance = new QWasmMediaDevices; + return std::make_unique<QWasmMediaDevices>(); #else - devicesHolder->nativeInstance = new QPlatformMediaDevices; + return std::make_unique<QPlatformMediaDevices>(); #endif - - if (!QCoreApplication::instance()) { - // QTBUG-120198: Destructors are not called when shutting down - // application with Windows backend. - qWarning("Accessing QMediaDevices without a QCoreApplication"); - } else { - connect(qApp, &QObject::destroyed, devicesHolder->nativeInstance, []() { - devicesHolder->reset(); - }); - } - - devicesHolder->instance = devicesHolder->nativeInstance; - return devicesHolder->instance; } - QPlatformMediaDevices::QPlatformMediaDevices() = default; void QPlatformMediaDevices::initVideoDevicesConnection() @@ -106,11 +58,6 @@ void QPlatformMediaDevices::initVideoDevicesConnection() &QPlatformMediaDevices::videoInputsChanged, Qt::UniqueConnection); } -void QPlatformMediaDevices::setDevices(QPlatformMediaDevices *devices) -{ - devicesHolder->instance = devices; -} - QPlatformMediaDevices::~QPlatformMediaDevices() = default; QList<QAudioDevice> QPlatformMediaDevices::audioInputs() const diff --git a/src/multimedia/platform/qplatformmediadevices_p.h b/src/multimedia/platform/qplatformmediadevices_p.h index 555e269c8..b7aa68f1d 100644 --- a/src/multimedia/platform/qplatformmediadevices_p.h +++ b/src/multimedia/platform/qplatformmediadevices_p.h @@ -19,6 +19,7 @@ #include <qlist.h> #include <qobject.h> #include <mutex> +#include <memory> QT_BEGIN_NAMESPACE @@ -37,8 +38,7 @@ public: QPlatformMediaDevices(); ~QPlatformMediaDevices() override; - static void setDevices(QPlatformMediaDevices *); - static QPlatformMediaDevices *instance(); + static std::unique_ptr<QPlatformMediaDevices> create(); virtual QList<QAudioDevice> audioInputs() const; virtual QList<QAudioDevice> audioOutputs() const; diff --git a/src/multimedia/platform/qplatformmediaintegration.cpp b/src/multimedia/platform/qplatformmediaintegration.cpp index 3df477e45..dcb412acf 100644 --- a/src/multimedia/platform/qplatformmediaintegration.cpp +++ b/src/multimedia/platform/qplatformmediaintegration.cpp @@ -14,16 +14,20 @@ #include <QtCore/qcoreapplication.h> #include "qplatformcapturablewindows_p.h" -#include "QtCore/private/qfactoryloader_p.h" -#include "private/qplatformmediaformatinfo_p.h" +#include "qplatformmediadevices_p.h" +#include <QtCore/private/qfactoryloader_p.h> +#include <QtCore/private/qcoreapplication_p.h> +#include <private/qplatformmediaformatinfo_p.h> #include "qplatformmediaplugin_p.h" -class QDummyIntegration : public QPlatformMediaIntegration +namespace { + +class QFallbackIntegration : public QPlatformMediaIntegration { public: - QDummyIntegration() + QFallbackIntegration() { - qCritical("QtMultimedia is not currently supported on this platform or compiler."); + qWarning("No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available."); } }; @@ -72,8 +76,6 @@ static QString defaultBackend(const QStringList &backends) return backends[0]; } -namespace { - struct InstanceHolder { InstanceHolder() @@ -91,8 +93,8 @@ struct InstanceHolder qLoadPlugin<QPlatformMediaIntegration, QPlatformMediaPlugin>(loader(), backend)); if (!instance) { - qWarning() << "could not load multimedia backend" << backend; - instance = std::make_unique<QDummyIntegration>(); + // No backends found. Use fallback to support basic functionality + instance = std::make_unique<QFallbackIntegration>(); } } @@ -152,22 +154,51 @@ QPlatformMediaFormatInfo *QPlatformMediaIntegration::createFormatInfo() return new QPlatformMediaFormatInfo; } +// clang-format off +std::unique_ptr<QPlatformMediaDevices> QPlatformMediaIntegration::createMediaDevices() +{ + // Avoid releasing WMF resources and uninitializing WMF during static + // destruction, QTBUG-120198 + if (QCoreApplication::instance()) + connect(qApp, &QObject::destroyed, this, [this] { + m_mediaDevices = nullptr; + }); + + return QPlatformMediaDevices::create(); +} + QPlatformVideoDevices *QPlatformMediaIntegration::videoDevices() { std::call_once(m_videoDevicesOnceFlag, - [this]() { m_videoDevices.reset(createVideoDevices()); }); + [this]() { + m_videoDevices.reset(createVideoDevices()); + }); return m_videoDevices.get(); } QPlatformCapturableWindows *QPlatformMediaIntegration::capturableWindows() { std::call_once(m_capturableWindowsOnceFlag, - [this]() { m_capturableWindows.reset(createCapturableWindows()); }); + [this]() { + m_capturableWindows.reset(createCapturableWindows()); + }); return m_capturableWindows.get(); } +QPlatformMediaDevices *QPlatformMediaIntegration::mediaDevices() +{ + std::call_once(m_mediaDevicesOnceFlag, [this] { + m_mediaDevices = createMediaDevices(); + }); + return m_mediaDevices.get(); +} + +// clang-format on + QPlatformMediaIntegration::QPlatformMediaIntegration() = default; QPlatformMediaIntegration::~QPlatformMediaIntegration() = default; QT_END_NAMESPACE + +#include "moc_qplatformmediaintegration_p.cpp" diff --git a/src/multimedia/platform/qplatformmediaintegration_p.h b/src/multimedia/platform/qplatformmediaintegration_p.h index 3f72c618b..4673c47b3 100644 --- a/src/multimedia/platform/qplatformmediaintegration_p.h +++ b/src/multimedia/platform/qplatformmediaintegration_p.h @@ -54,8 +54,9 @@ class QPlatformVideoDevices; class QCapturableWindow; class QPlatformCapturableWindows; -class Q_MULTIMEDIA_EXPORT QPlatformMediaIntegration +class Q_MULTIMEDIA_EXPORT QPlatformMediaIntegration : public QObject { + Q_OBJECT inline static const QString notAvailable = QStringLiteral("Not available"); public: static QPlatformMediaIntegration *instance(); @@ -93,6 +94,8 @@ public: QPlatformCapturableWindows *capturableWindows(); + QPlatformMediaDevices *mediaDevices(); + protected: virtual QPlatformMediaFormatInfo *createFormatInfo(); @@ -100,6 +103,8 @@ protected: virtual QPlatformCapturableWindows *createCapturableWindows() { return nullptr; } + virtual std::unique_ptr<QPlatformMediaDevices> createMediaDevices(); + private: std::unique_ptr<QPlatformVideoDevices> m_videoDevices; std::once_flag m_videoDevicesOnceFlag; @@ -109,6 +114,9 @@ private: mutable std::unique_ptr<QPlatformMediaFormatInfo> m_formatInfo; mutable std::once_flag m_formatInfoOnceFlg; + + std::unique_ptr<QPlatformMediaDevices> m_mediaDevices; + std::once_flag m_mediaDevicesOnceFlag; }; QT_END_NAMESPACE diff --git a/src/multimedia/platform/qplatformmediaplayer.cpp b/src/multimedia/platform/qplatformmediaplayer.cpp index 34c929b5a..ea22f94df 100644 --- a/src/multimedia/platform/qplatformmediaplayer.cpp +++ b/src/multimedia/platform/qplatformmediaplayer.cpp @@ -5,12 +5,13 @@ #include <private/qmediaplayer_p.h> #include "qmediaplayer.h" #include "qplatformmediadevices_p.h" +#include "qplatformmediaintegration_p.h" QT_BEGIN_NAMESPACE QPlatformMediaPlayer::QPlatformMediaPlayer(QMediaPlayer *parent) : player(parent) { - QPlatformMediaDevices::instance()->prepareAudio(); + QPlatformMediaIntegration::instance()->mediaDevices()->prepareAudio(); } QPlatformMediaPlayer::~QPlatformMediaPlayer() diff --git a/src/multimedia/qmediadevices.cpp b/src/multimedia/qmediadevices.cpp index fa6f8630e..1d77f4de8 100644 --- a/src/multimedia/qmediadevices.cpp +++ b/src/multimedia/qmediadevices.cpp @@ -126,7 +126,7 @@ QT_BEGIN_NAMESPACE */ QList<QAudioDevice> QMediaDevices::audioInputs() { - return QPlatformMediaDevices::instance()->audioInputs(); + return QPlatformMediaIntegration::instance()->mediaDevices()->audioInputs(); } /*! @@ -147,7 +147,7 @@ QList<QAudioDevice> QMediaDevices::audioInputs() */ QList<QAudioDevice> QMediaDevices::audioOutputs() { - return QPlatformMediaDevices::instance()->audioOutputs(); + return QPlatformMediaIntegration::instance()->mediaDevices()->audioOutputs(); } /*! @@ -162,7 +162,7 @@ QList<QAudioDevice> QMediaDevices::audioOutputs() */ QList<QCameraDevice> QMediaDevices::videoInputs() { - QPlatformMediaDevices::instance()->initVideoDevicesConnection(); + QPlatformMediaIntegration::instance()->mediaDevices()->initVideoDevicesConnection(); return QPlatformMediaIntegration::instance()->videoInputs(); } @@ -261,7 +261,7 @@ QCameraDevice QMediaDevices::defaultVideoInput() QMediaDevices::QMediaDevices(QObject *parent) : QObject(parent) { - auto platformDevices = QPlatformMediaDevices::instance(); + auto platformDevices = QPlatformMediaIntegration::instance()->mediaDevices(); connect(platformDevices, &QPlatformMediaDevices::videoInputsChanged, this, &QMediaDevices::videoInputsChanged); connect(platformDevices, &QPlatformMediaDevices::audioInputsChanged, this, @@ -278,7 +278,7 @@ QMediaDevices::~QMediaDevices() = default; void QMediaDevices::connectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&QMediaDevices::videoInputsChanged)) - QPlatformMediaDevices::instance()->initVideoDevicesConnection(); + QPlatformMediaIntegration::instance()->mediaDevices()->initVideoDevicesConnection(); QObject::connectNotify(signal); } diff --git a/src/multimedia/wasm/qwasmmediadevices.cpp b/src/multimedia/wasm/qwasmmediadevices.cpp index e985654ac..4e59fd161 100644 --- a/src/multimedia/wasm/qwasmmediadevices.cpp +++ b/src/multimedia/wasm/qwasmmediadevices.cpp @@ -3,7 +3,7 @@ #include "qwasmmediadevices_p.h" #include "private/qcameradevice_p.h" - +#include "private/qplatformmediaintegration_p.h" #include "qwasmaudiosource_p.h" #include "qwasmaudiosink_p.h" #include "qwasmaudiodevice_p.h" @@ -20,7 +20,7 @@ Q_LOGGING_CATEGORY(qWasmMediaDevices, "qt.multimedia.wasm.mediadevices") QWasmCameraDevices::QWasmCameraDevices(QPlatformMediaIntegration *integration) : QPlatformVideoDevices(integration) { - m_mediaDevices = QPlatformMediaDevices::instance(); + m_mediaDevices = QPlatformMediaIntegration::instance()->mediaDevices(); } QList<QCameraDevice> QWasmCameraDevices::videoDevices() const |