[Development] QMediaPlayer changes hardware sample rate unexpectedly on MacOS
Эдвард Даньковский
dankovskyedward at gmail.com
Mon Apr 13 14:31:48 CEST 2026
Hello,
I'm working on a messaging application that uses QMediaPlayer to play audio
messages.
These audio messages typically use a 22 kHz sample rate. I've noticed that
playing an
audio message on MacOS causes the output device's sample rate to change. In
some cases,
this significantly degrades the user experience:
1. When using Bose NC700 wireless headphones, the sample rate changes to 16
kHz, which
causes the headphones to disable active noise cancellation.
2. When background music is playing at 48 kHz, its playback quality
significantly
decreases after the sample rate change. Notably, the sample rate change
persists
even after the application exits, leaving the device in an altered state.
The sample rate change occurs in QCoreAudioSinkStream::open() [1]:
bool QCoreAudioSinkStream::open()
{
// ...
#ifdef Q_OS_MACOS
std::optional<int> bestNominalSamplingRate =
audioObjectFindBestNominalSampleRate(nativeDeviceId,
QAudioDevice::Output, m_format.sampleRate());
if (bestNominalSamplingRate) {
if (!audioObjectSetSamplingRate(nativeDeviceId,
*bestNominalSamplingRate))
return false;
}
// ...
#endif
// ...
}
Here, audioObjectFindBestNominalSampleRate [2] finds the sample rate
closest to
m_format.sampleRate() among the device's supported sample rates, and
audioObjectSetSamplingRate [2] sets the
kAudioDevicePropertyNominalSampleRate
property of the output device. In my case, the output device supports 16
kHz and
44.1 kHz rates, so the 22 kHz audio message is closer to 16 kHz, and Qt
switches
the device to that rate.
As I understand it, this logic serves an optimization purpose — to avoid
resampling
when the output device supports the required sample rate. However, as
described above,
this can lead to unexpected behavior.
On Windows (Shared Mode AudioClient) and with PulseAudio/PipeWire, this is
not a problem
because resampling is handled internally by the audio subsystem. In the
ALSA backend I'm
not sure if it is possible NOT to update the sample rate.
I see two possible solutions:
1. Remove the sample rate change entirely from the MacOS code. This is the
simplest approach.
The documentation does not mention sample rate changes as part of
QAudioSink behavior,
so this shouldn't break documented contracts.
2. Add a new property (e.g., allowHardwareSampleRateChange) to QAudioSink
and QAudioOutput, allowing the sample rate change to be disabled
conditionally
while preserving the current default behavior.
The first option seems cleanest, but it may affect users who rely on the
current
behavior for low-latency playback without resampling.
The second option preserves backward compatibility but introduces
complexity:
- With ALSA, I'm not sure if it's possible to avoid setting the sample rate
for a hardware device.
- With PipeWire, it may be impossible to guarantee the sample rate won't
change,
since PipeWire can update it when only one stream is active.
- Every media player backend would need updates to support this property.
My questions:
1. Is this considered a bug that needs fixing?
2. If so, can we simply remove the sample rate change from
QCoreAudioSinkStream::open?
3. If removal is not acceptable, what are your thoughts on adding an
allowHardwareSampleRateChange property?
[1] qtmultimedia/src/multimedia/darwin/qdarwinaudiosink.mm
[2] qtmultimedia/src/multimedia/darwin/qcoreaudioutils.cpp
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20260413/c4938327/attachment.htm>
More information about the Development
mailing list