blob: 5d94cbf498cc01bb6aa2d45444fa13689d772c04 [file] [log] [blame]
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +08001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <alsa/asoundlib.h>
8#include <getopt.h>
9#include <math.h>
10#include <pthread.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/time.h>
14#include <unistd.h>
15
16static unsigned rate = 48000;
17static unsigned channels = 2;
18static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
19static char *play_dev = "hw:0,0";
20/* Buffer size will be the maximum supported by hardware. */
21static snd_pcm_uframes_t buffer_frames;
22static snd_pcm_uframes_t period_size = 240;
23
24/* Fill frames of zeros. */
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +080025static void pcm_fill(snd_pcm_t *handle, snd_pcm_uframes_t frames,
26 int16_t value) {
27 int16_t *play_buf;
28 int err, i;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +080029
30 play_buf = calloc(frames * channels, sizeof(play_buf[0]));
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +080031 for (i = 0; i < frames * channels; i++)
32 play_buf[i] = value;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +080033
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +080034 printf("Write %ld of value %d into device\n", frames, (int)value);
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +080035
36 if ((err = snd_pcm_mmap_writei(handle, play_buf, frames))
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +080037 != frames) {
38 fprintf(stderr, "write to audio interface failed (%s)\n",
39 snd_strerror(err));
40 }
41
42 free(play_buf);
43}
44
45static void pcm_hw_param(snd_pcm_t *handle) {
46 int err;
47 snd_pcm_hw_params_t *hw_params;
48
49 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
50 fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",
51 snd_strerror(err));
52 exit(1);
53 }
54
55 if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {
56 fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",
57 snd_strerror(err));
58 exit(1);
59 }
60
61 if ((err = snd_pcm_hw_params_set_access(handle, hw_params,
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +080062 SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +080063 fprintf(stderr, "cannot set access type (%s)\n",
64 snd_strerror(err));
65 exit(1);
66 }
67
68 if ((err = snd_pcm_hw_params_set_format(handle, hw_params,
69 format)) < 0) {
70 fprintf(stderr, "cannot set sample format (%s)\n",
71 snd_strerror(err));
72 exit(1);
73 }
74
75 if ((err = snd_pcm_hw_params_set_rate_near(
76 handle, hw_params, &rate, 0)) < 0) {
77 fprintf(stderr, "cannot set sample rate (%s)\n",
78 snd_strerror(err));
79 exit(1);
80 }
81
82 if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, 2)) < 0) {
83 fprintf(stderr, "cannot set channel count (%s)\n",
84 snd_strerror(err));
85 exit(1);
86 }
87
88 /* Makes sure buffer frames is even, or snd_pcm_hw_params will
89 * return invalid argument error. */
90 if ((err = snd_pcm_hw_params_get_buffer_size_max(
91 hw_params, &buffer_frames)) < 0) {
92 fprintf(stderr, "get buffer max (%s)\n", snd_strerror(err));
93 exit(1);
94 }
95
96 buffer_frames &= ~0x01;
97 if ((err = snd_pcm_hw_params_set_buffer_size_max(
98 handle, hw_params, &buffer_frames)) < 0) {
99 fprintf(stderr, "set_buffer_size_max (%s)\n", snd_strerror(err));
100 exit(1);
101 }
102
103 printf("buffer size set to %u\n", (unsigned int)buffer_frames);
104
105 if ((err = snd_pcm_hw_params(handle, hw_params)) < 0) {
106 fprintf(stderr, "cannot set parameters (%s)\n",
107 snd_strerror(err));
108 exit(1);
109 }
110
111 snd_pcm_hw_params_free(hw_params);
112}
113
114static void pcm_sw_param(snd_pcm_t *handle) {
115 int err;
116 snd_pcm_sw_params_t *swparams;
117 snd_pcm_uframes_t boundary;
118
119 snd_pcm_sw_params_alloca(&swparams);
120
121 err = snd_pcm_sw_params_current(handle, swparams);
122 if (err < 0) {
123 fprintf(stderr, "sw_params_current: %s\n", snd_strerror(err));
124 exit(1);
125 }
126
127 err = snd_pcm_sw_params_get_boundary(swparams, &boundary);
128 if (err < 0) {
129 fprintf(stderr, "get_boundary: %s\n", snd_strerror(err));
130 exit(1);
131 }
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800132 printf("boundary = %lu\n", boundary);
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800133
134 err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, boundary);
135 if (err < 0) {
136 fprintf(stderr, "set_stop_threshold: %s\n", snd_strerror(err));
137 exit(1);
138 }
139
140 /* Don't auto start. */
141 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, boundary);
142 if (err < 0) {
143 fprintf(stderr, "set_stop_threshold: %s\n", snd_strerror(err));
144 exit(1);
145 }
146
147 /* Disable period events. */
148 err = snd_pcm_sw_params_set_period_event(handle, swparams, 0);
149 if (err < 0) {
150 fprintf(stderr, "set_period_event: %s\n", snd_strerror(err));
151 exit(1);
152 }
153
154 err = snd_pcm_sw_params(handle, swparams);
155 if (err < 0) {
156 fprintf(stderr, "sw_params: %s\n", snd_strerror(err));
157 exit(1);
158 }
159}
160
161static void pcm_init(snd_pcm_t *handle)
162{
163 int err;
164 pcm_hw_param(handle);
165 pcm_sw_param(handle);
166
167 if ((err = snd_pcm_prepare(handle)) < 0) {
168 fprintf(stderr, "cannot prepare audio interface (%s)\n",
169 snd_strerror(err));
170 exit(1);
171 }
172
173 if ((err = snd_pcm_start(handle)) < 0) {
174 fprintf(stderr, "cannot start audio interface (%s)\n",
175 snd_strerror(err));
176 exit(1);
177 }
178}
179
180/* Waits for target_periods periods and logs time stamp and snd_pcm_avail
181 * value in each period.
182 */
183static void wait_for_periods(snd_pcm_t *handle, unsigned int target_periods)
184{
185 unsigned int num_periods = 0;
186 unsigned int wake_period_us = period_size * 1E6 / rate;
187 struct timespec now;
188 snd_pcm_sframes_t avail_frames;
Cheng-Yi Chianga566ab82016-06-24 15:22:25 +0800189 while (1) {
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800190 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
191 printf("time: %ld.%09ld", (long)now.tv_sec, (long)now.tv_nsec);
192 avail_frames = snd_pcm_avail(handle);
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800193 printf(" state: %d, avail frames: %ld, hw_level: %ld\n",
194 (int)snd_pcm_state(handle), avail_frames,
195 buffer_frames - avail_frames);
Cheng-Yi Chianga566ab82016-06-24 15:22:25 +0800196 /* Breaks here so we can print the last timestamp and frames. */
197 if (num_periods == target_periods)
198 break;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800199 num_periods++;
200 usleep(wake_period_us);
201 }
202}
203
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800204void check_hw_level_in_range(snd_pcm_sframes_t hw_level,
205 snd_pcm_sframes_t min,
206 snd_pcm_sframes_t max)
207{
208 printf("Expected range: %ld - %ld\n", min, max);
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800209 if (hw_level <= max && hw_level >= min) {
210 printf("hw_level is in the expected range\n");
211 } else {
212 fprintf(stderr,
213 "hw_level is not in the expected range\n");
214 exit(1);
215 }
216}
217
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800218void move_appl_ptr(snd_pcm_t *handle, snd_pcm_sframes_t fuzz)
219{
220 int err = 0;
221 snd_pcm_sframes_t to_move, hw_level, avail_frames;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800222
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800223 avail_frames = snd_pcm_avail(handle);
224 printf("Available frames: %ld\n", avail_frames);
225 hw_level = buffer_frames - avail_frames;
226 printf("hw_level frames: %ld\n", hw_level);
227
228 /* We want to move appl_ptr to hw_ptr plus fuzz such that hardware can
229 * play the new samples as quick as possible.
230 * The difference between hw_ptr and app can be inferred from snd_pcm_avail.
231 * avail = buffer_frames - appl_ptr + hw_ptr
232 * => hw_ptr - appl_ptr = avail - buffer_frames.
233 * The amount to forward is fuzz - hw_level = fuzz - appl_ptr - hw_ptr.
234 * Depending on the sign of this value, we need to forward or rewind
235 * appl_ptr. Check go/cros-low-latency for detailed explanation.
236 */
237 to_move = fuzz + avail_frames - buffer_frames;
238 if (to_move > 0) {
239 printf("forward by %ld\n", to_move);
240 err = snd_pcm_forward(handle, to_move);
241 } else if (to_move < 0) {
242 printf("rewind by %ld\n", -to_move);
243 err = snd_pcm_rewind(handle, -to_move);
244 } else {
245 printf("no need to move\n");
246 return;
247 }
248
249 if (err < 0) {
250 fprintf(stderr, "cannot move appl ptr (%s)\n",
251 snd_strerror(err));
252 exit(1);
253 }
254}
255
256void check_appl_ptr(snd_pcm_t *handle, snd_pcm_sframes_t fuzz)
257{
258 snd_pcm_sframes_t hw_level, avail_frames;
Cheng-Yi Chiang0ce06552016-07-13 15:18:06 +0800259 int periods_after_move;
Cheng-Yi Chiang547ee7b2016-06-30 15:50:10 +0800260 struct timespec time_1, time_2;
261 snd_pcm_sframes_t level_1, level_2;
262 float time_diff, measure_rate;
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800263
264 /* Checks the result after moving. The hw_level should be in the range
265 * 0 - fuzz. */
266 avail_frames = snd_pcm_avail(handle);
267 printf("Available frames after move: %ld\n", avail_frames);
268 hw_level = buffer_frames - avail_frames;
269 printf("hw_level after moving: %ld\n", hw_level);
270
271 check_hw_level_in_range(hw_level, 0, fuzz);
272
Cheng-Yi Chiang0ce06552016-07-13 15:18:06 +0800273 /* Fills some zeros after moving to make sure PCM still plays fine.
274 * Sets periods_after_move so device will play half of buffer size.
275 * This would result in an accurate estimated sampling rate. */
276 periods_after_move = (buffer_frames >> 1) / period_size;
277 printf("Test playback for %d periods after move\n", periods_after_move);
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800278 pcm_fill(handle, period_size * periods_after_move, 0);
Cheng-Yi Chiang547ee7b2016-06-30 15:50:10 +0800279 clock_gettime(CLOCK_MONOTONIC_RAW, &time_1);
280 printf("time: %ld.%09ld", (long)time_1.tv_sec, (long)time_1.tv_nsec);
281 level_1 = buffer_frames - snd_pcm_avail(handle);
282 printf(" hw_level after filling %d period is %ld\n",
283 periods_after_move, level_1);
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800284
285 wait_for_periods(handle, periods_after_move - 1);
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800286
Cheng-Yi Chiang547ee7b2016-06-30 15:50:10 +0800287 clock_gettime(CLOCK_MONOTONIC_RAW, &time_2);
288 printf("time: %ld.%09ld", (long)time_2.tv_sec, (long)time_2.tv_nsec);
289 level_2 = buffer_frames - snd_pcm_avail(handle);
290 printf(" hw_level after playing %d period is %ld\n",
291 periods_after_move - 1, level_2);
292
293 /* Checks the device consumption rate in this duration is reasonable. */
294 time_diff = (time_2.tv_sec - time_1.tv_sec) +
295 (float)(time_2.tv_nsec - time_1.tv_nsec) * 1E-9;
296 measure_rate = (level_1 - level_2) / time_diff;
297
298 if (fabsf(measure_rate - rate) <= 1000) {
299 printf("rate %f is in the expected range near %u\n",
300 measure_rate, rate);
301 } else {
302 fprintf(stderr, "rate %f is not in the expected range near %u\n",
303 measure_rate, rate);
304 exit(1);
305 }
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800306}
307
308void move_and_check(snd_pcm_t *handle, snd_pcm_sframes_t fuzz)
309{
310 move_appl_ptr(handle, fuzz);
311 check_appl_ptr(handle, fuzz);
312}
313
314void alsa_move_test(unsigned int wait_periods)
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800315{
316 int err;
317 snd_pcm_t *handle;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800318 snd_pcm_sframes_t fuzz = 50;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800319
320 if ((err = snd_pcm_open(&handle, play_dev,
321 SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
322 fprintf(stderr, "cannot open audio device %s (%s)\n",
323 play_dev, snd_strerror(err));
324 exit(1);
325 }
326
327 pcm_init(handle);
328
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800329 pcm_fill(handle, buffer_frames, 0);
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800330
331 wait_for_periods(handle, wait_periods);
332
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800333 move_and_check(handle, fuzz);
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800334
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800335 if ((err = snd_pcm_close(handle)) < 0) {
336 fprintf(stderr, "cannot close device (%s)\n", snd_strerror(err));
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800337 exit(1);
338 }
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800339}
340
341/* Checks if snd_pcm_drop resets the hw_ptr to 0. See bug crosbug.com/p/51882.
342 */
343void alsa_drop_test()
344{
345 int err;
346 snd_pcm_t *handle;
347 snd_pcm_sframes_t frames;
348 snd_pcm_sframes_t fuzz = 50;
349 unsigned int wait_periods = 50;
350
351 if ((err = snd_pcm_open(
352 &handle, play_dev, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
353 fprintf(stderr, "cannot open audio device %s (%s)\n",
354 play_dev, snd_strerror(err));
355 exit(1);
356 }
357
358 pcm_init(handle);
359
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800360 pcm_fill(handle, buffer_frames, 0);
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800361
362 wait_for_periods(handle, wait_periods);
363
364 /* Drop the samples. */
365 if ((err = snd_pcm_drop(handle)) < 0) {
366 fprintf(stderr, "cannot drop audio interface (%s)\n",
367 snd_strerror(err));
368 exit(1);
369 }
370
371 /* Prepare and start playback again. */
372 if ((err = snd_pcm_prepare(handle)) < 0) {
373 fprintf(stderr, "cannot prepare audio interface (%s)\n",
374 snd_strerror(err));
375 exit(1);
376 }
377
378 if ((err = snd_pcm_start(handle)) < 0) {
379 fprintf(stderr, "cannot start for the second time (%s)\n",
380 snd_strerror(err));
381 exit(1);
382 }
383
384 /* The avail should be a reasonable value that is slightly larger than
385 * buffer level. avail = buffer - (appl_ptr - hw_ptr).
386 * The expected behavior:
387 * snd_pcm_drop: hw_ptr should be 0.
388 * snd_pcm_prepare: appl_ptr should be the same as hw_ptr, which is 0.
389 * snd_pcm_start: hw_ptr gets synced to hardware, should be a small number.
390 * So, the new avail should be slightly larger than buffer. */
391 frames = snd_pcm_avail(handle);
392
393 printf("Avail frames after drop, prepare, start: %d\n", (int)frames);
394
395 if ((err = snd_pcm_close(handle)) < 0) {
396 fprintf(stderr, "cannot close device (%s)\n", snd_strerror(err));
397 exit(1);
398 }
399
400 printf("Expected avail frames after drop, prepare, start is 0 - %d\n",
401 (int)(buffer_frames + fuzz));
402
403 if (frames < 0 || frames > buffer_frames + fuzz) {
404 fprintf(stderr, "Avail frames after drop, prepare, start is %d\n",
405 (int)frames);
406 exit(1);
407 }
408}
409
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800410void alsa_fill_test()
411{
412 int err;
413 snd_pcm_t *handle;
414 unsigned int wait_periods = 10;
415 const snd_pcm_channel_area_t *my_areas;
416 snd_pcm_uframes_t offset, frames;
417 int16_t *dst, *zeros;
418 int n_bytes;
419
420 if ((err = snd_pcm_open(&handle, play_dev,
421 SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
422 fprintf(stderr, "cannot open audio device %s (%s)\n",
423 play_dev, snd_strerror(err));
424 exit(1);
425 }
426
427 pcm_init(handle);
428
429 /* Write nonzero values into buffer. */
430 pcm_fill(handle, buffer_frames, 1);
431
432 /* Play for some periods. */
433 wait_for_periods(handle, wait_periods);
434
435 /* Get the mmap area. */
436 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
437 if (err < 0) {
438 fprintf(stderr, "cannot mmap begin (%s)\n", snd_strerror(err));
439 exit(1);
440 }
441
442 /* Fill whole buffer with zeros without committing it.
443 * The number of bytes is buffer_frames * channel * 2 (16 bit sample) */
444 n_bytes = buffer_frames * channels * 2;
445 memset((int8_t *)my_areas[0].addr, 0, n_bytes);
446 printf("Filled mmap buffer with zeros\n");
447
448 /* Play for some periods. */
449 wait_for_periods(handle, wait_periods);
450
451 /* Check the samples in buffer are all zeros. */
452 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
453 if (err < 0) {
454 fprintf(stderr, "cannot mmap begin the second time (%s)\n",
455 snd_strerror(err));
456 exit(1);
457 }
458 dst = (int16_t *)my_areas[0].addr;
459
460 zeros = calloc(buffer_frames * channels, sizeof(zeros[0]));
461
462 if (memcmp(zeros, dst, n_bytes)) {
463 fprintf(stderr, "buffer is not all zeros\n");
464 free(zeros);
465 exit(1);
466 }
467 free(zeros);
468 printf("Buffer is filled with zeros\n");
469}
470
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800471int main(int argc, char *argv[])
472{
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800473 int c, drop_test = 0, move_test = 0, fill_test = 0;
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800474 const char *short_opt = "hd:rm";
475 struct option long_opt[] =
476 {
477 {"help", no_argument, NULL, 'h'},
478 {"device", required_argument, NULL, 'd'},
479 {"drop", no_argument, NULL, 'r'},
480 {"move", no_argument, NULL, 'm'},
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800481 {"fill", no_argument, NULL, 'f'},
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800482 {NULL, 0, NULL, 0 }
483 };
484
485 while(1) {
486 c = getopt_long(argc, argv, short_opt, long_opt, NULL);
487 if (c == -1)
488 break;
489 switch(c) {
490 case 'd':
491 play_dev = optarg;
492 printf("Assign play_dev to %s\n", play_dev);
493 break;
494
495 case 'r':
496 drop_test = 1;
497 printf("Test snd_pcm_drop\n");
498 break;
499
500 case 'm':
501 move_test = 1;
502 printf("Test snd_pcm_forward\n");
503 break;
504
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800505 case 'f':
506 fill_test = 1;
507 printf("Test snd_pcm_mmap_begin and filling buffer.\n");
508 break;
509
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800510 case 'h':
511 printf("Usage: %s [OPTIONS]\n", argv[0]);
512 printf(" --device <Device> Device, default to hw:0,0\n");
513 printf(" -h, --help Print this help and exit\n");
514 printf(" --drop Test snd_pcm_drop\n");
Cheng-Yi Chiang0ce06552016-07-13 15:18:06 +0800515 printf(" --move Test snd_pcm_rewind and "
516 "snd_pcm_forward\n");
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800517 printf(" --fill Test snd_pcm_mmap_begin\n");
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800518 printf("\n");
519 return(0);
520 break;
521
522 case ':':
523 case '?':
524 fprintf(stderr, "Try `%s --help' for more information.\n",
525 argv[0]);
526 exit(EXIT_FAILURE);
527
528 default:
529 fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
530 fprintf(stderr, "Try `%s --help' for more information.\n",
531 argv[0]);
532 exit(EXIT_FAILURE);
533 }
534 }
535
536 if (drop_test) {
537 alsa_drop_test();
538 exit(0);
539 }
540
541 if (move_test) {
Cheng-Yi Chiang5af2f5e2016-05-13 18:25:48 +0800542 /* Test rewind and forward.
543 * - Waiting 10 periods: appl_ptr is still ahead of hw_ptr, test
544 * snd_pcm_rewind call.
545 * - Waiting 1000 periods: hw_ptr is ahead of appl_ptr, test
546 * snd_pcm_forward call.
547 */
548 alsa_move_test(10);
549 alsa_move_test(1000);
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800550 exit(0);
551 }
552
Cheng-Yi Chiang16c4c192016-05-03 12:28:42 +0800553 if (fill_test) {
554 alsa_fill_test();
555 exit(0);
556 }
557
Cheng-Yi Chiangb8755a32016-04-13 10:17:56 +0800558 exit(0);
559}