Hi,
Linux kernel v6.3 is out a few days ago, which includes a change to ALSA firewire stack that addresses an issue affecting user space applications. Specifically, the change introduces delay compensation with the current isochronous cycle in IEEE 1394 bus.
In UAPI of sound subsystem, `struct snd_pcm_status` is used to report status of runtime for PCM substream. User space application read the `delay` field of structure to obtain the number of PCM frames[1], which is comprised of two parts; one common to all drivers, and one specific to individual drivers.
The common part of the delay value reflects the gap between the pointer at which the application reads/writes PCM frames (applptr) and the pointer at which the driver receives/transmits the latest audio data frames (hwptr). The driver can increase this value arbitrarily based on the transmission method used.
In the current implementation of drivers in ALSA firewire stack, initial isochronous packets are scheduled to deliver audio data frames equivalent to the size of PCM buffer configured by user space application as part of the hardware parameters. In the case of PipeWire, 4,096 frames is used as a default value at a sample rate of 48.0 kHz for the size of PCM buffer[2], resulting in 684 initial packets[3] equivalent to 4,104 frames[4].
1394 OHCI hardware enables software to read the current isochronous cycle with a resolution of 8,000 times per second[5]. The change to ALSA firewire stack involves using the specific part of delay to report the gap between the current isochronous cycle and the isochronous cycle at which hwptr is located[6]. Prior to the change, the gap was not visible to user space applications, leading to unexpected delay[7].
For capture PCM substream, the gap is zero or a few packets, as 1394 OHCI hardware enables software to read the payload of isochronous packets immediately upon their arrival. The delay mostly comes from the common part, thus it is 4,096 or so as maximum in the case of PipeWire.
For playback PCM substream, the maximum gap is equivalent to 684 initial packets, resulting in the delay ranging from 4,104 frames to 8,200 frames (= 4,096 + 4,104) in the case of PipeWire.
Regardless of the driver and its transmission backend, I note that there is a limiting point beyond which the value of delay field cannot express true delay between the timing at which the application reads/writes PCM frames and the timing at which the hardware actually generates audio and samples audio signal, since the driver is only responsible for transmitting the audio data frame in the context[8], and cannot account for the circuit-level details on the board. While a driver that accounts for such details could result in more accurate delay measurements, such an implementation would be technically difficult, particularly for devices with thick implementations between transmission of audio data frames and audio signal processing (i.e. devices for packet-oriented communication).
[1] include/sound/pcm.h https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/tree/include... [2] at least pipewire version 0.3.58 [3] 684 = 8,000 * 4,096 / 48,000. You can see the computation at: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/tree/sound/f... [4] 4,104 = 48,000 * 684 / 8000. In IEC 61883-1/6, packet includes multiple audio data frames. [5] The drivers can retrieve the cycle since v5.19 or later, by a commit baa914cd81f5 ("firewire: add kernel API to access CYCLE_TIME register") https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/commit/?id=b... [6] It was finally done by a commit af13842cad44 ("ALSA: firewire-lib: compute extra delay for runtime of PCM substream") https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/commit/?id=b... [7] [pipewire-jack] Systematic delay in recording using REAPER of 0.07 to 0.08 seconds https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/2790 [8] In the most cases, the transmission itself is executed out of sound subsystem.
Thanks
Takashi Sakamoto