요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
=======================
Userspace-driven timers
=======================
:Author: Ivan Orlov <[email protected]>
Preface
=======
This 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).
Enabling userspace-driven timers
================================
The 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.
Userspace-driven timers API
===========================
Userspace 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:
::
struct snd_timer_uinfo {
__u64 resolution;
int fd;
unsigned int id;
unsigned char reserved[16];
}
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.
Besides 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.
So, the example code for creating and triggering the timer would be:
::
static 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);
More detailed example of creating and ticking the timer could be found
in the utimer ALSA selftest.
Userspace-driven timers and snd-aloop
-------------------------------------
Userspace-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.
To use userspace-driven ALSA timer as a timer source of snd-aloop, pass
the following string as the snd-aloop ``timer_source`` parameter:
::
# modprobe snd-aloop timer_source="-1.4.<utimer_id>"
Where ``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``).
``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.
After 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.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
개요와 사용 사례
1-20이 문서는 사용자 공간 응용 프로그램이 IOCTL 호출로 만들고 제어할 수 있는 가상 ALSA 타이머인 userspace-driven timer를 설명한다. 저자는 Ivan Orlov이다.
이 타이머는 ALSA 타이머로 내보내지 않은 PTP clock 같은 타이머 소스에 오디오 스트림을 동기화할 때 유용하다.
또한 `snd-aloop`을 사용하는 두 가상 사운드 장치를 통과하는 오디오 스트림을 동기화할 수 있다. 예를 들어 네트워크 응용 프로그램이 한 snd-aloop 장치에 프레임을 보내고 다른 사운드 응용 프로그램이 snd-aloop 반대편에서 수신하는 구성을 맞출 수 있다.
ALSA가 직접 제공하지 않는 외부 시점과 가상 오디오 경로를 연결한다.
네트워크 수신 시점이 가상 loopback 전송의 tick을 결정한다.
.. SPDX-License-Identifier: GPL-2.0
=======================
Userspace-driven timers
=======================
:Author: Ivan Orlov <[email protected]>
Preface
=======
This 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).
커널 설정에서 활성화
21-28사용자 공간 구동 타이머는 커널의 `CONFIG_SND_UTIMER` 설정 옵션으로 활성화한다. 이 옵션은 `CONFIG_SND_TIMER`에 의존하므로 두 옵션을 모두 켜야 한다.
기본 ALSA timer 지원 위에 userspace-driven timer 기능을 활성화한다.
Enabling userspace-driven timers
================================
The 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.
Userspace-driven timers API
생성·트리거·파괴 API
29-98사용자 공간 응용 프로그램은 `/dev/snd/timer` 장치의 파일 디스크립터에 `SNDRV_TIMER_IOCTL_CREATE` ioctl을 실행해 사용자 공간 구동 ALSA 타이머를 만든다. ioctl 인수로 `struct snd_timer_uinfo`를 전달한다.
`snd_timer_uinfo`에는 `__u64 resolution`, `int fd`, `unsigned int id`, `unsigned char reserved[16]` 필드가 있다.
타이머 생성 요청과 ioctl 반환 정보를 함께 담는다.
`resolution`은 가상 타이머에 관한 정보만 제공하며 실제 타이밍 자체에는 영향을 주지 않는다. `id`는 ioctl이 덮어쓰며, 호출 뒤 받은 값은 타이머를 `snd-aloop` 커널 모듈이나 다른 사용자 공간 응용 프로그램에 전달할 때 timer subdevice 번호로 사용할 수 있다.
한 시점에 시스템에는 최대 128개의 사용자 공간 구동 타이머가 존재할 수 있으므로 `id` 값의 범위는 0부터 127까지다.
ioctl은 `snd_timer_uinfo`를 갱신할 뿐 아니라 타이머를 trigger하는 데 쓸 파일 디스크립터를 구조체의 `fd` 필드에 저장한다. 타이머용 파일 디스크립터를 할당함으로써 타이머를 만든 프로세스만 이를 trigger할 수 있음을 보장한다.
생성된 타이머는 그 타이머 파일 디스크립터에 `SNDRV_TIMER_IOCTL_TRIGGER` ioctl을 실행해 tick시킨다.
장치 파일을 연 뒤 CREATE가 전용 fd와 id를 반환하고 TRIGGER가 callback을 실행한다.
예제는 `utimer_info.resolution`을 `1000000ULL`로 설정해 타이머가 대략 1,000,000ns마다 tick할 것이라는 정보를 제공하고, 생성 전 `id`를 -1로 초기화한다. `/dev/snd/timer`는 `O_RDWR | O_CLOEXEC`로 연다.
`SNDRV_TIMER_IOCTL_CREATE` 호출이 실패하면 오류를 출력하고 -1을 반환한다. 성공한 뒤 `ioctl(utimer_info.fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL)`을 호출하면 이 타이머에 bind된 모든 timer instance의 callback이 실행된다.
사용을 마치면 원문 예제의 `close(timer_info.fd)` 호출로 타이머를 파괴한다. 타이머 생성과 tick의 더 자세한 예제는 utimer ALSA selftest에서 찾을 수 있다.
코드 블록의 주요 호출과 상태 변화를 정리한다.
CREATE가 반환한 전용 fd로 생성 프로세스의 trigger 권한을 제한한다.
===========================
Userspace 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:
::
struct snd_timer_uinfo {
__u64 resolution;
int fd;
unsigned int id;
unsigned char reserved[16];
}
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.
Besides 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.
So, the example code for creating and triggering the timer would be:
::
static 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);
More detailed example of creating and ticking the timer could be found
in the utimer ALSA selftest.
Userspace-driven timers and snd-aloop
-------------------------------------
snd-aloop의 타이머 소스로 사용
99-126사용자 공간 구동 타이머는 가상 사운드 loopback 양 끝의 두 응용 프로그램을 동기화할 때 `snd-aloop` 모듈과 쉽게 함께 사용할 수 있다.
한 응용 프로그램이 네트워크에서 사운드 프레임을 받아 snd-aloop PCM 장치로 보내고 다른 응용 프로그램이 반대편 PCM 장치에서 프레임을 듣는다면, ALSA 중간 계층은 일정한 jiffies가 지난 때가 아니라 네트워크로 새 데이터 period를 받은 때 데이터 전송을 시작하는 것이 적절하다. 사용자 공간 구동 ALSA 타이머가 이 시점을 제공한다.
userspace-driven ALSA timer를 snd-aloop의 타이머 소스로 사용하려면 `snd-aloop`의 `timer_source` 매개변수에 `-1.4.<utimer_id>` 형식의 문자열을 전달한다. 예제 명령은 `modprobe snd-aloop timer_source="-1.4.<utimer_id>"`이다.
-1.4.<utimer_id> 문자열의 의미를 분해한다.
`utimer_id`는 `SNDRV_TIMER_IOCTL_CREATE`로 만든 타이머의 id이며, `4`는 사용자 공간 구동 타이머 장치 `SNDRV_TIMER_GLOBAL_UDRIVEN`의 번호다.
snd-aloop과 함께 쓰는 userspace-driven ALSA timer의 `resolution`은 `1000000000ULL / frame_rate * period_size`로 계산해야 한다. 새 프레임 period가 준비될 때마다 타이머가 tick하기 때문이다.
한 period에 해당하는 나노초를 타이머 정보로 설정한다.
그 뒤 `SNDRV_TIMER_IOCTL_TRIGGER`로 타이머를 trigger할 때마다 새 데이터 period가 한 snd-aloop 장치에서 다른 장치로 전송된다.
네트워크에서 period가 준비되는 순간을 명시적인 timer tick으로 바꾼다.
Userspace-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.
To use userspace-driven ALSA timer as a timer source of snd-aloop, pass
the following string as the snd-aloop ``timer_source`` parameter:
::
# modprobe snd-aloop timer_source="-1.4.<utimer_id>"
Where ``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``).
``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.
After 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.
요약·해설
utimers.rst:1-126사용자 공간 응용 프로그램이 `/dev/snd/timer`와 `SNDRV_TIMER_IOCTL_CREATE`·`TRIGGER`로 가상 ALSA 타이머를 생성하고 tick시키는 방법을 설명합니다. `snd_timer_uinfo`의 해상도·fd·id, 128개 제한, 생성 프로세스의 trigger 권한과 `snd-aloop timer_source=-1.4.<utimer_id>` 연동 및 period 해상도 계산식을 원문 코드와 함께 정리합니다.