5 #include <alsa/asoundlib.h>
7 static uint64_t timespec_us(const struct timespec
*ts
) {
9 ts
->tv_sec
* 1000000LLU +
10 ts
->tv_nsec
/ 1000LLU;
13 int main(int argc
, char *argv
[]) {
16 snd_pcm_hw_params_t
*hwparams
;
17 snd_pcm_sw_params_t
*swparams
;
18 snd_pcm_status_t
*status
;
20 unsigned rate
= 44100;
22 snd_pcm_uframes_t boundary
, buffer_size
= 44100/10; /* 100s */
24 struct timespec start
, last_timestamp
= { 0, 0 };
26 snd_pcm_sframes_t last_avail
= 0, last_delay
= 0;
27 struct pollfd
*pollfds
;
29 int64_t sample_count
= 0;
31 snd_pcm_hw_params_alloca(&hwparams
);
32 snd_pcm_sw_params_alloca(&swparams
);
33 snd_pcm_status_alloca(&status
);
35 r
= clock_gettime(CLOCK_MONOTONIC
, &start
);
38 start_us
= timespec_us(&start
);
40 dev
= argc
> 1 ? argv
[1] : "front:AudioPCI";
42 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_PLAYBACK
, 0);
45 r
= snd_pcm_hw_params_any(pcm
, hwparams
);
48 r
= snd_pcm_hw_params_set_rate_resample(pcm
, hwparams
, 0);
51 r
= snd_pcm_hw_params_set_access(pcm
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
);
54 r
= snd_pcm_hw_params_set_format(pcm
, hwparams
, SND_PCM_FORMAT_S16_LE
);
57 r
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rate
, NULL
);
60 r
= snd_pcm_hw_params_set_channels(pcm
, hwparams
, 2);
63 r
= snd_pcm_hw_params_set_periods_integer(pcm
, hwparams
);
66 r
= snd_pcm_hw_params_set_periods_near(pcm
, hwparams
, &periods
, &dir
);
69 r
= snd_pcm_hw_params_set_buffer_size_near(pcm
, hwparams
, &buffer_size
);
72 r
= snd_pcm_hw_params(pcm
, hwparams
);
75 r
= snd_pcm_hw_params_current(pcm
, hwparams
);
78 r
= snd_pcm_sw_params_current(pcm
, swparams
);
81 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 1);
84 r
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, 0);
87 r
= snd_pcm_hw_params_get_buffer_size(hwparams
, &buffer_size
);
89 r
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, buffer_size
);
92 r
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
);
94 r
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
);
97 r
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
);
100 r
= snd_pcm_sw_params(pcm
, swparams
);
103 r
= snd_pcm_prepare(pcm
);
106 r
= snd_pcm_sw_params_current(pcm
, swparams
);
109 /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */
111 n_pollfd
= snd_pcm_poll_descriptors_count(pcm
);
112 assert(n_pollfd
> 0);
114 pollfds
= malloc(sizeof(struct pollfd
) * n_pollfd
);
117 r
= snd_pcm_poll_descriptors(pcm
, pollfds
, n_pollfd
);
118 assert(r
== n_pollfd
);
121 snd_pcm_sframes_t avail
, delay
;
122 struct timespec now
, timestamp
;
123 unsigned short revents
;
125 uint64_t now_us
, timestamp_us
;
126 snd_pcm_state_t state
;
128 r
= poll(pollfds
, n_pollfd
, 0);
131 r
= snd_pcm_poll_descriptors_revents(pcm
, pollfds
, n_pollfd
, &revents
);
134 assert((revents
& ~POLLOUT
) == 0);
136 avail
= snd_pcm_avail(pcm
);
139 r
= snd_pcm_status(pcm
, status
);
142 /* This assertion fails from time to time. ALSA seems to be broken */
143 /* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */
144 /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */
146 snd_pcm_status_get_htstamp(status
, ×tamp
);
147 delay
= snd_pcm_status_get_delay(status
);
148 state
= snd_pcm_status_get_state(status
);
150 r
= clock_gettime(CLOCK_MONOTONIC
, &now
);
153 assert(!revents
|| avail
> 0);
156 snd_pcm_sframes_t sframes
;
157 static const uint16_t samples
[2] = { 0, 0 };
159 sframes
= snd_pcm_writei(pcm
, samples
, 1);
160 assert(sframes
== 1);
167 memcmp(×tamp
, &last_timestamp
, sizeof(timestamp
)) == 0 &&
168 avail
== last_avail
&&
169 delay
== last_delay
) {
174 now_us
= timespec_us(&now
);
175 timestamp_us
= timespec_us(×tamp
);
177 printf("%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n",
178 (unsigned long long) (now_us
- start_us
),
179 (unsigned long long) (timestamp_us
? timestamp_us
- start_us
: 0),
180 (unsigned long long) ((sample_count
- 1 - delay
) * 1000000LU / 44100),
187 /** When this assert is hit, most likely something bad
188 * happened, i.e. the avail jumped suddenly. */
189 assert((unsigned) avail
<= buffer_size
);
193 last_timestamp
= timestamp
;