blob: 707fe2d9a7857592d7b08c6302c17150bbabe37a [file] [log] [blame]
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +08001/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
Earl Ou7ae955b2016-11-30 16:41:22 +080021#include <math.h>
22#include <pthread.h>
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +080023#include <stdio.h>
24#include <stdlib.h>
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +080025#include <sys/time.h>
Earl Ou7ae955b2016-11-30 16:41:22 +080026
27#include <alsa/asoundlib.h>
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +080028
29#include "cras_client.h"
30
31#define CAPTURE_MORE_COUNT 50
32#define PLAYBACK_COUNT 50
33#define PLAYBACK_SILENT_COUNT 50
34#define PLAYBACK_TIMEOUT_COUNT 100
35
36static double phase = M_PI / 2;
37static unsigned rate = 48000;
38static unsigned channels = 2;
39static snd_pcm_uframes_t buffer_frames = 480;
40static snd_pcm_uframes_t period_size = 240;
41static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
42
43static struct timeval *cras_play_time = NULL;
44static struct timeval *cras_cap_time = NULL;
45static int noise_threshold = 0x4000;
46
47static int capture_count;
48static int playback_count;
49static snd_pcm_sframes_t playback_delay_frames;
50static struct timeval sine_start_tv;
51
52// Mutex and the variables to protect.
53static pthread_mutex_t latency_test_mutex;
54static pthread_cond_t terminate_test;
55static pthread_cond_t sine_start;
56static int terminate_playback;
57static int terminate_capture;
58static int sine_started = 0;
59
60static void generate_sine(const snd_pcm_channel_area_t *areas,
61 snd_pcm_uframes_t offset, int count,
62 double *_phase)
63{
64 static double max_phase = 2. * M_PI;
65 double phase = *_phase;
66 double step = max_phase * 1000 / (double)rate;
67 unsigned char *samples[channels];
68 int steps[channels];
69 unsigned int chn;
70 int format_bits = snd_pcm_format_width(format);
71 unsigned int maxval = (1 << (format_bits - 1)) - 1;
72 int bps = format_bits / 8; /* bytes per sample */
73 int phys_bps = snd_pcm_format_physical_width(format) / 8;
74 int big_endian = snd_pcm_format_big_endian(format) == 1;
75 int to_unsigned = snd_pcm_format_unsigned(format) == 1;
76 int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
77 format == SND_PCM_FORMAT_FLOAT_BE);
78
79 /* Verify and prepare the contents of areas */
80 for (chn = 0; chn < channels; chn++) {
81 if ((areas[chn].first % 8) != 0) {
82 fprintf(stderr, "areas[%i].first == %i, aborting...\n", chn,
83 areas[chn].first);
84 exit(EXIT_FAILURE);
85 }
86 if ((areas[chn].step % 16) != 0) {
87 fprintf(stderr, "areas[%i].step == %i, aborting...\n", chn, areas
88 [chn].step);
89 exit(EXIT_FAILURE);
90 }
91 steps[chn] = areas[chn].step / 8;
92 samples[chn] = ((unsigned char *)areas[chn].addr) +
93 (areas[chn].first / 8) + offset * steps[chn];
94 }
95
96 /* Fill the channel areas */
97 while (count-- > 0) {
98 union {
99 float f;
100 int i;
101 } fval;
102 int res, i;
103 if (is_float) {
104 fval.f = sin(phase) * maxval;
105 res = fval.i;
106 } else
107 res = sin(phase) * maxval;
108 if (to_unsigned)
109 res ^= 1U << (format_bits - 1);
110 for (chn = 0; chn < channels; chn++) {
111 /* Generate data in native endian format */
112 if (big_endian) {
113 for (i = 0; i < bps; i++)
114 *(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
115 } else {
116 for (i = 0; i < bps; i++)
117 *(samples[chn] + i) = (res >> i * 8) & 0xff;
118 }
119 samples[chn] += steps[chn];
120 }
121 phase += step;
122 if (phase >= max_phase)
123 phase -= max_phase;
124 }
125 *_phase = phase;
126}
127
128static void config_pcm(snd_pcm_t *handle,
129 unsigned int rate,
130 unsigned int channels,
131 snd_pcm_format_t format,
132 snd_pcm_uframes_t *buffer_size,
133 snd_pcm_uframes_t *period_size)
134{
135 int err;
136 snd_pcm_hw_params_t *hw_params;
137
138 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
139 fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",
140 snd_strerror(err));
141 exit(1);
142 }
143
144 if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {
145 fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",
146 snd_strerror(err));
147 exit(1);
148 }
149
150 if ((err = snd_pcm_hw_params_set_access(handle, hw_params,
151 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
152 fprintf(stderr, "cannot set access type (%s)\n",
153 snd_strerror(err));
154 exit(1);
155 }
156
157 if ((err = snd_pcm_hw_params_set_format(handle, hw_params,
158 format)) < 0) {
159 fprintf(stderr, "cannot set sample format (%s)\n",
160 snd_strerror(err));
161 exit(1);
162 }
163
164 if ((err = snd_pcm_hw_params_set_rate_near(
165 handle, hw_params, &rate, 0)) < 0) {
166 fprintf(stderr, "cannot set sample rate (%s)\n",
167 snd_strerror(err));
168 exit(1);
169 }
170
171 if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, 2)) < 0) {
172 fprintf(stderr, "cannot set channel count (%s)\n",
173 snd_strerror(err));
174 exit(1);
175 }
176
177 if ((err = snd_pcm_hw_params_set_buffer_size_near(
178 handle, hw_params, buffer_size)) < 0) {
179 fprintf(stderr, "cannot set channel count (%s)\n",
180 snd_strerror(err));
181 exit(1);
182 }
183
184 if ((err = snd_pcm_hw_params_set_period_size_near(
185 handle, hw_params, period_size, 0)) < 0) {
186 fprintf(stderr, "cannot set channel count (%s)\n",
187 snd_strerror(err));
188 exit(1);
189 }
190
191 if ((err = snd_pcm_hw_params(handle, hw_params)) < 0) {
192 fprintf(stderr, "cannot set parameters (%s)\n",
193 snd_strerror(err));
194 exit(1);
195 }
196
197 snd_pcm_hw_params_free(hw_params);
198
199 if ((err = snd_pcm_prepare(handle)) < 0) {
200 fprintf(stderr, "cannot prepare audio interface for use (%s)\n",
201 snd_strerror(err));
202 exit(1);
203 }
204}
205
206static int capture_some(snd_pcm_t *pcm, short *buf, unsigned len,
207 snd_pcm_sframes_t *cap_delay_frames)
208{
209 snd_pcm_sframes_t frames = snd_pcm_avail(pcm);
210 int err;
211
212 if (frames > 0) {
213 frames = frames > len ? len : frames;
214
215 snd_pcm_delay(pcm, cap_delay_frames);
216 if ((err = snd_pcm_readi(pcm, buf, frames)) != frames) {
217 fprintf(stderr, "read from audio interface failed (%s)\n",
218 snd_strerror(err));
219 exit(1);
220 }
221 }
222
223 return (int)frames;
224}
225
226/* Looks for the first sample in buffer whose absolute value exceeds
227 * noise_threshold. Returns the index of found sample in frames, -1
228 * if not found. */
229static int check_for_noise(short *buf, unsigned len, unsigned channels)
230{
231 unsigned int i;
232 for (i = 0; i < len * channels; i++)
233 if (abs(buf[i]) > noise_threshold)
234 return i / channels;
235 return -1;
236}
237
238static unsigned long subtract_timevals(const struct timeval *end,
239 const struct timeval *beg)
240{
241 struct timeval diff;
242 /* If end is before geb, return 0. */
243 if ((end->tv_sec < beg->tv_sec) ||
244 ((end->tv_sec == beg->tv_sec) && (end->tv_usec <= beg->tv_usec)))
245 diff.tv_sec = diff.tv_usec = 0;
246 else {
247 if (end->tv_usec < beg->tv_usec) {
248 diff.tv_sec = end->tv_sec - beg->tv_sec - 1;
249 diff.tv_usec =
250 end->tv_usec + 1000000L - beg->tv_usec;
251 } else {
252 diff.tv_sec = end->tv_sec - beg->tv_sec;
253 diff.tv_usec = end->tv_usec - beg->tv_usec;
254 }
255 }
256 return diff.tv_sec * 1000000 + diff.tv_usec;
257}
258
259static int cras_capture_tone(struct cras_client *client,
260 cras_stream_id_t stream_id,
261 uint8_t *samples, size_t frames,
262 const struct timespec *sample_time,
263 void *arg)
264{
265 assert(snd_pcm_format_physical_width(format) == 16);
266
267 short *data = (short *)samples;
268 int cap_frames_index;
269
270 if (!sine_started || terminate_capture) {
271 return frames;
272 }
273
274 if ((cap_frames_index = check_for_noise(data, frames, channels)) >= 0) {
275 fprintf(stderr, "Got noise\n");
276
277 struct timespec shifted_time = *sample_time;
278 shifted_time.tv_nsec += 1000000000L / rate * cap_frames_index;
279 while (shifted_time.tv_nsec > 1000000000L) {
280 shifted_time.tv_sec++;
281 shifted_time.tv_nsec -= 1000000000L;
282 }
Earl Ou7ae955b2016-11-30 16:41:22 +0800283 cras_client_calc_capture_latency(&shifted_time, (struct timespec *)arg);
284 cras_cap_time = (struct timeval *)malloc(sizeof(*cras_cap_time));
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +0800285 gettimeofday(cras_cap_time, NULL);
286
287 // Terminate the test since noise got captured.
288 pthread_mutex_lock(&latency_test_mutex);
289 terminate_capture = 1;
290 pthread_cond_signal(&terminate_test);
291 pthread_mutex_unlock(&latency_test_mutex);
292 }
293
294 return frames;
295}
296
297/* Callback for tone playback. Playback latency will be passed
298 * as arg and updated at the first sine tone right after silent.
299 */
300static int cras_play_tone(struct cras_client *client,
301 cras_stream_id_t stream_id,
302 uint8_t *samples, size_t frames,
303 const struct timespec *sample_time,
304 void *arg)
305{
306 snd_pcm_channel_area_t *areas;
307 int chn;
308 size_t sample_bytes;
309
310 sample_bytes = snd_pcm_format_physical_width(format) / 8;
311
312 areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
313 for (chn = 0; chn < channels; chn++) {
314 areas[chn].addr = samples + chn * sample_bytes;
315 areas[chn].first = 0;
316 areas[chn].step = channels *
317 snd_pcm_format_physical_width(format);
318 }
319
320 /* Write zero first when playback_count < PLAYBACK_SILENT_COUNT
321 * or noise got captured. */
322 if (playback_count < PLAYBACK_SILENT_COUNT) {
323 memset(samples, 0, sample_bytes * frames * channels);
324 } else if (playback_count > PLAYBACK_TIMEOUT_COUNT) {
325 // Timeout, terminate test.
326 pthread_mutex_lock(&latency_test_mutex);
327 terminate_capture = 1;
328 pthread_cond_signal(&terminate_test);
329 pthread_mutex_unlock(&latency_test_mutex);
330 } else {
331 generate_sine(areas, 0, frames, &phase);
332
333 if (!sine_started) {
334 /* Signal that sine tone started playing and update playback time
335 * and latency at first played frame. */
336 sine_started = 1;
337 cras_client_calc_playback_latency(sample_time,
Earl Ou7ae955b2016-11-30 16:41:22 +0800338 (struct timespec *)arg);
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +0800339 cras_play_time =
Earl Ou7ae955b2016-11-30 16:41:22 +0800340 (struct timeval *)malloc(sizeof(*cras_play_time));
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +0800341 gettimeofday(cras_play_time, NULL);
342 }
343 }
344
345 playback_count++;
346 return frames;
347}
348
349static int stream_error(struct cras_client *client,
350 cras_stream_id_t stream_id,
351 int err,
352 void *arg)
353{
354 fprintf(stderr, "Stream error %d\n", err);
355 return 0;
356}
357
358/* Adds stream to cras client. */
359static int cras_add_stream(struct cras_client *client,
360 struct cras_stream_params *params,
361 enum CRAS_STREAM_DIRECTION direction,
362 struct timespec *user_data)
363{
364 struct cras_audio_format *aud_format;
365 cras_playback_cb_t aud_cb;
366 cras_error_cb_t error_cb;
367 size_t cb_threshold = buffer_frames / 10;
368 size_t min_cb_level = buffer_frames / 10;
369 int rc = 0;
370 cras_stream_id_t stream_id = 0;
371
372 aud_format = cras_audio_format_create(format, rate, channels);
373 if (aud_format == NULL)
374 return -ENOMEM;
375
376 /* Create and start stream */
377 aud_cb = (direction == CRAS_STREAM_OUTPUT)
378 ? cras_play_tone
379 : cras_capture_tone;
380 error_cb = stream_error;
381 params = cras_client_stream_params_create(direction,
382 buffer_frames,
383 cb_threshold,
384 min_cb_level,
385 0,
386 0,
387 user_data,
388 aud_cb,
389 error_cb,
390 aud_format);
391 if (params == NULL)
392 return -ENOMEM;
393
394 rc = cras_client_add_stream(client, &stream_id, params);
395 if (rc < 0) {
396 fprintf(stderr, "Add a stream fail.\n");
397 return rc;
398 }
399 cras_audio_format_destroy(aud_format);
400 return 0;
401}
402
403static void *alsa_play(void *arg) {
404 snd_pcm_t *handle = (snd_pcm_t *)arg;
405 short *play_buf;
406 snd_pcm_channel_area_t *areas;
407 unsigned int chn, num_buffers;
408 int err;
409
410 play_buf = calloc(buffer_frames * channels, sizeof(play_buf[0]));
411 areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
412
413 for (chn = 0; chn < channels; chn++) {
414 areas[chn].addr = play_buf;
415 areas[chn].first = chn * snd_pcm_format_physical_width(format);
416 areas[chn].step = channels * snd_pcm_format_physical_width(format);
417 }
418
419 for (num_buffers = 0; num_buffers < PLAYBACK_SILENT_COUNT; num_buffers++) {
420 if ((err = snd_pcm_writei(handle, play_buf, period_size))
421 != period_size) {
422 fprintf(stderr, "write to audio interface failed (%s)\n",
423 snd_strerror(err));
424 exit(1);
425 }
426 }
427
428 generate_sine(areas, 0, period_size, &phase);
429 snd_pcm_delay(handle, &playback_delay_frames);
430 gettimeofday(&sine_start_tv, NULL);
431
432 num_buffers = 0;
433 int avail_frames;
434
435 /* Play a sine wave and look for it on capture thread.
436 * This will fail for latency > 500mS. */
437 while (!terminate_playback && num_buffers < PLAYBACK_COUNT) {
438 avail_frames = snd_pcm_avail(handle);
439 if (avail_frames >= period_size) {
440 pthread_mutex_lock(&latency_test_mutex);
441 if (!sine_started) {
442 sine_started = 1;
443 pthread_cond_signal(&sine_start);
444 }
445 pthread_mutex_unlock(&latency_test_mutex);
446 if ((err = snd_pcm_writei(handle, play_buf, period_size))
447 != period_size) {
448 fprintf(stderr, "write to audio interface failed (%s)\n",
449 snd_strerror(err));
450 }
451 num_buffers++;
452 }
453 }
454 terminate_playback = 1;
455
456 if (num_buffers == PLAYBACK_COUNT)
457 fprintf(stdout, "Audio not detected.\n");
458
459 free(play_buf);
460 free(areas);
461 return 0;
462}
463
464static void *alsa_capture(void *arg) {
465 int err;
466 short *cap_buf;
467 snd_pcm_t *capture_handle = (snd_pcm_t *)arg;
468 snd_pcm_sframes_t cap_delay_frames;
469 int num_cap, noise_delay_frames;
470
471
472 cap_buf = calloc(buffer_frames * channels, sizeof(cap_buf[0]));
473
474 pthread_mutex_lock(&latency_test_mutex);
475 while (!sine_started) {
476 pthread_cond_wait(&sine_start, &latency_test_mutex);
477 }
478 pthread_mutex_unlock(&latency_test_mutex);
479
480 /* Begin capture. */
481 if ((err = snd_pcm_start(capture_handle)) < 0) {
482 fprintf(stderr, "cannot start audio interface for use (%s)\n",
483 snd_strerror(err));
484 exit(1);
485 }
486
487 while (!terminate_capture) {
488 num_cap = capture_some(capture_handle, cap_buf,
489 buffer_frames, &cap_delay_frames);
490
491 if (num_cap > 0 && (noise_delay_frames = check_for_noise(cap_buf,
492 num_cap, channels)) >= 0) {
493 struct timeval cap_time;
494 unsigned long latency_us;
495 gettimeofday(&cap_time, NULL);
496
497 fprintf(stderr, "Found audio\n");
498 fprintf(stderr, "Played at %llu %llu, %ld delay\n",
499 (unsigned long long)sine_start_tv.tv_sec,
500 (unsigned long long)sine_start_tv.tv_usec,
501 playback_delay_frames);
502 fprintf(stderr, "Capture at %llu %llu, %ld delay sample %d\n",
503 (unsigned long long)cap_time.tv_sec,
504 (unsigned long long)cap_time.tv_usec,
505 cap_delay_frames, noise_delay_frames);
506
507 latency_us = subtract_timevals(&cap_time, &sine_start_tv);
508 fprintf(stdout, "Measured Latency: %lu uS\n", latency_us);
509
510 latency_us = (playback_delay_frames + cap_delay_frames -
511 noise_delay_frames) * 1000000 / rate;
512 fprintf(stdout, "Reported Latency: %lu uS\n", latency_us);
513
514 // Noise captured, terminate both threads.
515 terminate_playback = 1;
516 terminate_capture = 1;
517 } else {
518 // Capture some more buffers after playback thread has terminated.
519 if (terminate_playback && capture_count++ < CAPTURE_MORE_COUNT)
520 terminate_capture = 1;
521 }
522 }
523
524 free(cap_buf);
525 return 0;
526}
527
528void cras_test_latency()
529{
530 int rc;
531 struct cras_client *client = NULL;
532 struct cras_stream_params *playback_params = NULL;
533 struct cras_stream_params *capture_params = NULL;
534
535 struct timespec playback_latency;
536 struct timespec capture_latency;
537
538 rc = cras_client_create(&client);
539 if (rc < 0) {
540 fprintf(stderr, "Create client fail.\n");
541 exit(1);
542 }
543 rc = cras_client_connect(client);
544 if (rc < 0) {
545 fprintf(stderr, "Connect to server fail.\n");
546 cras_client_destroy(client);
547 exit(1);
548 }
549
550 pthread_mutex_init(&latency_test_mutex, NULL);
551 pthread_cond_init(&sine_start, NULL);
552 pthread_cond_init(&terminate_test, NULL);
553
554 cras_client_run_thread(client);
555 rc = cras_add_stream(client,
556 playback_params,
557 CRAS_STREAM_OUTPUT,
558 &playback_latency);
559 if (rc < 0) {
560 fprintf(stderr, "Fail to add playback stream.\n");
561 exit(1);
562 }
563 rc = cras_add_stream(client,
564 capture_params,
565 CRAS_STREAM_INPUT,
566 &capture_latency);
567 if (rc < 0) {
568 fprintf(stderr, "Fail to add capture stream.\n");
569 exit(1);
570 }
571
572 pthread_mutex_lock(&latency_test_mutex);
573 while (!terminate_capture) {
574 pthread_cond_wait(&terminate_test, &latency_test_mutex);
575 }
576 pthread_mutex_unlock(&latency_test_mutex);
577
578 if (cras_cap_time && cras_play_time) {
579 unsigned long latency = subtract_timevals(cras_cap_time,
580 cras_play_time);
581 fprintf(stdout, "Measured Latency: %lu uS.\n", latency);
582
583 latency = (playback_latency.tv_sec + capture_latency.tv_sec) * 1000000 +
584 (playback_latency.tv_nsec + capture_latency.tv_nsec) / 1000;
585 fprintf(stdout, "Reported Latency: %lu uS.\n", latency);
586 } else {
587 fprintf(stdout, "Audio not detected.\n");
588 }
589
590 /* Destruct things. */
591 cras_client_stop(client);
592 cras_client_stream_params_destroy(playback_params);
593 cras_client_stream_params_destroy(capture_params);
594 if (cras_play_time)
595 free(cras_play_time);
596 if (cras_cap_time)
597 free(cras_cap_time);
598}
599
Earl Ou7ae955b2016-11-30 16:41:22 +0800600void alsa_test_latency(char *play_dev, char *cap_dev)
Hsin-Yu Chao9a2dfb22013-08-06 16:43:56 +0800601{
602 int err;
603 snd_pcm_t *playback_handle;
604 snd_pcm_t *capture_handle;
605
606 pthread_t capture_thread;
607 pthread_t playback_thread;
608
609 if ((err = snd_pcm_open(&playback_handle, play_dev,
610 SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
611 fprintf(stderr, "cannot open audio device %s (%s)\n",
612 play_dev, snd_strerror(err));
613 exit(1);
614 }
615 config_pcm(playback_handle, rate, channels, format, &buffer_frames,
616 &period_size);
617
618 if ((err = snd_pcm_open(&capture_handle, cap_dev,
619 SND_PCM_STREAM_CAPTURE, 0)) < 0) {
620 fprintf(stderr, "cannot open audio device %s (%s)\n",
621 cap_dev, snd_strerror(err));
622 exit(1);
623 }
624 config_pcm(capture_handle, rate, channels, format, &buffer_frames,
625 &period_size);
626
627 pthread_mutex_init(&latency_test_mutex, NULL);
628 pthread_cond_init(&sine_start, NULL);
629
630 pthread_create(&playback_thread, NULL, alsa_play, playback_handle);
631 pthread_create(&capture_thread, NULL, alsa_capture, capture_handle);
632
633 pthread_join(capture_thread, NULL);
634 pthread_join(playback_thread, NULL);
635
636 snd_pcm_close(playback_handle);
637 snd_pcm_close(capture_handle);
638}
639
640int main (int argc, char *argv[])
641{
642 int cras_only = 0;
643 char *play_dev = "default";
644 char *cap_dev = "default";
645
646 int arg;
647 while ((arg = getopt(argc, argv, "b:i:o:n:r:p:c")) != -1) {
648 switch (arg) {
649 case 'b':
650 buffer_frames = atoi(optarg);
651 break;
652 case 'c':
653 cras_only = 1;
654 break;
655 case 'i':
656 cap_dev = optarg;
657 fprintf(stderr, "Assign cap_dev %s\n", cap_dev);
658 break;
659 case 'n':
660 noise_threshold = atoi(optarg);
661 break;
662 case 'r':
663 rate = atoi(optarg);
664 break;
665 case 'o':
666 play_dev = optarg;
667 fprintf(stderr, "Assign play_dev %s\n", play_dev);
668 break;
669 case 'p':
670 period_size = atoi(optarg);
671 break;
672 default:
673 return 1;
674 }
675 }
676
677 if (cras_only)
678 cras_test_latency();
679 else
680 alsa_test_latency(play_dev, cap_dev);
681 exit(0);
682}