diff options
author | Lars Knoll <lars.knoll@qt.io> | 2021-10-05 15:40:08 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-10-06 11:56:59 +0000 |
commit | 7a59fd2d38812197e84256ec7a193bf7a0d3a350 (patch) | |
tree | 5c9858e5a15d90b1aad7fb0fc291d9548d62b4e6 | |
parent | f3d81d6a79ad20e3cd75d80bc2748da395607da9 (diff) | |
download | qtmultimedia-7a59fd2d38812197e84256ec7a193bf7a0d3a350.tar.gz |
Fix deadlock in QSoundEffect on macOS
Calling stop() on the audio sink from QSoundEffect could deadlock
as it locked a mutex in QDarwinAudioSink::stop(), end emitted a changed
signal with the mutex held.
Change-Id: Idbbcb8fe76f43376a90113810926f4311c37e49c
Reviewed-by: Doris Verria <doris.verria@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit ca5692481e2192163b33dc3e9e613116ffc87aa3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm | 101 |
1 files changed, 52 insertions, 49 deletions
diff --git a/src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm b/src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm index 5fd5afbdf..d4d05d8ca 100644 --- a/src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm +++ b/src/multimedia/platform/darwin/audio/qdarwinaudiosink.mm @@ -299,50 +299,50 @@ QIODevice *QDarwinAudioSink::start() void QDarwinAudioSink::stop() { - QMutexLocker lock(&m_mutex); - if (m_stateCode != QAudio::StoppedState) { - audioThreadDrain(); + if (m_stateCode == QAudio::StoppedState) + return; - m_stateCode = QAudio::StoppedState; - m_errorCode = QAudio::NoError; - emit stateChanged(m_stateCode); - } + audioThreadDrain(); + + m_stateCode = QAudio::StoppedState; + m_errorCode = QAudio::NoError; + emit stateChanged(m_stateCode); } void QDarwinAudioSink::reset() { - QMutexLocker lock(&m_mutex); - if (m_stateCode != QAudio::StoppedState) { - audioThreadStop(); + if (m_stateCode == QAudio::StoppedState) + return; - m_stateCode = QAudio::StoppedState; - m_errorCode = QAudio::NoError; - emit stateChanged(m_stateCode); - } + audioThreadStop(); + + m_stateCode = QAudio::StoppedState; + m_errorCode = QAudio::NoError; + emit stateChanged(m_stateCode); } void QDarwinAudioSink::suspend() { - QMutexLocker lock(&m_mutex); - if (m_stateCode == QAudio::ActiveState || m_stateCode == QAudio::IdleState) { - audioThreadStop(); + if (m_stateCode != QAudio::ActiveState && m_stateCode != QAudio::IdleState) + return; - m_stateCode = QAudio::SuspendedState; - m_errorCode = QAudio::NoError; - emit stateChanged(m_stateCode); - } + audioThreadStop(); + + m_stateCode = QAudio::SuspendedState; + m_errorCode = QAudio::NoError; + emit stateChanged(m_stateCode); } void QDarwinAudioSink::resume() { - QMutexLocker lock(&m_mutex); - if (m_stateCode == QAudio::SuspendedState) { - audioThreadStart(); + if (m_stateCode != QAudio::SuspendedState) + return; - m_stateCode = m_pullMode ? QAudio::ActiveState : QAudio::IdleState; - m_errorCode = QAudio::NoError; - emit stateChanged(m_stateCode); - } + audioThreadStart(); + + m_stateCode = m_pullMode ? QAudio::ActiveState : QAudio::IdleState; + m_errorCode = QAudio::NoError; + emit stateChanged(m_stateCode); } qsizetype QDarwinAudioSink::bytesFree() const @@ -417,15 +417,15 @@ void QDarwinAudioSink::deviceStopped() void QDarwinAudioSink::inputReady() { - QMutexLocker lock(&m_mutex); - if (m_stateCode == QAudio::IdleState) { - audioThreadStart(); + if (m_stateCode != QAudio::IdleState) + return; - m_stateCode = QAudio::ActiveState; - m_errorCode = QAudio::NoError; + audioThreadStart(); - emit stateChanged(m_stateCode); - } + m_stateCode = QAudio::ActiveState; + m_errorCode = QAudio::NoError; + + emit stateChanged(m_stateCode); } OSStatus QDarwinAudioSink::renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) @@ -626,6 +626,7 @@ void QDarwinAudioSink::close() void QDarwinAudioSink::audioThreadStart() { + QMutexLocker lock(&m_mutex); startTimers(); m_audioThreadState.storeRelaxed(Running); AudioOutputUnitStart(m_audioUnit); @@ -633,6 +634,7 @@ void QDarwinAudioSink::audioThreadStart() void QDarwinAudioSink::audioThreadStop() { + QMutexLocker lock(&m_mutex); stopTimers(); if (m_audioThreadState.testAndSetAcquire(Running, Stopped)) m_threadFinished.wait(&m_mutex, 500); @@ -640,6 +642,7 @@ void QDarwinAudioSink::audioThreadStop() void QDarwinAudioSink::audioThreadDrain() { + QMutexLocker lock(&m_mutex); stopTimers(); if (m_audioThreadState.testAndSetAcquire(Running, Draining)) m_threadFinished.wait(&m_mutex, 500); @@ -654,26 +657,26 @@ void QDarwinAudioSink::audioDeviceStop() void QDarwinAudioSink::audioDeviceIdle() { - if (m_stateCode == QAudio::ActiveState) { - QMutexLocker lock(&m_mutex); - audioDeviceStop(); + if (m_stateCode != QAudio::ActiveState) + return; - m_errorCode = QAudio::UnderrunError; - m_stateCode = QAudio::IdleState; - QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); - } + audioDeviceStop(); + + m_errorCode = QAudio::UnderrunError; + m_stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); } void QDarwinAudioSink::audioDeviceError() { - if (m_stateCode == QAudio::ActiveState) { - QMutexLocker lock(&m_mutex); - audioDeviceStop(); + if (m_stateCode != QAudio::ActiveState) + return; - m_errorCode = QAudio::IOError; - m_stateCode = QAudio::StoppedState; - QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); - } + audioDeviceStop(); + + m_errorCode = QAudio::IOError; + m_stateCode = QAudio::StoppedState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); } void QDarwinAudioSink::startTimers() |