summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMikko Hallamaa <mikko.hallamaa@qt.io>2023-12-19 15:35:56 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-01-08 10:06:44 +0000
commit80abf2be0b3549c1e8ae92fce80205a36e66b845 (patch)
tree604d4beab4f3af3042e57e83392d9b53130baec1 /src
parent6b6ea0d42704db8f5fd5910dbe0e5959ec0c09e4 (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.cpp39
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