Jsphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget!/translations/zh_CN/sound/utimersmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/zh_TW/sound/utimersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/it_IT/sound/utimersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/ja_JP/sound/utimersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/ko_KR/sound/utimersmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/sp_SP/sound/utimersmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhh;/var/lib/git/docbuild/linux/Documentation/sound/utimers.rsthKubhsection)}(hhh](htitle)}(hUserspace-driven timersh]hUserspace-driven timers}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh field_list)}(hhh]hfield)}(hhh](h field_name)}(hAuthorh]hAuthor}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(h&Ivan Orlov h]h paragraph)}(h%Ivan Orlov h](h Ivan Orlov <}(hhhhhNhNubh reference)}(hivan.orlov0322@gmail.comh]hivan.orlov0322@gmail.com}(hhhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:ivan.orlov0322@gmail.comuh1hhhubh>}(hhhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hPrefaceh]hPreface}(hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj!hhhhhK ubh)}(hX0This document describes the userspace-driven timers: virtual ALSA timers which could be created and controlled by userspace applications using IOCTL calls. Such timers could be useful when synchronizing audio stream with timer sources which we don't have ALSA timers exported for (e.g. PTP clocks), and when synchronizing the audio stream going through two virtual sound devices using ``snd-aloop`` (for instance, when we have a network application sending frames to one snd-aloop device, and another sound application listening on the other end of snd-aloop).h](hXThis document describes the userspace-driven timers: virtual ALSA timers which could be created and controlled by userspace applications using IOCTL calls. Such timers could be useful when synchronizing audio stream with timer sources which we don’t have ALSA timers exported for (e.g. PTP clocks), and when synchronizing the audio stream going through two virtual sound devices using }(hj2hhhNhNubhliteral)}(h ``snd-aloop``h]h snd-aloop}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1j:hj2ubh (for instance, when we have a network application sending frames to one snd-aloop device, and another sound application listening on the other end of snd-aloop).}(hj2hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hj!hhubeh}(h]prefaceah ]h"]prefaceah$]h&]uh1hhhhhhhhK ubh)}(hhh](h)}(h Enabling userspace-driven timersh]h Enabling userspace-driven timers}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj\hhhhhKubh)}(hThe userspace-driven timers could be enabled in the kernel using the ``CONFIG_SND_UTIMER`` configuration option. It depends on the ``CONFIG_SND_TIMER`` option, so it also should be enabled.h](hEThe userspace-driven timers could be enabled in the kernel using the }(hjmhhhNhNubj;)}(h``CONFIG_SND_UTIMER``h]hCONFIG_SND_UTIMER}(hjuhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjmubh) configuration option. It depends on the }(hjmhhhNhNubj;)}(h``CONFIG_SND_TIMER``h]hCONFIG_SND_TIMER}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjmubh& option, so it also should be enabled.}(hjmhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj\hhubeh}(h] enabling-userspace-driven-timersah ]h"] enabling userspace-driven timersah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hUserspace-driven timers APIh]hUserspace-driven timers API}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hUserspace application can create a userspace-driven ALSA timer by executing the ``SNDRV_TIMER_IOCTL_CREATE`` ioctl call on the ``/dev/snd/timer`` device file descriptor. The ``snd_timer_uinfo`` structure should be passed as an ioctl argument:h](hPUserspace application can create a userspace-driven ALSA timer by executing the }(hjhhhNhNubj;)}(h``SNDRV_TIMER_IOCTL_CREATE``h]hSNDRV_TIMER_IOCTL_CREATE}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubh ioctl call on the }(hjhhhNhNubj;)}(h``/dev/snd/timer``h]h/dev/snd/timer}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubh device file descriptor. The }(hjhhhNhNubj;)}(h``snd_timer_uinfo``h]hsnd_timer_uinfo}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubh1 structure should be passed as an ioctl argument:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh literal_block)}(hqstruct snd_timer_uinfo { __u64 resolution; int fd; unsigned int id; unsigned char reserved[16]; }h]hqstruct snd_timer_uinfo { __u64 resolution; int fd; unsigned int id; unsigned char reserved[16]; }}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhK&hjhhubh)}(hX/The ``resolution`` field sets the desired resolution in nanoseconds for the virtual timer. ``resolution`` field simply provides an information about the virtual timer, but does not affect the timing itself. ``id`` field gets overwritten by the ioctl, and the identifier you get in this field after the call can be used as a timer subdevice number when passing the timer to ``snd-aloop`` kernel module or other userspace applications. There could be up to 128 userspace-driven timers in the system at one moment of time, thus the id value ranges from 0 to 127.h](hThe }(hj hhhNhNubj;)}(h``resolution``h]h resolution}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hj ubhI field sets the desired resolution in nanoseconds for the virtual timer. }(hj hhhNhNubj;)}(h``resolution``h]h resolution}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1j:hj ubhf field simply provides an information about the virtual timer, but does not affect the timing itself. }(hj hhhNhNubj;)}(h``id``h]hid}(hj8hhhNhNubah}(h]h ]h"]h$]h&]uh1j:hj ubh field gets overwritten by the ioctl, and the identifier you get in this field after the call can be used as a timer subdevice number when passing the timer to }(hj hhhNhNubj;)}(h ``snd-aloop``h]h snd-aloop}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hj ubh kernel module or other userspace applications. There could be up to 128 userspace-driven timers in the system at one moment of time, thus the id value ranges from 0 to 127.}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK-hjhhubh)}(hXBesides from overwriting the ``snd_timer_uinfo`` struct, ioctl stores a timer file descriptor, which can be used to trigger the timer, in the ``fd`` field of the ``snd_timer_uinfo`` struct. Allocation of a file descriptor for the timer guarantees that the timer can only be triggered by the process which created it. The timer then can be triggered with ``SNDRV_TIMER_IOCTL_TRIGGER`` ioctl call on the timer file descriptor.h](hBesides from overwriting the }(hjbhhhNhNubj;)}(h``snd_timer_uinfo``h]hsnd_timer_uinfo}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjbubh^ struct, ioctl stores a timer file descriptor, which can be used to trigger the timer, in the }(hjbhhhNhNubj;)}(h``fd``h]hfd}(hj|hhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjbubh field of the }(hjbhhhNhNubj;)}(h``snd_timer_uinfo``h]hsnd_timer_uinfo}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjbubh struct. Allocation of a file descriptor for the timer guarantees that the timer can only be triggered by the process which created it. The timer then can be triggered with }(hjbhhhNhNubj;)}(h``SNDRV_TIMER_IOCTL_TRIGGER``h]hSNDRV_TIMER_IOCTL_TRIGGER}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjbubh) ioctl call on the timer file descriptor.}(hjbhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK6hjhhubh)}(hDSo, the example code for creating and triggering the timer would be:h]hDSo, the example code for creating and triggering the timer would be:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK=hjhhubj)}(hXistatic struct snd_timer_uinfo utimer_info = { /* Timer is going to tick (presumably) every 1000000 ns */ .resolution = 1000000ULL, .id = -1, }; int timer_device_fd = open("/dev/snd/timer", O_RDWR | O_CLOEXEC); if (ioctl(timer_device_fd, SNDRV_TIMER_IOCTL_CREATE, &utimer_info)) { perror("Failed to create the timer"); return -1; } ... /* * Now we want to trigger the timer. Callbacks of all of the * timer instances binded to this timer will be executed after * this call. */ ioctl(utimer_info.fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL); ... /* Now, destroy the timer */ close(timer_info.fd);h]hXistatic struct snd_timer_uinfo utimer_info = { /* Timer is going to tick (presumably) every 1000000 ns */ .resolution = 1000000ULL, .id = -1, }; int timer_device_fd = open("/dev/snd/timer", O_RDWR | O_CLOEXEC); if (ioctl(timer_device_fd, SNDRV_TIMER_IOCTL_CREATE, &utimer_info)) { perror("Failed to create the timer"); return -1; } ... /* * Now we want to trigger the timer. Callbacks of all of the * timer instances binded to this timer will be executed after * this call. */ ioctl(utimer_info.fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL); ... /* Now, destroy the timer */ close(timer_info.fd);}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKAhjhhubh)}(hcMore detailed example of creating and ticking the timer could be found in the utimer ALSA selftest.h]hcMore detailed example of creating and ticking the timer could be found in the utimer ALSA selftest.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK]hjhhubh)}(hhh](h)}(h%Userspace-driven timers and snd-alooph]h%Userspace-driven timers and snd-aloop}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKaubh)}(hXTUserspace-driven timers could be easily used with ``snd-aloop`` module when synchronizing two sound applications on both ends of the virtual sound loopback. For instance, if one of the applications receives sound frames from network and sends them to snd-aloop pcm device, and another application listens for frames on the other snd-aloop pcm device, it makes sense that the ALSA middle layer should initiate a data transaction when the new period of data is received through network, but not when the certain amount of jiffies elapses. Userspace-driven ALSA timers could be used to achieve this.h](h2Userspace-driven timers could be easily used with }(hjhhhNhNubj;)}(h ``snd-aloop``h]h snd-aloop}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubhX module when synchronizing two sound applications on both ends of the virtual sound loopback. For instance, if one of the applications receives sound frames from network and sends them to snd-aloop pcm device, and another application listens for frames on the other snd-aloop pcm device, it makes sense that the ALSA middle layer should initiate a data transaction when the new period of data is received through network, but not when the certain amount of jiffies elapses. Userspace-driven ALSA timers could be used to achieve this.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKchjhhubh)}(hTo use userspace-driven ALSA timer as a timer source of snd-aloop, pass the following string as the snd-aloop ``timer_source`` parameter:h](hnTo use userspace-driven ALSA timer as a timer source of snd-aloop, pass the following string as the snd-aloop }(hjhhhNhNubj;)}(h``timer_source``h]h timer_source}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubh parameter:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKmhjhhubj)}(h4# modprobe snd-aloop timer_source="-1.4."h]h4# modprobe snd-aloop timer_source="-1.4."}hj3sbah}(h]h ]h"]h$]h&]hhuh1jhhhKrhjhhubh)}(hWhere ``utimer_id`` is the id of the timer you created with ``SNDRV_TIMER_IOCTL_CREATE``, and ``4`` is the number of userspace-driven timers device (``SNDRV_TIMER_GLOBAL_UDRIVEN``).h](hWhere }(hjAhhhNhNubj;)}(h ``utimer_id``h]h utimer_id}(hjIhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjAubh) is the id of the timer you created with }(hjAhhhNhNubj;)}(h``SNDRV_TIMER_IOCTL_CREATE``h]hSNDRV_TIMER_IOCTL_CREATE}(hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjAubh, and }(hjAhhhNhNubj;)}(h``4``h]h4}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjAubh2 is the number of userspace-driven timers device (}(hjAhhhNhNubj;)}(h``SNDRV_TIMER_GLOBAL_UDRIVEN``h]hSNDRV_TIMER_GLOBAL_UDRIVEN}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjAubh).}(hjAhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKthjhhubh)}(h``resolution`` for the userspace-driven ALSA timer used with snd-aloop should be calculated as ``1000000000ULL / frame_rate * period_size`` as the timer is going to tick every time a new period of frames is ready.h](j;)}(h``resolution``h]h resolution}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubhQ for the userspace-driven ALSA timer used with snd-aloop should be calculated as }(hjhhhNhNubj;)}(h,``1000000000ULL / frame_rate * period_size``h]h(1000000000ULL / frame_rate * period_size}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubhJ as the timer is going to tick every time a new period of frames is ready.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKxhjhhubh)}(hAfter that, each time you trigger the timer with ``SNDRV_TIMER_IOCTL_TRIGGER`` the new period of data will be transferred from one snd-aloop device to another.h](h1After that, each time you trigger the timer with }(hjhhhNhNubj;)}(h``SNDRV_TIMER_IOCTL_TRIGGER``h]hSNDRV_TIMER_IOCTL_TRIGGER}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j:hjubhQ the new period of data will be transferred from one snd-aloop device to another.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK|hjhhubeh}(h]%userspace-driven-timers-and-snd-aloopah ]h"]%userspace-driven timers and snd-aloopah$]h&]uh1hhjhhhhhKaubeh}(h]userspace-driven-timers-apiah ]h"]userspace-driven timers apiah$]h&]uh1hhhhhhhhKubeh}(h]userspace-driven-timersah ]h"]userspace-driven timersah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(jjjYjVjjjjjju nametypes}(jjYjjjuh}(jhjVj!jj\jjjju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}Rparse_messages]transform_messages] transformerN include_log] decorationNhhub.