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 "aconfig.h" 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_ci#include <stdio.h> 19c72fcc34Sopenharmony_ci#include <string.h> 20c72fcc34Sopenharmony_ci#include <stdbool.h> 21c72fcc34Sopenharmony_ci#include <stdlib.h> 22c72fcc34Sopenharmony_ci#include <pthread.h> 23c72fcc34Sopenharmony_ci#include <errno.h> 24c72fcc34Sopenharmony_ci 25c72fcc34Sopenharmony_ci#include <tinyalsa/asoundlib.h> 26c72fcc34Sopenharmony_ci 27c72fcc34Sopenharmony_ci#include "gettext.h" 28c72fcc34Sopenharmony_ci 29c72fcc34Sopenharmony_ci#include "common.h" 30c72fcc34Sopenharmony_ci#include "tinyalsa.h" 31c72fcc34Sopenharmony_ci#include "latencytest.h" 32c72fcc34Sopenharmony_ci 33c72fcc34Sopenharmony_cistruct format_map_table { 34c72fcc34Sopenharmony_ci enum _bat_pcm_format format_bat; 35c72fcc34Sopenharmony_ci enum pcm_format format_tiny; 36c72fcc34Sopenharmony_ci}; 37c72fcc34Sopenharmony_ci 38c72fcc34Sopenharmony_cistatic struct format_map_table map_tables[] = { 39c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_S16_LE, PCM_FORMAT_S16_LE }, 40c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_S32_LE, PCM_FORMAT_S32_LE }, 41c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_MAX, }, 42c72fcc34Sopenharmony_ci}; 43c72fcc34Sopenharmony_ci 44c72fcc34Sopenharmony_cistatic int format_convert(struct bat *bat, struct pcm_config *config) 45c72fcc34Sopenharmony_ci{ 46c72fcc34Sopenharmony_ci struct format_map_table *t = map_tables; 47c72fcc34Sopenharmony_ci 48c72fcc34Sopenharmony_ci for (; t->format_bat != BAT_PCM_FORMAT_MAX; t++) { 49c72fcc34Sopenharmony_ci if (t->format_bat == bat->format) { 50c72fcc34Sopenharmony_ci config->format = t->format_tiny; 51c72fcc34Sopenharmony_ci return 0; 52c72fcc34Sopenharmony_ci } 53c72fcc34Sopenharmony_ci } 54c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid format!\n")); 55c72fcc34Sopenharmony_ci return -EINVAL; 56c72fcc34Sopenharmony_ci} 57c72fcc34Sopenharmony_ci 58c72fcc34Sopenharmony_cistatic int init_config(struct bat *bat, struct pcm_config *config) 59c72fcc34Sopenharmony_ci{ 60c72fcc34Sopenharmony_ci config->channels = bat->channels; 61c72fcc34Sopenharmony_ci config->rate = bat->rate; 62c72fcc34Sopenharmony_ci if (bat->period_size > 0) 63c72fcc34Sopenharmony_ci config->period_size = bat->period_size; 64c72fcc34Sopenharmony_ci else 65c72fcc34Sopenharmony_ci config->period_size = TINYALSA_PERIODSIZE; 66c72fcc34Sopenharmony_ci config->period_count = 4; 67c72fcc34Sopenharmony_ci config->start_threshold = 0; 68c72fcc34Sopenharmony_ci config->stop_threshold = 0; 69c72fcc34Sopenharmony_ci config->silence_threshold = 0; 70c72fcc34Sopenharmony_ci 71c72fcc34Sopenharmony_ci return format_convert(bat, config); 72c72fcc34Sopenharmony_ci} 73c72fcc34Sopenharmony_ci 74c72fcc34Sopenharmony_ci/** 75c72fcc34Sopenharmony_ci * Called when thread is finished 76c72fcc34Sopenharmony_ci */ 77c72fcc34Sopenharmony_cistatic void close_handle(void *handle) 78c72fcc34Sopenharmony_ci{ 79c72fcc34Sopenharmony_ci struct pcm *pcm = handle; 80c72fcc34Sopenharmony_ci 81c72fcc34Sopenharmony_ci if (NULL != pcm) 82c72fcc34Sopenharmony_ci pcm_close(pcm); 83c72fcc34Sopenharmony_ci} 84c72fcc34Sopenharmony_ci 85c72fcc34Sopenharmony_ci/** 86c72fcc34Sopenharmony_ci * Check that a parameter is inside bounds 87c72fcc34Sopenharmony_ci */ 88c72fcc34Sopenharmony_cistatic int check_param(struct bat *bat, struct pcm_params *params, 89c72fcc34Sopenharmony_ci unsigned int param, unsigned int value, 90c72fcc34Sopenharmony_ci char *param_name, char *param_unit) 91c72fcc34Sopenharmony_ci{ 92c72fcc34Sopenharmony_ci unsigned int min; 93c72fcc34Sopenharmony_ci unsigned int max; 94c72fcc34Sopenharmony_ci int ret = 0; 95c72fcc34Sopenharmony_ci 96c72fcc34Sopenharmony_ci min = pcm_params_get_min(params, param); 97c72fcc34Sopenharmony_ci if (value < min) { 98c72fcc34Sopenharmony_ci fprintf(bat->err, 99c72fcc34Sopenharmony_ci _("%s is %u%s, device only supports >= %u%s!\n"), 100c72fcc34Sopenharmony_ci param_name, value, param_unit, min, param_unit); 101c72fcc34Sopenharmony_ci ret = -EINVAL; 102c72fcc34Sopenharmony_ci } 103c72fcc34Sopenharmony_ci 104c72fcc34Sopenharmony_ci max = pcm_params_get_max(params, param); 105c72fcc34Sopenharmony_ci if (value > max) { 106c72fcc34Sopenharmony_ci fprintf(bat->err, 107c72fcc34Sopenharmony_ci _("%s is %u%s, device only supports <= %u%s!\n"), 108c72fcc34Sopenharmony_ci param_name, value, param_unit, max, param_unit); 109c72fcc34Sopenharmony_ci ret = -EINVAL; 110c72fcc34Sopenharmony_ci } 111c72fcc34Sopenharmony_ci 112c72fcc34Sopenharmony_ci return ret; 113c72fcc34Sopenharmony_ci} 114c72fcc34Sopenharmony_ci 115c72fcc34Sopenharmony_ci/** 116c72fcc34Sopenharmony_ci * Check all parameters 117c72fcc34Sopenharmony_ci */ 118c72fcc34Sopenharmony_cistatic int check_playback_params(struct bat *bat, 119c72fcc34Sopenharmony_ci struct pcm_config *config) 120c72fcc34Sopenharmony_ci{ 121c72fcc34Sopenharmony_ci struct pcm_params *params; 122c72fcc34Sopenharmony_ci unsigned int card = bat->playback.card_tiny; 123c72fcc34Sopenharmony_ci unsigned int device = bat->playback.device_tiny; 124c72fcc34Sopenharmony_ci int err = 0; 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci params = pcm_params_get(card, device, PCM_OUT); 127c72fcc34Sopenharmony_ci if (params == NULL) { 128c72fcc34Sopenharmony_ci fprintf(bat->err, _("Unable to open PCM device %u!\n"), 129c72fcc34Sopenharmony_ci device); 130c72fcc34Sopenharmony_ci return -EINVAL; 131c72fcc34Sopenharmony_ci } 132c72fcc34Sopenharmony_ci 133c72fcc34Sopenharmony_ci err = check_param(bat, params, PCM_PARAM_RATE, 134c72fcc34Sopenharmony_ci config->rate, "Sample rate", "Hz"); 135c72fcc34Sopenharmony_ci if (err < 0) 136c72fcc34Sopenharmony_ci goto exit; 137c72fcc34Sopenharmony_ci err = check_param(bat, params, PCM_PARAM_CHANNELS, 138c72fcc34Sopenharmony_ci config->channels, "Sample", " channels"); 139c72fcc34Sopenharmony_ci if (err < 0) 140c72fcc34Sopenharmony_ci goto exit; 141c72fcc34Sopenharmony_ci err = check_param(bat, params, PCM_PARAM_SAMPLE_BITS, 142c72fcc34Sopenharmony_ci bat->sample_size * 8, "Bitrate", " bits"); 143c72fcc34Sopenharmony_ci if (err < 0) 144c72fcc34Sopenharmony_ci goto exit; 145c72fcc34Sopenharmony_ci err = check_param(bat, params, PCM_PARAM_PERIOD_SIZE, 146c72fcc34Sopenharmony_ci config->period_size, "Period size", "Hz"); 147c72fcc34Sopenharmony_ci if (err < 0) 148c72fcc34Sopenharmony_ci goto exit; 149c72fcc34Sopenharmony_ci err = check_param(bat, params, PCM_PARAM_PERIODS, 150c72fcc34Sopenharmony_ci config->period_count, "Period count", "Hz"); 151c72fcc34Sopenharmony_ci if (err < 0) 152c72fcc34Sopenharmony_ci goto exit; 153c72fcc34Sopenharmony_ci 154c72fcc34Sopenharmony_ciexit: 155c72fcc34Sopenharmony_ci pcm_params_free(params); 156c72fcc34Sopenharmony_ci 157c72fcc34Sopenharmony_ci return err; 158c72fcc34Sopenharmony_ci} 159c72fcc34Sopenharmony_ci 160c72fcc34Sopenharmony_ci/** 161c72fcc34Sopenharmony_ci * Process output data for latency test 162c72fcc34Sopenharmony_ci */ 163c72fcc34Sopenharmony_cistatic int latencytest_process_output(struct bat *bat, struct pcm *pcm, 164c72fcc34Sopenharmony_ci void *buffer, int bytes) 165c72fcc34Sopenharmony_ci{ 166c72fcc34Sopenharmony_ci int err = 0; 167c72fcc34Sopenharmony_ci int frames = bytes / bat->frame_size; 168c72fcc34Sopenharmony_ci 169c72fcc34Sopenharmony_ci fprintf(bat->log, _("Play sample with %d frames buffer\n"), frames); 170c72fcc34Sopenharmony_ci 171c72fcc34Sopenharmony_ci bat->latency.is_playing = true; 172c72fcc34Sopenharmony_ci 173c72fcc34Sopenharmony_ci while (1) { 174c72fcc34Sopenharmony_ci /* generate output data */ 175c72fcc34Sopenharmony_ci err = handleoutput(bat, buffer, bytes, frames); 176c72fcc34Sopenharmony_ci if (err != 0) 177c72fcc34Sopenharmony_ci break; 178c72fcc34Sopenharmony_ci 179c72fcc34Sopenharmony_ci err = pcm_write(pcm, buffer, bytes); 180c72fcc34Sopenharmony_ci if (err != 0) 181c72fcc34Sopenharmony_ci break; 182c72fcc34Sopenharmony_ci 183c72fcc34Sopenharmony_ci if (bat->latency.state == LATENCY_STATE_COMPLETE_SUCCESS) 184c72fcc34Sopenharmony_ci break; 185c72fcc34Sopenharmony_ci 186c72fcc34Sopenharmony_ci bat->periods_played++; 187c72fcc34Sopenharmony_ci } 188c72fcc34Sopenharmony_ci 189c72fcc34Sopenharmony_ci bat->latency.is_playing = false; 190c72fcc34Sopenharmony_ci 191c72fcc34Sopenharmony_ci return err; 192c72fcc34Sopenharmony_ci} 193c72fcc34Sopenharmony_ci 194c72fcc34Sopenharmony_ci/** 195c72fcc34Sopenharmony_ci * Play sample 196c72fcc34Sopenharmony_ci */ 197c72fcc34Sopenharmony_cistatic int play_sample(struct bat *bat, struct pcm *pcm, 198c72fcc34Sopenharmony_ci void *buffer, int bytes) 199c72fcc34Sopenharmony_ci{ 200c72fcc34Sopenharmony_ci int err = 0; 201c72fcc34Sopenharmony_ci int frames = bytes / bat->frame_size; 202c72fcc34Sopenharmony_ci FILE *fp = NULL; 203c72fcc34Sopenharmony_ci int bytes_total = 0; 204c72fcc34Sopenharmony_ci 205c72fcc34Sopenharmony_ci if (bat->debugplay) { 206c72fcc34Sopenharmony_ci fp = fopen(bat->debugplay, "wb"); 207c72fcc34Sopenharmony_ci err = -errno; 208c72fcc34Sopenharmony_ci if (fp == NULL) { 209c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 210c72fcc34Sopenharmony_ci bat->debugplay, err); 211c72fcc34Sopenharmony_ci return err; 212c72fcc34Sopenharmony_ci } 213c72fcc34Sopenharmony_ci /* leave space for file header */ 214c72fcc34Sopenharmony_ci if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 215c72fcc34Sopenharmony_ci err = -errno; 216c72fcc34Sopenharmony_ci fclose(fp); 217c72fcc34Sopenharmony_ci return err; 218c72fcc34Sopenharmony_ci } 219c72fcc34Sopenharmony_ci } 220c72fcc34Sopenharmony_ci 221c72fcc34Sopenharmony_ci while (1) { 222c72fcc34Sopenharmony_ci err = generate_input_data(bat, buffer, bytes, frames); 223c72fcc34Sopenharmony_ci if (err != 0) 224c72fcc34Sopenharmony_ci break; 225c72fcc34Sopenharmony_ci 226c72fcc34Sopenharmony_ci if (bat->debugplay) { 227c72fcc34Sopenharmony_ci if (fwrite(buffer, 1, bytes, fp) != bytes) { 228c72fcc34Sopenharmony_ci err = -EIO; 229c72fcc34Sopenharmony_ci break; 230c72fcc34Sopenharmony_ci } 231c72fcc34Sopenharmony_ci bytes_total += bytes; 232c72fcc34Sopenharmony_ci } 233c72fcc34Sopenharmony_ci 234c72fcc34Sopenharmony_ci bat->periods_played++; 235c72fcc34Sopenharmony_ci if (bat->period_is_limited 236c72fcc34Sopenharmony_ci && bat->periods_played >= bat->periods_total) 237c72fcc34Sopenharmony_ci break; 238c72fcc34Sopenharmony_ci 239c72fcc34Sopenharmony_ci err = pcm_write(pcm, buffer, bytes); 240c72fcc34Sopenharmony_ci if (err != 0) 241c72fcc34Sopenharmony_ci break; 242c72fcc34Sopenharmony_ci } 243c72fcc34Sopenharmony_ci 244c72fcc34Sopenharmony_ci if (bat->debugplay) { 245c72fcc34Sopenharmony_ci update_wav_header(bat, fp, bytes_total); 246c72fcc34Sopenharmony_ci fclose(fp); 247c72fcc34Sopenharmony_ci } 248c72fcc34Sopenharmony_ci return err; 249c72fcc34Sopenharmony_ci} 250c72fcc34Sopenharmony_ci 251c72fcc34Sopenharmony_cistatic int get_tiny_device(struct bat *bat, char *alsa_device, 252c72fcc34Sopenharmony_ci unsigned int *tiny_card, unsigned int *tiny_device) 253c72fcc34Sopenharmony_ci{ 254c72fcc34Sopenharmony_ci char *tmp1, *tmp2, *tmp3; 255c72fcc34Sopenharmony_ci 256c72fcc34Sopenharmony_ci if (alsa_device == NULL) 257c72fcc34Sopenharmony_ci goto fail; 258c72fcc34Sopenharmony_ci 259c72fcc34Sopenharmony_ci tmp1 = strchr(alsa_device, ':'); 260c72fcc34Sopenharmony_ci if (tmp1 == NULL) 261c72fcc34Sopenharmony_ci goto fail; 262c72fcc34Sopenharmony_ci 263c72fcc34Sopenharmony_ci tmp3 = tmp1 + 1; 264c72fcc34Sopenharmony_ci tmp2 = strchr(tmp3, ','); 265c72fcc34Sopenharmony_ci if (tmp2 == NULL) 266c72fcc34Sopenharmony_ci goto fail; 267c72fcc34Sopenharmony_ci 268c72fcc34Sopenharmony_ci tmp1 = tmp2 + 1; 269c72fcc34Sopenharmony_ci *tiny_device = atoi(tmp1); 270c72fcc34Sopenharmony_ci *tmp2 = '\0'; 271c72fcc34Sopenharmony_ci *tiny_card = atoi(tmp3); 272c72fcc34Sopenharmony_ci *tmp2 = ','; 273c72fcc34Sopenharmony_ci 274c72fcc34Sopenharmony_ci return 0; 275c72fcc34Sopenharmony_cifail: 276c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid tiny device: %s\n"), alsa_device); 277c72fcc34Sopenharmony_ci return -EINVAL; 278c72fcc34Sopenharmony_ci} 279c72fcc34Sopenharmony_ci 280c72fcc34Sopenharmony_ci/** 281c72fcc34Sopenharmony_ci * Play 282c72fcc34Sopenharmony_ci */ 283c72fcc34Sopenharmony_civoid *playback_tinyalsa(struct bat *bat) 284c72fcc34Sopenharmony_ci{ 285c72fcc34Sopenharmony_ci int err = 0; 286c72fcc34Sopenharmony_ci struct pcm_config config; 287c72fcc34Sopenharmony_ci struct pcm *pcm = NULL; 288c72fcc34Sopenharmony_ci void *buffer = NULL; 289c72fcc34Sopenharmony_ci int bufbytes; 290c72fcc34Sopenharmony_ci 291c72fcc34Sopenharmony_ci fprintf(bat->log, _("Entering playback thread (tinyalsa).\n")); 292c72fcc34Sopenharmony_ci 293c72fcc34Sopenharmony_ci retval_play = 0; 294c72fcc34Sopenharmony_ci 295c72fcc34Sopenharmony_ci /* init device */ 296c72fcc34Sopenharmony_ci err = get_tiny_device(bat, bat->playback.device, 297c72fcc34Sopenharmony_ci &bat->playback.card_tiny, 298c72fcc34Sopenharmony_ci &bat->playback.device_tiny); 299c72fcc34Sopenharmony_ci if (err < 0) { 300c72fcc34Sopenharmony_ci retval_play = err; 301c72fcc34Sopenharmony_ci goto exit1; 302c72fcc34Sopenharmony_ci } 303c72fcc34Sopenharmony_ci 304c72fcc34Sopenharmony_ci /* init config */ 305c72fcc34Sopenharmony_ci err = init_config(bat, &config); 306c72fcc34Sopenharmony_ci if (err < 0) { 307c72fcc34Sopenharmony_ci retval_play = err; 308c72fcc34Sopenharmony_ci goto exit1; 309c72fcc34Sopenharmony_ci } 310c72fcc34Sopenharmony_ci 311c72fcc34Sopenharmony_ci /* check param before open device */ 312c72fcc34Sopenharmony_ci err = check_playback_params(bat, &config); 313c72fcc34Sopenharmony_ci if (err < 0) { 314c72fcc34Sopenharmony_ci retval_play = err; 315c72fcc34Sopenharmony_ci goto exit1; 316c72fcc34Sopenharmony_ci } 317c72fcc34Sopenharmony_ci 318c72fcc34Sopenharmony_ci /* open device */ 319c72fcc34Sopenharmony_ci pcm = pcm_open(bat->playback.card_tiny, bat->playback.device_tiny, 320c72fcc34Sopenharmony_ci PCM_OUT, &config); 321c72fcc34Sopenharmony_ci if (!pcm || !pcm_is_ready(pcm)) { 322c72fcc34Sopenharmony_ci fprintf(bat->err, _("Unable to open PCM device %u (%s)!\n"), 323c72fcc34Sopenharmony_ci bat->playback.device_tiny, pcm_get_error(pcm)); 324c72fcc34Sopenharmony_ci retval_play = -EINVAL; 325c72fcc34Sopenharmony_ci goto exit1; 326c72fcc34Sopenharmony_ci } 327c72fcc34Sopenharmony_ci 328c72fcc34Sopenharmony_ci /* init buffer */ 329c72fcc34Sopenharmony_ci bufbytes = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); 330c72fcc34Sopenharmony_ci buffer = malloc(bufbytes); 331c72fcc34Sopenharmony_ci if (!buffer) { 332c72fcc34Sopenharmony_ci retval_play = -ENOMEM; 333c72fcc34Sopenharmony_ci goto exit2; 334c72fcc34Sopenharmony_ci } 335c72fcc34Sopenharmony_ci 336c72fcc34Sopenharmony_ci /* init playback source */ 337c72fcc34Sopenharmony_ci if (bat->playback.file == NULL) { 338c72fcc34Sopenharmony_ci fprintf(bat->log, _("Playing generated audio sine wave")); 339c72fcc34Sopenharmony_ci bat->sinus_duration == 0 ? 340c72fcc34Sopenharmony_ci fprintf(bat->log, _(" endlessly\n")) : 341c72fcc34Sopenharmony_ci fprintf(bat->log, _("\n")); 342c72fcc34Sopenharmony_ci } else { 343c72fcc34Sopenharmony_ci fprintf(bat->log, _("Playing input audio file: %s\n"), 344c72fcc34Sopenharmony_ci bat->playback.file); 345c72fcc34Sopenharmony_ci bat->fp = fopen(bat->playback.file, "rb"); 346c72fcc34Sopenharmony_ci err = -errno; 347c72fcc34Sopenharmony_ci if (bat->fp == NULL) { 348c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 349c72fcc34Sopenharmony_ci bat->playback.file, err); 350c72fcc34Sopenharmony_ci retval_play = err; 351c72fcc34Sopenharmony_ci goto exit3; 352c72fcc34Sopenharmony_ci } 353c72fcc34Sopenharmony_ci /* Skip header */ 354c72fcc34Sopenharmony_ci err = read_wav_header(bat, bat->playback.file, bat->fp, true); 355c72fcc34Sopenharmony_ci if (err != 0) { 356c72fcc34Sopenharmony_ci retval_play = err; 357c72fcc34Sopenharmony_ci goto exit4; 358c72fcc34Sopenharmony_ci } 359c72fcc34Sopenharmony_ci } 360c72fcc34Sopenharmony_ci 361c72fcc34Sopenharmony_ci if (bat->roundtriplatency) 362c72fcc34Sopenharmony_ci err = latencytest_process_output(bat, pcm, buffer, bufbytes); 363c72fcc34Sopenharmony_ci else 364c72fcc34Sopenharmony_ci err = play_sample(bat, pcm, buffer, bufbytes); 365c72fcc34Sopenharmony_ci if (err < 0) { 366c72fcc34Sopenharmony_ci retval_play = err; 367c72fcc34Sopenharmony_ci goto exit4; 368c72fcc34Sopenharmony_ci } 369c72fcc34Sopenharmony_ci 370c72fcc34Sopenharmony_ciexit4: 371c72fcc34Sopenharmony_ci if (bat->playback.file) 372c72fcc34Sopenharmony_ci fclose(bat->fp); 373c72fcc34Sopenharmony_ciexit3: 374c72fcc34Sopenharmony_ci free(buffer); 375c72fcc34Sopenharmony_ciexit2: 376c72fcc34Sopenharmony_ci pcm_close(pcm); 377c72fcc34Sopenharmony_ciexit1: 378c72fcc34Sopenharmony_ci pthread_exit(&retval_play); 379c72fcc34Sopenharmony_ci} 380c72fcc34Sopenharmony_ci 381c72fcc34Sopenharmony_ci/** 382c72fcc34Sopenharmony_ci * Capture sample 383c72fcc34Sopenharmony_ci */ 384c72fcc34Sopenharmony_cistatic int capture_sample(struct bat *bat, struct pcm *pcm, 385c72fcc34Sopenharmony_ci void *buffer, unsigned int bytes) 386c72fcc34Sopenharmony_ci{ 387c72fcc34Sopenharmony_ci int err = 0; 388c72fcc34Sopenharmony_ci FILE *fp = NULL; 389c72fcc34Sopenharmony_ci unsigned int bytes_read = 0; 390c72fcc34Sopenharmony_ci unsigned int bytes_count = bat->frames * bat->frame_size; 391c72fcc34Sopenharmony_ci 392c72fcc34Sopenharmony_ci remove(bat->capture.file); 393c72fcc34Sopenharmony_ci fp = fopen(bat->capture.file, "wb"); 394c72fcc34Sopenharmony_ci err = -errno; 395c72fcc34Sopenharmony_ci if (fp == NULL) { 396c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 397c72fcc34Sopenharmony_ci bat->capture.file, err); 398c72fcc34Sopenharmony_ci return err; 399c72fcc34Sopenharmony_ci } 400c72fcc34Sopenharmony_ci /* leave space for file header */ 401c72fcc34Sopenharmony_ci if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 402c72fcc34Sopenharmony_ci err = -errno; 403c72fcc34Sopenharmony_ci fclose(fp); 404c72fcc34Sopenharmony_ci return err; 405c72fcc34Sopenharmony_ci } 406c72fcc34Sopenharmony_ci 407c72fcc34Sopenharmony_ci while (bytes_read < bytes_count && !pcm_read(pcm, buffer, bytes)) { 408c72fcc34Sopenharmony_ci if (fwrite(buffer, 1, bytes, fp) != bytes) 409c72fcc34Sopenharmony_ci break; 410c72fcc34Sopenharmony_ci 411c72fcc34Sopenharmony_ci bytes_read += bytes; 412c72fcc34Sopenharmony_ci 413c72fcc34Sopenharmony_ci bat->periods_played++; 414c72fcc34Sopenharmony_ci 415c72fcc34Sopenharmony_ci if (bat->period_is_limited 416c72fcc34Sopenharmony_ci && bat->periods_played >= bat->periods_total) 417c72fcc34Sopenharmony_ci break; 418c72fcc34Sopenharmony_ci } 419c72fcc34Sopenharmony_ci 420c72fcc34Sopenharmony_ci err = update_wav_header(bat, fp, bytes_read); 421c72fcc34Sopenharmony_ci 422c72fcc34Sopenharmony_ci fclose(fp); 423c72fcc34Sopenharmony_ci return err; 424c72fcc34Sopenharmony_ci} 425c72fcc34Sopenharmony_ci 426c72fcc34Sopenharmony_ci/** 427c72fcc34Sopenharmony_ci * Process input data for latency test 428c72fcc34Sopenharmony_ci */ 429c72fcc34Sopenharmony_cistatic int latencytest_process_input(struct bat *bat, struct pcm *pcm, 430c72fcc34Sopenharmony_ci void *buffer, unsigned int bytes) 431c72fcc34Sopenharmony_ci{ 432c72fcc34Sopenharmony_ci int err = 0; 433c72fcc34Sopenharmony_ci FILE *fp = NULL; 434c72fcc34Sopenharmony_ci unsigned int bytes_read = 0; 435c72fcc34Sopenharmony_ci unsigned int bytes_count = bat->frames * bat->frame_size; 436c72fcc34Sopenharmony_ci 437c72fcc34Sopenharmony_ci remove(bat->capture.file); 438c72fcc34Sopenharmony_ci fp = fopen(bat->capture.file, "wb"); 439c72fcc34Sopenharmony_ci err = -errno; 440c72fcc34Sopenharmony_ci if (fp == NULL) { 441c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 442c72fcc34Sopenharmony_ci bat->capture.file, err); 443c72fcc34Sopenharmony_ci return err; 444c72fcc34Sopenharmony_ci } 445c72fcc34Sopenharmony_ci /* leave space for file header */ 446c72fcc34Sopenharmony_ci if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 447c72fcc34Sopenharmony_ci err = -errno; 448c72fcc34Sopenharmony_ci fclose(fp); 449c72fcc34Sopenharmony_ci return err; 450c72fcc34Sopenharmony_ci } 451c72fcc34Sopenharmony_ci 452c72fcc34Sopenharmony_ci bat->latency.is_capturing = true; 453c72fcc34Sopenharmony_ci 454c72fcc34Sopenharmony_ci while (bytes_read < bytes_count && !pcm_read(pcm, buffer, bytes)) { 455c72fcc34Sopenharmony_ci if (fwrite(buffer, 1, bytes, fp) != bytes) 456c72fcc34Sopenharmony_ci break; 457c72fcc34Sopenharmony_ci 458c72fcc34Sopenharmony_ci err = handleinput(bat, buffer, bytes / bat->frame_size); 459c72fcc34Sopenharmony_ci if (err != 0) 460c72fcc34Sopenharmony_ci break; 461c72fcc34Sopenharmony_ci 462c72fcc34Sopenharmony_ci if (bat->latency.is_playing == false) 463c72fcc34Sopenharmony_ci break; 464c72fcc34Sopenharmony_ci 465c72fcc34Sopenharmony_ci bytes_read += bytes; 466c72fcc34Sopenharmony_ci } 467c72fcc34Sopenharmony_ci 468c72fcc34Sopenharmony_ci bat->latency.is_capturing = false; 469c72fcc34Sopenharmony_ci 470c72fcc34Sopenharmony_ci err = update_wav_header(bat, fp, bytes_read); 471c72fcc34Sopenharmony_ci 472c72fcc34Sopenharmony_ci fclose(fp); 473c72fcc34Sopenharmony_ci return err; 474c72fcc34Sopenharmony_ci} 475c72fcc34Sopenharmony_ci 476c72fcc34Sopenharmony_ci/** 477c72fcc34Sopenharmony_ci * Record 478c72fcc34Sopenharmony_ci */ 479c72fcc34Sopenharmony_civoid *record_tinyalsa(struct bat *bat) 480c72fcc34Sopenharmony_ci{ 481c72fcc34Sopenharmony_ci int err = 0; 482c72fcc34Sopenharmony_ci struct pcm_config config; 483c72fcc34Sopenharmony_ci struct pcm *pcm; 484c72fcc34Sopenharmony_ci void *buffer; 485c72fcc34Sopenharmony_ci unsigned int bufbytes; 486c72fcc34Sopenharmony_ci 487c72fcc34Sopenharmony_ci pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 488c72fcc34Sopenharmony_ci 489c72fcc34Sopenharmony_ci fprintf(bat->log, _("Entering capture thread (tinyalsa).\n")); 490c72fcc34Sopenharmony_ci 491c72fcc34Sopenharmony_ci retval_record = 0; 492c72fcc34Sopenharmony_ci 493c72fcc34Sopenharmony_ci /* init device */ 494c72fcc34Sopenharmony_ci err = get_tiny_device(bat, bat->capture.device, 495c72fcc34Sopenharmony_ci &bat->capture.card_tiny, 496c72fcc34Sopenharmony_ci &bat->capture.device_tiny); 497c72fcc34Sopenharmony_ci if (err < 0) { 498c72fcc34Sopenharmony_ci retval_record = err; 499c72fcc34Sopenharmony_ci goto exit1; 500c72fcc34Sopenharmony_ci } 501c72fcc34Sopenharmony_ci 502c72fcc34Sopenharmony_ci /* init config */ 503c72fcc34Sopenharmony_ci err = init_config(bat, &config); 504c72fcc34Sopenharmony_ci if (err < 0) { 505c72fcc34Sopenharmony_ci retval_record = err; 506c72fcc34Sopenharmony_ci goto exit1; 507c72fcc34Sopenharmony_ci } 508c72fcc34Sopenharmony_ci 509c72fcc34Sopenharmony_ci /* open device */ 510c72fcc34Sopenharmony_ci pcm = pcm_open(bat->capture.card_tiny, bat->capture.device_tiny, 511c72fcc34Sopenharmony_ci PCM_IN, &config); 512c72fcc34Sopenharmony_ci if (!pcm || !pcm_is_ready(pcm)) { 513c72fcc34Sopenharmony_ci fprintf(bat->err, _("Unable to open PCM device (%s)!\n"), 514c72fcc34Sopenharmony_ci pcm_get_error(pcm)); 515c72fcc34Sopenharmony_ci retval_record = -EINVAL; 516c72fcc34Sopenharmony_ci goto exit1; 517c72fcc34Sopenharmony_ci } 518c72fcc34Sopenharmony_ci 519c72fcc34Sopenharmony_ci /* init buffer */ 520c72fcc34Sopenharmony_ci bufbytes = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); 521c72fcc34Sopenharmony_ci buffer = malloc(bufbytes); 522c72fcc34Sopenharmony_ci if (!buffer) { 523c72fcc34Sopenharmony_ci retval_record = -ENOMEM; 524c72fcc34Sopenharmony_ci goto exit2; 525c72fcc34Sopenharmony_ci } 526c72fcc34Sopenharmony_ci 527c72fcc34Sopenharmony_ci pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 528c72fcc34Sopenharmony_ci pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 529c72fcc34Sopenharmony_ci pthread_cleanup_push(close_handle, pcm); 530c72fcc34Sopenharmony_ci pthread_cleanup_push(free, buffer); 531c72fcc34Sopenharmony_ci 532c72fcc34Sopenharmony_ci fprintf(bat->log, _("Recording ...\n")); 533c72fcc34Sopenharmony_ci if (bat->roundtriplatency) 534c72fcc34Sopenharmony_ci err = latencytest_process_input(bat, pcm, buffer, bufbytes); 535c72fcc34Sopenharmony_ci else 536c72fcc34Sopenharmony_ci err = capture_sample(bat, pcm, buffer, bufbytes); 537c72fcc34Sopenharmony_ci if (err != 0) { 538c72fcc34Sopenharmony_ci retval_record = err; 539c72fcc34Sopenharmony_ci goto exit3; 540c72fcc34Sopenharmony_ci } 541c72fcc34Sopenharmony_ci 542c72fcc34Sopenharmony_ci /* Normally we will never reach this part of code (unless error in 543c72fcc34Sopenharmony_ci * previous call) (before exit3) as this thread will be cancelled 544c72fcc34Sopenharmony_ci * by end of play thread. Except in single line mode. */ 545c72fcc34Sopenharmony_ci pthread_cleanup_pop(0); 546c72fcc34Sopenharmony_ci pthread_cleanup_pop(0); 547c72fcc34Sopenharmony_ci pthread_exit(&retval_record); 548c72fcc34Sopenharmony_ci 549c72fcc34Sopenharmony_ciexit3: 550c72fcc34Sopenharmony_ci free(buffer); 551c72fcc34Sopenharmony_ciexit2: 552c72fcc34Sopenharmony_ci pcm_close(pcm); 553c72fcc34Sopenharmony_ciexit1: 554c72fcc34Sopenharmony_ci pthread_exit(&retval_record); 555c72fcc34Sopenharmony_ci} 556