[plasma/plasma-pa] src: Use the source's native sample rate for the microphone test
Nate Graham <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 459256d5482cab598da6e87642e72dffa93a99c9 by Nate Graham, on behalf of Dan Fi.
Committed on 17/08/2026 at 18:54.
Pushed by ngraham into branch 'master'.
Use the source's native sample rate for the microphone test
MicrophoneTest hardcoded the record/playback sample rate to
44.1 kHz. When the selected source (m_source) actually runs at a
different native rate — 48 kHz being common with PipeWire — this
forces the audio server to switch the stream/node clock rate for
the whole graph, triggering unnecessary resampling.
Query the source's native sample rate via
pa_context_get_source_info_by_name() before starting the record
stream, and reuse the detected rate for both the record and the
playback pa_sample_spec. The previous synchronous stream setup is
now split into startRecording() (kicks off the async query) and
beginRecording() (does the actual stream setup), invoked from the
source_info_callback(). Falls back to the previous 44.1 kHz default
if the query cannot be issued.
Test Plan:
Tested microphone test with a source running at 48 kHz
on PipeWire; confirmed via `pw-top` that the node clock rate no
longer switches to 44100 Hz during the test. Also verified the
fallback path (default 44.1 kHz) still works when the source info
query fails.
BUG: 523693
FIXED-IN: 6.8.0
M +44 -3 src/microphonetest.cpp
M +6 -0 src/microphonetest.h
https://invent.kde.org/plasma/plasma-pa/-/commit/459256d5482cab598da6e87642e72dffa93a99c9
diff --git a/src/microphonetest.cpp b/src/microphonetest.cpp
index 74bbd9ba..5c2bfd9e 100644
--- a/src/microphonetest.cpp
+++ b/src/microphonetest.cpp
@@ -14,7 +14,6 @@
namespace
{
- constexpr int SAMPLE_RATE = 44100;
constexpr std::chrono::milliseconds MAX_RECORD_DURATION{10000};
constexpr int MIN_FRAGMENT_SIZE = 256;
}
@@ -107,7 +106,49 @@ void MicrophoneTest::startRecording()
return;
}
- pa_sample_spec ss = {PA_SAMPLE_S16LE, SAMPLE_RATE, 1};
+ // Query the source's native sample rate first, so we don't force
+ // PipeWire/PulseAudio to switch the whole audio graph's clock rate to a
+ // fixed value (e.g. always 44.1 kHz) when the device is actually
+ // running at a different rate (e.g. 48 kHz).
+ pa_operation *op = pa_context_get_source_info_by_name(pa_ctx, m_source->name().toUtf8().constData(), source_info_callback, this);
+ if (op) {
+ pa_operation_unref(op);
+ } else {
+ // Couldn't query the source info; fall back to the last known (or
+ // default) sample rate rather than failing the test outright.
+ beginRecording();
+ }
+}
+
+void MicrophoneTest::source_info_callback(pa_context *c, const pa_source_info *i, int eol, void *userdata)
+{
+ Q_UNUSED(c)
+
+ auto *self = static_cast<MicrophoneTest *>(userdata);
+ if (!self || eol) {
+ return;
+ }
+
+ if (i && i->sample_spec.rate > 0) {
+ self->m_sampleRate = static_cast<int>(i->sample_spec.rate);
+ }
+
+ self->beginRecording();
+}
+
+void MicrophoneTest::beginRecording()
+{
+ if (m_recording || !m_source || m_playing) {
+ return;
+ }
+
+ auto pa_ctx = PulseAudioQt::Context::instance()->context();
+ if (!pa_ctx || pa_context_get_state(pa_ctx) != PA_CONTEXT_READY) {
+ Q_EMIT showErrorMessage(i18n("PulseAudio context is not ready"));
+ return;
+ }
+
+ pa_sample_spec ss = {PA_SAMPLE_S16LE, static_cast<uint32_t>(m_sampleRate), 1};
m_recordStream = pa_stream_new(pa_ctx, "MicTest-Record", &ss, nullptr);
if (!m_recordStream) {
@@ -218,7 +259,7 @@ void MicrophoneTest::playRecording()
return;
}
- pa_sample_spec ss = {PA_SAMPLE_S16LE, SAMPLE_RATE, 1};
+ pa_sample_spec ss = {PA_SAMPLE_S16LE, static_cast<uint32_t>(m_sampleRate), 1};
m_playbackOffset = 0;
diff --git a/src/microphonetest.h b/src/microphonetest.h
index 262820f5..46bdb8a0 100644
--- a/src/microphonetest.h
+++ b/src/microphonetest.h
@@ -8,6 +8,7 @@
#include <PulseAudioQt/Source>
#include <QByteArray>
#include <QTimer>
+#include <pulse/introspect.h>
#include <pulse/stream.h>
#include <qqmlregistration.h>
@@ -53,14 +54,19 @@ Q_SIGNALS:
private:
void calculateVolumeLevel(const void *data, size_t nbytes);
+ void beginRecording();
+
static void stream_state_callback(pa_stream *s, void *userdata);
static void stream_read_callback(pa_stream *s, size_t nbytes, void *userdata);
static void stream_write_callback(pa_stream *s, size_t nbytes, void *userdata);
+ static void source_info_callback(pa_context *c, const pa_source_info *i, int eol, void *userdata);
PulseAudioQt::Source *m_source = nullptr;
pa_stream *m_recordStream = nullptr;
pa_stream *m_playbackStream = nullptr;
+ int m_sampleRate = 44100;
+
QByteArray m_recordedData;
size_t m_playbackOffset = 0;