OSDN Git Service

test: add audio_time
[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_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
37 {
38         int err;
39         snd_pcm_status_t *status;
40
41         snd_pcm_status_alloca(&status);
42         if ((err = snd_pcm_status(handle, status)) < 0) {
43                 printf("Stream status error: %s\n", snd_strerror(err));
44                 exit(0);
45         }
46         snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
47         snd_pcm_status_get_htstamp(status, timestamp);
48         *avail = snd_pcm_status_get_avail(status);
49         *delay = snd_pcm_status_get_delay(status);
50 }
51
52 #define PERIOD 6000
53 #define PCM_LINK        /* sync start for playback and capture */
54 #define TRACK_CAPTURE   /* dump capture timing info  */
55 #define TRACK_PLAYBACK  /* dump playback timing info */
56 #define PLAYBACK_BUFFERS 4
57
58
59 int main(void)
60 {
61         int err;
62         unsigned int i;
63         snd_pcm_t *handle_p = NULL;
64         snd_pcm_t *handle_c = NULL;
65         snd_pcm_sframes_t frames;
66         snd_htimestamp_t tstamp_c, tstamp_p;
67         snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
68         unsigned char buffer_p[PERIOD*4*4];
69         unsigned char buffer_c[PERIOD*4*4];
70
71         snd_pcm_sw_params_t *swparams_p;
72         snd_pcm_sw_params_t *swparams_c;
73
74         snd_pcm_uframes_t curr_count_c;
75         snd_pcm_uframes_t frame_count_c = 0;
76         snd_pcm_uframes_t curr_count_p;
77         snd_pcm_uframes_t frame_count_p = 0;
78
79         snd_pcm_sframes_t delay_p, delay_c;
80         snd_pcm_uframes_t avail_p, avail_c;
81
82         if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
83                 printf("Playback open error: %s\n", snd_strerror(err));
84                 goto _exit;
85         }
86         if ((err = snd_pcm_set_params(handle_p,
87                                       SND_PCM_FORMAT_S16,
88                                       SND_PCM_ACCESS_RW_INTERLEAVED,
89                                       2,
90                                       48000,
91                                       0,
92                                       500000)) < 0) {   /* 0.5sec */
93                 printf("Playback open error: %s\n", snd_strerror(err));
94                 goto _exit;
95         }
96
97         snd_pcm_sw_params_alloca(&swparams_p);
98         /* get the current swparams */
99         err = snd_pcm_sw_params_current(handle_p, swparams_p);
100         if (err < 0) {
101                 printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
102                 goto _exit;
103         }
104
105         /* enable tstamp */
106         err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
107         if (err < 0) {
108                 printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
109                 goto _exit;
110         }
111
112         /* write the sw parameters */
113         err = snd_pcm_sw_params(handle_p, swparams_p);
114         if (err < 0) {
115                 printf("Unable to set swparams_p : %s\n", snd_strerror(err));
116                 goto _exit;
117         }
118
119         if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
120                 printf("Capture open error: %s\n", snd_strerror(err));
121                 goto _exit;
122         }
123         if ((err = snd_pcm_set_params(handle_c,
124                                       SND_PCM_FORMAT_S16,
125                                       SND_PCM_ACCESS_RW_INTERLEAVED,
126                                       2,
127                                       48000,
128                                       0,
129                                       500000)) < 0) {   /* 0.5sec */
130                 printf("Capture open error: %s\n", snd_strerror(err));
131                 goto _exit;
132         }
133
134         snd_pcm_sw_params_alloca(&swparams_c);
135         /* get the current swparams */
136         err = snd_pcm_sw_params_current(handle_c, swparams_c);
137         if (err < 0) {
138                 printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
139                 goto _exit;
140         }
141
142         /* enable tstamp */
143         err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
144         if (err < 0) {
145                 printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
146                 goto _exit;
147         }
148
149         /* write the sw parameters */
150         err = snd_pcm_sw_params(handle_c, swparams_c);
151         if (err < 0) {
152                 printf("Unable to set swparams_c : %s\n", snd_strerror(err));
153                 goto _exit;
154         }
155
156 #ifdef PCM_LINK
157         if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
158                 printf("Streams link error: %s\n", snd_strerror(err));
159                 exit(0);
160         }
161 #endif
162
163         i = PLAYBACK_BUFFERS;
164         while (i--) {
165                 frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
166                 if (frames < 0) {
167                         printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
168                         goto _exit;
169                 }
170                 frame_count_p += frames;
171         }
172
173         if (PLAYBACK_BUFFERS != 4)
174                 snd_pcm_start(handle_p);
175
176 #ifndef PCM_LINK
177         /* need to start capture explicitly */
178         snd_pcm_start(handle_c);
179 #endif
180
181         while (1) {
182
183                 frames = snd_pcm_wait(handle_c, -1);
184                 if (frames < 0) {
185                         printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
186                         goto _exit;
187                 }
188
189                 frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
190                 if (frames < 0) {
191                         printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
192                         goto _exit;
193                 }
194                 frame_count_c += frames;
195
196                 frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
197                 if (frames < 0) {
198                         printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
199                         goto _exit;
200                 }
201
202                 frame_count_p += frames;
203
204 #if defined(TRACK_PLAYBACK)
205                 gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &avail_p, &delay_p);
206
207                 curr_count_p = frame_count_p - delay_p; /* written minus queued */
208
209                 printf("playback: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
210                         timediff(tstamp_p,trigger_tstamp_p),
211                         (long long)round(((float)curr_count_p * 1000000000.0 / 48000.0)),
212                        timediff(tstamp_p, trigger_tstamp_p) - (long long)round((double)curr_count_p * 1000000000.0 / 48000.0)
213                        );
214 #endif
215
216 #if defined(TRACK_CAPTURE)
217                 gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &avail_c, &delay_c);
218
219                 curr_count_c = frame_count_c + delay_c; /* read plus queued */
220
221                 printf("\t capture: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
222                         timediff(tstamp_c,trigger_tstamp_c),
223                         (long long)round(((float)curr_count_c * 1000000000.0 / 48000.0)),
224                        timediff(tstamp_c, trigger_tstamp_c) - (long long)round((double)curr_count_c * 1000000000.0 / 48000.0)
225                        );
226 #endif
227
228         }
229
230 _exit:
231         if (handle_p)
232                 snd_pcm_close(handle_p);
233         if (handle_c)
234                 snd_pcm_close(handle_c);
235
236         return 0;
237 }