diff options
author | Jøger Hansegård <joger.hansegard@qt.io> | 2024-01-22 11:32:10 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-01-22 19:02:06 +0000 |
commit | ea027cb821ce77a3703a66e68e891f481ae25d76 (patch) | |
tree | 8b8b88e24c486ebcce8d847ec37d4e7477d66a58 | |
parent | bb5bd27ce1011753d43bff68a6e7ee2e98bf3a37 (diff) |
Fix abrupt termination during static destruction in QtMultimedia
Breaking change: After this change, QtMultimedia requires a
QCoreApplication to access or enumerate media devices (microphone,
speakers, and camera).
During destruction, a Windows application using QtMultimedia could exit
with success return code without having called all static destructors.
The root cause of the issue was that the internal QWindowsMediaDevices
singleton was making outgoing COM-calls during static destruction. This
is not handled well by the COM runtime, and resulted in
NtTerminateProcess being called from within the implementation of
Microsoft IMMDeviceEnumerator::UnregisterEndpointNotificationCallback.
After this point, destructors were never called even if the application
returned 0, indicating success.
This patch fixes this issue by ensuring that the QWindowMediaDevices
instance are deleted when the QCoreApplication is terminated, instead
of waiting until static destruction. If no QCoreApplication exists,
a warning is emitted, and destruction is executed as before, with
possible interruption of static destructors.
Fixes: QTBUG-120198
Pick-to: 6.5
Change-Id: I52a2b355052d61333fbff382dc4d4cd059d99d52
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
(cherry picked from commit 44f1e17d2843851d00c546f944582ab3fb409a45)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 073e0114241a8f6cf747290ec641c9332251f3ba)
-rw-r--r-- | src/multimedia/platform/qplatformmediadevices.cpp | 25 | ||||
-rw-r--r-- | src/multimedia/windows/qwindowsmediadevices.cpp | 3 |
2 files changed, 25 insertions, 3 deletions
diff --git a/src/multimedia/platform/qplatformmediadevices.cpp b/src/multimedia/platform/qplatformmediadevices.cpp index f971fb4c3..a9d591ee8 100644 --- a/src/multimedia/platform/qplatformmediadevices.cpp +++ b/src/multimedia/platform/qplatformmediadevices.cpp @@ -12,6 +12,7 @@ #include <qmutex.h> #include <qloggingcategory.h> +#include <QtCore/qcoreapplication.h> #if defined(Q_OS_ANDROID) #include <qandroidmediadevices_p.h> @@ -33,18 +34,26 @@ QT_BEGIN_NAMESPACE namespace { -struct DevicesHolder { - ~DevicesHolder() + +struct DevicesHolder +{ + ~DevicesHolder() { reset(); } + + void reset() { QMutexLocker locker(&mutex); + delete nativeInstance; nativeInstance = nullptr; instance = nullptr; } + QBasicMutex mutex; QPlatformMediaDevices *instance = nullptr; QPlatformMediaDevices *nativeInstance = nullptr; -} devicesHolder; +}; + +DevicesHolder devicesHolder; } @@ -72,6 +81,16 @@ QPlatformMediaDevices *QPlatformMediaDevices::instance() devicesHolder.nativeInstance = new 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; } diff --git a/src/multimedia/windows/qwindowsmediadevices.cpp b/src/multimedia/windows/qwindowsmediadevices.cpp index 4dc27f513..fccb7f20f 100644 --- a/src/multimedia/windows/qwindowsmediadevices.cpp +++ b/src/multimedia/windows/qwindowsmediadevices.cpp @@ -162,6 +162,9 @@ QWindowsMediaDevices::QWindowsMediaDevices() QWindowsMediaDevices::~QWindowsMediaDevices() { if (m_deviceEnumerator) { + // Note: Calling UnregisterEndpointNotificationCallback after CoUninitialize + // will abruptly terminate application, preventing remaining destructors from + // being called (QTBUG-120198). m_deviceEnumerator->UnregisterEndpointNotificationCallback(m_notificationClient.Get()); } if (m_warmUpAudioClient) { |