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";
41 cap
= argc
> 2 ? atoi(argv
[2]) : 0;
44 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_PLAYBACK
, 0);
46 r
= snd_pcm_open(&pcm
, dev
, SND_PCM_STREAM_CAPTURE
, 0);
49 r
= snd_pcm_hw_params_any(pcm
, hwparams
);
52 r
= snd_pcm_hw_params_set_rate_resample(pcm
, hwparams
, 0);
55 r
= snd_pcm_hw_params_set_access(pcm
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
);
58 r
= snd_pcm_hw_params_set_format(pcm
, hwparams
, SND_PCM_FORMAT_S16_LE
);
61 r
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rate
, NULL
);
64 r
= snd_pcm_hw_params_set_channels(pcm
, hwparams
, 2);
67 r
= snd_pcm_hw_params_set_periods_integer(pcm
, hwparams
);
70 r
= snd_pcm_hw_params_set_periods_near(pcm
, hwparams
, &periods
, &dir
);
73 r
= snd_pcm_hw_params_set_buffer_size_near(pcm
, hwparams
, &buffer_size
);
76 r
= snd_pcm_hw_params(pcm
, hwparams
);
79 r
= snd_pcm_hw_params_current(pcm
, hwparams
);
82 r
= snd_pcm_sw_params_current(pcm
, swparams
);
86 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 1);
88 r
= snd_pcm_sw_params_set_avail_min(pcm
, swparams
, 0);
91 r
= snd_pcm_sw_params_set_period_event(pcm
, swparams
, 0);
94 r
= snd_pcm_hw_params_get_buffer_size(hwparams
, &buffer_size
);
96 r
= snd_pcm_sw_params_set_start_threshold(pcm
, swparams
, buffer_size
);
99 r
= snd_pcm_sw_params_get_boundary(swparams
, &boundary
);
101 r
= snd_pcm_sw_params_set_stop_threshold(pcm
, swparams
, boundary
);
104 r
= snd_pcm_sw_params_set_tstamp_mode(pcm
, swparams
, SND_PCM_TSTAMP_ENABLE
);
107 r
= snd_pcm_sw_params(pcm
, swparams
);
110 r
= snd_pcm_prepare(pcm
);
113 r
= snd_pcm_sw_params_current(pcm
, swparams
);
116 /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */
118 n_pollfd
= snd_pcm_poll_descriptors_count(pcm
);
119 assert(n_pollfd
> 0);
121 pollfds
= malloc(sizeof(struct pollfd
) * n_pollfd
);
124 r
= snd_pcm_poll_descriptors(pcm
, pollfds
, n_pollfd
);
125 assert(r
== n_pollfd
);
128 r
= snd_pcm_start(pcm
);
133 snd_pcm_sframes_t avail
, delay
;
134 struct timespec now
, timestamp
;
135 unsigned short revents
;
137 uint64_t now_us
, timestamp_us
;
138 snd_pcm_state_t state
;
139 unsigned long long pos
;
141 r
= poll(pollfds
, n_pollfd
, 0);
144 r
= snd_pcm_poll_descriptors_revents(pcm
, pollfds
, n_pollfd
, &revents
);
148 assert((revents
& ~POLLOUT
) == 0);
150 assert((revents
& ~POLLIN
) == 0);
152 avail
= snd_pcm_avail(pcm
);
155 r
= snd_pcm_status(pcm
, status
);
158 /* This assertion fails from time to time. ALSA seems to be broken */
159 /* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */
160 /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */
162 snd_pcm_status_get_htstamp(status
, ×tamp
);
163 delay
= snd_pcm_status_get_delay(status
);
164 state
= snd_pcm_status_get_state(status
);
166 r
= clock_gettime(CLOCK_MONOTONIC
, &now
);
169 assert(!revents
|| avail
> 0);
171 if ((!cap
&& avail
) || (cap
&& (unsigned)avail
>= buffer_size
)) {
172 snd_pcm_sframes_t sframes
;
173 static const uint16_t psamples
[2] = { 0, 0 };
174 uint16_t csamples
[2];
177 sframes
= snd_pcm_writei(pcm
, psamples
, 1);
179 sframes
= snd_pcm_readi(pcm
, csamples
, 1);
180 assert(sframes
== 1);
187 memcmp(×tamp
, &last_timestamp
, sizeof(timestamp
)) == 0 &&
188 avail
== last_avail
&&
189 delay
== last_delay
) {
194 now_us
= timespec_us(&now
);
195 timestamp_us
= timespec_us(×tamp
);
198 pos
= (unsigned long long) ((sample_count
- handled
- delay
) * 1000000LU / 44100);
200 pos
= (unsigned long long) ((sample_count
- handled
+ delay
) * 1000000LU / 44100);
202 printf("%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n",
203 (unsigned long long) (now_us
- start_us
),
204 (unsigned long long) (timestamp_us
? timestamp_us
- start_us
: 0),
206 (unsigned long long) sample_count
,
214 /** When this assert is hit, most likely something bad
215 * happened, i.e. the avail jumped suddenly. */
216 assert((unsigned) avail
<= buffer_size
);
220 last_timestamp
= timestamp
;