Skip to content

Commit 72f770c

Browse files
committed
Merge branch 'topic/timestamp' into for-next
2 parents 0eee62e + c72638b commit 72f770c

File tree

7 files changed

+444
-55
lines changed

7 files changed

+444
-55
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
The ALSA API can provide two different system timestamps:
2+
3+
- Trigger_tstamp is the system time snapshot taken when the .trigger
4+
callback is invoked. This snapshot is taken by the ALSA core in the
5+
general case, but specific hardware may have synchronization
6+
capabilities or conversely may only be able to provide a correct
7+
estimate with a delay. In the latter two cases, the low-level driver
8+
is responsible for updating the trigger_tstamp at the most appropriate
9+
and precise moment. Applications should not rely solely on the first
10+
trigger_tstamp but update their internal calculations if the driver
11+
provides a refined estimate with a delay.
12+
13+
- tstamp is the current system timestamp updated during the last
14+
event or application query.
15+
The difference (tstamp - trigger_tstamp) defines the elapsed time.
16+
17+
The ALSA API provides reports two basic pieces of information, avail
18+
and delay, which combined with the trigger and current system
19+
timestamps allow for applications to keep track of the 'fullness' of
20+
the ring buffer and the amount of queued samples.
21+
22+
The use of these different pointers and time information depends on
23+
the application needs:
24+
25+
- 'avail' reports how much can be written in the ring buffer
26+
- 'delay' reports the time it will take to hear a new sample after all
27+
queued samples have been played out.
28+
29+
When timestamps are enabled, the avail/delay information is reported
30+
along with a snapshot of system time. Applications can select from
31+
CLOCK_REALTIME (NTP corrections including going backwards),
32+
CLOCK_MONOTONIC (NTP corrections but never going backwards),
33+
CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode
34+
dynamically with sw_params
35+
36+
37+
The ALSA API also provide an audio_tstamp which reflects the passage
38+
of time as measured by different components of audio hardware. In
39+
ascii-art, this could be represented as follows (for the playback
40+
case):
41+
42+
43+
--------------------------------------------------------------> time
44+
^ ^ ^ ^ ^
45+
| | | | |
46+
analog link dma app FullBuffer
47+
time time time time time
48+
| | | | |
49+
|< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
50+
|<----------------- delay---------------------->| |
51+
|<----ring buffer length---->|
52+
53+
The analog time is taken at the last stage of the playback, as close
54+
as possible to the actual transducer
55+
56+
The link time is taken at the output of the SOC/chipset as the samples
57+
are pushed on a link. The link time can be directly measured if
58+
supported in hardware by sample counters or wallclocks (e.g. with
59+
HDAudio 24MHz or PTP clock for networked solutions) or indirectly
60+
estimated (e.g. with the frame counter in USB).
61+
62+
The DMA time is measured using counters - typically the least reliable
63+
of all measurements due to the bursty natured of DMA transfers.
64+
65+
The app time corresponds to the time tracked by an application after
66+
writing in the ring buffer.
67+
68+
The application can query what the hardware supports, define which
69+
audio time it wants reported by selecting the relevant settings in
70+
audio_tstamp_config fields, get an estimate of the timestamp
71+
accuracy. It can also request the delay-to-analog be included in the
72+
measurement. Direct access to the link time is very interesting on
73+
platforms that provide an embedded DSP; measuring directly the link
74+
time with dedicated hardware, possibly synchronized with system time,
75+
removes the need to keep track of internal DSP processing times and
76+
latency.
77+
78+
In case the application requests an audio tstamp that is not supported
79+
in hardware/low-level driver, the type is overridden as DEFAULT and the
80+
timestamp will report the DMA time based on the hw_pointer value.
81+
82+
For backwards compatibility with previous implementations that did not
83+
provide timestamp selection, with a zero-valued COMPAT timestamp type
84+
the results will default to the HDAudio wall clock for playback
85+
streams and to the DMA time (hw_ptr) in all other cases.
86+
87+
The audio timestamp accuracy can be returned to user-space, so that
88+
appropriate decisions are made:
89+
90+
- for dma time (default), the granularity of the transfers can be
91+
inferred from the steps between updates and in turn provide
92+
information on how much the application pointer can be rewound
93+
safely.
94+
95+
- the link time can be used to track long-term drifts between audio
96+
and system time using the (tstamp-trigger_tstamp)/audio_tstamp
97+
ratio, the precision helps define how much smoothing/low-pass
98+
filtering is required. The link time can be either reset on startup
99+
or reported as is (the latter being useful to compare progress of
100+
different streams - but may require the wallclock to be always
101+
running and not wrap-around during idle periods). If supported in
102+
hardware, the absolute link time could also be used to define a
103+
precise start time (patches WIP)
104+
105+
- including the delay in the audio timestamp may
106+
counter-intuitively not increase the precision of timestamps, e.g. if a
107+
codec includes variable-latency DSP processing or a chain of
108+
hardware components the delay is typically not known with precision.
109+
110+
The accuracy is reported in nanosecond units (using an unsigned 32-bit
111+
word), which gives a max precision of 4.29s, more than enough for
112+
audio applications...
113+
114+
Due to the varied nature of timestamping needs, even for a single
115+
application, the audio_tstamp_config can be changed dynamically. In
116+
the STATUS ioctl, the parameters are read-only and do not allow for
117+
any application selection. To work around this limitation without
118+
impacting legacy applications, a new STATUS_EXT ioctl is introduced
119+
with read/write parameters. ALSA-lib will be modified to make use of
120+
STATUS_EXT and effectively deprecate STATUS.
121+
122+
The ALSA API only allows for a single audio timestamp to be reported
123+
at a time. This is a conscious design decision, reading the audio
124+
timestamps from hardware registers or from IPC takes time, the more
125+
timestamps are read the more imprecise the combined measurements
126+
are. To avoid any interpretation issues, a single (system, audio)
127+
timestamp is reported. Applications that need different timestamps
128+
will be required to issue multiple queries and perform an
129+
interpolation of the results
130+
131+
In some hardware-specific configuration, the system timestamp is
132+
latched by a low-level audio subsytem, and the information provided
133+
back to the driver. Due to potential delays in the communication with
134+
the hardware, there is a risk of misalignment with the avail and delay
135+
information. To make sure applications are not confused, a
136+
driver_timestamp field is added in the snd_pcm_status structure; this
137+
timestamp shows when the information is put together by the driver
138+
before returning from the STATUS and STATUS_EXT ioctl. in most cases
139+
this driver_timestamp will be identical to the regular system tstamp.
140+
141+
Examples of typestamping with HDaudio:
142+
143+
1. DMA timestamp, no compensation for DMA+analog delay
144+
$ ./audio_time -p --ts_type=1
145+
playback: systime: 341121338 nsec, audio time 342000000 nsec, systime delta -878662
146+
playback: systime: 426236663 nsec, audio time 427187500 nsec, systime delta -950837
147+
playback: systime: 597080580 nsec, audio time 598000000 nsec, systime delta -919420
148+
playback: systime: 682059782 nsec, audio time 683020833 nsec, systime delta -961051
149+
playback: systime: 852896415 nsec, audio time 853854166 nsec, systime delta -957751
150+
playback: systime: 937903344 nsec, audio time 938854166 nsec, systime delta -950822
151+
152+
2. DMA timestamp, compensation for DMA+analog delay
153+
$ ./audio_time -p --ts_type=1 -d
154+
playback: systime: 341053347 nsec, audio time 341062500 nsec, systime delta -9153
155+
playback: systime: 426072447 nsec, audio time 426062500 nsec, systime delta 9947
156+
playback: systime: 596899518 nsec, audio time 596895833 nsec, systime delta 3685
157+
playback: systime: 681915317 nsec, audio time 681916666 nsec, systime delta -1349
158+
playback: systime: 852741306 nsec, audio time 852750000 nsec, systime delta -8694
159+
160+
3. link timestamp, compensation for DMA+analog delay
161+
$ ./audio_time -p --ts_type=2 -d
162+
playback: systime: 341060004 nsec, audio time 341062791 nsec, systime delta -2787
163+
playback: systime: 426242074 nsec, audio time 426244875 nsec, systime delta -2801
164+
playback: systime: 597080992 nsec, audio time 597084583 nsec, systime delta -3591
165+
playback: systime: 682084512 nsec, audio time 682088291 nsec, systime delta -3779
166+
playback: systime: 852936229 nsec, audio time 852940916 nsec, systime delta -4687
167+
playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -5146
168+
169+
Example 1 shows that the timestamp at the DMA level is close to 1ms
170+
ahead of the actual playback time (as a side time this sort of
171+
measurement can help define rewind safeguards). Compensating for the
172+
DMA-link delay in example 2 helps remove the hardware buffering abut
173+
the information is still very jittery, with up to one sample of
174+
error. In example 3 where the timestamps are measured with the link
175+
wallclock, the timestamps show a monotonic behavior and a lower
176+
dispersion.
177+
178+
Example 3 and 4 are with USB audio class. Example 3 shows a high
179+
offset between audio time and system time due to buffering. Example 4
180+
shows how compensating for the delay exposes a 1ms accuracy (due to
181+
the use of the frame counter by the driver)
182+
183+
Example 3: DMA timestamp, no compensation for delay, delta of ~5ms
184+
$ ./audio_time -p -Dhw:1 -t1
185+
playback: systime: 120174019 nsec, audio time 125000000 nsec, systime delta -4825981
186+
playback: systime: 245041136 nsec, audio time 250000000 nsec, systime delta -4958864
187+
playback: systime: 370106088 nsec, audio time 375000000 nsec, systime delta -4893912
188+
playback: systime: 495040065 nsec, audio time 500000000 nsec, systime delta -4959935
189+
playback: systime: 620038179 nsec, audio time 625000000 nsec, systime delta -4961821
190+
playback: systime: 745087741 nsec, audio time 750000000 nsec, systime delta -4912259
191+
playback: systime: 870037336 nsec, audio time 875000000 nsec, systime delta -4962664
192+
193+
Example 4: DMA timestamp, compensation for delay, delay of ~1ms
194+
$ ./audio_time -p -Dhw:1 -t1 -d
195+
playback: systime: 120190520 nsec, audio time 120000000 nsec, systime delta 190520
196+
playback: systime: 245036740 nsec, audio time 244000000 nsec, systime delta 1036740
197+
playback: systime: 370034081 nsec, audio time 369000000 nsec, systime delta 1034081
198+
playback: systime: 495159907 nsec, audio time 494000000 nsec, systime delta 1159907
199+
playback: systime: 620098824 nsec, audio time 619000000 nsec, systime delta 1098824
200+
playback: systime: 745031847 nsec, audio time 744000000 nsec, systime delta 1031847

include/sound/pcm.h

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ struct snd_pcm_hardware {
6060

6161
struct snd_pcm_substream;
6262

63+
struct snd_pcm_audio_tstamp_config; /* definitions further down */
64+
struct snd_pcm_audio_tstamp_report;
65+
6366
struct snd_pcm_ops {
6467
int (*open)(struct snd_pcm_substream *substream);
6568
int (*close)(struct snd_pcm_substream *substream);
@@ -71,8 +74,10 @@ struct snd_pcm_ops {
7174
int (*prepare)(struct snd_pcm_substream *substream);
7275
int (*trigger)(struct snd_pcm_substream *substream, int cmd);
7376
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
74-
int (*wall_clock)(struct snd_pcm_substream *substream,
75-
struct timespec *audio_ts);
77+
int (*get_time_info)(struct snd_pcm_substream *substream,
78+
struct timespec *system_ts, struct timespec *audio_ts,
79+
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
80+
struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
7681
int (*copy)(struct snd_pcm_substream *substream, int channel,
7782
snd_pcm_uframes_t pos,
7883
void __user *buf, snd_pcm_uframes_t count);
@@ -281,6 +286,58 @@ struct snd_pcm_hw_constraint_ranges {
281286

282287
struct snd_pcm_hwptr_log;
283288

289+
/*
290+
* userspace-provided audio timestamp config to kernel,
291+
* structure is for internal use only and filled with dedicated unpack routine
292+
*/
293+
struct snd_pcm_audio_tstamp_config {
294+
/* 5 of max 16 bits used */
295+
u32 type_requested:4;
296+
u32 report_delay:1; /* add total delay to A/D or D/A */
297+
};
298+
299+
static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data,
300+
struct snd_pcm_audio_tstamp_config *config)
301+
{
302+
config->type_requested = data & 0xF;
303+
config->report_delay = (data >> 4) & 1;
304+
}
305+
306+
/*
307+
* kernel-provided audio timestamp report to user-space
308+
* structure is for internal use only and read by dedicated pack routine
309+
*/
310+
struct snd_pcm_audio_tstamp_report {
311+
/* 6 of max 16 bits used for bit-fields */
312+
313+
/* for backwards compatibility */
314+
u32 valid:1;
315+
316+
/* actual type if hardware could not support requested timestamp */
317+
u32 actual_type:4;
318+
319+
/* accuracy represented in ns units */
320+
u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
321+
u32 accuracy; /* up to 4.29s, will be packed in separate field */
322+
};
323+
324+
static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy,
325+
const struct snd_pcm_audio_tstamp_report *report)
326+
{
327+
u32 tmp;
328+
329+
tmp = report->accuracy_report;
330+
tmp <<= 4;
331+
tmp |= report->actual_type;
332+
tmp <<= 1;
333+
tmp |= report->valid;
334+
335+
*data &= 0xffff; /* zero-clear MSBs */
336+
*data |= (tmp << 16);
337+
*accuracy = report->accuracy;
338+
}
339+
340+
284341
struct snd_pcm_runtime {
285342
/* -- Status -- */
286343
struct snd_pcm_substream *trigger_master;
@@ -361,6 +418,11 @@ struct snd_pcm_runtime {
361418

362419
struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */
363420

421+
/* -- audio timestamp config -- */
422+
struct snd_pcm_audio_tstamp_config audio_tstamp_config;
423+
struct snd_pcm_audio_tstamp_report audio_tstamp_report;
424+
struct timespec driver_tstamp;
425+
364426
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
365427
/* -- OSS things -- */
366428
struct snd_pcm_oss_runtime oss;

include/uapi/sound/asound.h

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ struct snd_hwdep_dsp_image {
143143
* *
144144
*****************************************************************************/
145145

146-
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 12)
146+
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13)
147147

148148
typedef unsigned long snd_pcm_uframes_t;
149149
typedef signed long snd_pcm_sframes_t;
@@ -270,10 +270,17 @@ typedef int __bitwise snd_pcm_subformat_t;
270270
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
271271
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
272272
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
273-
#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */
273+
#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */
274+
#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */
275+
#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */
276+
#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */
277+
#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */
278+
274279
#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
275280
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
276281

282+
283+
277284
typedef int __bitwise snd_pcm_state_t;
278285
#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
279286
#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */
@@ -411,6 +418,22 @@ struct snd_pcm_channel_info {
411418
unsigned int step; /* samples distance in bits */
412419
};
413420

421+
enum {
422+
/*
423+
* first definition for backwards compatibility only,
424+
* maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else
425+
*/
426+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0,
427+
428+
/* timestamp definitions */
429+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */
430+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */
431+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */
432+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */
433+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */
434+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
435+
};
436+
414437
struct snd_pcm_status {
415438
snd_pcm_state_t state; /* stream state */
416439
struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */
@@ -422,9 +445,11 @@ struct snd_pcm_status {
422445
snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */
423446
snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */
424447
snd_pcm_state_t suspended_state; /* suspended stream state */
425-
__u32 reserved_alignment; /* must be filled with zero */
426-
struct timespec audio_tstamp; /* from sample counter or wall clock */
427-
unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
448+
__u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */
449+
struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */
450+
struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */
451+
__u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
452+
unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
428453
};
429454

430455
struct snd_pcm_mmap_status {
@@ -537,6 +562,7 @@ enum {
537562
#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
538563
#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
539564
#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
565+
#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status)
540566
#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
541567
#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
542568
#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)

0 commit comments

Comments
 (0)