Skip to content

Commit 081958f

Browse files
committed
Fix audio quality problems
This fixes audio quality in a Jitsi meeting using Firefox. It uses a delay-locked loop (DLL) to tell the resampler what rate it should use. If the buffer is too full, it tells the resampler to resample to a lower sample rate for playback, or to consume a higher sample rate for capture. If the buffer is not full enough, it tells the resampler to do the opposite. This ensures that buffer fill sizes are kept roughly constant, resulting in very stable performance even over substantial periods of time. This also allows using very large capture buffers (1MiB by default), which ensures that pacat-simple-vchan will not overrun its buffer unless something is very wrong. Without the DLL, such large capture buffers could fill up and cause massive latency spikes. Because rate-matching adversely affects audio quality and increases latency, this commit also adds support for driving the PipeWire processing graph. When this module is driving the graph, no rate-matching is done. Instead, the DLL is used to adjust the delay between runs of the processing graph. Since most Qubes OS VMs have no physical audio hardware connected to them, the only other driver is likely to be the "dummy" driver that just uses a timer. It is strictly preferable for this module to drive the graph instead, as this avoids rate matching and can sometimes avoid resampling. This was tested with PulseAudio in dom0 by me, and with both PulseAudio and PipeWire in dom0 by Marek. I also tested a version that does not drive the graph to ensure that this mode works fine, which it does. Using PipeWire in the AudioVM might provide a means of reducing overall system latency, especially since the current code needs rather large capture and playback buffers (8KiB by default) to smooth out uneven sample delivery and processing in the AudioVM. In the long term, I hope to improve Xen’s scheduler to prioritize audio and other hard-realtime tasks, which will allow the use of smaller buffers. This also adds two new tunables: - org.qubes-os.playback.target-buffer-fill (integer) sets the target fill level of the playback vchan. - org.qubes-os.record.target-buffer-fill (integer) sets the target fill level of the recording vchan. For consistency, org.qubes-os.record-buffer-size and org.qubes-os.playback-buffer-size have been replaced by org.qubes-os.record.buffer-size and org.qubes-os.playback.buffer-size, respectively. As it is believed that nobody but me is using these, backwards compatibility is not provided, but it is easy to add. The sample configuration has been updated accordingly.
1 parent bcc3000 commit 081958f

File tree

2 files changed

+418
-43
lines changed

2 files changed

+418
-43
lines changed

pipewire/30_qubes.conf

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,40 @@ context.properties = {
33
# experiencing a bunch of overruns or underruns.
44
#default.clock.min-quantum = 512
55

6-
# The Qubes PipeWire module requires a buffer size to be provided.
7-
# The record buffer size comes from the org.qubes-os.record-buffer-size
8-
# property, and the playback buffer size comes from the
9-
# org.qubes-os.record-buffer-size property. If either of these
10-
# properties is missing, the value of org.qubes-os.vchan-buffer-size is
11-
# used as a default.
12-
#org.qubes-os.vchan-buffer-size = 32768
6+
# Set the allowed audio rates to work around problems with Firefox
7+
default.clock.allowed-rates = [ 44100 48000 ]
138

14-
# Use a smaller buffer size for both recording and playback.
15-
#org.qubes-os.vchan-buffer-size = 16384;
9+
# Default size of the recording buffer in bytes. This is very large
10+
# because a larger buffer only wastes some memory, whereas a small
11+
# buffer risks overruns in the audio daemon (pacat-simple-vchan).
12+
org.qubes-os.record.buffer-size = 1048576
1613

17-
# Use a larger buffer size for recording only
18-
#org.qubes-os.record-buffer-size = 65536
14+
# Default size of the playback buffer in bytes. This is smaller
15+
# because a large buffer provides less benefit here: it is much more
16+
# likely for the audio daemon to underrun (not be able to obtain
17+
# enough samples) than for this module to overrun (run out of space).
18+
org.qubes-os.playback.buffer-size = 65536
1919

20-
# Use a smaller buffer size for playback only
21-
#org.qubes-os.playback-buffer-size = 16384
20+
# The Qubes PipeWire module tries to keep the amount of data buffered
21+
# in each vchan roughly constant. These parameters set this amount.
22+
# Note that these parameters have units of *bytes*, not samples!
23+
# FIXME: use samples instead.
24+
25+
# Target number of bytes in the playback vchan
26+
org.qubes-os.playback.target-buffer = 8192
27+
28+
# Target number of bytes in the recording vchan
29+
org.qubes-os.record.target-buffer = 8192
2230
}
2331

2432
context.modules = [
2533
{
2634
name = libpipewire-module-qubes
35+
# Arguments passed to the module override context properties.
36+
# To reduce xruns at the expense of increased recording latency,
37+
# one could add:
38+
#
39+
# args = { org.qubes-os.record.target-buffer = 16384 }
2740
args = { }
2841
}
2942
]

0 commit comments

Comments
 (0)