pipewire-pulse: generate silence on underflow correctly

Filling a buffer with zeros to produce silence is wrong for
unsigned sample formats and compressed sample formats. This is
silence with an offset. A silent stream with unsigned or
compressed samples mixed with another stream produces a clipped
stream. To hear the problem start QEMU with

qemu-system-x86_64 -accel kvm -smp 4 -m 4096 \
 -audiodev pa,id=audio0,out.mixing-engine=off \
 -machine pc,pcspk-audiodev=audio0 \
 -device ich9-intel-hda -device hda-duplex,audiodev=audio0 \
 -boot d -cdrom Fedora-Workstation-Live-x86_64-37-1.7.iso

on a host configured to use PipeWire and start audio playback on
the guest HDA device.

PA_SAMPLE_U8 is the only unsigned PulseAudio sample format.
There is no need to care about unsigned multi-byte formats.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
This commit is contained in:
Volker Rümelin 2023-03-23 19:30:21 +01:00
parent 3698593481
commit 92a41ba21f

View file

@ -1411,7 +1411,20 @@ static void stream_process(void *data)
if (avail < (int32_t)minreq || stream->corked) {
/* underrun, produce a silence buffer */
size = SPA_MIN(d->maxsize, minreq);
memset(p, 0, size);
switch (stream->ss.format) {
case SPA_AUDIO_FORMAT_U8:
memset(p, 0x80, size);
break;
case SPA_AUDIO_FORMAT_ALAW:
memset(p, 0x80 ^ 0x55, size);
break;
case SPA_AUDIO_FORMAT_ULAW:
memset(p, 0x00 ^ 0xff, size);
break;
default:
memset(p, 0, size);
break;
}
if (stream->draining && !stream->corked) {
stream->draining = false;