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