summaryrefslogtreecommitdiffstats
path: root/src/multimedia
diff options
context:
space:
mode:
authorJøger Hansegård <joger.hansegard@qt.io>2024-01-29 20:31:00 +0100
committerJøger Hansegård <joger.hansegard@qt.io>2024-02-28 00:17:50 +0100
commit5fcfa339bc45460cfadb645620f0fa1e3f32ed20 (patch)
treea8c0c1cb890228a87fb2dd58ecc15ecd0e938c6e /src/multimedia
parenta8757116f014f465b643ca9446cea8f82af8e8da (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.cpp4
-rw-r--r--src/multimedia/audio/qaudiosink.cpp2
-rw-r--r--src/multimedia/audio/qaudiosource.cpp2
-rw-r--r--src/multimedia/audio/qsoundeffect.cpp2
-rw-r--r--src/multimedia/platform/qplatformmediadevices.cpp71
-rw-r--r--src/multimedia/platform/qplatformmediadevices_p.h4
-rw-r--r--src/multimedia/platform/qplatformmediaintegration.cpp53
-rw-r--r--src/multimedia/platform/qplatformmediaintegration_p.h10
-rw-r--r--src/multimedia/platform/qplatformmediaplayer.cpp3
-rw-r--r--src/multimedia/qmediadevices.cpp10
-rw-r--r--src/multimedia/wasm/qwasmmediadevices.cpp4
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