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 <stdint.h> 22c72fcc34Sopenharmony_ci#include <pthread.h> 23c72fcc34Sopenharmony_ci#include <errno.h> 24c72fcc34Sopenharmony_ci 25c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h> 26c72fcc34Sopenharmony_ci 27c72fcc34Sopenharmony_ci#include "gettext.h" 28c72fcc34Sopenharmony_ci 29c72fcc34Sopenharmony_ci#include "common.h" 30c72fcc34Sopenharmony_ci#include "alsa.h" 31c72fcc34Sopenharmony_ci#include "latencytest.h" 32c72fcc34Sopenharmony_ci#include "os_compat.h" 33c72fcc34Sopenharmony_ci 34c72fcc34Sopenharmony_cistruct pcm_container { 35c72fcc34Sopenharmony_ci snd_pcm_t *handle; 36c72fcc34Sopenharmony_ci snd_pcm_uframes_t period_size; 37c72fcc34Sopenharmony_ci snd_pcm_uframes_t buffer_size; 38c72fcc34Sopenharmony_ci snd_pcm_format_t format; 39c72fcc34Sopenharmony_ci unsigned short channels; 40c72fcc34Sopenharmony_ci size_t period_bytes; 41c72fcc34Sopenharmony_ci size_t sample_bits; 42c72fcc34Sopenharmony_ci size_t frame_bits; 43c72fcc34Sopenharmony_ci char *buffer; 44c72fcc34Sopenharmony_ci}; 45c72fcc34Sopenharmony_ci 46c72fcc34Sopenharmony_cistruct format_map_table { 47c72fcc34Sopenharmony_ci enum _bat_pcm_format format_bat; 48c72fcc34Sopenharmony_ci snd_pcm_format_t format_alsa; 49c72fcc34Sopenharmony_ci}; 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_cistatic struct format_map_table map_tables[] = { 52c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN }, 53c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_U8, SND_PCM_FORMAT_U8 }, 54c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_LE }, 55c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3LE }, 56c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_LE }, 57c72fcc34Sopenharmony_ci { BAT_PCM_FORMAT_MAX, 0 }, 58c72fcc34Sopenharmony_ci}; 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_cistatic int format_convert(struct bat *bat, snd_pcm_format_t *fmt) 61c72fcc34Sopenharmony_ci{ 62c72fcc34Sopenharmony_ci struct format_map_table *t = map_tables; 63c72fcc34Sopenharmony_ci 64c72fcc34Sopenharmony_ci for (; t->format_bat != BAT_PCM_FORMAT_MAX; t++) { 65c72fcc34Sopenharmony_ci if (t->format_bat == bat->format) { 66c72fcc34Sopenharmony_ci *fmt = t->format_alsa; 67c72fcc34Sopenharmony_ci return 0; 68c72fcc34Sopenharmony_ci } 69c72fcc34Sopenharmony_ci } 70c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid format!\n")); 71c72fcc34Sopenharmony_ci return -EINVAL; 72c72fcc34Sopenharmony_ci} 73c72fcc34Sopenharmony_ci 74c72fcc34Sopenharmony_cistatic int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm) 75c72fcc34Sopenharmony_ci{ 76c72fcc34Sopenharmony_ci snd_pcm_hw_params_t *params; 77c72fcc34Sopenharmony_ci snd_pcm_format_t format; 78c72fcc34Sopenharmony_ci unsigned int buffer_time = 0; 79c72fcc34Sopenharmony_ci unsigned int period_time = 0; 80c72fcc34Sopenharmony_ci snd_pcm_uframes_t buffer_size = 0; 81c72fcc34Sopenharmony_ci snd_pcm_uframes_t period_size = 0; 82c72fcc34Sopenharmony_ci unsigned int rate; 83c72fcc34Sopenharmony_ci int err; 84c72fcc34Sopenharmony_ci const char *device_name = snd_pcm_name(sndpcm->handle); 85c72fcc34Sopenharmony_ci 86c72fcc34Sopenharmony_ci /* Convert common format to ALSA format */ 87c72fcc34Sopenharmony_ci err = format_convert(bat, &format); 88c72fcc34Sopenharmony_ci if (err != 0) 89c72fcc34Sopenharmony_ci return err; 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_ci /* Allocate a hardware parameters object. */ 92c72fcc34Sopenharmony_ci snd_pcm_hw_params_alloca(¶ms); 93c72fcc34Sopenharmony_ci 94c72fcc34Sopenharmony_ci /* Fill it in with default values. */ 95c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_any(sndpcm->handle, params); 96c72fcc34Sopenharmony_ci if (err < 0) { 97c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 98c72fcc34Sopenharmony_ci fprintf(bat->err, _("default params: %s: %s(%d)\n"), 99c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 100c72fcc34Sopenharmony_ci return err; 101c72fcc34Sopenharmony_ci } 102c72fcc34Sopenharmony_ci 103c72fcc34Sopenharmony_ci /* Set access mode */ 104c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_access(sndpcm->handle, params, 105c72fcc34Sopenharmony_ci SND_PCM_ACCESS_RW_INTERLEAVED); 106c72fcc34Sopenharmony_ci if (err < 0) { 107c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 108c72fcc34Sopenharmony_ci fprintf(bat->err, _("access type: %s: %s(%d)\n"), 109c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 110c72fcc34Sopenharmony_ci return err; 111c72fcc34Sopenharmony_ci } 112c72fcc34Sopenharmony_ci 113c72fcc34Sopenharmony_ci /* Set format */ 114c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_format(sndpcm->handle, params, format); 115c72fcc34Sopenharmony_ci if (err < 0) { 116c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 117c72fcc34Sopenharmony_ci fprintf(bat->err, _("PCM format: %d %s: %s(%d)\n"), format, 118c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 119c72fcc34Sopenharmony_ci return err; 120c72fcc34Sopenharmony_ci } 121c72fcc34Sopenharmony_ci 122c72fcc34Sopenharmony_ci /* Set channels */ 123c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_channels(sndpcm->handle, 124c72fcc34Sopenharmony_ci params, bat->channels); 125c72fcc34Sopenharmony_ci if (err < 0) { 126c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 127c72fcc34Sopenharmony_ci fprintf(bat->err, _("channel number: %d %s: %s(%d)\n"), 128c72fcc34Sopenharmony_ci bat->channels, 129c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 130c72fcc34Sopenharmony_ci return err; 131c72fcc34Sopenharmony_ci } 132c72fcc34Sopenharmony_ci 133c72fcc34Sopenharmony_ci /* Set sampling rate */ 134c72fcc34Sopenharmony_ci rate = bat->rate; 135c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_rate_near(sndpcm->handle, 136c72fcc34Sopenharmony_ci params, &bat->rate, 137c72fcc34Sopenharmony_ci 0); 138c72fcc34Sopenharmony_ci if (err < 0) { 139c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 140c72fcc34Sopenharmony_ci fprintf(bat->err, _("sample rate: %d %s: %s(%d)\n"), 141c72fcc34Sopenharmony_ci bat->rate, 142c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 143c72fcc34Sopenharmony_ci return err; 144c72fcc34Sopenharmony_ci } 145c72fcc34Sopenharmony_ci if ((float) rate * (1 + RATE_RANGE) < bat->rate 146c72fcc34Sopenharmony_ci || (float) rate * (1 - RATE_RANGE) > bat->rate) { 147c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid parameters: sample rate: ")); 148c72fcc34Sopenharmony_ci fprintf(bat->err, _("requested %dHz, got %dHz\n"), 149c72fcc34Sopenharmony_ci rate, bat->rate); 150c72fcc34Sopenharmony_ci return -EINVAL; 151c72fcc34Sopenharmony_ci } 152c72fcc34Sopenharmony_ci 153c72fcc34Sopenharmony_ci if (bat->buffer_size > 0 && bat->period_size == 0) 154c72fcc34Sopenharmony_ci bat->period_size = bat->buffer_size / DIV_BUFFERSIZE; 155c72fcc34Sopenharmony_ci 156c72fcc34Sopenharmony_ci if (bat->roundtriplatency && bat->buffer_size == 0) { 157c72fcc34Sopenharmony_ci /* Set to minimum buffer size and period size 158c72fcc34Sopenharmony_ci for latency test */ 159c72fcc34Sopenharmony_ci if (snd_pcm_hw_params_get_buffer_size_min(params, 160c72fcc34Sopenharmony_ci &buffer_size) < 0) { 161c72fcc34Sopenharmony_ci fprintf(bat->err, 162c72fcc34Sopenharmony_ci _("Get parameter from device error: ")); 163c72fcc34Sopenharmony_ci fprintf(bat->err, _("buffer size min: %d %s: %s(%d)\n"), 164c72fcc34Sopenharmony_ci (int) buffer_size, 165c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 166c72fcc34Sopenharmony_ci return -EINVAL; 167c72fcc34Sopenharmony_ci } 168c72fcc34Sopenharmony_ci 169c72fcc34Sopenharmony_ci if (snd_pcm_hw_params_get_period_size_min(params, 170c72fcc34Sopenharmony_ci &period_size, 0) < 0) { 171c72fcc34Sopenharmony_ci fprintf(bat->err, 172c72fcc34Sopenharmony_ci _("Get parameter from device error: ")); 173c72fcc34Sopenharmony_ci fprintf(bat->err, _("period size min: %d %s: %s(%d)\n"), 174c72fcc34Sopenharmony_ci (int) period_size, 175c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 176c72fcc34Sopenharmony_ci return -EINVAL; 177c72fcc34Sopenharmony_ci } 178c72fcc34Sopenharmony_ci bat->buffer_size = (int) buffer_size; 179c72fcc34Sopenharmony_ci bat->period_size = (int) period_size; 180c72fcc34Sopenharmony_ci } 181c72fcc34Sopenharmony_ci 182c72fcc34Sopenharmony_ci if (bat->buffer_size > 0) { 183c72fcc34Sopenharmony_ci buffer_size = bat->buffer_size; 184c72fcc34Sopenharmony_ci period_size = bat->period_size; 185c72fcc34Sopenharmony_ci 186c72fcc34Sopenharmony_ci fprintf(bat->log, _("Set period size: %d buffer size: %d\n"), 187c72fcc34Sopenharmony_ci (int) period_size, (int) buffer_size); 188c72fcc34Sopenharmony_ci 189c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_buffer_size_near(sndpcm->handle, 190c72fcc34Sopenharmony_ci params, &buffer_size); 191c72fcc34Sopenharmony_ci if (err < 0) { 192c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 193c72fcc34Sopenharmony_ci fprintf(bat->err, _("buffer size: %d %s: %s(%d)\n"), 194c72fcc34Sopenharmony_ci (int) buffer_size, 195c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 196c72fcc34Sopenharmony_ci return err; 197c72fcc34Sopenharmony_ci } 198c72fcc34Sopenharmony_ci 199c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_period_size_near(sndpcm->handle, 200c72fcc34Sopenharmony_ci params, &period_size, 0); 201c72fcc34Sopenharmony_ci if (err < 0) { 202c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 203c72fcc34Sopenharmony_ci fprintf(bat->err, _("period size: %d %s: %s(%d)\n"), 204c72fcc34Sopenharmony_ci (int) period_size, 205c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 206c72fcc34Sopenharmony_ci return err; 207c72fcc34Sopenharmony_ci } 208c72fcc34Sopenharmony_ci } else { 209c72fcc34Sopenharmony_ci if (snd_pcm_hw_params_get_buffer_time_max(params, 210c72fcc34Sopenharmony_ci &buffer_time, 0) < 0) { 211c72fcc34Sopenharmony_ci fprintf(bat->err, 212c72fcc34Sopenharmony_ci _("Get parameter from device error: ")); 213c72fcc34Sopenharmony_ci fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), 214c72fcc34Sopenharmony_ci buffer_time, 215c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 216c72fcc34Sopenharmony_ci return -EINVAL; 217c72fcc34Sopenharmony_ci } 218c72fcc34Sopenharmony_ci 219c72fcc34Sopenharmony_ci if (buffer_time > MAX_BUFFERTIME) 220c72fcc34Sopenharmony_ci buffer_time = MAX_BUFFERTIME; 221c72fcc34Sopenharmony_ci 222c72fcc34Sopenharmony_ci period_time = buffer_time / DIV_BUFFERTIME; 223c72fcc34Sopenharmony_ci 224c72fcc34Sopenharmony_ci /* Set buffer time and period time */ 225c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, 226c72fcc34Sopenharmony_ci params, &buffer_time, 0); 227c72fcc34Sopenharmony_ci if (err < 0) { 228c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 229c72fcc34Sopenharmony_ci fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), 230c72fcc34Sopenharmony_ci buffer_time, 231c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 232c72fcc34Sopenharmony_ci return err; 233c72fcc34Sopenharmony_ci } 234c72fcc34Sopenharmony_ci 235c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, 236c72fcc34Sopenharmony_ci params, &period_time, 0); 237c72fcc34Sopenharmony_ci if (err < 0) { 238c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 239c72fcc34Sopenharmony_ci fprintf(bat->err, _("period time: %d %s: %s(%d)\n"), 240c72fcc34Sopenharmony_ci period_time, 241c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 242c72fcc34Sopenharmony_ci return err; 243c72fcc34Sopenharmony_ci } 244c72fcc34Sopenharmony_ci } 245c72fcc34Sopenharmony_ci 246c72fcc34Sopenharmony_ci /* Write the parameters to the driver */ 247c72fcc34Sopenharmony_ci if (snd_pcm_hw_params(sndpcm->handle, params) < 0) { 248c72fcc34Sopenharmony_ci fprintf(bat->err, _("Set parameter to device error: ")); 249c72fcc34Sopenharmony_ci fprintf(bat->err, _("hw params: %s: %s(%d)\n"), 250c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 251c72fcc34Sopenharmony_ci return -EINVAL; 252c72fcc34Sopenharmony_ci } 253c72fcc34Sopenharmony_ci 254c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_period_size(params, 255c72fcc34Sopenharmony_ci &sndpcm->period_size, 0); 256c72fcc34Sopenharmony_ci if (err < 0) { 257c72fcc34Sopenharmony_ci fprintf(bat->err, _("Get parameter from device error: ")); 258c72fcc34Sopenharmony_ci fprintf(bat->err, _("period size: %zd %s: %s(%d)\n"), 259c72fcc34Sopenharmony_ci sndpcm->period_size, 260c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 261c72fcc34Sopenharmony_ci return err; 262c72fcc34Sopenharmony_ci } 263c72fcc34Sopenharmony_ci 264c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size); 265c72fcc34Sopenharmony_ci if (err < 0) { 266c72fcc34Sopenharmony_ci fprintf(bat->err, _("Get parameter from device error: ")); 267c72fcc34Sopenharmony_ci fprintf(bat->err, _("buffer size: %zd %s: %s(%d)\n"), 268c72fcc34Sopenharmony_ci sndpcm->buffer_size, 269c72fcc34Sopenharmony_ci device_name, snd_strerror(err), err); 270c72fcc34Sopenharmony_ci return err; 271c72fcc34Sopenharmony_ci } 272c72fcc34Sopenharmony_ci 273c72fcc34Sopenharmony_ci if (sndpcm->period_size == sndpcm->buffer_size) { 274c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid parameters: can't use period ")); 275c72fcc34Sopenharmony_ci fprintf(bat->err, _("equal to buffer size (%zd)\n"), 276c72fcc34Sopenharmony_ci sndpcm->period_size); 277c72fcc34Sopenharmony_ci return -EINVAL; 278c72fcc34Sopenharmony_ci } 279c72fcc34Sopenharmony_ci 280c72fcc34Sopenharmony_ci fprintf(bat->log, _("Get period size: %d buffer size: %d\n"), 281c72fcc34Sopenharmony_ci (int) sndpcm->period_size, (int) sndpcm->buffer_size); 282c72fcc34Sopenharmony_ci 283c72fcc34Sopenharmony_ci err = snd_pcm_format_physical_width(format); 284c72fcc34Sopenharmony_ci if (err < 0) { 285c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid parameters: ")); 286c72fcc34Sopenharmony_ci fprintf(bat->err, _("snd_pcm_format_physical_width: %d\n"), 287c72fcc34Sopenharmony_ci err); 288c72fcc34Sopenharmony_ci return err; 289c72fcc34Sopenharmony_ci } 290c72fcc34Sopenharmony_ci sndpcm->sample_bits = err; 291c72fcc34Sopenharmony_ci 292c72fcc34Sopenharmony_ci sndpcm->frame_bits = sndpcm->sample_bits * bat->channels; 293c72fcc34Sopenharmony_ci 294c72fcc34Sopenharmony_ci /* Calculate the period bytes */ 295c72fcc34Sopenharmony_ci sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8; 296c72fcc34Sopenharmony_ci sndpcm->buffer = (char *) malloc(sndpcm->period_bytes); 297c72fcc34Sopenharmony_ci if (sndpcm->buffer == NULL) { 298c72fcc34Sopenharmony_ci fprintf(bat->err, _("Not enough memory: size=%zd\n"), 299c72fcc34Sopenharmony_ci sndpcm->period_bytes); 300c72fcc34Sopenharmony_ci return -ENOMEM; 301c72fcc34Sopenharmony_ci } 302c72fcc34Sopenharmony_ci 303c72fcc34Sopenharmony_ci return 0; 304c72fcc34Sopenharmony_ci} 305c72fcc34Sopenharmony_ci 306c72fcc34Sopenharmony_cistatic int write_to_pcm(const struct pcm_container *sndpcm, 307c72fcc34Sopenharmony_ci int frames, struct bat *bat) 308c72fcc34Sopenharmony_ci{ 309c72fcc34Sopenharmony_ci int err; 310c72fcc34Sopenharmony_ci int offset = 0; 311c72fcc34Sopenharmony_ci int remain = frames; 312c72fcc34Sopenharmony_ci 313c72fcc34Sopenharmony_ci while (remain > 0) { 314c72fcc34Sopenharmony_ci err = snd_pcm_writei(sndpcm->handle, sndpcm->buffer + offset, 315c72fcc34Sopenharmony_ci remain); 316c72fcc34Sopenharmony_ci if (err == -EAGAIN || (err >= 0 && err < frames)) { 317c72fcc34Sopenharmony_ci snd_pcm_wait(sndpcm->handle, 500); 318c72fcc34Sopenharmony_ci } else if (err == -EPIPE) { 319c72fcc34Sopenharmony_ci fprintf(bat->err, _("Underrun: %s(%d)\n"), 320c72fcc34Sopenharmony_ci snd_strerror(err), err); 321c72fcc34Sopenharmony_ci if (bat->roundtriplatency) 322c72fcc34Sopenharmony_ci bat->latency.xrun_error = true; 323c72fcc34Sopenharmony_ci snd_pcm_prepare(sndpcm->handle); 324c72fcc34Sopenharmony_ci } else if (err == -ESTRPIPE) { 325c72fcc34Sopenharmony_ci while ((err = snd_pcm_resume(sndpcm->handle)) == -EAGAIN) 326c72fcc34Sopenharmony_ci sleep(1); /* wait until resume flag is released */ 327c72fcc34Sopenharmony_ci if (err < 0) 328c72fcc34Sopenharmony_ci snd_pcm_prepare(sndpcm->handle); 329c72fcc34Sopenharmony_ci } else if (err < 0) { 330c72fcc34Sopenharmony_ci fprintf(bat->err, _("Write PCM device error: %s(%d)\n"), 331c72fcc34Sopenharmony_ci snd_strerror(err), err); 332c72fcc34Sopenharmony_ci return err; 333c72fcc34Sopenharmony_ci } 334c72fcc34Sopenharmony_ci 335c72fcc34Sopenharmony_ci if (err > 0) { 336c72fcc34Sopenharmony_ci remain -= err; 337c72fcc34Sopenharmony_ci offset += err * sndpcm->frame_bits / 8; 338c72fcc34Sopenharmony_ci } 339c72fcc34Sopenharmony_ci } 340c72fcc34Sopenharmony_ci 341c72fcc34Sopenharmony_ci return 0; 342c72fcc34Sopenharmony_ci} 343c72fcc34Sopenharmony_ci 344c72fcc34Sopenharmony_ci/** 345c72fcc34Sopenharmony_ci * Process output data for latency test 346c72fcc34Sopenharmony_ci */ 347c72fcc34Sopenharmony_cistatic int latencytest_process_output(struct pcm_container *sndpcm, 348c72fcc34Sopenharmony_ci struct bat *bat) 349c72fcc34Sopenharmony_ci{ 350c72fcc34Sopenharmony_ci int err = 0; 351c72fcc34Sopenharmony_ci int bytes = sndpcm->period_bytes; /* playback buffer size */ 352c72fcc34Sopenharmony_ci int frames = sndpcm->period_size; /* frame count */ 353c72fcc34Sopenharmony_ci 354c72fcc34Sopenharmony_ci bat->latency.is_playing = true; 355c72fcc34Sopenharmony_ci 356c72fcc34Sopenharmony_ci while (1) { 357c72fcc34Sopenharmony_ci /* generate output data */ 358c72fcc34Sopenharmony_ci err = handleoutput(bat, sndpcm->buffer, bytes, frames); 359c72fcc34Sopenharmony_ci if (err != 0) 360c72fcc34Sopenharmony_ci break; 361c72fcc34Sopenharmony_ci 362c72fcc34Sopenharmony_ci err = write_to_pcm(sndpcm, frames, bat); 363c72fcc34Sopenharmony_ci if (err != 0) 364c72fcc34Sopenharmony_ci break; 365c72fcc34Sopenharmony_ci 366c72fcc34Sopenharmony_ci /* Xrun error, terminate the playback thread*/ 367c72fcc34Sopenharmony_ci if (bat->latency.xrun_error == true) 368c72fcc34Sopenharmony_ci break; 369c72fcc34Sopenharmony_ci 370c72fcc34Sopenharmony_ci if (bat->latency.state == LATENCY_STATE_COMPLETE_SUCCESS) 371c72fcc34Sopenharmony_ci break; 372c72fcc34Sopenharmony_ci 373c72fcc34Sopenharmony_ci bat->periods_played++; 374c72fcc34Sopenharmony_ci } 375c72fcc34Sopenharmony_ci 376c72fcc34Sopenharmony_ci bat->latency.is_playing = false; 377c72fcc34Sopenharmony_ci 378c72fcc34Sopenharmony_ci return err; 379c72fcc34Sopenharmony_ci} 380c72fcc34Sopenharmony_ci 381c72fcc34Sopenharmony_cistatic int write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat) 382c72fcc34Sopenharmony_ci{ 383c72fcc34Sopenharmony_ci int err = 0; 384c72fcc34Sopenharmony_ci int bytes = sndpcm->period_bytes; /* playback buffer size */ 385c72fcc34Sopenharmony_ci int frames = bytes * 8 / sndpcm->frame_bits; /* frame count */ 386c72fcc34Sopenharmony_ci FILE *fp = NULL; 387c72fcc34Sopenharmony_ci int bytes_total = 0; 388c72fcc34Sopenharmony_ci 389c72fcc34Sopenharmony_ci if (bat->debugplay) { 390c72fcc34Sopenharmony_ci fp = fopen(bat->debugplay, "wb"); 391c72fcc34Sopenharmony_ci err = -errno; 392c72fcc34Sopenharmony_ci if (fp == NULL) { 393c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 394c72fcc34Sopenharmony_ci bat->debugplay, err); 395c72fcc34Sopenharmony_ci return err; 396c72fcc34Sopenharmony_ci } 397c72fcc34Sopenharmony_ci /* leave space for wav header */ 398c72fcc34Sopenharmony_ci if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 399c72fcc34Sopenharmony_ci err = -errno; 400c72fcc34Sopenharmony_ci fclose(fp); 401c72fcc34Sopenharmony_ci return err; 402c72fcc34Sopenharmony_ci } 403c72fcc34Sopenharmony_ci } 404c72fcc34Sopenharmony_ci 405c72fcc34Sopenharmony_ci while (1) { 406c72fcc34Sopenharmony_ci err = generate_input_data(bat, sndpcm->buffer, bytes, frames); 407c72fcc34Sopenharmony_ci if (err != 0) 408c72fcc34Sopenharmony_ci break; 409c72fcc34Sopenharmony_ci 410c72fcc34Sopenharmony_ci if (bat->debugplay) { 411c72fcc34Sopenharmony_ci if (fwrite(sndpcm->buffer, 1, bytes, fp) != (size_t)bytes) { 412c72fcc34Sopenharmony_ci err = -EIO; 413c72fcc34Sopenharmony_ci break; 414c72fcc34Sopenharmony_ci } 415c72fcc34Sopenharmony_ci bytes_total += bytes; 416c72fcc34Sopenharmony_ci } 417c72fcc34Sopenharmony_ci 418c72fcc34Sopenharmony_ci bat->periods_played++; 419c72fcc34Sopenharmony_ci if (bat->period_is_limited 420c72fcc34Sopenharmony_ci && bat->periods_played >= bat->periods_total) 421c72fcc34Sopenharmony_ci break; 422c72fcc34Sopenharmony_ci 423c72fcc34Sopenharmony_ci err = write_to_pcm(sndpcm, frames, bat); 424c72fcc34Sopenharmony_ci if (err != 0) 425c72fcc34Sopenharmony_ci break; 426c72fcc34Sopenharmony_ci } 427c72fcc34Sopenharmony_ci 428c72fcc34Sopenharmony_ci if (bat->debugplay) { 429c72fcc34Sopenharmony_ci update_wav_header(bat, fp, bytes_total); 430c72fcc34Sopenharmony_ci fclose(fp); 431c72fcc34Sopenharmony_ci } 432c72fcc34Sopenharmony_ci 433c72fcc34Sopenharmony_ci snd_pcm_drain(sndpcm->handle); 434c72fcc34Sopenharmony_ci 435c72fcc34Sopenharmony_ci return err; 436c72fcc34Sopenharmony_ci} 437c72fcc34Sopenharmony_ci 438c72fcc34Sopenharmony_ci/** 439c72fcc34Sopenharmony_ci * Play 440c72fcc34Sopenharmony_ci */ 441c72fcc34Sopenharmony_civoid *playback_alsa(struct bat *bat) 442c72fcc34Sopenharmony_ci{ 443c72fcc34Sopenharmony_ci int err = 0; 444c72fcc34Sopenharmony_ci struct pcm_container sndpcm; 445c72fcc34Sopenharmony_ci 446c72fcc34Sopenharmony_ci fprintf(bat->log, _("Entering playback thread (ALSA).\n")); 447c72fcc34Sopenharmony_ci 448c72fcc34Sopenharmony_ci retval_play = 0; 449c72fcc34Sopenharmony_ci memset(&sndpcm, 0, sizeof(sndpcm)); 450c72fcc34Sopenharmony_ci 451c72fcc34Sopenharmony_ci err = snd_pcm_open(&sndpcm.handle, bat->playback.device, 452c72fcc34Sopenharmony_ci SND_PCM_STREAM_PLAYBACK, 0); 453c72fcc34Sopenharmony_ci if (err != 0) { 454c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open PCM playback device: ")); 455c72fcc34Sopenharmony_ci fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err); 456c72fcc34Sopenharmony_ci retval_play = err; 457c72fcc34Sopenharmony_ci goto exit1; 458c72fcc34Sopenharmony_ci } 459c72fcc34Sopenharmony_ci 460c72fcc34Sopenharmony_ci err = set_snd_pcm_params(bat, &sndpcm); 461c72fcc34Sopenharmony_ci if (err != 0) { 462c72fcc34Sopenharmony_ci retval_play = err; 463c72fcc34Sopenharmony_ci goto exit2; 464c72fcc34Sopenharmony_ci } 465c72fcc34Sopenharmony_ci 466c72fcc34Sopenharmony_ci if (bat->playback.file == NULL) { 467c72fcc34Sopenharmony_ci fprintf(bat->log, _("Playing generated audio sine wave")); 468c72fcc34Sopenharmony_ci bat->sinus_duration == 0 ? 469c72fcc34Sopenharmony_ci fprintf(bat->log, _(" endlessly\n")) : 470c72fcc34Sopenharmony_ci fprintf(bat->log, _("\n")); 471c72fcc34Sopenharmony_ci } else { 472c72fcc34Sopenharmony_ci fprintf(bat->log, _("Playing input audio file: %s\n"), 473c72fcc34Sopenharmony_ci bat->playback.file); 474c72fcc34Sopenharmony_ci bat->fp = fopen(bat->playback.file, "rb"); 475c72fcc34Sopenharmony_ci err = -errno; 476c72fcc34Sopenharmony_ci if (bat->fp == NULL) { 477c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 478c72fcc34Sopenharmony_ci bat->playback.file, err); 479c72fcc34Sopenharmony_ci retval_play = err; 480c72fcc34Sopenharmony_ci goto exit3; 481c72fcc34Sopenharmony_ci } 482c72fcc34Sopenharmony_ci /* Skip header */ 483c72fcc34Sopenharmony_ci err = read_wav_header(bat, bat->playback.file, bat->fp, true); 484c72fcc34Sopenharmony_ci if (err != 0) { 485c72fcc34Sopenharmony_ci retval_play = err; 486c72fcc34Sopenharmony_ci goto exit4; 487c72fcc34Sopenharmony_ci } 488c72fcc34Sopenharmony_ci } 489c72fcc34Sopenharmony_ci 490c72fcc34Sopenharmony_ci if (bat->roundtriplatency) 491c72fcc34Sopenharmony_ci err = latencytest_process_output(&sndpcm, bat); 492c72fcc34Sopenharmony_ci else 493c72fcc34Sopenharmony_ci err = write_to_pcm_loop(&sndpcm, bat); 494c72fcc34Sopenharmony_ci if (err < 0) { 495c72fcc34Sopenharmony_ci retval_play = err; 496c72fcc34Sopenharmony_ci goto exit4; 497c72fcc34Sopenharmony_ci } 498c72fcc34Sopenharmony_ci 499c72fcc34Sopenharmony_ciexit4: 500c72fcc34Sopenharmony_ci if (bat->playback.file) 501c72fcc34Sopenharmony_ci fclose(bat->fp); 502c72fcc34Sopenharmony_ciexit3: 503c72fcc34Sopenharmony_ci free(sndpcm.buffer); 504c72fcc34Sopenharmony_ciexit2: 505c72fcc34Sopenharmony_ci snd_pcm_close(sndpcm.handle); 506c72fcc34Sopenharmony_ciexit1: 507c72fcc34Sopenharmony_ci pthread_exit(&retval_play); 508c72fcc34Sopenharmony_ci} 509c72fcc34Sopenharmony_ci 510c72fcc34Sopenharmony_cistatic int read_from_pcm(struct pcm_container *sndpcm, 511c72fcc34Sopenharmony_ci int frames, struct bat *bat) 512c72fcc34Sopenharmony_ci{ 513c72fcc34Sopenharmony_ci int err = 0; 514c72fcc34Sopenharmony_ci int offset = 0; 515c72fcc34Sopenharmony_ci int remain = frames; 516c72fcc34Sopenharmony_ci 517c72fcc34Sopenharmony_ci while (remain > 0) { 518c72fcc34Sopenharmony_ci err = snd_pcm_readi(sndpcm->handle, 519c72fcc34Sopenharmony_ci sndpcm->buffer + offset, remain); 520c72fcc34Sopenharmony_ci if (err == -EAGAIN || (err >= 0 && err < remain)) { 521c72fcc34Sopenharmony_ci snd_pcm_wait(sndpcm->handle, 500); 522c72fcc34Sopenharmony_ci } else if (err == -EPIPE) { 523c72fcc34Sopenharmony_ci snd_pcm_prepare(sndpcm->handle); 524c72fcc34Sopenharmony_ci fprintf(bat->err, _("Overrun: %s(%d)\n"), 525c72fcc34Sopenharmony_ci snd_strerror(err), err); 526c72fcc34Sopenharmony_ci if (bat->roundtriplatency) 527c72fcc34Sopenharmony_ci bat->latency.xrun_error = true; 528c72fcc34Sopenharmony_ci } else if (err == -ESTRPIPE) { 529c72fcc34Sopenharmony_ci while ((err = snd_pcm_resume(sndpcm->handle)) == -EAGAIN) 530c72fcc34Sopenharmony_ci sleep(1); /* wait until resume flag is released */ 531c72fcc34Sopenharmony_ci if (err < 0) 532c72fcc34Sopenharmony_ci snd_pcm_prepare(sndpcm->handle); 533c72fcc34Sopenharmony_ci } else if (err < 0) { 534c72fcc34Sopenharmony_ci fprintf(bat->err, _("Read PCM device error: %s(%d)\n"), 535c72fcc34Sopenharmony_ci snd_strerror(err), err); 536c72fcc34Sopenharmony_ci return err; 537c72fcc34Sopenharmony_ci } 538c72fcc34Sopenharmony_ci 539c72fcc34Sopenharmony_ci if (err > 0) { 540c72fcc34Sopenharmony_ci remain -= err; 541c72fcc34Sopenharmony_ci offset += err * sndpcm->frame_bits / 8; 542c72fcc34Sopenharmony_ci } 543c72fcc34Sopenharmony_ci } 544c72fcc34Sopenharmony_ci 545c72fcc34Sopenharmony_ci return 0; 546c72fcc34Sopenharmony_ci} 547c72fcc34Sopenharmony_ci 548c72fcc34Sopenharmony_cistatic int read_from_pcm_loop(struct pcm_container *sndpcm, struct bat *bat) 549c72fcc34Sopenharmony_ci{ 550c72fcc34Sopenharmony_ci int err = 0; 551c72fcc34Sopenharmony_ci FILE *fp = NULL; 552c72fcc34Sopenharmony_ci int size, frames; 553c72fcc34Sopenharmony_ci int bytes_read = 0; 554c72fcc34Sopenharmony_ci int bytes_count = bat->frames * bat->frame_size; 555c72fcc34Sopenharmony_ci unsigned int remain = bytes_count; 556c72fcc34Sopenharmony_ci 557c72fcc34Sopenharmony_ci remove(bat->capture.file); 558c72fcc34Sopenharmony_ci fp = fopen(bat->capture.file, "wb"); 559c72fcc34Sopenharmony_ci err = -errno; 560c72fcc34Sopenharmony_ci if (fp == NULL) { 561c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 562c72fcc34Sopenharmony_ci bat->capture.file, err); 563c72fcc34Sopenharmony_ci return err; 564c72fcc34Sopenharmony_ci } 565c72fcc34Sopenharmony_ci /* leave space for file header */ 566c72fcc34Sopenharmony_ci if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 567c72fcc34Sopenharmony_ci err = -errno; 568c72fcc34Sopenharmony_ci fclose(fp); 569c72fcc34Sopenharmony_ci return err; 570c72fcc34Sopenharmony_ci } 571c72fcc34Sopenharmony_ci 572c72fcc34Sopenharmony_ci while (remain > 0) { 573c72fcc34Sopenharmony_ci size = (remain <= sndpcm->period_bytes) ? 574c72fcc34Sopenharmony_ci remain : sndpcm->period_bytes; 575c72fcc34Sopenharmony_ci frames = size * 8 / sndpcm->frame_bits; 576c72fcc34Sopenharmony_ci 577c72fcc34Sopenharmony_ci /* read a chunk from pcm device */ 578c72fcc34Sopenharmony_ci err = read_from_pcm(sndpcm, frames, bat); 579c72fcc34Sopenharmony_ci if (err != 0) 580c72fcc34Sopenharmony_ci break; 581c72fcc34Sopenharmony_ci 582c72fcc34Sopenharmony_ci /* write the chunk to file */ 583c72fcc34Sopenharmony_ci if (fwrite(sndpcm->buffer, 1, size, fp) != (size_t)size) { 584c72fcc34Sopenharmony_ci err = -EIO; 585c72fcc34Sopenharmony_ci break; 586c72fcc34Sopenharmony_ci } 587c72fcc34Sopenharmony_ci 588c72fcc34Sopenharmony_ci bytes_read += size; 589c72fcc34Sopenharmony_ci remain -= size; 590c72fcc34Sopenharmony_ci bat->periods_played++; 591c72fcc34Sopenharmony_ci 592c72fcc34Sopenharmony_ci if (bat->period_is_limited 593c72fcc34Sopenharmony_ci && bat->periods_played >= bat->periods_total) 594c72fcc34Sopenharmony_ci break; 595c72fcc34Sopenharmony_ci } 596c72fcc34Sopenharmony_ci 597c72fcc34Sopenharmony_ci update_wav_header(bat, fp, bytes_read); 598c72fcc34Sopenharmony_ci 599c72fcc34Sopenharmony_ci fclose(fp); 600c72fcc34Sopenharmony_ci return err; 601c72fcc34Sopenharmony_ci} 602c72fcc34Sopenharmony_ci 603c72fcc34Sopenharmony_ci/** 604c72fcc34Sopenharmony_ci * Process input data for latency test 605c72fcc34Sopenharmony_ci */ 606c72fcc34Sopenharmony_cistatic int latencytest_process_input(struct pcm_container *sndpcm, 607c72fcc34Sopenharmony_ci struct bat *bat) 608c72fcc34Sopenharmony_ci{ 609c72fcc34Sopenharmony_ci int err = 0; 610c72fcc34Sopenharmony_ci FILE *fp = NULL; 611c72fcc34Sopenharmony_ci int bytes_read = 0; 612c72fcc34Sopenharmony_ci int frames = sndpcm->period_size; 613c72fcc34Sopenharmony_ci int size = sndpcm->period_bytes; 614c72fcc34Sopenharmony_ci int bytes_count = bat->frames * bat->frame_size; 615c72fcc34Sopenharmony_ci 616c72fcc34Sopenharmony_ci remove(bat->capture.file); 617c72fcc34Sopenharmony_ci fp = fopen(bat->capture.file, "wb"); 618c72fcc34Sopenharmony_ci err = -errno; 619c72fcc34Sopenharmony_ci if (fp == NULL) { 620c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 621c72fcc34Sopenharmony_ci bat->capture.file, err); 622c72fcc34Sopenharmony_ci return err; 623c72fcc34Sopenharmony_ci } 624c72fcc34Sopenharmony_ci /* leave space for file header */ 625c72fcc34Sopenharmony_ci if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 626c72fcc34Sopenharmony_ci fclose(fp); 627c72fcc34Sopenharmony_ci return err; 628c72fcc34Sopenharmony_ci } 629c72fcc34Sopenharmony_ci 630c72fcc34Sopenharmony_ci bat->latency.is_capturing = true; 631c72fcc34Sopenharmony_ci 632c72fcc34Sopenharmony_ci while (bytes_read < bytes_count) { 633c72fcc34Sopenharmony_ci /* read a chunk from pcm device */ 634c72fcc34Sopenharmony_ci err = read_from_pcm(sndpcm, frames, bat); 635c72fcc34Sopenharmony_ci if (err != 0) 636c72fcc34Sopenharmony_ci break; 637c72fcc34Sopenharmony_ci 638c72fcc34Sopenharmony_ci /* Xrun error, terminate the capture thread*/ 639c72fcc34Sopenharmony_ci if (bat->latency.xrun_error == true) 640c72fcc34Sopenharmony_ci break; 641c72fcc34Sopenharmony_ci 642c72fcc34Sopenharmony_ci err = handleinput(bat, sndpcm->buffer, frames); 643c72fcc34Sopenharmony_ci if (err != 0) 644c72fcc34Sopenharmony_ci break; 645c72fcc34Sopenharmony_ci 646c72fcc34Sopenharmony_ci if (bat->latency.is_playing == false) 647c72fcc34Sopenharmony_ci break; 648c72fcc34Sopenharmony_ci 649c72fcc34Sopenharmony_ci /* write the chunk to file */ 650c72fcc34Sopenharmony_ci if (fwrite(sndpcm->buffer, 1, size, fp) != (size_t)size) { 651c72fcc34Sopenharmony_ci err = -EIO; 652c72fcc34Sopenharmony_ci break; 653c72fcc34Sopenharmony_ci } 654c72fcc34Sopenharmony_ci 655c72fcc34Sopenharmony_ci bytes_read += size; 656c72fcc34Sopenharmony_ci } 657c72fcc34Sopenharmony_ci 658c72fcc34Sopenharmony_ci bat->latency.is_capturing = false; 659c72fcc34Sopenharmony_ci 660c72fcc34Sopenharmony_ci update_wav_header(bat, fp, bytes_read); 661c72fcc34Sopenharmony_ci 662c72fcc34Sopenharmony_ci fclose(fp); 663c72fcc34Sopenharmony_ci return err; 664c72fcc34Sopenharmony_ci} 665c72fcc34Sopenharmony_ci 666c72fcc34Sopenharmony_ci 667c72fcc34Sopenharmony_cistatic void pcm_cleanup(void *p) 668c72fcc34Sopenharmony_ci{ 669c72fcc34Sopenharmony_ci snd_pcm_close(p); 670c72fcc34Sopenharmony_ci} 671c72fcc34Sopenharmony_ci 672c72fcc34Sopenharmony_ci/** 673c72fcc34Sopenharmony_ci * Record 674c72fcc34Sopenharmony_ci */ 675c72fcc34Sopenharmony_civoid *record_alsa(struct bat *bat) 676c72fcc34Sopenharmony_ci{ 677c72fcc34Sopenharmony_ci int err = 0; 678c72fcc34Sopenharmony_ci struct pcm_container sndpcm; 679c72fcc34Sopenharmony_ci 680c72fcc34Sopenharmony_ci pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 681c72fcc34Sopenharmony_ci 682c72fcc34Sopenharmony_ci fprintf(bat->log, _("Entering capture thread (ALSA).\n")); 683c72fcc34Sopenharmony_ci 684c72fcc34Sopenharmony_ci retval_record = 0; 685c72fcc34Sopenharmony_ci memset(&sndpcm, 0, sizeof(sndpcm)); 686c72fcc34Sopenharmony_ci 687c72fcc34Sopenharmony_ci err = snd_pcm_open(&sndpcm.handle, bat->capture.device, 688c72fcc34Sopenharmony_ci SND_PCM_STREAM_CAPTURE, 0); 689c72fcc34Sopenharmony_ci if (err != 0) { 690c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open PCM capture device: ")); 691c72fcc34Sopenharmony_ci fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err); 692c72fcc34Sopenharmony_ci retval_record = err; 693c72fcc34Sopenharmony_ci goto exit1; 694c72fcc34Sopenharmony_ci } 695c72fcc34Sopenharmony_ci 696c72fcc34Sopenharmony_ci err = set_snd_pcm_params(bat, &sndpcm); 697c72fcc34Sopenharmony_ci if (err != 0) { 698c72fcc34Sopenharmony_ci retval_record = err; 699c72fcc34Sopenharmony_ci goto exit2; 700c72fcc34Sopenharmony_ci } 701c72fcc34Sopenharmony_ci 702c72fcc34Sopenharmony_ci pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 703c72fcc34Sopenharmony_ci pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 704c72fcc34Sopenharmony_ci pthread_cleanup_push(pcm_cleanup, sndpcm.handle); 705c72fcc34Sopenharmony_ci pthread_cleanup_push(free, sndpcm.buffer); 706c72fcc34Sopenharmony_ci 707c72fcc34Sopenharmony_ci fprintf(bat->log, _("Recording ...\n")); 708c72fcc34Sopenharmony_ci if (bat->roundtriplatency) 709c72fcc34Sopenharmony_ci err = latencytest_process_input(&sndpcm, bat); 710c72fcc34Sopenharmony_ci else 711c72fcc34Sopenharmony_ci err = read_from_pcm_loop(&sndpcm, bat); 712c72fcc34Sopenharmony_ci 713c72fcc34Sopenharmony_ci pthread_cleanup_pop(0); 714c72fcc34Sopenharmony_ci pthread_cleanup_pop(0); 715c72fcc34Sopenharmony_ci 716c72fcc34Sopenharmony_ci if (err != 0) { 717c72fcc34Sopenharmony_ci retval_record = err; 718c72fcc34Sopenharmony_ci goto exit3; 719c72fcc34Sopenharmony_ci } 720c72fcc34Sopenharmony_ci 721c72fcc34Sopenharmony_ci /* Normally we will never reach this part of code (unless error in 722c72fcc34Sopenharmony_ci * previous call) (before exit3) as this thread will be cancelled 723c72fcc34Sopenharmony_ci * by end of play thread. Except in single line mode. */ 724c72fcc34Sopenharmony_ci snd_pcm_drain(sndpcm.handle); 725c72fcc34Sopenharmony_ci pthread_exit(&retval_record); 726c72fcc34Sopenharmony_ci 727c72fcc34Sopenharmony_ciexit3: 728c72fcc34Sopenharmony_ci free(sndpcm.buffer); 729c72fcc34Sopenharmony_ciexit2: 730c72fcc34Sopenharmony_ci snd_pcm_close(sndpcm.handle); 731c72fcc34Sopenharmony_ciexit1: 732c72fcc34Sopenharmony_ci pthread_exit(&retval_record); 733c72fcc34Sopenharmony_ci} 734