From 57bf3f66359ad193dff0925fba6a5799bc40f757 Mon Sep 17 00:00:00 2001 From: Mikko Hallamaa Date: Mon, 19 Feb 2024 15:36:17 +0100 Subject: PulseAudio: Fix tlength setting of QPulseAudioSink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With PA_STREAM_ADJUST_LATENCY set, PulseAudio will use the requested tlength value to configure playback buffer size + overall sink latency. The configured stream has a tlength of actual buffer size, which was then used as the requested tlenght on subsequent playback streams. This lead to buffer size getting smaller after multiple restarts, and leading to underflows and "static" glitches caused by skipped samples. This patch changes the requested tlength attribute to always be either the buffer size set by the user, or the default buffer size if no buffer size is set. Fixes: QTBUG-116519 Pick-to: 6.7 6.6 6.5 Change-Id: Ib9ad0dc72ad7f70f172b3cc484672c9f426bde06 Reviewed-by: Artem Dyomin Reviewed-by: Jøger Hansegård --- src/multimedia/pulseaudio/qpulseaudiosink.cpp | 29 ++++++++++++++++++--------- src/multimedia/pulseaudio/qpulseaudiosink_p.h | 5 ++++- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src/multimedia') diff --git a/src/multimedia/pulseaudio/qpulseaudiosink.cpp b/src/multimedia/pulseaudio/qpulseaudiosink.cpp index 39d21b560..ff526e1b1 100644 --- a/src/multimedia/pulseaudio/qpulseaudiosink.cpp +++ b/src/multimedia/pulseaudio/qpulseaudiosink.cpp @@ -303,8 +303,9 @@ bool QPulseAudioSink::open() pa_buffer_attr requestedBuffer; // Request a target buffer size - auto targetBufferSize = bufferSize(); - requestedBuffer.tlength = targetBufferSize ? targetBufferSize : static_cast(-1); + auto targetBufferSize = m_userBufferSize ? *m_userBufferSize : defaultBufferSize(); + requestedBuffer.tlength = + targetBufferSize ? static_cast(targetBufferSize) : static_cast(-1); // Rest should be determined by PulseAudio requestedBuffer.fragsize = static_cast(-1); requestedBuffer.maxlength = static_cast(-1); @@ -537,7 +538,7 @@ qsizetype QPulseAudioSink::bytesFree() const void QPulseAudioSink::setBufferSize(qsizetype value) { - m_bufferSize = value; + m_userBufferSize = value; } qsizetype QPulseAudioSink::bufferSize() const @@ -545,14 +546,10 @@ qsizetype QPulseAudioSink::bufferSize() const if (m_bufferSize) return m_bufferSize; - if (m_spec.rate > 0) - return pa_usec_to_bytes(DefaultBufferLengthMs * 1000, &m_spec); + if (m_userBufferSize) + return *m_userBufferSize; - auto spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format); - if (pa_sample_spec_valid(&spec)) - return pa_usec_to_bytes(DefaultBufferLengthMs * 1000, &spec); - - return 0; + return defaultBufferSize(); } static qint64 operator-(timeval t1, timeval t2) @@ -732,6 +729,18 @@ PAOperationUPtr QPulseAudioSink::exchangeDrainOperation(pa_operation *newOperati return PAOperationUPtr(m_drainOperation.exchange(newOperation)); } +qsizetype QPulseAudioSink::defaultBufferSize() const +{ + if (m_spec.rate > 0) + return pa_usec_to_bytes(DefaultBufferLengthMs * 1000, &m_spec); + + auto spec = QPulseAudioInternal::audioFormatToSampleSpec(m_format); + if (pa_sample_spec_valid(&spec)) + return pa_usec_to_bytes(DefaultBufferLengthMs * 1000, &spec); + + return 0; +} + QT_END_NAMESPACE #include "moc_qpulseaudiosink_p.cpp" diff --git a/src/multimedia/pulseaudio/qpulseaudiosink_p.h b/src/multimedia/pulseaudio/qpulseaudiosink_p.h index d7c320f7c..cf0b181ec 100644 --- a/src/multimedia/pulseaudio/qpulseaudiosink_p.h +++ b/src/multimedia/pulseaudio/qpulseaudiosink_p.h @@ -80,6 +80,8 @@ private Q_SLOTS: PAOperationUPtr exchangeDrainOperation(pa_operation *newOperation); private: + qsizetype defaultBufferSize() const; + pa_sample_spec m_spec = {}; // calculate timing manually, as pulseaudio doesn't give us good enough data mutable timeval lastTimingInfo = {}; @@ -102,8 +104,9 @@ private: qreal m_volume = 1.0; std::atomic m_drainOperation = nullptr; + qsizetype m_bufferSize = 0; + std::optional m_userBufferSize = std::nullopt; int m_pullingPeriodSize = 0; - int m_bufferSize = 0; int m_pullingPeriodTime = 0; bool m_pullMode = true; bool m_opened = false; -- cgit v1.2.3