OSDN Git Service

test/audio_time: Set timestamp type explicitly
[android-x86/external-alsa-lib.git] / test / audio_time.c
1 /*
2  * This program only tracks the difference between system time
3  * and audio time, as reported in snd_pcm_status(). It should be
4  * helpful to verify the information reported by drivers.
5  */
6
7 #include "../include/asoundlib.h"
8 #include <math.h>
9
10 static char *device = "hw:0,0";
11
12 snd_output_t *output = NULL;
13
14 long long timestamp2ns(snd_htimestamp_t t)
15 {
16         long long nsec;
17
18         nsec = t.tv_sec * 1000000000;
19         nsec += t.tv_nsec;
20
21         return nsec;
22 }
23
24 long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
25 {
26         long long nsec1, nsec2;
27
28         nsec1 = timestamp2ns(t1);
29         nsec2 = timestamp2ns(t2);
30
31         return nsec1 - nsec2;
32 }
33
34 void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
35                   snd_htimestamp_t *trigger_timestamp,
36                   snd_htimestamp_t *audio_timestamp,
37                   snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
38 {
39         int err;
40         snd_pcm_status_t *status;
41
42         snd_pcm_status_alloca(&status);
43         if ((err = snd_pcm_status(handle, status)) < 0) {
44                 printf("Stream status error: %s\n", snd_strerror(err));
45                 exit(0);
46         }
47         snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
48         snd_pcm_status_get_htstamp(status, timestamp);
49         snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
50         *avail = snd_pcm_status_get_avail(status);
51         *delay = snd_pcm_status_get_delay(status);
52 }
53
54 #define PERIOD 6000
55 #define PCM_LINK        /* sync start for playback and capture */
56 #define TRACK_CAPTURE   /* dump capture timing info  */
57 #define TRACK_PLAYBACK  /* dump playback timing info */
58 #define TRACK_SAMPLE_COUNTS /* show difference between sample counters and audiotimestamps returned by driver */
59 #define PLAYBACK_BUFFERS 4
60 #define TSTAMP_TYPE     SND_PCM_TSTAMP_TYPE_MONOTONIC
61
62
63 int main(void)
64 {
65         int err;
66         unsigned int i;
67         snd_pcm_t *handle_p = NULL;
68         snd_pcm_t *handle_c = NULL;
69         snd_pcm_sframes_t frames;
70         snd_htimestamp_t tstamp_c, tstamp_p;
71         snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
72         snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
73         unsigned char buffer_p[PERIOD*4*4];
74         unsigned char buffer_c[PERIOD*4*4];
75
76         snd_pcm_hw_params_t *hwparams_p;
77         snd_pcm_hw_params_t *hwparams_c;
78
79         snd_pcm_sw_params_t *swparams_p;
80         snd_pcm_sw_params_t *swparams_c;
81
82         snd_pcm_uframes_t curr_count_c;
83         snd_pcm_uframes_t frame_count_c = 0;
84         snd_pcm_uframes_t curr_count_p;
85         snd_pcm_uframes_t frame_count_p = 0;
86
87         snd_pcm_sframes_t delay_p, delay_c;
88         snd_pcm_uframes_t avail_p, avail_c;
89
90         if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
91                 printf("Playback open error: %s\n", snd_strerror(err));
92                 goto _exit;
93         }
94         if ((err = snd_pcm_set_params(handle_p,
95                                       SND_PCM_FORMAT_S16,
96                                       SND_PCM_ACCESS_RW_INTERLEAVED,
97                                       2,
98                                       48000,
99                                       0,
100                                       500000)) < 0) {   /* 0.5sec */
101                 printf("Playback open error: %s\n", snd_strerror(err));
102                 goto _exit;
103         }
104
105         snd_pcm_hw_params_alloca(&hwparams_p);
106         /* get the current hwparams */
107         err = snd_pcm_hw_params_current(handle_p, hwparams_p);
108         if (err < 0) {
109                 printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
110                 goto _exit;
111         }
112         if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_p))
113                 printf("Playback relies on audio wallclock timestamps\n");
114         else
115                 printf("Playback relies on audio sample counter timestamps\n");
116
117         snd_pcm_sw_params_alloca(&swparams_p);
118         /* get the current swparams */
119         err = snd_pcm_sw_params_current(handle_p, swparams_p);
120         if (err < 0) {
121                 printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
122                 goto _exit;
123         }
124
125         /* enable tstamp */
126         err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
127         if (err < 0) {
128                 printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
129                 goto _exit;
130         }
131
132         err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
133         if (err < 0) {
134                 printf("Unable to set tstamp type : %s\n", snd_strerror(err));
135                 goto _exit;
136         }
137
138         /* write the sw parameters */
139         err = snd_pcm_sw_params(handle_p, swparams_p);
140         if (err < 0) {
141                 printf("Unable to set swparams_p : %s\n", snd_strerror(err));
142                 goto _exit;
143         }
144
145         if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
146                 printf("Capture open error: %s\n", snd_strerror(err));
147                 goto _exit;
148         }
149         if ((err = snd_pcm_set_params(handle_c,
150                                       SND_PCM_FORMAT_S16,
151                                       SND_PCM_ACCESS_RW_INTERLEAVED,
152                                       2,
153                                       48000,
154                                       0,
155                                       500000)) < 0) {   /* 0.5sec */
156                 printf("Capture open error: %s\n", snd_strerror(err));
157                 goto _exit;
158         }
159
160         snd_pcm_hw_params_alloca(&hwparams_c);
161         /* get the current hwparams */
162         err = snd_pcm_hw_params_current(handle_c, hwparams_c);
163         if (err < 0) {
164                 printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
165                 goto _exit;
166         }
167         if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_c))
168                 printf("Capture relies on audio wallclock timestamps\n");
169         else
170                 printf("Capture relies on audio sample counter timestamps\n");
171
172         snd_pcm_sw_params_alloca(&swparams_c);
173         /* get the current swparams */
174         err = snd_pcm_sw_params_current(handle_c, swparams_c);
175         if (err < 0) {
176                 printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
177                 goto _exit;
178         }
179
180         /* enable tstamp */
181         err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
182         if (err < 0) {
183                 printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
184                 goto _exit;
185         }
186
187         err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
188         if (err < 0) {
189                 printf("Unable to set tstamp type : %s\n", snd_strerror(err));
190                 goto _exit;
191         }
192
193         /* write the sw parameters */
194         err = snd_pcm_sw_params(handle_c, swparams_c);
195         if (err < 0) {
196                 printf("Unable to set swparams_c : %s\n", snd_strerror(err));
197                 goto _exit;
198         }
199
200 #ifdef PCM_LINK
201         if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
202                 printf("Streams link error: %s\n", snd_strerror(err));
203                 exit(0);
204         }
205 #endif
206
207         i = PLAYBACK_BUFFERS;
208         while (i--) {
209                 frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
210                 if (frames < 0) {
211                         printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
212                         goto _exit;
213                 }
214                 frame_count_p += frames;
215         }
216
217         if (PLAYBACK_BUFFERS != 4)
218                 snd_pcm_start(handle_p);
219
220 #ifndef PCM_LINK
221         /* need to start capture explicitly */
222         snd_pcm_start(handle_c);
223 #endif
224
225         while (1) {
226
227                 frames = snd_pcm_wait(handle_c, -1);
228                 if (frames < 0) {
229                         printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
230                         goto _exit;
231                 }
232
233                 frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
234                 if (frames < 0) {
235                         printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
236                         goto _exit;
237                 }
238                 frame_count_c += frames;
239
240                 frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
241                 if (frames < 0) {
242                         printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
243                         goto _exit;
244                 }
245
246                 frame_count_p += frames;
247
248 #if defined(TRACK_PLAYBACK)
249                 gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &audio_tstamp_p, &avail_p, &delay_p);
250
251 #if defined(TRACK_SAMPLE_COUNTS)
252                 curr_count_p = frame_count_p - delay_p; /* written minus queued */
253
254                 printf("playback: curr_count %lli driver count %lli, delta %lli\n",
255                        (long long)curr_count_p * 1000000000LL / 48000 ,
256                        timestamp2ns(audio_tstamp_p),
257                        (long long)curr_count_p * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_p)
258                        );
259 #endif
260
261                 printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
262                        timediff(tstamp_p, trigger_tstamp_p),
263                        timestamp2ns(audio_tstamp_p),
264                        timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
265                        );
266 #endif
267
268 #if defined(TRACK_CAPTURE)
269                 gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &audio_tstamp_c, &avail_c, &delay_c);
270
271 #if defined(TRACK_SAMPLE_COUNTS)
272                 curr_count_c = frame_count_c + delay_c; /* read plus queued */
273
274
275                 printf("capture: curr_count %lli driver count %lli, delta %lli\n",
276                        (long long)curr_count_c * 1000000000LL / 48000 ,
277                        timestamp2ns(audio_tstamp_c),
278                        (long long)curr_count_c * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_c)
279                        );
280 #endif
281
282                 printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
283                        timediff(tstamp_c, trigger_tstamp_c),
284                        timestamp2ns(audio_tstamp_c),
285                        timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
286                        );
287 #endif
288
289         }
290
291 _exit:
292         if (handle_p)
293                 snd_pcm_close(handle_p);
294         if (handle_c)
295                 snd_pcm_close(handle_c);
296
297         return 0;
298 }