diff options
author | Artem Dyomin <artem.dyomin@qt.io> | 2023-03-02 20:54:15 +0100 |
---|---|---|
committer | Artem Dyomin <artem.dyomin@qt.io> | 2023-03-05 23:29:42 +0000 |
commit | 03a44e5a6b6aa452143948e71c364d11f6b5992e (patch) | |
tree | f270abd6c449e30059b510c0c57cd593fefc9aae /src/multimedia/darwin/qdarwinaudiosink.mm | |
parent | e6c476d407fd282d064065941eba477a911bb3c9 (diff) |
Fix audiosink issues on darwin6.4
Fixed problems:
- Fix sound stucks on multiple resets/starts of QAudioSink.
It was possible to reproduce on playback position change in
mediaplayer.
- Improve audiosink stop (reduce waiting time). The optimization is
based on the fact that it's possible to call AudioOutputUnitStop from
the thread where it was started.
- add some auto test + imrove errors logging in tests. Tests work
fine locally but still need some tune on CI
Task-number: QTBUG-111567
Change-Id: I0eb5c32af4c12dfc0694ee8f5967b4960a0b4ab2
Reviewed-by: Doris Verria <doris.verria@qt.io>
(cherry picked from commit 919b3d308b711c0b267808c783327f2c95233428)
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
Diffstat (limited to 'src/multimedia/darwin/qdarwinaudiosink.mm')
-rw-r--r-- | src/multimedia/darwin/qdarwinaudiosink.mm | 65 |
1 files changed, 48 insertions, 17 deletions
diff --git a/src/multimedia/darwin/qdarwinaudiosink.mm b/src/multimedia/darwin/qdarwinaudiosink.mm index 340472671..f29b642c2 100644 --- a/src/multimedia/darwin/qdarwinaudiosink.mm +++ b/src/multimedia/darwin/qdarwinaudiosink.mm @@ -104,7 +104,7 @@ int QDarwinAudioSinkBuffer::available() const void QDarwinAudioSinkBuffer::reset() { m_buffer->reset(); - m_device = 0; + m_device = nullptr; m_deviceError = false; } @@ -582,7 +582,7 @@ bool QDarwinAudioSink::open() void QDarwinAudioSink::close() { if (m_audioUnit != 0) { - AudioOutputUnitStop(m_audioUnit); + audioDeviceStop(); AudioUnitUninitialize(m_audioUnit); AudioComponentInstanceDispose(m_audioUnit); } @@ -592,32 +592,61 @@ void QDarwinAudioSink::close() void QDarwinAudioSink::audioThreadStart() { - QMutexLocker lock(&m_mutex); startTimers(); - m_audioThreadState.storeRelaxed(Running); - AudioOutputUnitStart(m_audioUnit); + audioDeviceStart(); } void QDarwinAudioSink::audioThreadStop() { - QMutexLocker lock(&m_mutex); stopTimers(); - if (m_audioThreadState.testAndSetAcquire(Running, Stopped)) - m_threadFinished.wait(&m_mutex, 500); + + // It's common practice to call AudioOutputUnitStop + // from the thread where the audio output was started, + // so we don't have to rely on the stops inside renderCallback. + audioDeviceStop(); } void QDarwinAudioSink::audioThreadDrain() { - QMutexLocker lock(&m_mutex); stopTimers(); - if (m_audioThreadState.testAndSetAcquire(Running, Draining)) - m_threadFinished.wait(&m_mutex, 500); + + QMutexLocker lock(&m_mutex); + + if (m_audioThreadState.testAndSetAcquire(Running, Draining)) { + constexpr int MaxDrainWaitingTime = 500; + + m_threadFinished.wait(&m_mutex, MaxDrainWaitingTime); + + if (m_audioThreadState.fetchAndStoreRelaxed(Stopped) != Stopped) { + qWarning() << "Couldn't wait for draining; force stop"; + + AudioOutputUnitStop(m_audioUnit); + } + } +} + +void QDarwinAudioSink::audioDeviceStart() +{ + QMutexLocker lock(&m_mutex); + + const auto state = m_audioThreadState.loadAcquire(); + if (state == Stopped) { + m_audioThreadState.storeRelaxed(Running); + AudioOutputUnitStart(m_audioUnit); + } else { + qWarning() << "Unexpected state on audio device start:" << state; + } } void QDarwinAudioSink::audioDeviceStop() { - AudioOutputUnitStop(m_audioUnit); - m_audioThreadState.storeRelaxed(Stopped); + { + QMutexLocker lock(&m_mutex); + + AudioOutputUnitStop(m_audioUnit); + m_audioThreadState.storeRelaxed(Stopped); + } + m_threadFinished.wakeOne(); } @@ -626,10 +655,11 @@ void QDarwinAudioSink::audioDeviceIdle() if (m_stateCode != QAudio::ActiveState) return; - audioDeviceStop(); - m_errorCode = QAudio::UnderrunError; m_stateCode = QAudio::IdleState; + + audioDeviceStop(); + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); } @@ -638,10 +668,11 @@ void QDarwinAudioSink::audioDeviceError() if (m_stateCode != QAudio::ActiveState) return; - audioDeviceStop(); - m_errorCode = QAudio::IOError; m_stateCode = QAudio::StoppedState; + + audioDeviceStop(); + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); } |