OSDN Git Service

Android: add makefile and config.h
[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 <stdio.h>
8 #include <malloc.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <getopt.h>
13 #include <fcntl.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <limits.h>
17 #include <time.h>
18 #include <locale.h>
19 #include <math.h>
20 #include "../include/asoundlib.h"
21
22 static char *pcm_name = "hw:0";
23 snd_output_t *output = NULL;
24
25 static void usage(char *command)
26 {
27         printf("Usage: %s [OPTION]... \n"
28                 "\n"
29                 "-h, --help              help\n"
30                 "-c, --capture           capture tstamps \n"
31                 "-d, --delay             add delay \n"
32                 "-D, --device=NAME       select PCM by name \n"
33                 "-p, --playback          playback tstamps \n"
34                 "-t, --ts_type=TYPE      Compat(0),default(1),link(2),link_absolute(3),link_estimated(4),link_synchronized(5) \n"
35                 "-r, --report            show audio timestamp and accuracy validity\n"
36                 , command);
37 }
38
39
40 long long timestamp2ns(snd_htimestamp_t t)
41 {
42         long long nsec;
43
44         nsec = t.tv_sec * 1000000000ULL;
45         nsec += t.tv_nsec;
46
47         return nsec;
48 }
49
50 long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
51 {
52         long long nsec1, nsec2;
53
54         nsec1 = timestamp2ns(t1);
55         nsec2 = timestamp2ns(t2);
56
57         return nsec1 - nsec2;
58 }
59
60 void _gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
61                    snd_htimestamp_t *trigger_timestamp,
62                    snd_htimestamp_t *audio_timestamp,
63                    snd_pcm_audio_tstamp_config_t  *audio_tstamp_config,
64                    snd_pcm_audio_tstamp_report_t  *audio_tstamp_report,
65                    snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
66 {
67         int err;
68         snd_pcm_status_t *status;
69
70         snd_pcm_status_alloca(&status);
71
72         snd_pcm_status_set_audio_htstamp_config(status, audio_tstamp_config);
73
74         if ((err = snd_pcm_status(handle, status)) < 0) {
75                 printf("Stream status error: %s\n", snd_strerror(err));
76                 exit(0);
77         }
78         snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
79         snd_pcm_status_get_htstamp(status, timestamp);
80         snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
81         snd_pcm_status_get_audio_htstamp_report(status, audio_tstamp_report);
82         *avail = snd_pcm_status_get_avail(status);
83         *delay = snd_pcm_status_get_delay(status);
84 }
85
86 #define TIMESTAMP_FREQ 8 /* Hz */
87 #define SAMPLE_FREQ 48000
88 #define PERIOD (SAMPLE_FREQ/TIMESTAMP_FREQ)
89 #define PCM_LINK        /* sync start for playback and capture */
90 #define TRACK_CAPTURE   /* dump capture timing info  */
91 #define TRACK_PLAYBACK  /* dump playback timing info */
92 /*#define TRACK_SAMPLE_COUNTS */ /* show difference between sample counters and audiotimestamps returned by driver */
93 #define PLAYBACK_BUFFERS 4
94 #define TSTAMP_TYPE     SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW
95
96
97 int main(int argc, char *argv[])
98 {
99         int c;
100         int err;
101         unsigned int i;
102         snd_pcm_t *handle_p = NULL;
103         snd_pcm_t *handle_c = NULL;
104         snd_pcm_sframes_t frames;
105         snd_htimestamp_t tstamp_c, tstamp_p;
106         snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
107         snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
108         unsigned char buffer_p[PERIOD*4*4];
109         unsigned char buffer_c[PERIOD*4*4];
110
111         snd_pcm_hw_params_t *hwparams_p;
112         snd_pcm_hw_params_t *hwparams_c;
113
114         snd_pcm_sw_params_t *swparams_p;
115         snd_pcm_sw_params_t *swparams_c;
116
117         snd_pcm_uframes_t frame_count_c = 0;
118         snd_pcm_uframes_t frame_count_p = 0;
119
120         snd_pcm_sframes_t delay_p, delay_c;
121         snd_pcm_uframes_t avail_p, avail_c;
122
123         snd_pcm_audio_tstamp_config_t audio_tstamp_config_p;
124         snd_pcm_audio_tstamp_config_t audio_tstamp_config_c;
125         snd_pcm_audio_tstamp_report_t audio_tstamp_report_p;
126         snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
127
128         int option_index;
129         static const char short_options[] = "hcpdrD:t:";
130
131         static const struct option long_options[] = {
132                 {"capture", 0, 0, 'c'},
133                 {"delay", 0, 0, 'd'},
134                 {"device", required_argument, 0, 'D'},
135                 {"help", no_argument, 0, 'h'},
136                 {"playback", 0, 0, 'p'},
137                 {"ts_type", required_argument, 0, 't'},
138                 {"report", 0, 0, 'r'},
139                 {0, 0, 0, 0}
140         };
141
142         int do_delay = 0;
143         int do_playback = 0;
144         int do_capture = 0;
145         int type = 0;
146         int do_report = 0;
147
148         while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
149                 switch (c) {
150                 case 'h':
151                         usage(argv[0]);
152                         return 0;
153                 case 'p':
154                         do_playback = 1;
155                         break;
156                 case 'c':
157                         do_capture = 1;
158                         break;
159                 case 'd':
160                         do_delay = 1;
161                         break;
162                 case 'D':
163                         pcm_name = optarg;
164                         break;
165                 case 't':
166                         type = atoi(optarg);
167                         break;
168                 case 'r':
169                         do_report = 1;
170                 }
171         }
172
173         memset(&audio_tstamp_config_p, 0, sizeof(snd_pcm_audio_tstamp_config_t));
174         memset(&audio_tstamp_config_c, 0, sizeof(snd_pcm_audio_tstamp_config_t));
175         memset(&audio_tstamp_report_p, 0, sizeof(snd_pcm_audio_tstamp_report_t));
176         memset(&audio_tstamp_report_c, 0, sizeof(snd_pcm_audio_tstamp_report_t));
177
178         if (do_playback) {
179                 if ((err = snd_pcm_open(&handle_p, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
180                         printf("Playback open error: %s\n", snd_strerror(err));
181                         goto _exit;
182                 }
183
184                 if ((err = snd_pcm_set_params(handle_p,
185                                                         SND_PCM_FORMAT_S16,
186                                                         SND_PCM_ACCESS_RW_INTERLEAVED,
187                                                         2,
188                                                         SAMPLE_FREQ,
189                                                         0,
190                                                         4*1000000/TIMESTAMP_FREQ)) < 0) {
191                         printf("Playback open error: %s\n", snd_strerror(err));
192                         goto _exit;
193                 }
194
195                 snd_pcm_hw_params_alloca(&hwparams_p);
196 /* get the current hwparams */
197                 err = snd_pcm_hw_params_current(handle_p, hwparams_p);
198                 if (err < 0) {
199                         printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
200                         goto _exit;
201                 }
202
203                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT))
204                         printf("Playback supports audio compat timestamps\n");
205                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT))
206                         printf("Playback supports audio default timestamps\n");
207                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK))
208                         printf("Playback supports audio link timestamps\n");
209                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE))
210                         printf("Playback supports audio link absolute timestamps\n");
211                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED))
212                         printf("Playback supports audio link estimated timestamps\n");
213                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED))
214                         printf("Playback supports audio link synchronized timestamps\n");
215
216                 snd_pcm_sw_params_alloca(&swparams_p);
217                 /* get the current swparams */
218                 err = snd_pcm_sw_params_current(handle_p, swparams_p);
219                 if (err < 0) {
220                         printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
221                         goto _exit;
222                 }
223
224                 /* enable tstamp */
225                 err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
226                 if (err < 0) {
227                         printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
228                         goto _exit;
229                 }
230
231                 err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
232                 if (err < 0) {
233                         printf("Unable to set tstamp type : %s\n", snd_strerror(err));
234                         goto _exit;
235                 }
236
237                 /* write the sw parameters */
238                 err = snd_pcm_sw_params(handle_p, swparams_p);
239                 if (err < 0) {
240                         printf("Unable to set swparams_p : %s\n", snd_strerror(err));
241                         goto _exit;
242                 }
243
244         }
245
246         if (do_capture) {
247
248                 if ((err = snd_pcm_open(&handle_c, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
249                         printf("Capture open error: %s\n", snd_strerror(err));
250                         goto _exit;
251                 }
252                 if ((err = snd_pcm_set_params(handle_c,
253                                                         SND_PCM_FORMAT_S16,
254                                                         SND_PCM_ACCESS_RW_INTERLEAVED,
255                                                         2,
256                                                         SAMPLE_FREQ,
257                                                         0,
258                                                         4*1000000/TIMESTAMP_FREQ)) < 0) {
259                         printf("Capture open error: %s\n", snd_strerror(err));
260                         goto _exit;
261                 }
262
263                 snd_pcm_hw_params_alloca(&hwparams_c);
264                 /* get the current hwparams */
265                 err = snd_pcm_hw_params_current(handle_c, hwparams_c);
266                 if (err < 0) {
267                         printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
268                         goto _exit;
269                 }
270
271                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT))
272                         printf("Capture supports audio compat timestamps\n");
273                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT))
274                         printf("Capture supports audio default timestamps\n");
275                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK))
276                         printf("Capture supports audio link timestamps\n");
277                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE))
278                         printf("Capture supports audio link absolute timestamps\n");
279                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED))
280                         printf("Capture supports audio link estimated timestamps\n");
281                 if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED))
282                         printf("Capture supports audio link synchronized timestamps\n");
283
284                 snd_pcm_sw_params_alloca(&swparams_c);
285                 /* get the current swparams */
286                 err = snd_pcm_sw_params_current(handle_c, swparams_c);
287                 if (err < 0) {
288                         printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
289                         goto _exit;
290                 }
291
292                 /* enable tstamp */
293                 err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
294                 if (err < 0) {
295                         printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
296                         goto _exit;
297                 }
298
299                 err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
300                 if (err < 0) {
301                         printf("Unable to set tstamp type : %s\n", snd_strerror(err));
302                         goto _exit;
303                 }
304
305                 /* write the sw parameters */
306                 err = snd_pcm_sw_params(handle_c, swparams_c);
307                 if (err < 0) {
308                         printf("Unable to set swparams_c : %s\n", snd_strerror(err));
309                         goto _exit;
310                 }
311         }
312
313         if (do_playback && do_capture) {
314 #ifdef PCM_LINK
315                 if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
316                         printf("Streams link error: %s\n", snd_strerror(err));
317                         exit(0);
318                 }
319 #endif
320         }
321
322         if (do_playback) {
323                 i = PLAYBACK_BUFFERS;
324                 while (i--) {
325                         frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
326                         if (frames < 0) {
327                                 printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
328                                 goto _exit;
329                         }
330                         frame_count_p += frames;
331                 }
332
333                 if (PLAYBACK_BUFFERS != 4)
334                         snd_pcm_start(handle_p);
335         }
336
337         if (do_capture) {
338 #ifndef PCM_LINK
339                 /* need to start capture explicitly */
340                 snd_pcm_start(handle_c);
341 #else
342                 if (!do_playback)
343                         /* need to start capture explicitly */
344                         snd_pcm_start(handle_c);
345 #endif
346         }
347
348         while (1) {
349
350                 if (do_capture) {
351
352                         frames = snd_pcm_wait(handle_c, -1);
353                         if (frames < 0) {
354                                 printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
355                                 goto _exit;
356                         }
357
358                         frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
359                         if (frames < 0) {
360                                 printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
361                                 goto _exit;
362                         }
363                         frame_count_c += frames;
364
365 #if defined(TRACK_CAPTURE)
366                         audio_tstamp_config_c.type_requested = type;
367                         audio_tstamp_config_c.report_delay = do_delay;
368                         _gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c,
369                                 &audio_tstamp_c, &audio_tstamp_config_c, &audio_tstamp_report_c,
370                                 &avail_c, &delay_c);
371 #if defined(TRACK_SAMPLE_COUNTS)
372                         curr_count_c = frame_count_c + delay_c; /* read plus queued */
373
374
375                         printf("capture: curr_count %lli driver count %lli, delta %lli\n",
376                                 (long long)curr_count_c * 1000000000LL / SAMPLE_FREQ ,
377                                 timestamp2ns(audio_tstamp_c),
378                                 (long long)curr_count_c * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
379                                 );
380 #endif
381                         if (do_report) {
382                                 if (audio_tstamp_report_c.valid == 0)
383                                         printf("Audio capture timestamp report invalid - ");
384                                 if (audio_tstamp_report_c.accuracy_report == 0)
385                                         printf("Audio capture timestamp accuracy report invalid");
386                                 printf("\n");
387                         }
388
389
390                         printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli \t resolution %d ns \n", 
391                                 timediff(tstamp_c, trigger_tstamp_c),
392                                 timestamp2ns(audio_tstamp_c),
393                                 timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c), audio_tstamp_report_c.accuracy
394                                 );
395 #endif
396                 }
397
398                 if (do_playback) {
399                         frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
400                         if (frames < 0) {
401                                 printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
402                                 goto _exit;
403                         }
404
405                         frame_count_p += frames;
406
407 #if defined(TRACK_PLAYBACK)
408
409                         audio_tstamp_config_p.type_requested = type;
410                         audio_tstamp_config_p.report_delay = do_delay;
411                         _gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p,
412                                 &audio_tstamp_p, &audio_tstamp_config_p, &audio_tstamp_report_p,
413                                 &avail_p, &delay_p);
414
415 #if defined(TRACK_SAMPLE_COUNTS)
416                         curr_count_p = frame_count_p - delay_p; /* written minus queued */
417
418                         printf("playback: curr_count %lli driver count %lli, delta %lli\n",
419                                 (long long)curr_count_p * 1000000000LL / SAMPLE_FREQ ,
420                                 timestamp2ns(audio_tstamp_p),
421                                 (long long)curr_count_p * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
422                                 );
423 #endif
424                         if (do_report) {
425                                 if (audio_tstamp_report_p.valid == 0)
426                                         printf("Audio playback timestamp report invalid - ");
427                                 if (audio_tstamp_report_p.accuracy_report == 0)
428                                         printf("Audio playback timestamp accuracy report invalid");
429                                 printf("\n");
430                         }
431
432                         printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli resolution %d ns\n",
433                                 timediff(tstamp_p, trigger_tstamp_p),
434                                 timestamp2ns(audio_tstamp_p),
435                                 timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p), audio_tstamp_report_p.accuracy
436                                 );
437 #endif
438                 }
439
440
441         } /* while(1) */
442
443 _exit:
444         if (handle_p)
445                 snd_pcm_close(handle_p);
446         if (handle_c)
447                 snd_pcm_close(handle_c);
448
449         return 0;
450 }