11 #include <alsa/asoundlib.h>
13 static const char *dev
;
16 static uint64_t timespec_us(const struct timespec
*ts
) {
18 ts
->tv_sec
* 1000000LLU +
19 ts
->tv_nsec
/ 1000LLU;
22 START_TEST (alsa_time_test
) {
24 snd_pcm_hw_params_t
*hwparams
;
25 snd_pcm_sw_params_t
*swparams
;
26 snd_pcm_status_t
*status
;
28 unsigned rate
= 44100;
30 snd_pcm_uframes_t boundary
, buffer_size
= 44100/10; /* 100s */
32 struct timespec start
, last_timestamp
= { 0, 0 };
34 snd_pcm_sframes_t last_avail
= 0, last_delay
= 0;
35 struct pollfd
*pollfds
;
37 int64_t sample_count
= 0;
39 snd_pcm_hw_params_alloca(&hwparams
);
40 snd_pcm_sw_params_alloca(&swparams
);
41 snd_pcm_status_alloca(&status
);
43 r
= clock_gettime(CLOCK_MONOTONIC
, &start
);
46 start_us
= timespec_us(&start
);
49 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_PLAYBACK
, 0);
51 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_CAPTURE
, 0);
54 r
= snd_pcm_hw_params_any(pcm
, hwparams
);
57 r
= snd_pcm_hw_params_set_rate_resample(pcm
, hwparams
, 0);
60 r
= snd_pcm_hw_params_set_access(pcm
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
);
63 r
= snd_pcm_hw_params_set_format(pcm
, hwparams
, SND_PCM_FORMAT_S16_LE
);
66 r
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rate
, NULL
);
69 r
= snd_pcm_hw_params_set_channels(pcm
, hwparams
, 2);
72 r
= snd_pcm_hw_params_set_periods_integer(pcm
, hwparams
);
75 r
= snd_pcm_hw_params_set_periods_near(pcm
, hwparams
, &periods
, &dir
);
78 r
= snd_pcm_hw_params_set_buffer_size_near(pcm
, hwparams
, &buffer_size
);
81 r
= snd_pcm_hw_params(pcm
, hwparams
);
84 r
= snd_pcm_hw_params_current(pcm
, hwparams
);
87 r
= snd_pcm_sw_params_current(pcm
, swparams
);
91 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 1);
93 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 0);
96 r
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, 0);
99 r
= snd_pcm_hw_params_get_buffer_size(hwparams
, &buffer_size
);
101 r
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, buffer_size
);
104 r
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
);
106 r
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
);
109 r
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
);
112 r
= snd_pcm_sw_params(pcm
, swparams
);
115 r
= snd_pcm_prepare(pcm
);
118 r
= snd_pcm_sw_params_current(pcm
, swparams
);
121 /* fail_unless(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */
123 n_pollfd
= snd_pcm_poll_descriptors_count(pcm
);
124 fail_unless(n_pollfd
> 0);
126 pollfds
= malloc(sizeof(struct pollfd
) * n_pollfd
);
127 fail_unless(pollfds
!= NULL
);
129 r
= snd_pcm_poll_descriptors(pcm
, pollfds
, n_pollfd
);
130 fail_unless(r
== n_pollfd
);
133 r
= snd_pcm_start(pcm
);
138 snd_pcm_sframes_t avail
, delay
;
139 struct timespec now
, timestamp
;
140 unsigned short revents
;
142 uint64_t now_us
, timestamp_us
;
143 snd_pcm_state_t state
;
144 unsigned long long pos
;
146 r
= poll(pollfds
, n_pollfd
, 0);
149 r
= snd_pcm_poll_descriptors_revents(pcm
, pollfds
, n_pollfd
, &revents
);
153 fail_unless((revents
& ~POLLOUT
) == 0);
155 fail_unless((revents
& ~POLLIN
) == 0);
157 avail
= snd_pcm_avail(pcm
);
158 fail_unless(avail
>= 0);
160 r
= snd_pcm_status(pcm
, status
);
163 /* This assertion fails from time to time. ALSA seems to be broken */
164 /* fail_unless(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */
165 /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */
167 snd_pcm_status_get_htstamp(status
, ×tamp
);
168 delay
= snd_pcm_status_get_delay(status
);
169 state
= snd_pcm_status_get_state(status
);
171 r
= clock_gettime(CLOCK_MONOTONIC
, &now
);
174 fail_unless(!revents
|| avail
> 0);
176 if ((!cap
&& avail
) || (cap
&& (unsigned)avail
>= buffer_size
)) {
177 snd_pcm_sframes_t sframes
;
178 static const uint16_t psamples
[2] = { 0, 0 };
179 uint16_t csamples
[2];
182 sframes
= snd_pcm_writei(pcm
, psamples
, 1);
184 sframes
= snd_pcm_readi(pcm
, csamples
, 1);
185 fail_unless(sframes
== 1);
192 memcmp(×tamp
, &last_timestamp
, sizeof(timestamp
)) == 0 &&
193 avail
== last_avail
&&
194 delay
== last_delay
) {
199 now_us
= timespec_us(&now
);
200 timestamp_us
= timespec_us(×tamp
);
203 pos
= (unsigned long long) ((sample_count
- handled
- delay
) * 1000000LU / 44100);
205 pos
= (unsigned long long) ((sample_count
- handled
+ delay
) * 1000000LU / 44100);
207 printf("%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n",
208 (unsigned long long) (now_us
- start_us
),
209 (unsigned long long) (timestamp_us
? timestamp_us
- start_us
: 0),
211 (unsigned long long) sample_count
,
219 /** When this fail_unless is hit, most likely something bad
220 * happened, i.e. the avail jumped suddenly. */
221 fail_unless((unsigned) avail
<= buffer_size
);
225 last_timestamp
= timestamp
;
230 int main(int argc
, char *argv
[]) {
236 dev
= argc
> 1 ? argv
[1] : "front:AudioPCI";
237 cap
= argc
> 2 ? atoi(argv
[2]) : 0;
239 s
= suite_create("ALSA Time");
240 tc
= tcase_create("alsatime");
241 tcase_add_test(tc
, alsa_time_test
);
242 suite_add_tcase(s
, tc
);
244 sr
= srunner_create(s
);
245 srunner_run_all(sr
, CK_NORMAL
);
246 failed
= srunner_ntests_failed(sr
);
249 return (failed
== 0) ? EXIT_SUCCESS
: EXIT_FAILURE
;