xref: /third_party/alsa-utils/bat/bat.c (revision c72fcc34)
1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation
3c72fcc34Sopenharmony_ci *
4c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
5c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by
6c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
7c72fcc34Sopenharmony_ci * (at your option) any later version.
8c72fcc34Sopenharmony_ci *
9c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful,
10c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12c72fcc34Sopenharmony_ci * GNU General Public License for more details.
13c72fcc34Sopenharmony_ci *
14c72fcc34Sopenharmony_ci */
15c72fcc34Sopenharmony_ci
16c72fcc34Sopenharmony_ci#include <unistd.h>
17c72fcc34Sopenharmony_ci#include <stdio.h>
18c72fcc34Sopenharmony_ci#include <stdlib.h>
19c72fcc34Sopenharmony_ci#include <stdbool.h>
20c72fcc34Sopenharmony_ci#include <string.h>
21c72fcc34Sopenharmony_ci#include <errno.h>
22c72fcc34Sopenharmony_ci#include <pthread.h>
23c72fcc34Sopenharmony_ci#include <getopt.h>
24c72fcc34Sopenharmony_ci#include <math.h>
25c72fcc34Sopenharmony_ci#include <limits.h>
26c72fcc34Sopenharmony_ci#include <locale.h>
27c72fcc34Sopenharmony_ci#include <math.h>
28c72fcc34Sopenharmony_ci
29c72fcc34Sopenharmony_ci#include "aconfig.h"
30c72fcc34Sopenharmony_ci#include "gettext.h"
31c72fcc34Sopenharmony_ci#include "version.h"
32c72fcc34Sopenharmony_ci
33c72fcc34Sopenharmony_ci#include "common.h"
34c72fcc34Sopenharmony_ci
35c72fcc34Sopenharmony_ci#ifdef HAVE_LIBTINYALSA
36c72fcc34Sopenharmony_ci#include "tinyalsa.h"
37c72fcc34Sopenharmony_ci#else
38c72fcc34Sopenharmony_ci#include "alsa.h"
39c72fcc34Sopenharmony_ci#endif
40c72fcc34Sopenharmony_ci#include "convert.h"
41c72fcc34Sopenharmony_ci#ifdef HAVE_LIBFFTW3F
42c72fcc34Sopenharmony_ci#include "analyze.h"
43c72fcc34Sopenharmony_ci#endif
44c72fcc34Sopenharmony_ci#include "latencytest.h"
45c72fcc34Sopenharmony_ci
46c72fcc34Sopenharmony_ci/* get snr threshold in dB */
47c72fcc34Sopenharmony_cistatic void get_snr_thd_db(struct bat *bat, char *thd)
48c72fcc34Sopenharmony_ci{
49c72fcc34Sopenharmony_ci	int err;
50c72fcc34Sopenharmony_ci	float thd_db;
51c72fcc34Sopenharmony_ci	char *ptrf;
52c72fcc34Sopenharmony_ci
53c72fcc34Sopenharmony_ci	thd_db = strtof(thd, &ptrf);
54c72fcc34Sopenharmony_ci	err = -errno;
55c72fcc34Sopenharmony_ci	if (!snr_is_valid(thd_db)) {
56c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Invalid threshold '%s':%d\n"), thd, err);
57c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
58c72fcc34Sopenharmony_ci	}
59c72fcc34Sopenharmony_ci	bat->snr_thd_db = thd_db;
60c72fcc34Sopenharmony_ci}
61c72fcc34Sopenharmony_ci
62c72fcc34Sopenharmony_ci/* get snr threshold in %, and convert to dB */
63c72fcc34Sopenharmony_cistatic void get_snr_thd_pc(struct bat *bat, char *thd)
64c72fcc34Sopenharmony_ci{
65c72fcc34Sopenharmony_ci	int err;
66c72fcc34Sopenharmony_ci	float thd_pc;
67c72fcc34Sopenharmony_ci	char *ptrf;
68c72fcc34Sopenharmony_ci
69c72fcc34Sopenharmony_ci	thd_pc = strtof(thd, &ptrf);
70c72fcc34Sopenharmony_ci	err = -errno;
71c72fcc34Sopenharmony_ci	if (thd_pc <= 0.0 || thd_pc >= 100.0) {
72c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Invalid threshold '%s':%d\n"), thd, err);
73c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
74c72fcc34Sopenharmony_ci	}
75c72fcc34Sopenharmony_ci	bat->snr_thd_db = 20.0 * log10f(100.0 / thd_pc);
76c72fcc34Sopenharmony_ci}
77c72fcc34Sopenharmony_ci
78c72fcc34Sopenharmony_cistatic int get_duration(struct bat *bat)
79c72fcc34Sopenharmony_ci{
80c72fcc34Sopenharmony_ci	int err;
81c72fcc34Sopenharmony_ci	float duration_f;
82c72fcc34Sopenharmony_ci	long duration_i;
83c72fcc34Sopenharmony_ci	char *ptrf, *ptri;
84c72fcc34Sopenharmony_ci
85c72fcc34Sopenharmony_ci	duration_f = strtof(bat->narg, &ptrf);
86c72fcc34Sopenharmony_ci	err = -errno;
87c72fcc34Sopenharmony_ci	if (duration_f == HUGE_VALF || duration_f == -HUGE_VALF
88c72fcc34Sopenharmony_ci			|| (duration_f == 0.0 && err != 0))
89c72fcc34Sopenharmony_ci		goto err_exit;
90c72fcc34Sopenharmony_ci
91c72fcc34Sopenharmony_ci	duration_i = strtol(bat->narg, &ptri, 10);
92c72fcc34Sopenharmony_ci	if (duration_i == LONG_MAX || duration_i == LONG_MIN)
93c72fcc34Sopenharmony_ci		goto err_exit;
94c72fcc34Sopenharmony_ci
95c72fcc34Sopenharmony_ci	if (*ptrf == 's')
96c72fcc34Sopenharmony_ci		bat->frames = duration_f * bat->rate;
97c72fcc34Sopenharmony_ci	else if (*ptri == 0)
98c72fcc34Sopenharmony_ci		bat->frames = duration_i;
99c72fcc34Sopenharmony_ci	else
100c72fcc34Sopenharmony_ci		bat->frames = -1;
101c72fcc34Sopenharmony_ci
102c72fcc34Sopenharmony_ci	if (bat->frames <= 0 || bat->frames > MAX_FRAMES) {
103c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Invalid duration. Range: (0, %d(%fs))\n"),
104c72fcc34Sopenharmony_ci				MAX_FRAMES, (float)MAX_FRAMES / bat->rate);
105c72fcc34Sopenharmony_ci		return -EINVAL;
106c72fcc34Sopenharmony_ci	}
107c72fcc34Sopenharmony_ci
108c72fcc34Sopenharmony_ci	return 0;
109c72fcc34Sopenharmony_ci
110c72fcc34Sopenharmony_cierr_exit:
111c72fcc34Sopenharmony_ci	fprintf(bat->err, _("Duration overflow/underflow: %d\n"), err);
112c72fcc34Sopenharmony_ci
113c72fcc34Sopenharmony_ci	return err;
114c72fcc34Sopenharmony_ci}
115c72fcc34Sopenharmony_ci
116c72fcc34Sopenharmony_cistatic void get_sine_frequencies(struct bat *bat, char *freq)
117c72fcc34Sopenharmony_ci{
118c72fcc34Sopenharmony_ci	char *tmp1;
119c72fcc34Sopenharmony_ci
120c72fcc34Sopenharmony_ci	tmp1 = strchr(freq, ':');
121c72fcc34Sopenharmony_ci	if (tmp1 == NULL) {
122c72fcc34Sopenharmony_ci		bat->target_freq[1] = bat->target_freq[0] = atof(optarg);
123c72fcc34Sopenharmony_ci	} else {
124c72fcc34Sopenharmony_ci		*tmp1 = '\0';
125c72fcc34Sopenharmony_ci		bat->target_freq[0] = atof(optarg);
126c72fcc34Sopenharmony_ci		bat->target_freq[1] = atof(tmp1 + 1);
127c72fcc34Sopenharmony_ci	}
128c72fcc34Sopenharmony_ci}
129c72fcc34Sopenharmony_ci
130c72fcc34Sopenharmony_cistatic void get_format(struct bat *bat, char *optarg)
131c72fcc34Sopenharmony_ci{
132c72fcc34Sopenharmony_ci	if (strcasecmp(optarg, "cd") == 0) {
133c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_S16_LE;
134c72fcc34Sopenharmony_ci		bat->rate = 44100;
135c72fcc34Sopenharmony_ci		bat->channels = 2;
136c72fcc34Sopenharmony_ci		bat->sample_size = 2;
137c72fcc34Sopenharmony_ci	} else if (strcasecmp(optarg, "dat") == 0) {
138c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_S16_LE;
139c72fcc34Sopenharmony_ci		bat->rate = 48000;
140c72fcc34Sopenharmony_ci		bat->channels = 2;
141c72fcc34Sopenharmony_ci		bat->sample_size = 2;
142c72fcc34Sopenharmony_ci	} else if (strcasecmp(optarg, "U8") == 0) {
143c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_U8;
144c72fcc34Sopenharmony_ci		bat->sample_size = 1;
145c72fcc34Sopenharmony_ci	} else if (strcasecmp(optarg, "S16_LE") == 0) {
146c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_S16_LE;
147c72fcc34Sopenharmony_ci		bat->sample_size = 2;
148c72fcc34Sopenharmony_ci	} else if (strcasecmp(optarg, "S24_3LE") == 0) {
149c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_S24_3LE;
150c72fcc34Sopenharmony_ci		bat->sample_size = 3;
151c72fcc34Sopenharmony_ci	} else if (strcasecmp(optarg, "S32_LE") == 0) {
152c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_S32_LE;
153c72fcc34Sopenharmony_ci		bat->sample_size = 4;
154c72fcc34Sopenharmony_ci	} else {
155c72fcc34Sopenharmony_ci		bat->format = BAT_PCM_FORMAT_UNKNOWN;
156c72fcc34Sopenharmony_ci		fprintf(bat->err, _("wrong extended format '%s'\n"), optarg);
157c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
158c72fcc34Sopenharmony_ci	}
159c72fcc34Sopenharmony_ci}
160c72fcc34Sopenharmony_ci
161c72fcc34Sopenharmony_cistatic inline int thread_wait_completion(struct bat *bat ATTRIBUTE_UNUSED,
162c72fcc34Sopenharmony_ci					 pthread_t id, int **val)
163c72fcc34Sopenharmony_ci{
164c72fcc34Sopenharmony_ci	int err;
165c72fcc34Sopenharmony_ci
166c72fcc34Sopenharmony_ci	err = pthread_join(id, (void **) val);
167c72fcc34Sopenharmony_ci	if (err)
168c72fcc34Sopenharmony_ci		pthread_cancel(id);
169c72fcc34Sopenharmony_ci
170c72fcc34Sopenharmony_ci	return err;
171c72fcc34Sopenharmony_ci}
172c72fcc34Sopenharmony_ci
173c72fcc34Sopenharmony_ci/* loopback test where we play sine wave and capture the same sine wave */
174c72fcc34Sopenharmony_cistatic void test_loopback(struct bat *bat)
175c72fcc34Sopenharmony_ci{
176c72fcc34Sopenharmony_ci	pthread_t capture_id, playback_id;
177c72fcc34Sopenharmony_ci	int err;
178c72fcc34Sopenharmony_ci	int *thread_result_capture, *thread_result_playback;
179c72fcc34Sopenharmony_ci
180c72fcc34Sopenharmony_ci	/* start playback */
181c72fcc34Sopenharmony_ci	err = pthread_create(&playback_id, NULL,
182c72fcc34Sopenharmony_ci			(void *) bat->playback.fct, bat);
183c72fcc34Sopenharmony_ci	if (err != 0) {
184c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot create playback thread: %d\n"),
185c72fcc34Sopenharmony_ci				err);
186c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
187c72fcc34Sopenharmony_ci	}
188c72fcc34Sopenharmony_ci
189c72fcc34Sopenharmony_ci	/* TODO: use a pipe to signal stream start etc - i.e. to sync threads */
190c72fcc34Sopenharmony_ci	/* Let some time for playing something before capturing */
191c72fcc34Sopenharmony_ci	usleep(CAPTURE_DELAY * 1000);
192c72fcc34Sopenharmony_ci
193c72fcc34Sopenharmony_ci	/* start capture */
194c72fcc34Sopenharmony_ci	err = pthread_create(&capture_id, NULL, (void *) bat->capture.fct, bat);
195c72fcc34Sopenharmony_ci	if (err != 0) {
196c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot create capture thread: %d\n"), err);
197c72fcc34Sopenharmony_ci		pthread_cancel(playback_id);
198c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
199c72fcc34Sopenharmony_ci	}
200c72fcc34Sopenharmony_ci
201c72fcc34Sopenharmony_ci	/* wait for playback to complete */
202c72fcc34Sopenharmony_ci	err = thread_wait_completion(bat, playback_id, &thread_result_playback);
203c72fcc34Sopenharmony_ci	if (err != 0) {
204c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot join playback thread: %d\n"), err);
205c72fcc34Sopenharmony_ci		free(thread_result_playback);
206c72fcc34Sopenharmony_ci		pthread_cancel(capture_id);
207c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
208c72fcc34Sopenharmony_ci	}
209c72fcc34Sopenharmony_ci
210c72fcc34Sopenharmony_ci	/* check playback status */
211c72fcc34Sopenharmony_ci	if (*thread_result_playback != 0) {
212c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Exit playback thread fail: %d\n"),
213c72fcc34Sopenharmony_ci				*thread_result_playback);
214c72fcc34Sopenharmony_ci		pthread_cancel(capture_id);
215c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
216c72fcc34Sopenharmony_ci	} else {
217c72fcc34Sopenharmony_ci		fprintf(bat->log, _("Playback completed.\n"));
218c72fcc34Sopenharmony_ci	}
219c72fcc34Sopenharmony_ci
220c72fcc34Sopenharmony_ci	/* now stop and wait for capture to finish */
221c72fcc34Sopenharmony_ci	pthread_cancel(capture_id);
222c72fcc34Sopenharmony_ci	err = thread_wait_completion(bat, capture_id, &thread_result_capture);
223c72fcc34Sopenharmony_ci	if (err != 0) {
224c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot join capture thread: %d\n"), err);
225c72fcc34Sopenharmony_ci		free(thread_result_capture);
226c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
227c72fcc34Sopenharmony_ci	}
228c72fcc34Sopenharmony_ci
229c72fcc34Sopenharmony_ci	/* check if capture thread is canceled or not */
230c72fcc34Sopenharmony_ci	if (thread_result_capture == PTHREAD_CANCELED) {
231c72fcc34Sopenharmony_ci		fprintf(bat->log, _("Capture canceled.\n"));
232c72fcc34Sopenharmony_ci		return;
233c72fcc34Sopenharmony_ci	}
234c72fcc34Sopenharmony_ci
235c72fcc34Sopenharmony_ci	/* check capture status */
236c72fcc34Sopenharmony_ci	if (*thread_result_capture != 0) {
237c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Exit capture thread fail: %d\n"),
238c72fcc34Sopenharmony_ci				*thread_result_capture);
239c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
240c72fcc34Sopenharmony_ci	} else {
241c72fcc34Sopenharmony_ci		fprintf(bat->log, _("Capture completed.\n"));
242c72fcc34Sopenharmony_ci	}
243c72fcc34Sopenharmony_ci}
244c72fcc34Sopenharmony_ci
245c72fcc34Sopenharmony_ci/* single ended playback only test */
246c72fcc34Sopenharmony_cistatic void test_playback(struct bat *bat)
247c72fcc34Sopenharmony_ci{
248c72fcc34Sopenharmony_ci	pthread_t playback_id;
249c72fcc34Sopenharmony_ci	int err;
250c72fcc34Sopenharmony_ci	int *thread_result;
251c72fcc34Sopenharmony_ci
252c72fcc34Sopenharmony_ci	/* start playback */
253c72fcc34Sopenharmony_ci	err = pthread_create(&playback_id, NULL,
254c72fcc34Sopenharmony_ci			(void *) bat->playback.fct, bat);
255c72fcc34Sopenharmony_ci	if (err != 0) {
256c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot create playback thread: %d\n"),
257c72fcc34Sopenharmony_ci				err);
258c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
259c72fcc34Sopenharmony_ci	}
260c72fcc34Sopenharmony_ci
261c72fcc34Sopenharmony_ci	/* wait for playback to complete */
262c72fcc34Sopenharmony_ci	err = thread_wait_completion(bat, playback_id, &thread_result);
263c72fcc34Sopenharmony_ci	if (err != 0) {
264c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot join playback thread: %d\n"), err);
265c72fcc34Sopenharmony_ci		free(thread_result);
266c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
267c72fcc34Sopenharmony_ci	}
268c72fcc34Sopenharmony_ci
269c72fcc34Sopenharmony_ci	/* check playback status */
270c72fcc34Sopenharmony_ci	if (*thread_result != 0) {
271c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Exit playback thread fail: %d\n"),
272c72fcc34Sopenharmony_ci				*thread_result);
273c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
274c72fcc34Sopenharmony_ci	} else {
275c72fcc34Sopenharmony_ci		fprintf(bat->log, _("Playback completed.\n"));
276c72fcc34Sopenharmony_ci	}
277c72fcc34Sopenharmony_ci}
278c72fcc34Sopenharmony_ci
279c72fcc34Sopenharmony_ci/* single ended capture only test */
280c72fcc34Sopenharmony_cistatic void test_capture(struct bat *bat)
281c72fcc34Sopenharmony_ci{
282c72fcc34Sopenharmony_ci	pthread_t capture_id;
283c72fcc34Sopenharmony_ci	int err;
284c72fcc34Sopenharmony_ci	int *thread_result;
285c72fcc34Sopenharmony_ci
286c72fcc34Sopenharmony_ci	/* start capture */
287c72fcc34Sopenharmony_ci	err = pthread_create(&capture_id, NULL, (void *) bat->capture.fct, bat);
288c72fcc34Sopenharmony_ci	if (err != 0) {
289c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot create capture thread: %d\n"), err);
290c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
291c72fcc34Sopenharmony_ci	}
292c72fcc34Sopenharmony_ci
293c72fcc34Sopenharmony_ci	/* TODO: stop capture */
294c72fcc34Sopenharmony_ci
295c72fcc34Sopenharmony_ci	/* wait for capture to complete */
296c72fcc34Sopenharmony_ci	err = thread_wait_completion(bat, capture_id, &thread_result);
297c72fcc34Sopenharmony_ci	if (err != 0) {
298c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Cannot join capture thread: %d\n"), err);
299c72fcc34Sopenharmony_ci		free(thread_result);
300c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
301c72fcc34Sopenharmony_ci	}
302c72fcc34Sopenharmony_ci
303c72fcc34Sopenharmony_ci	/* check playback status */
304c72fcc34Sopenharmony_ci	if (*thread_result != 0) {
305c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Exit capture thread fail: %d\n"),
306c72fcc34Sopenharmony_ci				*thread_result);
307c72fcc34Sopenharmony_ci		exit(EXIT_FAILURE);
308c72fcc34Sopenharmony_ci	} else {
309c72fcc34Sopenharmony_ci		fprintf(bat->log, _("Capture completed.\n"));
310c72fcc34Sopenharmony_ci	}
311c72fcc34Sopenharmony_ci}
312c72fcc34Sopenharmony_ci
313c72fcc34Sopenharmony_cistatic void usage(struct bat *bat)
314c72fcc34Sopenharmony_ci{
315c72fcc34Sopenharmony_ci	fprintf(bat->log,
316c72fcc34Sopenharmony_ci_("Usage: alsabat [-options]...\n"
317c72fcc34Sopenharmony_ci"\n"
318c72fcc34Sopenharmony_ci"  -h, --help             this help\n"
319c72fcc34Sopenharmony_ci"  -D                     pcm device for both playback and capture\n"
320c72fcc34Sopenharmony_ci"  -P                     pcm device for playback\n"
321c72fcc34Sopenharmony_ci"  -C                     pcm device for capture\n"
322c72fcc34Sopenharmony_ci"  -f                     sample format\n"
323c72fcc34Sopenharmony_ci"  -c                     number of channels\n"
324c72fcc34Sopenharmony_ci"  -r                     sampling rate\n"
325c72fcc34Sopenharmony_ci"  -n                     frames to playback or capture\n"
326c72fcc34Sopenharmony_ci"  -k                     parameter for frequency detecting threshold\n"
327c72fcc34Sopenharmony_ci"  -F                     target frequency\n"
328c72fcc34Sopenharmony_ci"  -p                     total number of periods to play/capture\n"
329c72fcc34Sopenharmony_ci"  -B                     buffer size in frames\n"
330c72fcc34Sopenharmony_ci"  -E                     period size in frames\n"
331c72fcc34Sopenharmony_ci"      --log=#            file that both stdout and strerr redirecting to\n"
332c72fcc34Sopenharmony_ci"      --file=#           file for playback\n"
333c72fcc34Sopenharmony_ci"      --saveplay=#       file that storing playback content, for debug\n"
334c72fcc34Sopenharmony_ci"      --readcapture=#    file with previously captured content.  File data\n"
335c72fcc34Sopenharmony_ci"                         is used for analysis instead of capturing it.\n"
336c72fcc34Sopenharmony_ci"      --local            internal loop, set to bypass pcm hardware devices\n"
337c72fcc34Sopenharmony_ci"      --standalone       standalone mode, to bypass analysis\n"
338c72fcc34Sopenharmony_ci"      --roundtriplatency round trip latency mode\n"
339c72fcc34Sopenharmony_ci"      --snr-db=#         noise detect threshold, in SNR(dB)\n"
340c72fcc34Sopenharmony_ci"      --snr-pc=#         noise detect threshold, in noise percentage(%%)\n"
341c72fcc34Sopenharmony_ci));
342c72fcc34Sopenharmony_ci	fprintf(bat->log, _("Recognized sample formats are: "));
343c72fcc34Sopenharmony_ci	fprintf(bat->log, _("U8 S16_LE S24_3LE S32_LE\n"));
344c72fcc34Sopenharmony_ci	fprintf(bat->log, _("The available format shotcuts are:\n"));
345c72fcc34Sopenharmony_ci	fprintf(bat->log, _("-f cd (16 bit little endian, 44100, stereo)\n"));
346c72fcc34Sopenharmony_ci	fprintf(bat->log, _("-f dat (16 bit little endian, 48000, stereo)\n"));
347c72fcc34Sopenharmony_ci}
348c72fcc34Sopenharmony_ci
349c72fcc34Sopenharmony_cistatic void set_defaults(struct bat *bat)
350c72fcc34Sopenharmony_ci{
351c72fcc34Sopenharmony_ci	memset(bat, 0, sizeof(struct bat));
352c72fcc34Sopenharmony_ci
353c72fcc34Sopenharmony_ci	/* Set default values */
354c72fcc34Sopenharmony_ci	bat->rate = 44100;
355c72fcc34Sopenharmony_ci	bat->frame_size = 2;
356c72fcc34Sopenharmony_ci	bat->sample_size = 2;
357c72fcc34Sopenharmony_ci	bat->format = BAT_PCM_FORMAT_S16_LE;
358c72fcc34Sopenharmony_ci	bat->convert_float_to_sample = convert_float_to_int16;
359c72fcc34Sopenharmony_ci	bat->convert_sample_to_float = convert_int16_to_float;
360c72fcc34Sopenharmony_ci	bat->frames = bat->rate * 2;
361c72fcc34Sopenharmony_ci	bat->target_freq[0] = 997.0;
362c72fcc34Sopenharmony_ci	bat->target_freq[1] = 997.0;
363c72fcc34Sopenharmony_ci	bat->sigma_k = 3.0;
364c72fcc34Sopenharmony_ci	bat->snr_thd_db = SNR_DB_INVALID;
365c72fcc34Sopenharmony_ci	bat->playback.device = NULL;
366c72fcc34Sopenharmony_ci	bat->capture.device = NULL;
367c72fcc34Sopenharmony_ci	bat->buf = NULL;
368c72fcc34Sopenharmony_ci	bat->local = false;
369c72fcc34Sopenharmony_ci	bat->buffer_size = 0;
370c72fcc34Sopenharmony_ci	bat->period_size = 0;
371c72fcc34Sopenharmony_ci	bat->roundtriplatency = false;
372c72fcc34Sopenharmony_ci#ifdef HAVE_LIBTINYALSA
373c72fcc34Sopenharmony_ci	bat->channels = 2;
374c72fcc34Sopenharmony_ci	bat->playback.fct = &playback_tinyalsa;
375c72fcc34Sopenharmony_ci	bat->capture.fct = &record_tinyalsa;
376c72fcc34Sopenharmony_ci#else
377c72fcc34Sopenharmony_ci	bat->channels = 1;
378c72fcc34Sopenharmony_ci	bat->playback.fct = &playback_alsa;
379c72fcc34Sopenharmony_ci	bat->capture.fct = &record_alsa;
380c72fcc34Sopenharmony_ci#endif
381c72fcc34Sopenharmony_ci	bat->playback.mode = MODE_LOOPBACK;
382c72fcc34Sopenharmony_ci	bat->capture.mode = MODE_LOOPBACK;
383c72fcc34Sopenharmony_ci	bat->period_is_limited = false;
384c72fcc34Sopenharmony_ci	bat->log = stdout;
385c72fcc34Sopenharmony_ci	bat->err = stderr;
386c72fcc34Sopenharmony_ci}
387c72fcc34Sopenharmony_ci
388c72fcc34Sopenharmony_cistatic void parse_arguments(struct bat *bat, int argc, char *argv[])
389c72fcc34Sopenharmony_ci{
390c72fcc34Sopenharmony_ci	int c, option_index, err;
391c72fcc34Sopenharmony_ci	static const char short_options[] = "D:P:C:f:n:F:c:r:s:k:p:B:E:lth";
392c72fcc34Sopenharmony_ci	static const struct option long_options[] = {
393c72fcc34Sopenharmony_ci		{"help",     0, 0, 'h'},
394c72fcc34Sopenharmony_ci		{"log",      1, 0, OPT_LOG},
395c72fcc34Sopenharmony_ci		{"file",     1, 0, OPT_READFILE},
396c72fcc34Sopenharmony_ci		{"saveplay", 1, 0, OPT_SAVEPLAY},
397c72fcc34Sopenharmony_ci		{"local",    0, 0, OPT_LOCAL},
398c72fcc34Sopenharmony_ci		{"standalone", 0, 0, OPT_STANDALONE},
399c72fcc34Sopenharmony_ci		{"roundtriplatency", 0, 0, OPT_ROUNDTRIPLATENCY},
400c72fcc34Sopenharmony_ci		{"snr-db",   1, 0, OPT_SNRTHD_DB},
401c72fcc34Sopenharmony_ci		{"snr-pc",   1, 0, OPT_SNRTHD_PC},
402c72fcc34Sopenharmony_ci		{"readcapture", 1, 0, OPT_READCAPTURE},
403c72fcc34Sopenharmony_ci		{0, 0, 0, 0}
404c72fcc34Sopenharmony_ci	};
405c72fcc34Sopenharmony_ci
406c72fcc34Sopenharmony_ci	while ((c = getopt_long(argc, argv, short_options, long_options,
407c72fcc34Sopenharmony_ci					&option_index)) != -1) {
408c72fcc34Sopenharmony_ci		switch (c) {
409c72fcc34Sopenharmony_ci		case OPT_LOG:
410c72fcc34Sopenharmony_ci			bat->logarg = optarg;
411c72fcc34Sopenharmony_ci			break;
412c72fcc34Sopenharmony_ci		case OPT_READFILE:
413c72fcc34Sopenharmony_ci			bat->playback.file = optarg;
414c72fcc34Sopenharmony_ci			break;
415c72fcc34Sopenharmony_ci		case OPT_SAVEPLAY:
416c72fcc34Sopenharmony_ci			bat->debugplay = optarg;
417c72fcc34Sopenharmony_ci			break;
418c72fcc34Sopenharmony_ci		case OPT_READCAPTURE:
419c72fcc34Sopenharmony_ci			bat->capturefile = optarg;
420c72fcc34Sopenharmony_ci			bat->capture.mode = MODE_ANALYZE_ONLY;
421c72fcc34Sopenharmony_ci			bat->playback.mode = MODE_ANALYZE_ONLY;
422c72fcc34Sopenharmony_ci			break;
423c72fcc34Sopenharmony_ci		case OPT_LOCAL:
424c72fcc34Sopenharmony_ci			bat->local = true;
425c72fcc34Sopenharmony_ci			break;
426c72fcc34Sopenharmony_ci		case OPT_STANDALONE:
427c72fcc34Sopenharmony_ci			bat->standalone = true;
428c72fcc34Sopenharmony_ci			break;
429c72fcc34Sopenharmony_ci		case OPT_ROUNDTRIPLATENCY:
430c72fcc34Sopenharmony_ci			bat->roundtriplatency = true;
431c72fcc34Sopenharmony_ci			break;
432c72fcc34Sopenharmony_ci		case OPT_SNRTHD_DB:
433c72fcc34Sopenharmony_ci			get_snr_thd_db(bat, optarg);
434c72fcc34Sopenharmony_ci			break;
435c72fcc34Sopenharmony_ci		case OPT_SNRTHD_PC:
436c72fcc34Sopenharmony_ci			get_snr_thd_pc(bat, optarg);
437c72fcc34Sopenharmony_ci			break;
438c72fcc34Sopenharmony_ci		case 'D':
439c72fcc34Sopenharmony_ci			if (bat->playback.device == NULL)
440c72fcc34Sopenharmony_ci				bat->playback.device = optarg;
441c72fcc34Sopenharmony_ci			if (bat->capture.device == NULL)
442c72fcc34Sopenharmony_ci				bat->capture.device = optarg;
443c72fcc34Sopenharmony_ci			break;
444c72fcc34Sopenharmony_ci		case 'P':
445c72fcc34Sopenharmony_ci			if (bat->capture.mode == MODE_SINGLE)
446c72fcc34Sopenharmony_ci				bat->capture.mode = MODE_LOOPBACK;
447c72fcc34Sopenharmony_ci			else
448c72fcc34Sopenharmony_ci				bat->playback.mode = MODE_SINGLE;
449c72fcc34Sopenharmony_ci			bat->playback.device = optarg;
450c72fcc34Sopenharmony_ci			break;
451c72fcc34Sopenharmony_ci		case 'C':
452c72fcc34Sopenharmony_ci			if (bat->playback.mode == MODE_SINGLE)
453c72fcc34Sopenharmony_ci				bat->playback.mode = MODE_LOOPBACK;
454c72fcc34Sopenharmony_ci			else
455c72fcc34Sopenharmony_ci				bat->capture.mode = MODE_SINGLE;
456c72fcc34Sopenharmony_ci			bat->capture.device = optarg;
457c72fcc34Sopenharmony_ci			break;
458c72fcc34Sopenharmony_ci		case 'n':
459c72fcc34Sopenharmony_ci			bat->narg = optarg;
460c72fcc34Sopenharmony_ci			break;
461c72fcc34Sopenharmony_ci		case 'F':
462c72fcc34Sopenharmony_ci			get_sine_frequencies(bat, optarg);
463c72fcc34Sopenharmony_ci			break;
464c72fcc34Sopenharmony_ci		case 'c':
465c72fcc34Sopenharmony_ci			bat->channels = atoi(optarg);
466c72fcc34Sopenharmony_ci			break;
467c72fcc34Sopenharmony_ci		case 'r':
468c72fcc34Sopenharmony_ci			bat->rate = atoi(optarg);
469c72fcc34Sopenharmony_ci			break;
470c72fcc34Sopenharmony_ci		case 'f':
471c72fcc34Sopenharmony_ci			get_format(bat, optarg);
472c72fcc34Sopenharmony_ci			break;
473c72fcc34Sopenharmony_ci		case 'k':
474c72fcc34Sopenharmony_ci			bat->sigma_k = atof(optarg);
475c72fcc34Sopenharmony_ci			break;
476c72fcc34Sopenharmony_ci		case 'p':
477c72fcc34Sopenharmony_ci			bat->periods_total = atoi(optarg);
478c72fcc34Sopenharmony_ci			bat->period_is_limited = true;
479c72fcc34Sopenharmony_ci			break;
480c72fcc34Sopenharmony_ci		case 'B':
481c72fcc34Sopenharmony_ci			err = atoi(optarg);
482c72fcc34Sopenharmony_ci			bat->buffer_size = err >= MIN_BUFFERSIZE
483c72fcc34Sopenharmony_ci					&& err < MAX_BUFFERSIZE ? err : 0;
484c72fcc34Sopenharmony_ci			break;
485c72fcc34Sopenharmony_ci		case 'E':
486c72fcc34Sopenharmony_ci			err = atoi(optarg);
487c72fcc34Sopenharmony_ci			bat->period_size = err >= MIN_PERIODSIZE
488c72fcc34Sopenharmony_ci					&& err < MAX_PERIODSIZE ? err : 0;
489c72fcc34Sopenharmony_ci			break;
490c72fcc34Sopenharmony_ci		case 'h':
491c72fcc34Sopenharmony_ci		default:
492c72fcc34Sopenharmony_ci			usage(bat);
493c72fcc34Sopenharmony_ci			exit(EXIT_SUCCESS);
494c72fcc34Sopenharmony_ci		}
495c72fcc34Sopenharmony_ci	}
496c72fcc34Sopenharmony_ci}
497c72fcc34Sopenharmony_ci
498c72fcc34Sopenharmony_cistatic int validate_options(struct bat *bat)
499c72fcc34Sopenharmony_ci{
500c72fcc34Sopenharmony_ci	int c;
501c72fcc34Sopenharmony_ci	float freq_low, freq_high;
502c72fcc34Sopenharmony_ci
503c72fcc34Sopenharmony_ci	/* check if we have an input file for local mode */
504c72fcc34Sopenharmony_ci	if ((bat->local == true) && (bat->capture.file == NULL)) {
505c72fcc34Sopenharmony_ci		fprintf(bat->err, _("no input file for local testing\n"));
506c72fcc34Sopenharmony_ci		return -EINVAL;
507c72fcc34Sopenharmony_ci	}
508c72fcc34Sopenharmony_ci
509c72fcc34Sopenharmony_ci	/* check supported channels */
510c72fcc34Sopenharmony_ci	if (bat->channels > MAX_CHANNELS || bat->channels < MIN_CHANNELS) {
511c72fcc34Sopenharmony_ci		fprintf(bat->err, _("%d channels not supported\n"),
512c72fcc34Sopenharmony_ci				bat->channels);
513c72fcc34Sopenharmony_ci		return -EINVAL;
514c72fcc34Sopenharmony_ci	}
515c72fcc34Sopenharmony_ci
516c72fcc34Sopenharmony_ci	/* check single ended is in either playback or capture - not both */
517c72fcc34Sopenharmony_ci	if ((bat->playback.mode == MODE_SINGLE)
518c72fcc34Sopenharmony_ci			&& (bat->capture.mode == MODE_SINGLE)) {
519c72fcc34Sopenharmony_ci		fprintf(bat->err, _("single ended mode is simplex\n"));
520c72fcc34Sopenharmony_ci		return -EINVAL;
521c72fcc34Sopenharmony_ci	}
522c72fcc34Sopenharmony_ci
523c72fcc34Sopenharmony_ci	/* check sine wave frequency range */
524c72fcc34Sopenharmony_ci	freq_low = DC_THRESHOLD;
525c72fcc34Sopenharmony_ci	freq_high = bat->rate * RATE_FACTOR;
526c72fcc34Sopenharmony_ci	for (c = 0; c < bat->channels; c++) {
527c72fcc34Sopenharmony_ci		if (bat->target_freq[c] < freq_low
528c72fcc34Sopenharmony_ci				|| bat->target_freq[c] > freq_high) {
529c72fcc34Sopenharmony_ci			fprintf(bat->err, _("sine wave frequency out of"));
530c72fcc34Sopenharmony_ci			fprintf(bat->err, _(" range: (%.1f, %.1f)\n"),
531c72fcc34Sopenharmony_ci				freq_low, freq_high);
532c72fcc34Sopenharmony_ci			return -EINVAL;
533c72fcc34Sopenharmony_ci		}
534c72fcc34Sopenharmony_ci	}
535c72fcc34Sopenharmony_ci
536c72fcc34Sopenharmony_ci	return 0;
537c72fcc34Sopenharmony_ci}
538c72fcc34Sopenharmony_ci
539c72fcc34Sopenharmony_cistatic int bat_init(struct bat *bat)
540c72fcc34Sopenharmony_ci{
541c72fcc34Sopenharmony_ci	int err = 0;
542c72fcc34Sopenharmony_ci	int fd = 0;
543c72fcc34Sopenharmony_ci	char name[] = TEMP_RECORD_FILE_NAME;
544c72fcc34Sopenharmony_ci
545c72fcc34Sopenharmony_ci	/* Determine logging to a file or stdout and stderr */
546c72fcc34Sopenharmony_ci	if (bat->logarg) {
547c72fcc34Sopenharmony_ci		bat->log = NULL;
548c72fcc34Sopenharmony_ci		bat->log = fopen(bat->logarg, "wb");
549c72fcc34Sopenharmony_ci		if (bat->log == NULL) {
550c72fcc34Sopenharmony_ci			err = -errno;
551c72fcc34Sopenharmony_ci			fprintf(bat->err, _("Cannot open file: %s %d\n"),
552c72fcc34Sopenharmony_ci					bat->logarg, err);
553c72fcc34Sopenharmony_ci			return err;
554c72fcc34Sopenharmony_ci		}
555c72fcc34Sopenharmony_ci		bat->err = bat->log;
556c72fcc34Sopenharmony_ci	}
557c72fcc34Sopenharmony_ci
558c72fcc34Sopenharmony_ci	/* Determine duration of playback and/or capture */
559c72fcc34Sopenharmony_ci	if (bat->narg) {
560c72fcc34Sopenharmony_ci		err = get_duration(bat);
561c72fcc34Sopenharmony_ci		if (err < 0)
562c72fcc34Sopenharmony_ci			return err;
563c72fcc34Sopenharmony_ci	}
564c72fcc34Sopenharmony_ci
565c72fcc34Sopenharmony_ci	/* Set default playback and capture devices */
566c72fcc34Sopenharmony_ci	if (bat->playback.device == NULL && bat->capture.device == NULL)
567c72fcc34Sopenharmony_ci		bat->playback.device = bat->capture.device = DEFAULT_DEV_NAME;
568c72fcc34Sopenharmony_ci
569c72fcc34Sopenharmony_ci	/* Determine capture file */
570c72fcc34Sopenharmony_ci	if (bat->local) {
571c72fcc34Sopenharmony_ci		bat->capture.file = bat->playback.file;
572c72fcc34Sopenharmony_ci	} else {
573c72fcc34Sopenharmony_ci		/* create temp file for sound record and analysis */
574c72fcc34Sopenharmony_ci		fd = mkstemp(name);
575c72fcc34Sopenharmony_ci		if (fd == -1) {
576c72fcc34Sopenharmony_ci			err = -errno;
577c72fcc34Sopenharmony_ci			fprintf(bat->err, _("Fail to create record file: %d\n"),
578c72fcc34Sopenharmony_ci					err);
579c72fcc34Sopenharmony_ci			return err;
580c72fcc34Sopenharmony_ci		}
581c72fcc34Sopenharmony_ci		/* store file name which is dynamically created */
582c72fcc34Sopenharmony_ci		bat->capture.file = strdup(name);
583c72fcc34Sopenharmony_ci		if (bat->capture.file == NULL)
584c72fcc34Sopenharmony_ci			return -ENOMEM;
585c72fcc34Sopenharmony_ci		/* close temp file */
586c72fcc34Sopenharmony_ci		close(fd);
587c72fcc34Sopenharmony_ci	}
588c72fcc34Sopenharmony_ci
589c72fcc34Sopenharmony_ci	/* Initial for playback */
590c72fcc34Sopenharmony_ci	if (bat->playback.file == NULL) {
591c72fcc34Sopenharmony_ci		/* No input file so we will generate our own sine wave */
592c72fcc34Sopenharmony_ci		if (bat->frames) {
593c72fcc34Sopenharmony_ci			if (bat->playback.mode == MODE_SINGLE) {
594c72fcc34Sopenharmony_ci				/* Play nb of frames given by -n argument */
595c72fcc34Sopenharmony_ci				bat->sinus_duration = bat->frames;
596c72fcc34Sopenharmony_ci			} else {
597c72fcc34Sopenharmony_ci				/* Play CAPTURE_DELAY msec +
598c72fcc34Sopenharmony_ci				 * 150% of the nb of frames to be analyzed */
599c72fcc34Sopenharmony_ci				bat->sinus_duration = bat->rate *
600c72fcc34Sopenharmony_ci						CAPTURE_DELAY / 1000;
601c72fcc34Sopenharmony_ci				bat->sinus_duration +=
602c72fcc34Sopenharmony_ci						(bat->frames + bat->frames / 2);
603c72fcc34Sopenharmony_ci			}
604c72fcc34Sopenharmony_ci		} else {
605c72fcc34Sopenharmony_ci			/* Special case where we want to generate a sine wave
606c72fcc34Sopenharmony_ci			 * endlessly without capturing */
607c72fcc34Sopenharmony_ci			bat->sinus_duration = 0;
608c72fcc34Sopenharmony_ci			bat->playback.mode = MODE_SINGLE;
609c72fcc34Sopenharmony_ci		}
610c72fcc34Sopenharmony_ci	} else {
611c72fcc34Sopenharmony_ci		bat->fp = fopen(bat->playback.file, "rb");
612c72fcc34Sopenharmony_ci		if (bat->fp == NULL) {
613c72fcc34Sopenharmony_ci			err = -errno;
614c72fcc34Sopenharmony_ci			fprintf(bat->err, _("Cannot open file: %s %d\n"),
615c72fcc34Sopenharmony_ci					bat->playback.file, err);
616c72fcc34Sopenharmony_ci			return err;
617c72fcc34Sopenharmony_ci		}
618c72fcc34Sopenharmony_ci		err = read_wav_header(bat, bat->playback.file, bat->fp, false);
619c72fcc34Sopenharmony_ci		fclose(bat->fp);
620c72fcc34Sopenharmony_ci		if (err != 0)
621c72fcc34Sopenharmony_ci			return err;
622c72fcc34Sopenharmony_ci	}
623c72fcc34Sopenharmony_ci
624c72fcc34Sopenharmony_ci	bat->frame_size = bat->sample_size * bat->channels;
625c72fcc34Sopenharmony_ci
626c72fcc34Sopenharmony_ci	/* Set conversion functions */
627c72fcc34Sopenharmony_ci	switch (bat->sample_size) {
628c72fcc34Sopenharmony_ci	case 1:
629c72fcc34Sopenharmony_ci		bat->convert_float_to_sample = convert_float_to_uint8;
630c72fcc34Sopenharmony_ci		bat->convert_sample_to_float = convert_uint8_to_float;
631c72fcc34Sopenharmony_ci		break;
632c72fcc34Sopenharmony_ci	case 2:
633c72fcc34Sopenharmony_ci		bat->convert_float_to_sample = convert_float_to_int16;
634c72fcc34Sopenharmony_ci		bat->convert_sample_to_float = convert_int16_to_float;
635c72fcc34Sopenharmony_ci		break;
636c72fcc34Sopenharmony_ci	case 3:
637c72fcc34Sopenharmony_ci		bat->convert_float_to_sample = convert_float_to_int24;
638c72fcc34Sopenharmony_ci		bat->convert_sample_to_float = convert_int24_to_float;
639c72fcc34Sopenharmony_ci		break;
640c72fcc34Sopenharmony_ci	case 4:
641c72fcc34Sopenharmony_ci		bat->convert_float_to_sample = convert_float_to_int32;
642c72fcc34Sopenharmony_ci		bat->convert_sample_to_float = convert_int32_to_float;
643c72fcc34Sopenharmony_ci		break;
644c72fcc34Sopenharmony_ci	default:
645c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Invalid PCM format: size=%d\n"),
646c72fcc34Sopenharmony_ci				bat->sample_size);
647c72fcc34Sopenharmony_ci		return -EINVAL;
648c72fcc34Sopenharmony_ci	}
649c72fcc34Sopenharmony_ci
650c72fcc34Sopenharmony_ci	return err;
651c72fcc34Sopenharmony_ci}
652c72fcc34Sopenharmony_ci
653c72fcc34Sopenharmony_ciint main(int argc, char *argv[])
654c72fcc34Sopenharmony_ci{
655c72fcc34Sopenharmony_ci	struct bat bat;
656c72fcc34Sopenharmony_ci	int err = 0;
657c72fcc34Sopenharmony_ci
658c72fcc34Sopenharmony_ci	set_defaults(&bat);
659c72fcc34Sopenharmony_ci
660c72fcc34Sopenharmony_ci#ifdef ENABLE_NLS
661c72fcc34Sopenharmony_ci	setlocale(LC_ALL, "");
662c72fcc34Sopenharmony_ci	textdomain(PACKAGE);
663c72fcc34Sopenharmony_ci#endif
664c72fcc34Sopenharmony_ci
665c72fcc34Sopenharmony_ci	fprintf(bat.log, _("%s version %s\n\n"), PACKAGE_NAME, PACKAGE_VERSION);
666c72fcc34Sopenharmony_ci
667c72fcc34Sopenharmony_ci	parse_arguments(&bat, argc, argv);
668c72fcc34Sopenharmony_ci
669c72fcc34Sopenharmony_ci	err = bat_init(&bat);
670c72fcc34Sopenharmony_ci	if (err < 0)
671c72fcc34Sopenharmony_ci		goto out;
672c72fcc34Sopenharmony_ci
673c72fcc34Sopenharmony_ci	err = validate_options(&bat);
674c72fcc34Sopenharmony_ci	if (err < 0)
675c72fcc34Sopenharmony_ci		goto out;
676c72fcc34Sopenharmony_ci
677c72fcc34Sopenharmony_ci	/* round trip latency test thread */
678c72fcc34Sopenharmony_ci	if (bat.roundtriplatency) {
679c72fcc34Sopenharmony_ci		while (1) {
680c72fcc34Sopenharmony_ci			fprintf(bat.log,
681c72fcc34Sopenharmony_ci				_("\nStart round trip latency\n"));
682c72fcc34Sopenharmony_ci			roundtrip_latency_init(&bat);
683c72fcc34Sopenharmony_ci			test_loopback(&bat);
684c72fcc34Sopenharmony_ci
685c72fcc34Sopenharmony_ci			if (bat.latency.xrun_error == false)
686c72fcc34Sopenharmony_ci				break;
687c72fcc34Sopenharmony_ci			else {
688c72fcc34Sopenharmony_ci				/* Xrun error in playback or capture,
689c72fcc34Sopenharmony_ci				increase period size and try again */
690c72fcc34Sopenharmony_ci				bat.period_size += bat.rate / 1000;
691c72fcc34Sopenharmony_ci				bat.buffer_size =
692c72fcc34Sopenharmony_ci					bat.period_size * DIV_BUFFERSIZE;
693c72fcc34Sopenharmony_ci
694c72fcc34Sopenharmony_ci				/* terminate the test if period_size is
695c72fcc34Sopenharmony_ci				large enough */
696c72fcc34Sopenharmony_ci				if (bat.period_size > bat.rate * 0.2)
697c72fcc34Sopenharmony_ci					break;
698c72fcc34Sopenharmony_ci			}
699c72fcc34Sopenharmony_ci
700c72fcc34Sopenharmony_ci			/* Waiting 500ms and start the next round */
701c72fcc34Sopenharmony_ci			usleep(CAPTURE_DELAY * 1000);
702c72fcc34Sopenharmony_ci		}
703c72fcc34Sopenharmony_ci		goto out;
704c72fcc34Sopenharmony_ci	}
705c72fcc34Sopenharmony_ci
706c72fcc34Sopenharmony_ci	/* single line playback thread: playback only, no capture */
707c72fcc34Sopenharmony_ci	if (bat.playback.mode == MODE_SINGLE) {
708c72fcc34Sopenharmony_ci		test_playback(&bat);
709c72fcc34Sopenharmony_ci		goto out;
710c72fcc34Sopenharmony_ci	}
711c72fcc34Sopenharmony_ci
712c72fcc34Sopenharmony_ci	/* single line capture thread: capture only, no playback */
713c72fcc34Sopenharmony_ci	if (bat.capture.mode == MODE_SINGLE) {
714c72fcc34Sopenharmony_ci		test_capture(&bat);
715c72fcc34Sopenharmony_ci		goto analyze;
716c72fcc34Sopenharmony_ci	}
717c72fcc34Sopenharmony_ci
718c72fcc34Sopenharmony_ci	if (bat.capture.mode == MODE_ANALYZE_ONLY && bat.capturefile) {
719c72fcc34Sopenharmony_ci		bat.capture.file = strdup(bat.capturefile);
720c72fcc34Sopenharmony_ci		fprintf(bat.log,
721c72fcc34Sopenharmony_ci			_("Using data from file %s for analysis\n"),
722c72fcc34Sopenharmony_ci			bat.capture.file);
723c72fcc34Sopenharmony_ci		fprintf(bat.log, _("Skipping playback and capture\n"));
724c72fcc34Sopenharmony_ci		goto analyze;
725c72fcc34Sopenharmony_ci	}
726c72fcc34Sopenharmony_ci
727c72fcc34Sopenharmony_ci	/* loopback thread: playback and capture in a loop */
728c72fcc34Sopenharmony_ci	if (bat.local == false)
729c72fcc34Sopenharmony_ci		test_loopback(&bat);
730c72fcc34Sopenharmony_ci
731c72fcc34Sopenharmony_cianalyze:
732c72fcc34Sopenharmony_ci#ifdef HAVE_LIBFFTW3F
733c72fcc34Sopenharmony_ci	if (!bat.standalone || snr_is_valid(bat.snr_thd_db))
734c72fcc34Sopenharmony_ci		err = analyze_capture(&bat);
735c72fcc34Sopenharmony_ci#else
736c72fcc34Sopenharmony_ci	fprintf(bat.log, _("No libfftw3 library. Exit without analysis.\n"));
737c72fcc34Sopenharmony_ci#endif
738c72fcc34Sopenharmony_ciout:
739c72fcc34Sopenharmony_ci	fprintf(bat.log, _("\nReturn value is %d\n"), err);
740c72fcc34Sopenharmony_ci
741c72fcc34Sopenharmony_ci	if (bat.logarg)
742c72fcc34Sopenharmony_ci		fclose(bat.log);
743c72fcc34Sopenharmony_ci	if (!bat.local)
744c72fcc34Sopenharmony_ci		free(bat.capture.file);
745c72fcc34Sopenharmony_ci
746c72fcc34Sopenharmony_ci	return err;
747c72fcc34Sopenharmony_ci}
748