sink, source: Really set the fixed latency in set_fixed_latency_within_thread(),...
[platform/upstream/pulseaudio.git] / src / tests / alsa-time-test.c
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE
3 #endif
4
5 #include <assert.h>
6 #include <inttypes.h>
7 #include <time.h>
8 #include <unistd.h>
9 #include <pthread.h>
10
11 #include <alsa/asoundlib.h>
12
13 static uint64_t timespec_us(const struct timespec *ts) {
14     return
15         ts->tv_sec * 1000000LLU +
16         ts->tv_nsec / 1000LLU;
17 }
18
19 int main(int argc, char *argv[]) {
20     const char *dev;
21     int r, cap, count = 0;
22     snd_pcm_hw_params_t *hwparams;
23     snd_pcm_sw_params_t *swparams;
24     snd_pcm_status_t *status;
25     snd_pcm_t *pcm;
26     unsigned rate = 44100;
27     unsigned periods = 2;
28     snd_pcm_uframes_t boundary, buffer_size = 44100/10; /* 100s */
29     int dir = 1;
30     struct timespec start, last_timestamp = { 0, 0 };
31     uint64_t start_us, last_us = 0;
32     snd_pcm_sframes_t last_avail = 0, last_delay = 0;
33     struct pollfd *pollfds;
34     int n_pollfd;
35     int64_t sample_count = 0;
36     struct sched_param sp;
37
38     r = -1;
39 #ifdef _POSIX_PRIORITY_SCHEDULING
40     sp.sched_priority = 5;
41     r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp);
42 #endif
43     if (r)
44         printf("Could not get RT prio. :(\n");
45
46     snd_pcm_hw_params_alloca(&hwparams);
47     snd_pcm_sw_params_alloca(&swparams);
48     snd_pcm_status_alloca(&status);
49
50     r = clock_gettime(CLOCK_MONOTONIC, &start);
51     assert(r == 0);
52
53     start_us = timespec_us(&start);
54
55     dev = argc > 1 ? argv[1] : "front:AudioPCI";
56     cap = argc > 2 ? atoi(argv[2]) : 0;
57
58     if (cap == 0)
59       r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_PLAYBACK, 0);
60     else
61       r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_CAPTURE, 0);
62     assert(r == 0);
63
64     r = snd_pcm_hw_params_any(pcm, hwparams);
65     assert(r == 0);
66
67     r = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0);
68     assert(r == 0);
69
70     r = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
71     assert(r == 0);
72
73     r = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE);
74     assert(r == 0);
75
76     r = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL);
77     assert(r == 0);
78
79     r = snd_pcm_hw_params_set_channels(pcm, hwparams, 2);
80     assert(r == 0);
81
82     r = snd_pcm_hw_params_set_periods_integer(pcm, hwparams);
83     assert(r == 0);
84
85     r = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir);
86     assert(r == 0);
87
88     r = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size);
89     assert(r == 0);
90
91     r = snd_pcm_hw_params(pcm, hwparams);
92     assert(r == 0);
93
94     r = snd_pcm_hw_params_current(pcm, hwparams);
95     assert(r == 0);
96
97     r = snd_pcm_sw_params_current(pcm, swparams);
98     assert(r == 0);
99
100     if (cap == 0)
101       r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 1);
102     else
103       r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 0);
104     assert(r == 0);
105
106     r = snd_pcm_sw_params_set_period_event(pcm, swparams, 0);
107     assert(r == 0);
108
109     r = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
110     assert(r == 0);
111     r = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size);
112     assert(r == 0);
113
114     r = snd_pcm_sw_params_get_boundary(swparams, &boundary);
115     assert(r == 0);
116     r = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary);
117     assert(r == 0);
118
119     r = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE);
120     assert(r == 0);
121
122     r = snd_pcm_sw_params(pcm, swparams);
123     assert(r == 0);
124
125     r = snd_pcm_prepare(pcm);
126     assert(r == 0);
127
128     r = snd_pcm_sw_params_current(pcm, swparams);
129     assert(r == 0);
130
131 /*     assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */
132
133     n_pollfd = snd_pcm_poll_descriptors_count(pcm);
134     assert(n_pollfd > 0);
135
136     pollfds = malloc(sizeof(struct pollfd) * n_pollfd);
137     assert(pollfds);
138
139     r = snd_pcm_poll_descriptors(pcm, pollfds, n_pollfd);
140     assert(r == n_pollfd);
141
142     printf("Starting. Buffer size is %u frames\n", (unsigned int) buffer_size);
143
144     if (cap) {
145       r = snd_pcm_start(pcm);
146       assert(r == 0);
147     }
148
149     for (;;) {
150         snd_pcm_sframes_t avail, delay;
151         struct timespec now, timestamp;
152         unsigned short revents;
153         int handled = 0;
154         uint64_t now_us, timestamp_us;
155         snd_pcm_state_t state;
156         unsigned long long pos;
157
158         r = poll(pollfds, n_pollfd, 0);
159         assert(r >= 0);
160
161         r = snd_pcm_poll_descriptors_revents(pcm, pollfds, n_pollfd, &revents);
162         assert(r == 0);
163
164         if (cap == 0)
165           assert((revents & ~POLLOUT) == 0);
166         else
167           assert((revents & ~POLLIN) == 0);
168
169         avail = snd_pcm_avail(pcm);
170         assert(avail >= 0);
171
172         r = snd_pcm_status(pcm, status);
173         assert(r == 0);
174
175         /* This assertion fails from time to time. ALSA seems to be broken */
176 /*         assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */
177 /*         printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */
178
179         snd_pcm_status_get_htstamp(status, &timestamp);
180         delay = snd_pcm_status_get_delay(status);
181         state = snd_pcm_status_get_state(status);
182
183         r = clock_gettime(CLOCK_MONOTONIC, &now);
184         assert(r == 0);
185
186         assert(!revents || avail > 0);
187
188         if ((!cap && avail) || (cap && (unsigned)avail >= buffer_size)) {
189             snd_pcm_sframes_t sframes;
190             static const uint16_t psamples[2] = { 0, 0 };
191             uint16_t csamples[2];
192
193             if (cap == 0)
194               sframes = snd_pcm_writei(pcm, psamples, 1);
195             else
196               sframes = snd_pcm_readi(pcm, csamples, 1);
197             assert(sframes == 1);
198
199             handled = 1;
200             sample_count++;
201         }
202
203         if (!handled &&
204             memcmp(&timestamp, &last_timestamp, sizeof(timestamp)) == 0 &&
205             avail == last_avail &&
206             delay == last_delay) {
207             /* This is boring */
208             continue;
209         }
210
211         now_us = timespec_us(&now);
212         timestamp_us = timespec_us(&timestamp);
213
214         if (cap == 0)
215             pos = (unsigned long long) ((sample_count - handled - delay) * 1000000LU / 44100);
216         else
217             pos = (unsigned long long) ((sample_count - handled + delay) * 1000000LU / 44100);
218
219         if (count++ % 50 == 0)
220             printf("Elapsed\tCPU\tALSA\tPos\tSamples\tavail\tdelay\trevents\thandled\tstate\n");
221
222         printf("%llu\t%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n",
223                (unsigned long long) (now_us - last_us),
224                (unsigned long long) (now_us - start_us),
225                (unsigned long long) (timestamp_us ? timestamp_us - start_us : 0),
226                pos,
227                (unsigned long long) sample_count,
228                (signed long) avail,
229                (signed long) delay,
230                revents,
231                handled,
232                state);
233
234         if (cap == 0)
235           /** When this assert is hit, most likely something bad
236            * happened, i.e. the avail jumped suddenly. */
237           assert((unsigned) avail <= buffer_size);
238
239         last_avail = avail;
240         last_delay = delay;
241         last_timestamp = timestamp;
242         last_us = now_us;
243     }
244
245     return 0;
246 }