Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Docs/sound: Add documentation for userspace-driven ALSA timers

Add the documentation which describes the new userspace-driven timers
API introduced in this patch series. The documentation contains:

- Description of userspace-driven ALSA timers, what they are for
- Description of the timers API
- Example of how the timers can be created and triggered
- How the timers can be used as a timer sources for snd-aloop module

Suggested-by: Axel Holzinger <aholzinger@gmx.de>
Signed-off-by: Ivan Orlov <ivan.orlov0322@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20240813120701.171743-3-ivan.orlov0322@gmail.com

authored by

Ivan Orlov and committed by
Takashi Iwai
8fad71b6 e949df0b

+127
+1
Documentation/sound/index.rst
··· 13 13 alsa-configuration 14 14 hd-audio/index 15 15 cards/index 16 + utimers 16 17 17 18 .. only:: subproject and html 18 19
+126
Documentation/sound/utimers.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ======================= 4 + Userspace-driven timers 5 + ======================= 6 + 7 + :Author: Ivan Orlov <ivan.orlov0322@gmail.com> 8 + 9 + Preface 10 + ======= 11 + 12 + This document describes the userspace-driven timers: virtual ALSA timers 13 + which could be created and controlled by userspace applications using 14 + IOCTL calls. Such timers could be useful when synchronizing audio 15 + stream with timer sources which we don't have ALSA timers exported for 16 + (e.g. PTP clocks), and when synchronizing the audio stream going through 17 + two virtual sound devices using ``snd-aloop`` (for instance, when 18 + we have a network application sending frames to one snd-aloop device, 19 + and another sound application listening on the other end of snd-aloop). 20 + 21 + Enabling userspace-driven timers 22 + ================================ 23 + 24 + The userspace-driven timers could be enabled in the kernel using the 25 + ``CONFIG_SND_UTIMER`` configuration option. It depends on the 26 + ``CONFIG_SND_TIMER`` option, so it also should be enabled. 27 + 28 + Userspace-driven timers API 29 + =========================== 30 + 31 + Userspace application can create a userspace-driven ALSA timer by 32 + executing the ``SNDRV_TIMER_IOCTL_CREATE`` ioctl call on the 33 + ``/dev/snd/timer`` device file descriptor. The ``snd_timer_uinfo`` 34 + structure should be passed as an ioctl argument: 35 + 36 + :: 37 + 38 + struct snd_timer_uinfo { 39 + __u64 resolution; 40 + int fd; 41 + unsigned int id; 42 + unsigned char reserved[16]; 43 + } 44 + 45 + The ``resolution`` field sets the desired resolution in nanoseconds for 46 + the virtual timer. ``resolution`` field simply provides an information 47 + about the virtual timer, but does not affect the timing itself. ``id`` 48 + field gets overwritten by the ioctl, and the identifier you get in this 49 + field after the call can be used as a timer subdevice number when 50 + passing the timer to ``snd-aloop`` kernel module or other userspace 51 + applications. There could be up to 128 userspace-driven timers in the 52 + system at one moment of time, thus the id value ranges from 0 to 127. 53 + 54 + Besides from overwriting the ``snd_timer_uinfo`` struct, ioctl stores 55 + a timer file descriptor, which can be used to trigger the timer, in the 56 + ``fd`` field of the ``snd_timer_uinfo`` struct. Allocation of a file 57 + descriptor for the timer guarantees that the timer can only be triggered 58 + by the process which created it. The timer then can be triggered with 59 + ``SNDRV_TIMER_IOCTL_TRIGGER`` ioctl call on the timer file descriptor. 60 + 61 + So, the example code for creating and triggering the timer would be: 62 + 63 + :: 64 + 65 + static struct snd_timer_uinfo utimer_info = { 66 + /* Timer is going to tick (presumably) every 1000000 ns */ 67 + .resolution = 1000000ULL, 68 + .id = -1, 69 + }; 70 + 71 + int timer_device_fd = open("/dev/snd/timer", O_RDWR | O_CLOEXEC); 72 + 73 + if (ioctl(timer_device_fd, SNDRV_TIMER_IOCTL_CREATE, &utimer_info)) { 74 + perror("Failed to create the timer"); 75 + return -1; 76 + } 77 + 78 + ... 79 + 80 + /* 81 + * Now we want to trigger the timer. Callbacks of all of the 82 + * timer instances binded to this timer will be executed after 83 + * this call. 84 + */ 85 + ioctl(utimer_info.fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL); 86 + 87 + ... 88 + 89 + /* Now, destroy the timer */ 90 + close(timer_info.fd); 91 + 92 + 93 + More detailed example of creating and ticking the timer could be found 94 + in the utimer ALSA selftest. 95 + 96 + Userspace-driven timers and snd-aloop 97 + ------------------------------------- 98 + 99 + Userspace-driven timers could be easily used with ``snd-aloop`` module 100 + when synchronizing two sound applications on both ends of the virtual 101 + sound loopback. For instance, if one of the applications receives sound 102 + frames from network and sends them to snd-aloop pcm device, and another 103 + application listens for frames on the other snd-aloop pcm device, it 104 + makes sense that the ALSA middle layer should initiate a data 105 + transaction when the new period of data is received through network, but 106 + not when the certain amount of jiffies elapses. Userspace-driven ALSA 107 + timers could be used to achieve this. 108 + 109 + To use userspace-driven ALSA timer as a timer source of snd-aloop, pass 110 + the following string as the snd-aloop ``timer_source`` parameter: 111 + 112 + :: 113 + 114 + # modprobe snd-aloop timer_source="-1.4.<utimer_id>" 115 + 116 + Where ``utimer_id`` is the id of the timer you created with 117 + ``SNDRV_TIMER_IOCTL_CREATE``, and ``4`` is the number of 118 + userspace-driven timers device (``SNDRV_TIMER_GLOBAL_UDRIVEN``). 119 + 120 + ``resolution`` for the userspace-driven ALSA timer used with snd-aloop 121 + should be calculated as ``1000000000ULL / frame_rate * period_size`` as 122 + the timer is going to tick every time a new period of frames is ready. 123 + 124 + After that, each time you trigger the timer with 125 + ``SNDRV_TIMER_IOCTL_TRIGGER`` the new period of data will be transferred 126 + from one snd-aloop device to another.