diff options
author | Mikko Hallamaa <mikko.hallamaa@qt.io> | 2023-12-19 15:35:56 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-01-08 10:06:44 +0000 |
commit | 80abf2be0b3549c1e8ae92fce80205a36e66b845 (patch) | |
tree | 604d4beab4f3af3042e57e83392d9b53130baec1 /src | |
parent | 6b6ea0d42704db8f5fd5910dbe0e5959ec0c09e4 (diff) |
Fully drain PulseAudio stream when stopping the sink
Currently when a PulseAudio stream is closed, pa_stream_drain is called
and the stream is disconnected and deleted, which causes the draining
operation to fail.
This patch moves stream drain to be handled synchronously when calling
stop(), after which close() is called which handles stream disconnect.
The stream is flushed in close() so it can be called for sink
destruction and reset where draining is not wanted.
Task-number: QTBUG-111045
Pick-to: 6.6 6.5
Change-Id: I7a6daf38a410518e98974b807e8f9c8ed9802293
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
(cherry picked from commit 9262a8abde7aa2aa5629bc8c382eda2ab91d8e96)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/multimedia/pulseaudio/qpulseaudiosink.cpp | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/src/multimedia/pulseaudio/qpulseaudiosink.cpp b/src/multimedia/pulseaudio/qpulseaudiosink.cpp index de08a450e..c9af00aa6 100644 --- a/src/multimedia/pulseaudio/qpulseaudiosink.cpp +++ b/src/multimedia/pulseaudio/qpulseaudiosink.cpp @@ -98,10 +98,20 @@ static void outputStreamDrainComplete(pa_stream *stream, int success, void *user qCDebug(qLcPulseAudioOut) << "Stream drained:" << bool(success) << userdata; + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); + if (userdata && success) static_cast<QPulseAudioSink *>(userdata)->streamDrainedCallback(); } +static void outputStreamFlushComplete(pa_stream *stream, int success, void *userdata) +{ + Q_UNUSED(stream); + + qCDebug(qLcPulseAudioOut) << "Stream flushed:" << bool(success) << userdata; +} + static void streamAdjustPrebufferCallback(pa_stream *stream, int success, void *userdata) { Q_UNUSED(stream); @@ -135,9 +145,10 @@ QAudio::State QPulseAudioSink::state() const void QPulseAudioSink::streamUnderflowCallback() { if (m_audioSource && m_audioSource->atEnd()) { - qCDebug(qLcPulseAudioOut) << "Draining stream at end of buffer"; - - exchangeDrainOperation(pa_stream_drain(m_stream, outputStreamDrainComplete, this)); + if (m_stateMachine.state() != QAudio::StoppedState) { + qCDebug(qLcPulseAudioOut) << "Draining stream at end of buffer"; + exchangeDrainOperation(pa_stream_drain(m_stream, outputStreamDrainComplete, this)); + } } else if (!m_resuming) { m_stateMachine.updateActiveOrIdle(false, QAudio::UnderrunError); } @@ -353,11 +364,7 @@ void QPulseAudioSink::close() pa_stream_set_overflow_callback(m_stream, nullptr, nullptr); pa_stream_set_latency_update_callback(m_stream, nullptr, nullptr); - if (auto prevOp = exchangeDrainOperation(nullptr)) - // cancel the draining callback that is not relevant already - pa_operation_cancel(prevOp.get()); - - PAOperationUPtr(pa_stream_drain(m_stream, outputStreamDrainComplete, nullptr)); + PAOperationUPtr(pa_stream_flush(m_stream, outputStreamFlushComplete, nullptr)); pa_stream_disconnect(m_stream); pa_stream_unref(m_stream); @@ -375,6 +382,7 @@ void QPulseAudioSink::close() m_audioSource = nullptr; } } + m_opened = false; m_resuming = false; m_audioBuffer.clear(); @@ -491,8 +499,21 @@ qint64 QPulseAudioSink::write(const char *data, qint64 len) void QPulseAudioSink::stop() { - if (auto notifier = m_stateMachine.stop()) + if (auto notifier = m_stateMachine.stop()) { + { + QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); + std::lock_guard lock(*pulseEngine); + + if (auto prevOp = exchangeDrainOperation(nullptr)) + // cancel the draining callback that is not relevant already + pa_operation_cancel(prevOp.get()); + + PAOperationUPtr drainOp(pa_stream_drain(m_stream, outputStreamDrainComplete, nullptr)); + pulseEngine->wait(drainOp.get()); + } + close(); + } } qsizetype QPulseAudioSink::bytesFree() const |