9 #include <alsa/asoundlib.h>
11 static uint64_t timespec_us(const struct timespec
*ts
) {
13 ts
->tv_sec
* 1000000LLU +
14 ts
->tv_nsec
/ 1000LLU;
17 int main(int argc
, char *argv
[]) {
20 snd_pcm_hw_params_t
*hwparams
;
21 snd_pcm_sw_params_t
*swparams
;
22 snd_pcm_status_t
*status
;
24 unsigned rate
= 44100;
26 snd_pcm_uframes_t boundary
, buffer_size
= 44100/10; /* 100s */
28 struct timespec start
, last_timestamp
= { 0, 0 };
30 snd_pcm_sframes_t last_avail
= 0, last_delay
= 0;
31 struct pollfd
*pollfds
;
33 int64_t sample_count
= 0;
35 snd_pcm_hw_params_alloca(&hwparams
);
36 snd_pcm_sw_params_alloca(&swparams
);
37 snd_pcm_status_alloca(&status
);
39 r
= clock_gettime(CLOCK_MONOTONIC
, &start
);
42 start_us
= timespec_us(&start
);
44 dev
= argc
> 1 ? argv
[1] : "front:AudioPCI";
45 cap
= argc
> 2 ? atoi(argv
[2]) : 0;
48 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_PLAYBACK
, 0);
50 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_CAPTURE
, 0);
53 r
= snd_pcm_hw_params_any(pcm
, hwparams
);
56 r
= snd_pcm_hw_params_set_rate_resample(pcm
, hwparams
, 0);
59 r
= snd_pcm_hw_params_set_access(pcm
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
);
62 r
= snd_pcm_hw_params_set_format(pcm
, hwparams
, SND_PCM_FORMAT_S16_LE
);
65 r
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rate
, NULL
);
68 r
= snd_pcm_hw_params_set_channels(pcm
, hwparams
, 2);
71 r
= snd_pcm_hw_params_set_periods_integer(pcm
, hwparams
);
74 r
= snd_pcm_hw_params_set_periods_near(pcm
, hwparams
, &periods
, &dir
);
77 r
= snd_pcm_hw_params_set_buffer_size_near(pcm
, hwparams
, &buffer_size
);
80 r
= snd_pcm_hw_params(pcm
, hwparams
);
83 r
= snd_pcm_hw_params_current(pcm
, hwparams
);
86 r
= snd_pcm_sw_params_current(pcm
, swparams
);
90 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 1);
92 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 0);
95 r
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, 0);
98 r
= snd_pcm_hw_params_get_buffer_size(hwparams
, &buffer_size
);
100 r
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, buffer_size
);
103 r
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
);
105 r
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
);
108 r
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
);
111 r
= snd_pcm_sw_params(pcm
, swparams
);
114 r
= snd_pcm_prepare(pcm
);
117 r
= snd_pcm_sw_params_current(pcm
, swparams
);
120 /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */
122 n_pollfd
= snd_pcm_poll_descriptors_count(pcm
);
123 assert(n_pollfd
> 0);
125 pollfds
= malloc(sizeof(struct pollfd
) * n_pollfd
);
128 r
= snd_pcm_poll_descriptors(pcm
, pollfds
, n_pollfd
);
129 assert(r
== n_pollfd
);
132 r
= snd_pcm_start(pcm
);
137 snd_pcm_sframes_t avail
, delay
;
138 struct timespec now
, timestamp
;
139 unsigned short revents
;
141 uint64_t now_us
, timestamp_us
;
142 snd_pcm_state_t state
;
143 unsigned long long pos
;
145 r
= poll(pollfds
, n_pollfd
, 0);
148 r
= snd_pcm_poll_descriptors_revents(pcm
, pollfds
, n_pollfd
, &revents
);
152 assert((revents
& ~POLLOUT
) == 0);
154 assert((revents
& ~POLLIN
) == 0);
156 avail
= snd_pcm_avail(pcm
);
159 r
= snd_pcm_status(pcm
, status
);
162 /* This assertion fails from time to time. ALSA seems to be broken */
163 /* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */
164 /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */
166 snd_pcm_status_get_htstamp(status
, ×tamp
);
167 delay
= snd_pcm_status_get_delay(status
);
168 state
= snd_pcm_status_get_state(status
);
170 r
= clock_gettime(CLOCK_MONOTONIC
, &now
);
173 assert(!revents
|| avail
> 0);
175 if ((!cap
&& avail
) || (cap
&& (unsigned)avail
>= buffer_size
)) {
176 snd_pcm_sframes_t sframes
;
177 static const uint16_t psamples
[2] = { 0, 0 };
178 uint16_t csamples
[2];
181 sframes
= snd_pcm_writei(pcm
, psamples
, 1);
183 sframes
= snd_pcm_readi(pcm
, csamples
, 1);
184 assert(sframes
== 1);
191 memcmp(×tamp
, &last_timestamp
, sizeof(timestamp
)) == 0 &&
192 avail
== last_avail
&&
193 delay
== last_delay
) {
198 now_us
= timespec_us(&now
);
199 timestamp_us
= timespec_us(×tamp
);
202 pos
= (unsigned long long) ((sample_count
- handled
- delay
) * 1000000LU / 44100);
204 pos
= (unsigned long long) ((sample_count
- handled
+ delay
) * 1000000LU / 44100);
206 printf("%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n",
207 (unsigned long long) (now_us
- start_us
),
208 (unsigned long long) (timestamp_us
? timestamp_us
- start_us
: 0),
210 (unsigned long long) sample_count
,
218 /** When this assert is hit, most likely something bad
219 * happened, i.e. the avail jumped suddenly. */
220 assert((unsigned) avail
<= buffer_size
);
224 last_timestamp
= timestamp
;