1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Copyright (C) 2000-2004 James Courtier-Dutton 3c72fcc34Sopenharmony_ci * Copyright (C) 2005 Nathan Hurst 4c72fcc34Sopenharmony_ci * 5c72fcc34Sopenharmony_ci * This file is part of the speaker-test tool. 6c72fcc34Sopenharmony_ci * 7c72fcc34Sopenharmony_ci * This small program sends a simple sinusoidal wave to your speakers. 8c72fcc34Sopenharmony_ci * 9c72fcc34Sopenharmony_ci * speaker-test is free software; you can redistribute it and/or modify 10c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 11c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 12c72fcc34Sopenharmony_ci * (at your option) any later version. 13c72fcc34Sopenharmony_ci * 14c72fcc34Sopenharmony_ci * speaker-test is distributed in the hope that it will be useful, 15c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17c72fcc34Sopenharmony_ci * GNU General Public License for more details. 18c72fcc34Sopenharmony_ci * 19c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 20c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 21c72fcc34Sopenharmony_ci * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 22c72fcc34Sopenharmony_ci * 23c72fcc34Sopenharmony_ci * 24c72fcc34Sopenharmony_ci * Main program by James Courtier-Dutton (including some source code fragments from the alsa project.) 25c72fcc34Sopenharmony_ci * Some cleanup from Daniel Caujolle-Bert <segfault@club-internet.fr> 26c72fcc34Sopenharmony_ci * Pink noise option added Nathan Hurst, 27c72fcc34Sopenharmony_ci * based on generator by Phil Burk (pink.c) 28c72fcc34Sopenharmony_ci * ST-2095 noise option added Rick Sayre, 29c72fcc34Sopenharmony_ci * based on generator specified by SMPTE ST-2095:1-2015 30c72fcc34Sopenharmony_ci * Also switched to stable harmonic oscillator for sine 31c72fcc34Sopenharmony_ci * 32c72fcc34Sopenharmony_ci * Changelog: 33c72fcc34Sopenharmony_ci * 0.0.9 Added support for ST-2095 band-limited pink noise output, switched to harmonic oscillator for sine 34c72fcc34Sopenharmony_ci * Changelog: 35c72fcc34Sopenharmony_ci * 0.0.8 Added support for pink noise output. 36c72fcc34Sopenharmony_ci * Changelog: 37c72fcc34Sopenharmony_ci * 0.0.7 Added support for more than 6 channels. 38c72fcc34Sopenharmony_ci * Changelog: 39c72fcc34Sopenharmony_ci * 0.0.6 Added support for different sample formats. 40c72fcc34Sopenharmony_ci * 41c72fcc34Sopenharmony_ci * $Id: speaker_test.c,v 1.00 2003/11/26 19:43:38 jcdutton Exp $ 42c72fcc34Sopenharmony_ci */ 43c72fcc34Sopenharmony_ci 44c72fcc34Sopenharmony_ci#include "aconfig.h" 45c72fcc34Sopenharmony_ci 46c72fcc34Sopenharmony_ci#include <stdio.h> 47c72fcc34Sopenharmony_ci#include <stdlib.h> 48c72fcc34Sopenharmony_ci#include <string.h> 49c72fcc34Sopenharmony_ci#include <sched.h> 50c72fcc34Sopenharmony_ci#include <errno.h> 51c72fcc34Sopenharmony_ci#include <getopt.h> 52c72fcc34Sopenharmony_ci#include <inttypes.h> 53c72fcc34Sopenharmony_ci#include <ctype.h> 54c72fcc34Sopenharmony_ci#include <limits.h> 55c72fcc34Sopenharmony_ci#include "bswap.h" 56c72fcc34Sopenharmony_ci#include <signal.h> 57c72fcc34Sopenharmony_ci 58c72fcc34Sopenharmony_ci#define ALSA_PCM_NEW_HW_PARAMS_API 59c72fcc34Sopenharmony_ci#define ALSA_PCM_NEW_SW_PARAMS_API 60c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h> 61c72fcc34Sopenharmony_ci#include <sys/time.h> 62c72fcc34Sopenharmony_ci#include <math.h> 63c72fcc34Sopenharmony_ci#include "pink.h" 64c72fcc34Sopenharmony_ci#include "st2095.h" 65c72fcc34Sopenharmony_ci#include "gettext.h" 66c72fcc34Sopenharmony_ci#include "version.h" 67c72fcc34Sopenharmony_ci#include "os_compat.h" 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_ci#ifdef ENABLE_NLS 70c72fcc34Sopenharmony_ci#include <locale.h> 71c72fcc34Sopenharmony_ci#endif 72c72fcc34Sopenharmony_ci 73c72fcc34Sopenharmony_ci#ifdef SND_CHMAP_API_VERSION 74c72fcc34Sopenharmony_ci#define CONFIG_SUPPORT_CHMAP 1 75c72fcc34Sopenharmony_ci#endif 76c72fcc34Sopenharmony_ci 77c72fcc34Sopenharmony_cienum { 78c72fcc34Sopenharmony_ci TEST_PINK_NOISE = 1, 79c72fcc34Sopenharmony_ci TEST_SINE, 80c72fcc34Sopenharmony_ci TEST_WAV, 81c72fcc34Sopenharmony_ci TEST_ST2095_NOISE, 82c72fcc34Sopenharmony_ci TEST_PATTERN, 83c72fcc34Sopenharmony_ci}; 84c72fcc34Sopenharmony_ci 85c72fcc34Sopenharmony_ci#define MAX_CHANNELS 16 86c72fcc34Sopenharmony_ci 87c72fcc34Sopenharmony_ci#if __BYTE_ORDER == __LITTLE_ENDIAN 88c72fcc34Sopenharmony_ci#define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) 89c72fcc34Sopenharmony_ci#define LE_SHORT(v) (v) 90c72fcc34Sopenharmony_ci#define LE_INT(v) (v) 91c72fcc34Sopenharmony_ci#define BE_SHORT(v) bswap_16(v) 92c72fcc34Sopenharmony_ci#define BE_INT(v) bswap_32(v) 93c72fcc34Sopenharmony_ci#else /* __BIG_ENDIAN */ 94c72fcc34Sopenharmony_ci#define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24)) 95c72fcc34Sopenharmony_ci#define LE_SHORT(v) bswap_16(v) 96c72fcc34Sopenharmony_ci#define LE_INT(v) bswap_32(v) 97c72fcc34Sopenharmony_ci#define BE_SHORT(v) (v) 98c72fcc34Sopenharmony_ci#define BE_INT(v) (v) 99c72fcc34Sopenharmony_ci#endif 100c72fcc34Sopenharmony_ci 101c72fcc34Sopenharmony_ci#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0])) 102c72fcc34Sopenharmony_ci 103c72fcc34Sopenharmony_cistatic char *device = "default"; /* playback device */ 104c72fcc34Sopenharmony_cistatic snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */ 105c72fcc34Sopenharmony_cistatic unsigned int rate = 48000; /* stream rate */ 106c72fcc34Sopenharmony_cistatic unsigned int channels = 1; /* count of channels */ 107c72fcc34Sopenharmony_cistatic unsigned int speaker = 0; /* count of channels */ 108c72fcc34Sopenharmony_cistatic unsigned int buffer_time = 0; /* ring buffer length in us */ 109c72fcc34Sopenharmony_cistatic unsigned int period_time = UINT_MAX; /* period time in us */ 110c72fcc34Sopenharmony_cistatic unsigned int nperiods = 4; /* number of periods */ 111c72fcc34Sopenharmony_cistatic double freq = 440.0; /* sinusoidal wave frequency in Hz */ 112c72fcc34Sopenharmony_cistatic int test_type = TEST_PINK_NOISE; /* Test type. 1 = noise, 2 = sine wave */ 113c72fcc34Sopenharmony_cistatic float generator_scale = 0.8; /* Scale to use for sine volume */ 114c72fcc34Sopenharmony_cistatic snd_pcm_uframes_t buffer_size; 115c72fcc34Sopenharmony_cistatic snd_pcm_uframes_t period_size; 116c72fcc34Sopenharmony_cistatic const char *given_test_wav_file = NULL; 117c72fcc34Sopenharmony_cistatic char *wav_file_dir = SOUNDSDIR; 118c72fcc34Sopenharmony_cistatic int debug = 0; 119c72fcc34Sopenharmony_cistatic int force_frequency = 0; 120c72fcc34Sopenharmony_cistatic int in_aborting = 0; 121c72fcc34Sopenharmony_cistatic snd_pcm_t *pcm_handle = NULL; 122c72fcc34Sopenharmony_ci 123c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 124c72fcc34Sopenharmony_cistatic snd_pcm_chmap_t *channel_map; 125c72fcc34Sopenharmony_cistatic int channel_map_set; 126c72fcc34Sopenharmony_cistatic int *ordered_channels; 127c72fcc34Sopenharmony_ci#endif 128c72fcc34Sopenharmony_ci 129c72fcc34Sopenharmony_cistatic const char *const channel_name[MAX_CHANNELS] = { 130c72fcc34Sopenharmony_ci /* 0 */ N_("Front Left"), 131c72fcc34Sopenharmony_ci /* 1 */ N_("Front Right"), 132c72fcc34Sopenharmony_ci /* 2 */ N_("Rear Left"), 133c72fcc34Sopenharmony_ci /* 3 */ N_("Rear Right"), 134c72fcc34Sopenharmony_ci /* 4 */ N_("Center"), 135c72fcc34Sopenharmony_ci /* 5 */ N_("LFE"), 136c72fcc34Sopenharmony_ci /* 6 */ N_("Side Left"), 137c72fcc34Sopenharmony_ci /* 7 */ N_("Side Right"), 138c72fcc34Sopenharmony_ci /* 8 */ N_("Channel 9"), 139c72fcc34Sopenharmony_ci /* 9 */ N_("Channel 10"), 140c72fcc34Sopenharmony_ci /* 10 */ N_("Channel 11"), 141c72fcc34Sopenharmony_ci /* 11 */ N_("Channel 12"), 142c72fcc34Sopenharmony_ci /* 12 */ N_("Channel 13"), 143c72fcc34Sopenharmony_ci /* 13 */ N_("Channel 14"), 144c72fcc34Sopenharmony_ci /* 14 */ N_("Channel 15"), 145c72fcc34Sopenharmony_ci /* 15 */ N_("Channel 16") 146c72fcc34Sopenharmony_ci}; 147c72fcc34Sopenharmony_ci 148c72fcc34Sopenharmony_cistatic const int channels4[] = { 149c72fcc34Sopenharmony_ci 0, /* Front Left */ 150c72fcc34Sopenharmony_ci 1, /* Front Right */ 151c72fcc34Sopenharmony_ci 3, /* Rear Right */ 152c72fcc34Sopenharmony_ci 2, /* Rear Left */ 153c72fcc34Sopenharmony_ci}; 154c72fcc34Sopenharmony_cistatic const int channels6[] = { 155c72fcc34Sopenharmony_ci 0, /* Front Left */ 156c72fcc34Sopenharmony_ci 4, /* Center */ 157c72fcc34Sopenharmony_ci 1, /* Front Right */ 158c72fcc34Sopenharmony_ci 3, /* Rear Right */ 159c72fcc34Sopenharmony_ci 2, /* Rear Left */ 160c72fcc34Sopenharmony_ci 5, /* LFE */ 161c72fcc34Sopenharmony_ci}; 162c72fcc34Sopenharmony_cistatic const int channels8[] = { 163c72fcc34Sopenharmony_ci 0, /* Front Left */ 164c72fcc34Sopenharmony_ci 4, /* Center */ 165c72fcc34Sopenharmony_ci 1, /* Front Right */ 166c72fcc34Sopenharmony_ci 7, /* Side Right */ 167c72fcc34Sopenharmony_ci 3, /* Rear Right */ 168c72fcc34Sopenharmony_ci 2, /* Rear Left */ 169c72fcc34Sopenharmony_ci 6, /* Side Left */ 170c72fcc34Sopenharmony_ci 5, /* LFE */ 171c72fcc34Sopenharmony_ci}; 172c72fcc34Sopenharmony_ci 173c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 174c72fcc34Sopenharmony_ci/* circular clockwise and bottom-to-top order */ 175c72fcc34Sopenharmony_cistatic const int channel_order[] = { 176c72fcc34Sopenharmony_ci [SND_CHMAP_FLW] = 10, 177c72fcc34Sopenharmony_ci [SND_CHMAP_FL] = 20, 178c72fcc34Sopenharmony_ci [SND_CHMAP_TFL] = 30, 179c72fcc34Sopenharmony_ci [SND_CHMAP_FLC] = 40, 180c72fcc34Sopenharmony_ci [SND_CHMAP_TFLC] = 50, 181c72fcc34Sopenharmony_ci [SND_CHMAP_FC] = 60, 182c72fcc34Sopenharmony_ci [SND_CHMAP_TFC] = 70, 183c72fcc34Sopenharmony_ci [SND_CHMAP_FRC] = 80, 184c72fcc34Sopenharmony_ci [SND_CHMAP_TFRC] = 90, 185c72fcc34Sopenharmony_ci [SND_CHMAP_FR] = 100, 186c72fcc34Sopenharmony_ci [SND_CHMAP_TFR] = 110, 187c72fcc34Sopenharmony_ci [SND_CHMAP_FRW] = 120, 188c72fcc34Sopenharmony_ci [SND_CHMAP_SR] = 130, 189c72fcc34Sopenharmony_ci [SND_CHMAP_TSR] = 140, 190c72fcc34Sopenharmony_ci [SND_CHMAP_RR] = 150, 191c72fcc34Sopenharmony_ci [SND_CHMAP_TRR] = 160, 192c72fcc34Sopenharmony_ci [SND_CHMAP_RRC] = 170, 193c72fcc34Sopenharmony_ci [SND_CHMAP_RC] = 180, 194c72fcc34Sopenharmony_ci [SND_CHMAP_TRC] = 190, 195c72fcc34Sopenharmony_ci [SND_CHMAP_RLC] = 200, 196c72fcc34Sopenharmony_ci [SND_CHMAP_RL] = 210, 197c72fcc34Sopenharmony_ci [SND_CHMAP_TRL] = 220, 198c72fcc34Sopenharmony_ci [SND_CHMAP_SL] = 230, 199c72fcc34Sopenharmony_ci [SND_CHMAP_TSL] = 240, 200c72fcc34Sopenharmony_ci [SND_CHMAP_BC] = 250, 201c72fcc34Sopenharmony_ci [SND_CHMAP_TC] = 260, 202c72fcc34Sopenharmony_ci [SND_CHMAP_LLFE] = 270, 203c72fcc34Sopenharmony_ci [SND_CHMAP_LFE] = 280, 204c72fcc34Sopenharmony_ci [SND_CHMAP_RLFE] = 290, 205c72fcc34Sopenharmony_ci /* not in table = 10000 */ 206c72fcc34Sopenharmony_ci [SND_CHMAP_UNKNOWN] = 20000, 207c72fcc34Sopenharmony_ci [SND_CHMAP_NA] = 30000, 208c72fcc34Sopenharmony_ci}; 209c72fcc34Sopenharmony_ci 210c72fcc34Sopenharmony_cistatic int chpos_cmp(const void *chnum1p, const void *chnum2p) 211c72fcc34Sopenharmony_ci{ 212c72fcc34Sopenharmony_ci int chnum1 = *(int *)chnum1p; 213c72fcc34Sopenharmony_ci int chnum2 = *(int *)chnum2p; 214c72fcc34Sopenharmony_ci int chpos1 = channel_map->pos[chnum1]; 215c72fcc34Sopenharmony_ci int chpos2 = channel_map->pos[chnum2]; 216c72fcc34Sopenharmony_ci int weight1 = 10000; 217c72fcc34Sopenharmony_ci int weight2 = 10000; 218c72fcc34Sopenharmony_ci 219c72fcc34Sopenharmony_ci if (chpos1 < ARRAY_SIZE(channel_order) && channel_order[chpos1]) 220c72fcc34Sopenharmony_ci weight1 = channel_order[chpos1]; 221c72fcc34Sopenharmony_ci if (chpos2 < ARRAY_SIZE(channel_order) && channel_order[chpos2]) 222c72fcc34Sopenharmony_ci weight2 = channel_order[chpos2]; 223c72fcc34Sopenharmony_ci 224c72fcc34Sopenharmony_ci if (weight1 == weight2) { 225c72fcc34Sopenharmony_ci /* order by channel number if both have the same position (e.g. UNKNOWN) 226c72fcc34Sopenharmony_ci * or if neither is in channel_order[] */ 227c72fcc34Sopenharmony_ci return chnum1 - chnum2; 228c72fcc34Sopenharmony_ci } 229c72fcc34Sopenharmony_ci 230c72fcc34Sopenharmony_ci /* order according to channel_order[] */ 231c72fcc34Sopenharmony_ci return weight1 - weight2; 232c72fcc34Sopenharmony_ci} 233c72fcc34Sopenharmony_ci 234c72fcc34Sopenharmony_cistatic int *order_channels(void) 235c72fcc34Sopenharmony_ci{ 236c72fcc34Sopenharmony_ci /* create a (playback order => channel number) table with channels ordered 237c72fcc34Sopenharmony_ci * according to channel_order[] values */ 238c72fcc34Sopenharmony_ci unsigned int i; 239c72fcc34Sopenharmony_ci int *ordered_chs; 240c72fcc34Sopenharmony_ci 241c72fcc34Sopenharmony_ci ordered_chs = calloc(channel_map->channels, sizeof(*ordered_chs)); 242c72fcc34Sopenharmony_ci if (!ordered_chs) 243c72fcc34Sopenharmony_ci return NULL; 244c72fcc34Sopenharmony_ci 245c72fcc34Sopenharmony_ci for (i = 0; i < channel_map->channels; i++) 246c72fcc34Sopenharmony_ci ordered_chs[i] = i; 247c72fcc34Sopenharmony_ci 248c72fcc34Sopenharmony_ci qsort(ordered_chs, channel_map->channels, sizeof(*ordered_chs), chpos_cmp); 249c72fcc34Sopenharmony_ci 250c72fcc34Sopenharmony_ci return ordered_chs; 251c72fcc34Sopenharmony_ci} 252c72fcc34Sopenharmony_ci#endif 253c72fcc34Sopenharmony_ci 254c72fcc34Sopenharmony_cistatic int get_speaker_channel(int chn) 255c72fcc34Sopenharmony_ci{ 256c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 257c72fcc34Sopenharmony_ci if (channel_map_set || (ordered_channels && (unsigned int)chn >= channel_map->channels)) 258c72fcc34Sopenharmony_ci return chn; 259c72fcc34Sopenharmony_ci if (ordered_channels) 260c72fcc34Sopenharmony_ci return ordered_channels[chn]; 261c72fcc34Sopenharmony_ci#endif 262c72fcc34Sopenharmony_ci 263c72fcc34Sopenharmony_ci switch (channels) { 264c72fcc34Sopenharmony_ci case 4: 265c72fcc34Sopenharmony_ci chn = channels4[chn]; 266c72fcc34Sopenharmony_ci break; 267c72fcc34Sopenharmony_ci case 6: 268c72fcc34Sopenharmony_ci chn = channels6[chn]; 269c72fcc34Sopenharmony_ci break; 270c72fcc34Sopenharmony_ci case 8: 271c72fcc34Sopenharmony_ci chn = channels8[chn]; 272c72fcc34Sopenharmony_ci break; 273c72fcc34Sopenharmony_ci } 274c72fcc34Sopenharmony_ci 275c72fcc34Sopenharmony_ci return chn; 276c72fcc34Sopenharmony_ci} 277c72fcc34Sopenharmony_ci 278c72fcc34Sopenharmony_cistatic const char *get_channel_name(int chn) 279c72fcc34Sopenharmony_ci{ 280c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 281c72fcc34Sopenharmony_ci if (channel_map) { 282c72fcc34Sopenharmony_ci const char *name = NULL; 283c72fcc34Sopenharmony_ci if ((unsigned int)chn < channel_map->channels) 284c72fcc34Sopenharmony_ci name = snd_pcm_chmap_long_name(channel_map->pos[chn]); 285c72fcc34Sopenharmony_ci return name ? name : "Unknown"; 286c72fcc34Sopenharmony_ci } 287c72fcc34Sopenharmony_ci#endif 288c72fcc34Sopenharmony_ci return gettext(channel_name[chn]); 289c72fcc34Sopenharmony_ci} 290c72fcc34Sopenharmony_ci 291c72fcc34Sopenharmony_cistatic const int supported_formats[] = { 292c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S8, 293c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S16_LE, 294c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S16_BE, 295c72fcc34Sopenharmony_ci SND_PCM_FORMAT_FLOAT_LE, 296c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S24_3LE, 297c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S24_3BE, 298c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S24_LE, 299c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S24_BE, 300c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S32_LE, 301c72fcc34Sopenharmony_ci SND_PCM_FORMAT_S32_BE, 302c72fcc34Sopenharmony_ci -1 303c72fcc34Sopenharmony_ci}; 304c72fcc34Sopenharmony_ci 305c72fcc34Sopenharmony_citypedef union { 306c72fcc34Sopenharmony_ci float f; 307c72fcc34Sopenharmony_ci int32_t i; 308c72fcc34Sopenharmony_ci} value_t; 309c72fcc34Sopenharmony_ci 310c72fcc34Sopenharmony_cistatic void do_generate(uint8_t *frames, int channel, int count, 311c72fcc34Sopenharmony_ci value_t (*generate)(void *), void *arg) 312c72fcc34Sopenharmony_ci{ 313c72fcc34Sopenharmony_ci value_t res; 314c72fcc34Sopenharmony_ci unsigned int chn; 315c72fcc34Sopenharmony_ci int8_t *samp8 = (int8_t*) frames; 316c72fcc34Sopenharmony_ci int16_t *samp16 = (int16_t*) frames; 317c72fcc34Sopenharmony_ci int32_t *samp32 = (int32_t*) frames; 318c72fcc34Sopenharmony_ci float *samp_f = (float*) frames; 319c72fcc34Sopenharmony_ci 320c72fcc34Sopenharmony_ci while (count-- > 0) { 321c72fcc34Sopenharmony_ci for(chn=0;chn<channels;chn++) { 322c72fcc34Sopenharmony_ci if (chn==(unsigned int)channel) { 323c72fcc34Sopenharmony_ci res = generate(arg); 324c72fcc34Sopenharmony_ci } else { 325c72fcc34Sopenharmony_ci res.i = 0; 326c72fcc34Sopenharmony_ci } 327c72fcc34Sopenharmony_ci 328c72fcc34Sopenharmony_ci switch (format) { 329c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S8: 330c72fcc34Sopenharmony_ci *samp8++ = res.i >> 24; 331c72fcc34Sopenharmony_ci break; 332c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S16_LE: 333c72fcc34Sopenharmony_ci *samp16++ = LE_SHORT(res.i >> 16); 334c72fcc34Sopenharmony_ci break; 335c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S16_BE: 336c72fcc34Sopenharmony_ci *samp16++ = BE_SHORT(res.i >> 16); 337c72fcc34Sopenharmony_ci break; 338c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_FLOAT_LE: 339c72fcc34Sopenharmony_ci *samp_f++ = res.f; 340c72fcc34Sopenharmony_ci break; 341c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S24_3LE: 342c72fcc34Sopenharmony_ci res.i >>= 8; 343c72fcc34Sopenharmony_ci *samp8++ = LE_INT(res.i); 344c72fcc34Sopenharmony_ci *samp8++ = LE_INT(res.i) >> 8; 345c72fcc34Sopenharmony_ci *samp8++ = LE_INT(res.i) >> 16; 346c72fcc34Sopenharmony_ci break; 347c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S24_3BE: 348c72fcc34Sopenharmony_ci res.i >>= 8; 349c72fcc34Sopenharmony_ci *samp8++ = BE_INT(res.i); 350c72fcc34Sopenharmony_ci *samp8++ = BE_INT(res.i) >> 8; 351c72fcc34Sopenharmony_ci *samp8++ = BE_INT(res.i) >> 16; 352c72fcc34Sopenharmony_ci break; 353c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S24_LE: 354c72fcc34Sopenharmony_ci res.i >>= 8; 355c72fcc34Sopenharmony_ci *samp8++ = LE_INT(res.i); 356c72fcc34Sopenharmony_ci *samp8++ = LE_INT(res.i) >> 8; 357c72fcc34Sopenharmony_ci *samp8++ = LE_INT(res.i) >> 16; 358c72fcc34Sopenharmony_ci *samp8++ = 0; 359c72fcc34Sopenharmony_ci break; 360c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S24_BE: 361c72fcc34Sopenharmony_ci res.i >>= 8; 362c72fcc34Sopenharmony_ci *samp8++ = 0; 363c72fcc34Sopenharmony_ci *samp8++ = BE_INT(res.i); 364c72fcc34Sopenharmony_ci *samp8++ = BE_INT(res.i) >> 8; 365c72fcc34Sopenharmony_ci *samp8++ = BE_INT(res.i) >> 16; 366c72fcc34Sopenharmony_ci break; 367c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S32_LE: 368c72fcc34Sopenharmony_ci *samp32++ = LE_INT(res.i); 369c72fcc34Sopenharmony_ci break; 370c72fcc34Sopenharmony_ci case SND_PCM_FORMAT_S32_BE: 371c72fcc34Sopenharmony_ci *samp32++ = BE_INT(res.i); 372c72fcc34Sopenharmony_ci break; 373c72fcc34Sopenharmony_ci default: 374c72fcc34Sopenharmony_ci ; 375c72fcc34Sopenharmony_ci } 376c72fcc34Sopenharmony_ci } 377c72fcc34Sopenharmony_ci } 378c72fcc34Sopenharmony_ci} 379c72fcc34Sopenharmony_ci 380c72fcc34Sopenharmony_ci/* 381c72fcc34Sopenharmony_ci * Sine generator 382c72fcc34Sopenharmony_ci */ 383c72fcc34Sopenharmony_citypedef struct { 384c72fcc34Sopenharmony_ci double a; 385c72fcc34Sopenharmony_ci double s; 386c72fcc34Sopenharmony_ci double c; 387c72fcc34Sopenharmony_ci} sine_t; 388c72fcc34Sopenharmony_ci 389c72fcc34Sopenharmony_cistatic void init_sine(sine_t *sine) 390c72fcc34Sopenharmony_ci{ 391c72fcc34Sopenharmony_ci // symplectic integration for fast, stable harmonic oscillator 392c72fcc34Sopenharmony_ci sine->a = 2.0*M_PI * freq / rate; 393c72fcc34Sopenharmony_ci sine->c = 1.0; 394c72fcc34Sopenharmony_ci sine->s = 0.0; 395c72fcc34Sopenharmony_ci} 396c72fcc34Sopenharmony_ci 397c72fcc34Sopenharmony_cistatic value_t generate_sine(void *arg) 398c72fcc34Sopenharmony_ci{ 399c72fcc34Sopenharmony_ci sine_t *sine = arg; 400c72fcc34Sopenharmony_ci value_t res; 401c72fcc34Sopenharmony_ci 402c72fcc34Sopenharmony_ci res.f = sine->s * generator_scale; 403c72fcc34Sopenharmony_ci if (format != SND_PCM_FORMAT_FLOAT_LE) 404c72fcc34Sopenharmony_ci res.i = res.f * INT32_MAX; 405c72fcc34Sopenharmony_ci 406c72fcc34Sopenharmony_ci // update the oscillator 407c72fcc34Sopenharmony_ci sine->c -= sine->a * sine->s; 408c72fcc34Sopenharmony_ci sine->s += sine->a * sine->c; 409c72fcc34Sopenharmony_ci return res; 410c72fcc34Sopenharmony_ci} 411c72fcc34Sopenharmony_ci 412c72fcc34Sopenharmony_ci/* Pink noise is a better test than sine wave because we can tell 413c72fcc34Sopenharmony_ci * where pink noise is coming from more easily that a sine wave. 414c72fcc34Sopenharmony_ci */ 415c72fcc34Sopenharmony_cistatic value_t generate_pink_noise(void *arg) 416c72fcc34Sopenharmony_ci{ 417c72fcc34Sopenharmony_ci pink_noise_t *pink = arg; 418c72fcc34Sopenharmony_ci value_t res; 419c72fcc34Sopenharmony_ci 420c72fcc34Sopenharmony_ci res.f = generate_pink_noise_sample(pink) * generator_scale; 421c72fcc34Sopenharmony_ci if (format != SND_PCM_FORMAT_FLOAT_LE) 422c72fcc34Sopenharmony_ci res.i = res.f * INT32_MAX; 423c72fcc34Sopenharmony_ci return res; 424c72fcc34Sopenharmony_ci} 425c72fcc34Sopenharmony_ci 426c72fcc34Sopenharmony_ci/* Band-Limited Pink Noise, per SMPTE ST 2095-1 427c72fcc34Sopenharmony_ci * beyond speaker localization, this can be used for setting loudness to standard 428c72fcc34Sopenharmony_ci */ 429c72fcc34Sopenharmony_cistatic value_t generate_st2095_noise(void *arg) 430c72fcc34Sopenharmony_ci{ 431c72fcc34Sopenharmony_ci st2095_noise_t *st2095 = arg; 432c72fcc34Sopenharmony_ci value_t res; 433c72fcc34Sopenharmony_ci 434c72fcc34Sopenharmony_ci res.f = generate_st2095_noise_sample(st2095); 435c72fcc34Sopenharmony_ci if (format != SND_PCM_FORMAT_FLOAT_LE) 436c72fcc34Sopenharmony_ci res.i = res.f * INT32_MAX; 437c72fcc34Sopenharmony_ci return res; 438c72fcc34Sopenharmony_ci} 439c72fcc34Sopenharmony_ci 440c72fcc34Sopenharmony_ci/* 441c72fcc34Sopenharmony_ci * useful for tests 442c72fcc34Sopenharmony_ci */ 443c72fcc34Sopenharmony_cistatic value_t generate_pattern(void *arg) 444c72fcc34Sopenharmony_ci{ 445c72fcc34Sopenharmony_ci value_t res; 446c72fcc34Sopenharmony_ci 447c72fcc34Sopenharmony_ci res.i = *(int *)arg; 448c72fcc34Sopenharmony_ci *(int *)arg = res.i + 1; 449c72fcc34Sopenharmony_ci if (format != SND_PCM_FORMAT_FLOAT_LE) 450c72fcc34Sopenharmony_ci res.f = (float)res.i / (float)INT32_MAX; 451c72fcc34Sopenharmony_ci return res; 452c72fcc34Sopenharmony_ci} 453c72fcc34Sopenharmony_ci 454c72fcc34Sopenharmony_cistatic int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) { 455c72fcc34Sopenharmony_ci unsigned int rrate; 456c72fcc34Sopenharmony_ci int err; 457c72fcc34Sopenharmony_ci snd_pcm_uframes_t period_size_min; 458c72fcc34Sopenharmony_ci snd_pcm_uframes_t period_size_max; 459c72fcc34Sopenharmony_ci snd_pcm_uframes_t buffer_size_min; 460c72fcc34Sopenharmony_ci snd_pcm_uframes_t buffer_size_max; 461c72fcc34Sopenharmony_ci 462c72fcc34Sopenharmony_ci /* choose all parameters */ 463c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_any(handle, params); 464c72fcc34Sopenharmony_ci if (err < 0) { 465c72fcc34Sopenharmony_ci fprintf(stderr, _("Broken configuration for playback: no configurations available: %s\n"), snd_strerror(err)); 466c72fcc34Sopenharmony_ci return err; 467c72fcc34Sopenharmony_ci } 468c72fcc34Sopenharmony_ci 469c72fcc34Sopenharmony_ci /* set the interleaved read/write format */ 470c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_access(handle, params, access); 471c72fcc34Sopenharmony_ci if (err < 0) { 472c72fcc34Sopenharmony_ci fprintf(stderr, _("Access type not available for playback: %s\n"), snd_strerror(err)); 473c72fcc34Sopenharmony_ci return err; 474c72fcc34Sopenharmony_ci } 475c72fcc34Sopenharmony_ci 476c72fcc34Sopenharmony_ci /* set the sample format */ 477c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_format(handle, params, format); 478c72fcc34Sopenharmony_ci if (err < 0) { 479c72fcc34Sopenharmony_ci fprintf(stderr, _("Sample format not available for playback: %s\n"), snd_strerror(err)); 480c72fcc34Sopenharmony_ci return err; 481c72fcc34Sopenharmony_ci } 482c72fcc34Sopenharmony_ci 483c72fcc34Sopenharmony_ci /* set the count of channels */ 484c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_channels(handle, params, channels); 485c72fcc34Sopenharmony_ci if (err < 0) { 486c72fcc34Sopenharmony_ci fprintf(stderr, _("Channels count (%i) not available for playbacks: %s\n"), channels, snd_strerror(err)); 487c72fcc34Sopenharmony_ci return err; 488c72fcc34Sopenharmony_ci } 489c72fcc34Sopenharmony_ci 490c72fcc34Sopenharmony_ci /* set the stream rate */ 491c72fcc34Sopenharmony_ci rrate = rate; 492c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_rate(handle, params, rate, 0); 493c72fcc34Sopenharmony_ci if (err < 0) { 494c72fcc34Sopenharmony_ci fprintf(stderr, _("Rate %iHz not available for playback: %s\n"), rate, snd_strerror(err)); 495c72fcc34Sopenharmony_ci return err; 496c72fcc34Sopenharmony_ci } 497c72fcc34Sopenharmony_ci 498c72fcc34Sopenharmony_ci if (rrate != rate) { 499c72fcc34Sopenharmony_ci fprintf(stderr, _("Rate doesn't match (requested %iHz, get %iHz, err %d)\n"), rate, rrate, err); 500c72fcc34Sopenharmony_ci return -EINVAL; 501c72fcc34Sopenharmony_ci } 502c72fcc34Sopenharmony_ci 503c72fcc34Sopenharmony_ci printf(_("Rate set to %iHz (requested %iHz)\n"), rrate, rate); 504c72fcc34Sopenharmony_ci /* set the buffer time */ 505c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min); 506c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max); 507c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_period_size_min(params, &period_size_min, NULL); 508c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_period_size_max(params, &period_size_max, NULL); 509c72fcc34Sopenharmony_ci printf(_("Buffer size range from %lu to %lu\n"),buffer_size_min, buffer_size_max); 510c72fcc34Sopenharmony_ci printf(_("Period size range from %lu to %lu\n"),period_size_min, period_size_max); 511c72fcc34Sopenharmony_ci if (period_time > 0) { 512c72fcc34Sopenharmony_ci unsigned int tmp = period_time; 513c72fcc34Sopenharmony_ci if (period_time > 0 && period_time < UINT_MAX) 514c72fcc34Sopenharmony_ci printf(_("Requested period time %u us\n"), period_time); 515c72fcc34Sopenharmony_ci else 516c72fcc34Sopenharmony_ci tmp = 250000; /* 0.25 second */ 517c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_period_time_near(handle, params, &tmp, NULL); 518c72fcc34Sopenharmony_ci if (err < 0) { 519c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set period time %u us for playback: %s\n"), 520c72fcc34Sopenharmony_ci tmp, snd_strerror(err)); 521c72fcc34Sopenharmony_ci return err; 522c72fcc34Sopenharmony_ci } 523c72fcc34Sopenharmony_ci } 524c72fcc34Sopenharmony_ci if (buffer_time > 0) { 525c72fcc34Sopenharmony_ci printf(_("Requested buffer time %u us\n"), buffer_time); 526c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, NULL); 527c72fcc34Sopenharmony_ci if (err < 0) { 528c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set buffer time %u us for playback: %s\n"), 529c72fcc34Sopenharmony_ci buffer_time, snd_strerror(err)); 530c72fcc34Sopenharmony_ci return err; 531c72fcc34Sopenharmony_ci } 532c72fcc34Sopenharmony_ci } 533c72fcc34Sopenharmony_ci if (! buffer_time && ! period_time) { 534c72fcc34Sopenharmony_ci buffer_size = buffer_size_max; 535c72fcc34Sopenharmony_ci if (! period_time) 536c72fcc34Sopenharmony_ci buffer_size = (buffer_size / nperiods) * nperiods; 537c72fcc34Sopenharmony_ci printf(_("Using max buffer size %lu\n"), buffer_size); 538c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size); 539c72fcc34Sopenharmony_ci if (err < 0) { 540c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set buffer size %lu for playback: %s\n"), 541c72fcc34Sopenharmony_ci buffer_size, snd_strerror(err)); 542c72fcc34Sopenharmony_ci return err; 543c72fcc34Sopenharmony_ci } 544c72fcc34Sopenharmony_ci } 545c72fcc34Sopenharmony_ci if (! buffer_time || ! period_time) { 546c72fcc34Sopenharmony_ci printf(_("Periods = %u\n"), nperiods); 547c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_set_periods_near(handle, params, &nperiods, NULL); 548c72fcc34Sopenharmony_ci if (err < 0) { 549c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set nperiods %u for playback: %s\n"), 550c72fcc34Sopenharmony_ci nperiods, snd_strerror(err)); 551c72fcc34Sopenharmony_ci return err; 552c72fcc34Sopenharmony_ci } 553c72fcc34Sopenharmony_ci } 554c72fcc34Sopenharmony_ci 555c72fcc34Sopenharmony_ci /* write the parameters to device */ 556c72fcc34Sopenharmony_ci err = snd_pcm_hw_params(handle, params); 557c72fcc34Sopenharmony_ci if (err < 0) { 558c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set hw params for playback: %s\n"), snd_strerror(err)); 559c72fcc34Sopenharmony_ci return err; 560c72fcc34Sopenharmony_ci } 561c72fcc34Sopenharmony_ci 562c72fcc34Sopenharmony_ci snd_pcm_hw_params_get_buffer_size(params, &buffer_size); 563c72fcc34Sopenharmony_ci snd_pcm_hw_params_get_period_size(params, &period_size, NULL); 564c72fcc34Sopenharmony_ci printf(_("was set period_size = %lu\n"),period_size); 565c72fcc34Sopenharmony_ci printf(_("was set buffer_size = %lu\n"),buffer_size); 566c72fcc34Sopenharmony_ci if (2*period_size > buffer_size) { 567c72fcc34Sopenharmony_ci fprintf(stderr, _("buffer to small, could not use\n")); 568c72fcc34Sopenharmony_ci return -EINVAL; 569c72fcc34Sopenharmony_ci } 570c72fcc34Sopenharmony_ci 571c72fcc34Sopenharmony_ci return 0; 572c72fcc34Sopenharmony_ci} 573c72fcc34Sopenharmony_ci 574c72fcc34Sopenharmony_cistatic int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) { 575c72fcc34Sopenharmony_ci int err; 576c72fcc34Sopenharmony_ci 577c72fcc34Sopenharmony_ci /* get the current swparams */ 578c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_current(handle, swparams); 579c72fcc34Sopenharmony_ci if (err < 0) { 580c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to determine current swparams for playback: %s\n"), snd_strerror(err)); 581c72fcc34Sopenharmony_ci return err; 582c72fcc34Sopenharmony_ci } 583c72fcc34Sopenharmony_ci 584c72fcc34Sopenharmony_ci /* start the transfer when a buffer is full */ 585c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size); 586c72fcc34Sopenharmony_ci if (err < 0) { 587c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set start threshold mode for playback: %s\n"), snd_strerror(err)); 588c72fcc34Sopenharmony_ci return err; 589c72fcc34Sopenharmony_ci } 590c72fcc34Sopenharmony_ci 591c72fcc34Sopenharmony_ci /* allow the transfer when at least period_size frames can be processed */ 592c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size); 593c72fcc34Sopenharmony_ci if (err < 0) { 594c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set avail min for playback: %s\n"), snd_strerror(err)); 595c72fcc34Sopenharmony_ci return err; 596c72fcc34Sopenharmony_ci } 597c72fcc34Sopenharmony_ci 598c72fcc34Sopenharmony_ci /* write the parameters to the playback device */ 599c72fcc34Sopenharmony_ci err = snd_pcm_sw_params(handle, swparams); 600c72fcc34Sopenharmony_ci if (err < 0) { 601c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set sw params for playback: %s\n"), snd_strerror(err)); 602c72fcc34Sopenharmony_ci return err; 603c72fcc34Sopenharmony_ci } 604c72fcc34Sopenharmony_ci 605c72fcc34Sopenharmony_ci return 0; 606c72fcc34Sopenharmony_ci} 607c72fcc34Sopenharmony_ci 608c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 609c72fcc34Sopenharmony_cistatic int config_chmap(snd_pcm_t *handle, const char *mapstr) 610c72fcc34Sopenharmony_ci{ 611c72fcc34Sopenharmony_ci int err; 612c72fcc34Sopenharmony_ci 613c72fcc34Sopenharmony_ci if (mapstr) { 614c72fcc34Sopenharmony_ci channel_map = snd_pcm_chmap_parse_string(mapstr); 615c72fcc34Sopenharmony_ci if (!channel_map) { 616c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to parse channel map string: %s\n"), mapstr); 617c72fcc34Sopenharmony_ci return -EINVAL; 618c72fcc34Sopenharmony_ci } 619c72fcc34Sopenharmony_ci err = snd_pcm_set_chmap(handle, channel_map); 620c72fcc34Sopenharmony_ci if (err < 0) { 621c72fcc34Sopenharmony_ci fprintf(stderr, _("Unable to set channel map: %s\n"), mapstr); 622c72fcc34Sopenharmony_ci return err; 623c72fcc34Sopenharmony_ci } 624c72fcc34Sopenharmony_ci channel_map_set = 1; 625c72fcc34Sopenharmony_ci return 0; 626c72fcc34Sopenharmony_ci } 627c72fcc34Sopenharmony_ci 628c72fcc34Sopenharmony_ci channel_map = snd_pcm_get_chmap(handle); 629c72fcc34Sopenharmony_ci 630c72fcc34Sopenharmony_ci /* create a channel order table for default layouts */ 631c72fcc34Sopenharmony_ci if (channel_map) 632c72fcc34Sopenharmony_ci ordered_channels = order_channels(); 633c72fcc34Sopenharmony_ci 634c72fcc34Sopenharmony_ci return 0; 635c72fcc34Sopenharmony_ci} 636c72fcc34Sopenharmony_ci#endif 637c72fcc34Sopenharmony_ci 638c72fcc34Sopenharmony_ci/* 639c72fcc34Sopenharmony_ci * Underrun and suspend recovery 640c72fcc34Sopenharmony_ci */ 641c72fcc34Sopenharmony_ci 642c72fcc34Sopenharmony_cistatic int xrun_recovery(snd_pcm_t *handle, int err) { 643c72fcc34Sopenharmony_ci if (err == -EPIPE) { /* under-run */ 644c72fcc34Sopenharmony_ci err = snd_pcm_prepare(handle); 645c72fcc34Sopenharmony_ci if (err < 0) 646c72fcc34Sopenharmony_ci fprintf(stderr, _("Can't recovery from underrun, prepare failed: %s\n"), snd_strerror(err)); 647c72fcc34Sopenharmony_ci return 0; 648c72fcc34Sopenharmony_ci } 649c72fcc34Sopenharmony_ci else if (err == -ESTRPIPE) { 650c72fcc34Sopenharmony_ci 651c72fcc34Sopenharmony_ci while ((err = snd_pcm_resume(handle)) == -EAGAIN) 652c72fcc34Sopenharmony_ci sleep(1); /* wait until the suspend flag is released */ 653c72fcc34Sopenharmony_ci 654c72fcc34Sopenharmony_ci if (err < 0) { 655c72fcc34Sopenharmony_ci err = snd_pcm_prepare(handle); 656c72fcc34Sopenharmony_ci if (err < 0) 657c72fcc34Sopenharmony_ci fprintf(stderr, _("Can't recovery from suspend, prepare failed: %s\n"), snd_strerror(err)); 658c72fcc34Sopenharmony_ci } 659c72fcc34Sopenharmony_ci 660c72fcc34Sopenharmony_ci return 0; 661c72fcc34Sopenharmony_ci } 662c72fcc34Sopenharmony_ci 663c72fcc34Sopenharmony_ci return err; 664c72fcc34Sopenharmony_ci} 665c72fcc34Sopenharmony_ci 666c72fcc34Sopenharmony_ci/* 667c72fcc34Sopenharmony_ci * Handle WAV files 668c72fcc34Sopenharmony_ci */ 669c72fcc34Sopenharmony_ci 670c72fcc34Sopenharmony_cistatic const char *wav_file[MAX_CHANNELS]; 671c72fcc34Sopenharmony_cistatic int wav_file_size[MAX_CHANNELS]; 672c72fcc34Sopenharmony_ci 673c72fcc34Sopenharmony_cistruct wave_header { 674c72fcc34Sopenharmony_ci struct { 675c72fcc34Sopenharmony_ci uint32_t magic; 676c72fcc34Sopenharmony_ci uint32_t length; 677c72fcc34Sopenharmony_ci uint32_t type; 678c72fcc34Sopenharmony_ci } hdr; 679c72fcc34Sopenharmony_ci struct { 680c72fcc34Sopenharmony_ci uint32_t type; 681c72fcc34Sopenharmony_ci uint32_t length; 682c72fcc34Sopenharmony_ci } chunk1; 683c72fcc34Sopenharmony_ci struct { 684c72fcc34Sopenharmony_ci uint16_t format; 685c72fcc34Sopenharmony_ci uint16_t channels; 686c72fcc34Sopenharmony_ci uint32_t rate; 687c72fcc34Sopenharmony_ci uint32_t bytes_per_sec; 688c72fcc34Sopenharmony_ci uint16_t sample_size; 689c72fcc34Sopenharmony_ci uint16_t sample_bits; 690c72fcc34Sopenharmony_ci } body; 691c72fcc34Sopenharmony_ci struct { 692c72fcc34Sopenharmony_ci uint32_t type; 693c72fcc34Sopenharmony_ci uint32_t length; 694c72fcc34Sopenharmony_ci } chunk; 695c72fcc34Sopenharmony_ci}; 696c72fcc34Sopenharmony_ci 697c72fcc34Sopenharmony_ci#define WAV_RIFF COMPOSE_ID('R','I','F','F') 698c72fcc34Sopenharmony_ci#define WAV_WAVE COMPOSE_ID('W','A','V','E') 699c72fcc34Sopenharmony_ci#define WAV_FMT COMPOSE_ID('f','m','t',' ') 700c72fcc34Sopenharmony_ci#define WAV_DATA COMPOSE_ID('d','a','t','a') 701c72fcc34Sopenharmony_ci#define WAV_PCM_CODE 1 702c72fcc34Sopenharmony_ci 703c72fcc34Sopenharmony_cistatic const char *search_for_file(const char *name) 704c72fcc34Sopenharmony_ci{ 705c72fcc34Sopenharmony_ci char *file; 706c72fcc34Sopenharmony_ci if (*name == '/') 707c72fcc34Sopenharmony_ci return strdup(name); 708c72fcc34Sopenharmony_ci file = malloc(strlen(wav_file_dir) + strlen(name) + 2); 709c72fcc34Sopenharmony_ci if (file) 710c72fcc34Sopenharmony_ci sprintf(file, "%s/%s", wav_file_dir, name); 711c72fcc34Sopenharmony_ci return file; 712c72fcc34Sopenharmony_ci} 713c72fcc34Sopenharmony_ci 714c72fcc34Sopenharmony_cistatic int check_wav_file(int channel, const char *name) 715c72fcc34Sopenharmony_ci{ 716c72fcc34Sopenharmony_ci struct wave_header header; 717c72fcc34Sopenharmony_ci int fd; 718c72fcc34Sopenharmony_ci 719c72fcc34Sopenharmony_ci wav_file[channel] = search_for_file(name); 720c72fcc34Sopenharmony_ci if (! wav_file[channel]) { 721c72fcc34Sopenharmony_ci fprintf(stderr, _("No enough memory\n")); 722c72fcc34Sopenharmony_ci return -ENOMEM; 723c72fcc34Sopenharmony_ci } 724c72fcc34Sopenharmony_ci 725c72fcc34Sopenharmony_ci if ((fd = open(wav_file[channel], O_RDONLY)) < 0) { 726c72fcc34Sopenharmony_ci fprintf(stderr, _("Cannot open WAV file %s\n"), wav_file[channel]); 727c72fcc34Sopenharmony_ci return -EINVAL; 728c72fcc34Sopenharmony_ci } 729c72fcc34Sopenharmony_ci if (read(fd, &header, sizeof(header)) < (int)sizeof(header)) { 730c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid WAV file %s\n"), wav_file[channel]); 731c72fcc34Sopenharmony_ci goto error; 732c72fcc34Sopenharmony_ci } 733c72fcc34Sopenharmony_ci 734c72fcc34Sopenharmony_ci if (header.hdr.magic != WAV_RIFF || header.hdr.type != WAV_WAVE) { 735c72fcc34Sopenharmony_ci fprintf(stderr, _("Not a WAV file: %s\n"), wav_file[channel]); 736c72fcc34Sopenharmony_ci goto error; 737c72fcc34Sopenharmony_ci } 738c72fcc34Sopenharmony_ci if (header.body.format != LE_SHORT(WAV_PCM_CODE)) { 739c72fcc34Sopenharmony_ci fprintf(stderr, _("Unsupported WAV format %d for %s\n"), 740c72fcc34Sopenharmony_ci LE_SHORT(header.body.format), wav_file[channel]); 741c72fcc34Sopenharmony_ci goto error; 742c72fcc34Sopenharmony_ci } 743c72fcc34Sopenharmony_ci if (header.body.channels != LE_SHORT(1)) { 744c72fcc34Sopenharmony_ci fprintf(stderr, _("%s is not a mono stream (%d channels)\n"), 745c72fcc34Sopenharmony_ci wav_file[channel], LE_SHORT(header.body.channels)); 746c72fcc34Sopenharmony_ci goto error; 747c72fcc34Sopenharmony_ci } 748c72fcc34Sopenharmony_ci if (header.body.rate != LE_INT(rate)) { 749c72fcc34Sopenharmony_ci fprintf(stderr, _("Sample rate doesn't match (%d) for %s\n"), 750c72fcc34Sopenharmony_ci LE_INT(header.body.rate), wav_file[channel]); 751c72fcc34Sopenharmony_ci goto error; 752c72fcc34Sopenharmony_ci } 753c72fcc34Sopenharmony_ci if (header.body.sample_bits != LE_SHORT(16)) { 754c72fcc34Sopenharmony_ci fprintf(stderr, _("Unsupported sample format bits %d for %s\n"), 755c72fcc34Sopenharmony_ci LE_SHORT(header.body.sample_bits), wav_file[channel]); 756c72fcc34Sopenharmony_ci goto error; 757c72fcc34Sopenharmony_ci } 758c72fcc34Sopenharmony_ci if (header.chunk.type != WAV_DATA) { 759c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid WAV file %s\n"), wav_file[channel]); 760c72fcc34Sopenharmony_ci goto error; 761c72fcc34Sopenharmony_ci } 762c72fcc34Sopenharmony_ci wav_file_size[channel] = LE_INT(header.chunk.length); 763c72fcc34Sopenharmony_ci close(fd); 764c72fcc34Sopenharmony_ci return 0; 765c72fcc34Sopenharmony_ci 766c72fcc34Sopenharmony_ci error: 767c72fcc34Sopenharmony_ci close(fd); 768c72fcc34Sopenharmony_ci return -EINVAL; 769c72fcc34Sopenharmony_ci} 770c72fcc34Sopenharmony_ci 771c72fcc34Sopenharmony_cistatic int setup_wav_file(int chn) 772c72fcc34Sopenharmony_ci{ 773c72fcc34Sopenharmony_ci static const char *const wavs[MAX_CHANNELS] = { 774c72fcc34Sopenharmony_ci "Front_Left.wav", 775c72fcc34Sopenharmony_ci "Front_Right.wav", 776c72fcc34Sopenharmony_ci "Rear_Left.wav", 777c72fcc34Sopenharmony_ci "Rear_Right.wav", 778c72fcc34Sopenharmony_ci "Front_Center.wav", 779c72fcc34Sopenharmony_ci "Rear_Center.wav", /* FIXME: should be "Bass" or so */ 780c72fcc34Sopenharmony_ci "Side_Left.wav", 781c72fcc34Sopenharmony_ci "Side_Right.wav", 782c72fcc34Sopenharmony_ci "Channel_9.wav", 783c72fcc34Sopenharmony_ci "Channel_10.wav", 784c72fcc34Sopenharmony_ci "Channel_11.wav", 785c72fcc34Sopenharmony_ci "Channel_12.wav", 786c72fcc34Sopenharmony_ci "Channel_13.wav", 787c72fcc34Sopenharmony_ci "Channel_14.wav", 788c72fcc34Sopenharmony_ci "Channel_15.wav", 789c72fcc34Sopenharmony_ci "Channel_16.wav" 790c72fcc34Sopenharmony_ci }; 791c72fcc34Sopenharmony_ci 792c72fcc34Sopenharmony_ci if (given_test_wav_file) 793c72fcc34Sopenharmony_ci return check_wav_file(chn, given_test_wav_file); 794c72fcc34Sopenharmony_ci 795c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 796c72fcc34Sopenharmony_ci if (channel_map && (unsigned int)chn < channel_map->channels) { 797c72fcc34Sopenharmony_ci int channel = channel_map->pos[chn] - SND_CHMAP_FL; 798c72fcc34Sopenharmony_ci if (channel >= 0 && channel < MAX_CHANNELS) 799c72fcc34Sopenharmony_ci return check_wav_file(chn, wavs[channel]); 800c72fcc34Sopenharmony_ci } 801c72fcc34Sopenharmony_ci#endif 802c72fcc34Sopenharmony_ci 803c72fcc34Sopenharmony_ci return check_wav_file(chn, wavs[chn]); 804c72fcc34Sopenharmony_ci} 805c72fcc34Sopenharmony_ci 806c72fcc34Sopenharmony_cistatic int read_wav(uint16_t *buf, int channel, int offset, int bufsize) 807c72fcc34Sopenharmony_ci{ 808c72fcc34Sopenharmony_ci static FILE *wavfp = NULL; 809c72fcc34Sopenharmony_ci int size; 810c72fcc34Sopenharmony_ci 811c72fcc34Sopenharmony_ci if (in_aborting) 812c72fcc34Sopenharmony_ci return -EFAULT; 813c72fcc34Sopenharmony_ci 814c72fcc34Sopenharmony_ci if (! wav_file[channel]) { 815c72fcc34Sopenharmony_ci fprintf(stderr, _("Undefined channel %d\n"), channel); 816c72fcc34Sopenharmony_ci return -EINVAL; 817c72fcc34Sopenharmony_ci } 818c72fcc34Sopenharmony_ci 819c72fcc34Sopenharmony_ci if (offset >= wav_file_size[channel]) 820c72fcc34Sopenharmony_ci return 0; /* finished */ 821c72fcc34Sopenharmony_ci 822c72fcc34Sopenharmony_ci if (! offset) { 823c72fcc34Sopenharmony_ci if (wavfp) 824c72fcc34Sopenharmony_ci fclose(wavfp); 825c72fcc34Sopenharmony_ci wavfp = fopen(wav_file[channel], "r"); 826c72fcc34Sopenharmony_ci if (! wavfp) 827c72fcc34Sopenharmony_ci return -errno; 828c72fcc34Sopenharmony_ci if (fseek(wavfp, sizeof(struct wave_header), SEEK_SET) < 0) 829c72fcc34Sopenharmony_ci return -errno; 830c72fcc34Sopenharmony_ci } 831c72fcc34Sopenharmony_ci if (offset + bufsize > wav_file_size[channel]) 832c72fcc34Sopenharmony_ci bufsize = wav_file_size[channel] - offset; 833c72fcc34Sopenharmony_ci bufsize /= channels; 834c72fcc34Sopenharmony_ci for (size = 0; size < bufsize; size += 2) { 835c72fcc34Sopenharmony_ci unsigned int chn; 836c72fcc34Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 837c72fcc34Sopenharmony_ci if (chn == (unsigned int)channel) { 838c72fcc34Sopenharmony_ci if (fread(buf, 2, 1, wavfp) != 1) 839c72fcc34Sopenharmony_ci return size; 840c72fcc34Sopenharmony_ci } 841c72fcc34Sopenharmony_ci else 842c72fcc34Sopenharmony_ci *buf = 0; 843c72fcc34Sopenharmony_ci buf++; 844c72fcc34Sopenharmony_ci } 845c72fcc34Sopenharmony_ci } 846c72fcc34Sopenharmony_ci return size; 847c72fcc34Sopenharmony_ci} 848c72fcc34Sopenharmony_ci 849c72fcc34Sopenharmony_ci 850c72fcc34Sopenharmony_ci/* 851c72fcc34Sopenharmony_ci * Transfer method - write only 852c72fcc34Sopenharmony_ci */ 853c72fcc34Sopenharmony_ci 854c72fcc34Sopenharmony_cistatic int write_buffer(snd_pcm_t *handle, uint8_t *ptr, int cptr) 855c72fcc34Sopenharmony_ci{ 856c72fcc34Sopenharmony_ci int err; 857c72fcc34Sopenharmony_ci 858c72fcc34Sopenharmony_ci while (cptr > 0 && !in_aborting) { 859c72fcc34Sopenharmony_ci 860c72fcc34Sopenharmony_ci err = snd_pcm_writei(handle, ptr, cptr); 861c72fcc34Sopenharmony_ci 862c72fcc34Sopenharmony_ci if (err == -EAGAIN) 863c72fcc34Sopenharmony_ci continue; 864c72fcc34Sopenharmony_ci 865c72fcc34Sopenharmony_ci if (err < 0) { 866c72fcc34Sopenharmony_ci fprintf(stderr, _("Write error: %d,%s\n"), err, snd_strerror(err)); 867c72fcc34Sopenharmony_ci if ((err = xrun_recovery(handle, err)) < 0) { 868c72fcc34Sopenharmony_ci fprintf(stderr, _("xrun_recovery failed: %d,%s\n"), err, snd_strerror(err)); 869c72fcc34Sopenharmony_ci return err; 870c72fcc34Sopenharmony_ci } 871c72fcc34Sopenharmony_ci break; /* skip one period */ 872c72fcc34Sopenharmony_ci } 873c72fcc34Sopenharmony_ci 874c72fcc34Sopenharmony_ci ptr += snd_pcm_frames_to_bytes(handle, err); 875c72fcc34Sopenharmony_ci cptr -= err; 876c72fcc34Sopenharmony_ci } 877c72fcc34Sopenharmony_ci return 0; 878c72fcc34Sopenharmony_ci} 879c72fcc34Sopenharmony_ci 880c72fcc34Sopenharmony_cistatic int pattern; 881c72fcc34Sopenharmony_cistatic sine_t sine; 882c72fcc34Sopenharmony_cistatic pink_noise_t pink; 883c72fcc34Sopenharmony_cistatic st2095_noise_t st2095; 884c72fcc34Sopenharmony_ci 885c72fcc34Sopenharmony_cistatic void init_loop(void) 886c72fcc34Sopenharmony_ci{ 887c72fcc34Sopenharmony_ci switch (test_type) { 888c72fcc34Sopenharmony_ci case TEST_ST2095_NOISE: 889c72fcc34Sopenharmony_ci initialize_st2095_noise(&st2095, rate); 890c72fcc34Sopenharmony_ci break; 891c72fcc34Sopenharmony_ci case TEST_PINK_NOISE: 892c72fcc34Sopenharmony_ci initialize_pink_noise(&pink, 16); 893c72fcc34Sopenharmony_ci break; 894c72fcc34Sopenharmony_ci case TEST_SINE: 895c72fcc34Sopenharmony_ci init_sine(&sine); 896c72fcc34Sopenharmony_ci break; 897c72fcc34Sopenharmony_ci case TEST_PATTERN: 898c72fcc34Sopenharmony_ci pattern = 0; 899c72fcc34Sopenharmony_ci break; 900c72fcc34Sopenharmony_ci } 901c72fcc34Sopenharmony_ci} 902c72fcc34Sopenharmony_ci 903c72fcc34Sopenharmony_cistatic int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *frames) 904c72fcc34Sopenharmony_ci{ 905c72fcc34Sopenharmony_ci unsigned int cnt; 906c72fcc34Sopenharmony_ci int n; 907c72fcc34Sopenharmony_ci int err; 908c72fcc34Sopenharmony_ci 909c72fcc34Sopenharmony_ci fflush(stdout); 910c72fcc34Sopenharmony_ci if (test_type == TEST_WAV) { 911c72fcc34Sopenharmony_ci int bufsize = snd_pcm_frames_to_bytes(handle, period_size); 912c72fcc34Sopenharmony_ci cnt = 0; 913c72fcc34Sopenharmony_ci while ((err = read_wav((uint16_t *)frames, channel, cnt, bufsize)) > 0 && !in_aborting) { 914c72fcc34Sopenharmony_ci cnt += err; 915c72fcc34Sopenharmony_ci if ((err = write_buffer(handle, frames, 916c72fcc34Sopenharmony_ci snd_pcm_bytes_to_frames(handle, err * channels))) < 0) 917c72fcc34Sopenharmony_ci break; 918c72fcc34Sopenharmony_ci } 919c72fcc34Sopenharmony_ci if (buffer_size > cnt && !in_aborting) { 920c72fcc34Sopenharmony_ci snd_pcm_drain(handle); 921c72fcc34Sopenharmony_ci snd_pcm_prepare(handle); 922c72fcc34Sopenharmony_ci } 923c72fcc34Sopenharmony_ci return err; 924c72fcc34Sopenharmony_ci } 925c72fcc34Sopenharmony_ci 926c72fcc34Sopenharmony_ci 927c72fcc34Sopenharmony_ci if (periods <= 0) 928c72fcc34Sopenharmony_ci periods = 1; 929c72fcc34Sopenharmony_ci 930c72fcc34Sopenharmony_ci for(n = 0; n < periods && !in_aborting; n++) { 931c72fcc34Sopenharmony_ci if (test_type == TEST_PINK_NOISE) 932c72fcc34Sopenharmony_ci do_generate(frames, channel, period_size, generate_pink_noise, &pink); 933c72fcc34Sopenharmony_ci else if (test_type == TEST_PATTERN) 934c72fcc34Sopenharmony_ci do_generate(frames, channel, period_size, generate_pattern, &pattern); 935c72fcc34Sopenharmony_ci else if (test_type == TEST_ST2095_NOISE) { 936c72fcc34Sopenharmony_ci reset_st2095_noise_measurement(&st2095); 937c72fcc34Sopenharmony_ci do_generate(frames, channel, period_size, generate_st2095_noise, &st2095); 938c72fcc34Sopenharmony_ci printf(_("\tSMPTE ST-2095 noise batch was %2.2fdB RMS\n"), 939c72fcc34Sopenharmony_ci compute_st2095_noise_measurement(&st2095, period_size)); 940c72fcc34Sopenharmony_ci } else 941c72fcc34Sopenharmony_ci do_generate(frames, channel, period_size, generate_sine, &sine); 942c72fcc34Sopenharmony_ci 943c72fcc34Sopenharmony_ci if ((err = write_buffer(handle, frames, period_size)) < 0) 944c72fcc34Sopenharmony_ci return err; 945c72fcc34Sopenharmony_ci } 946c72fcc34Sopenharmony_ci if (buffer_size > n * period_size && !in_aborting) { 947c72fcc34Sopenharmony_ci snd_pcm_drain(handle); 948c72fcc34Sopenharmony_ci snd_pcm_prepare(handle); 949c72fcc34Sopenharmony_ci } 950c72fcc34Sopenharmony_ci return 0; 951c72fcc34Sopenharmony_ci} 952c72fcc34Sopenharmony_ci 953c72fcc34Sopenharmony_cistatic int prg_exit(int code) 954c72fcc34Sopenharmony_ci{ 955c72fcc34Sopenharmony_ci if (pcm_handle) 956c72fcc34Sopenharmony_ci snd_pcm_close(pcm_handle); 957c72fcc34Sopenharmony_ci exit(code); 958c72fcc34Sopenharmony_ci return code; 959c72fcc34Sopenharmony_ci} 960c72fcc34Sopenharmony_ci 961c72fcc34Sopenharmony_cistatic void signal_handler(int sig) 962c72fcc34Sopenharmony_ci{ 963c72fcc34Sopenharmony_ci if (in_aborting) 964c72fcc34Sopenharmony_ci return; 965c72fcc34Sopenharmony_ci 966c72fcc34Sopenharmony_ci in_aborting = 1; 967c72fcc34Sopenharmony_ci 968c72fcc34Sopenharmony_ci if (pcm_handle) 969c72fcc34Sopenharmony_ci snd_pcm_abort(pcm_handle); 970c72fcc34Sopenharmony_ci if (sig == SIGABRT) { 971c72fcc34Sopenharmony_ci pcm_handle = NULL; 972c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 973c72fcc34Sopenharmony_ci } 974c72fcc34Sopenharmony_ci signal(sig, signal_handler); 975c72fcc34Sopenharmony_ci} 976c72fcc34Sopenharmony_ci 977c72fcc34Sopenharmony_cistatic void help(void) 978c72fcc34Sopenharmony_ci{ 979c72fcc34Sopenharmony_ci const int *fmt; 980c72fcc34Sopenharmony_ci 981c72fcc34Sopenharmony_ci printf( 982c72fcc34Sopenharmony_ci _("Usage: speaker-test [OPTION]... \n" 983c72fcc34Sopenharmony_ci "-h,--help help\n" 984c72fcc34Sopenharmony_ci "-D,--device playback device\n" 985c72fcc34Sopenharmony_ci "-r,--rate stream rate in Hz\n" 986c72fcc34Sopenharmony_ci "-c,--channels count of channels in stream\n" 987c72fcc34Sopenharmony_ci "-f,--frequency sine wave frequency in Hz\n" 988c72fcc34Sopenharmony_ci "-F,--format sample format\n" 989c72fcc34Sopenharmony_ci "-b,--buffer ring buffer size in us\n" 990c72fcc34Sopenharmony_ci "-p,--period period size in us\n" 991c72fcc34Sopenharmony_ci "-P,--nperiods number of periods\n" 992c72fcc34Sopenharmony_ci "-t,--test pink=use pink noise, sine=use sine wave, st2095=use SMPTE ST-2095 noise, wav=WAV file\n" 993c72fcc34Sopenharmony_ci "-l,--nloops specify number of loops to test, 0 = infinite\n" 994c72fcc34Sopenharmony_ci "-s,--speaker single speaker test. Values 1=Left, 2=right, etc\n" 995c72fcc34Sopenharmony_ci "-w,--wavfile Use the given WAV file as a test sound\n" 996c72fcc34Sopenharmony_ci "-W,--wavdir Specify the directory containing WAV files\n" 997c72fcc34Sopenharmony_ci "-m,--chmap Specify the channel map to override\n" 998c72fcc34Sopenharmony_ci "-X,--force-frequency force frequencies outside the 30-8000hz range\n" 999c72fcc34Sopenharmony_ci "-S,--scale Scale of generated test tones in percent (default=80)\n" 1000c72fcc34Sopenharmony_ci "\n")); 1001c72fcc34Sopenharmony_ci printf(_("Recognized sample formats are:")); 1002c72fcc34Sopenharmony_ci for (fmt = supported_formats; *fmt >= 0; fmt++) { 1003c72fcc34Sopenharmony_ci const char *s = snd_pcm_format_name(*fmt); 1004c72fcc34Sopenharmony_ci if (s) 1005c72fcc34Sopenharmony_ci printf(" %s", s); 1006c72fcc34Sopenharmony_ci } 1007c72fcc34Sopenharmony_ci 1008c72fcc34Sopenharmony_ci printf("\n\n"); 1009c72fcc34Sopenharmony_ci} 1010c72fcc34Sopenharmony_ci 1011c72fcc34Sopenharmony_ciint main(int argc, char *argv[]) { 1012c72fcc34Sopenharmony_ci snd_pcm_t *handle; 1013c72fcc34Sopenharmony_ci int err, morehelp; 1014c72fcc34Sopenharmony_ci snd_pcm_hw_params_t *hwparams; 1015c72fcc34Sopenharmony_ci snd_pcm_sw_params_t *swparams; 1016c72fcc34Sopenharmony_ci uint8_t *frames; 1017c72fcc34Sopenharmony_ci unsigned int chn; 1018c72fcc34Sopenharmony_ci const int *fmt; 1019c72fcc34Sopenharmony_ci double time1,time2,time3; 1020c72fcc34Sopenharmony_ci unsigned int n, nloops; 1021c72fcc34Sopenharmony_ci struct timeval tv1,tv2; 1022c72fcc34Sopenharmony_ci int speakeroptset = 0; 1023c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 1024c72fcc34Sopenharmony_ci const char *chmap = NULL; 1025c72fcc34Sopenharmony_ci#endif 1026c72fcc34Sopenharmony_ci 1027c72fcc34Sopenharmony_ci static const struct option long_option[] = { 1028c72fcc34Sopenharmony_ci {"help", 0, NULL, 'h'}, 1029c72fcc34Sopenharmony_ci {"device", 1, NULL, 'D'}, 1030c72fcc34Sopenharmony_ci {"rate", 1, NULL, 'r'}, 1031c72fcc34Sopenharmony_ci {"channels", 1, NULL, 'c'}, 1032c72fcc34Sopenharmony_ci {"frequency", 1, NULL, 'f'}, 1033c72fcc34Sopenharmony_ci {"format", 1, NULL, 'F'}, 1034c72fcc34Sopenharmony_ci {"buffer", 1, NULL, 'b'}, 1035c72fcc34Sopenharmony_ci {"period", 1, NULL, 'p'}, 1036c72fcc34Sopenharmony_ci {"nperiods", 1, NULL, 'P'}, 1037c72fcc34Sopenharmony_ci {"test", 1, NULL, 't'}, 1038c72fcc34Sopenharmony_ci {"nloops", 1, NULL, 'l'}, 1039c72fcc34Sopenharmony_ci {"speaker", 1, NULL, 's'}, 1040c72fcc34Sopenharmony_ci {"wavfile", 1, NULL, 'w'}, 1041c72fcc34Sopenharmony_ci {"wavdir", 1, NULL, 'W'}, 1042c72fcc34Sopenharmony_ci {"debug", 0, NULL, 'd'}, 1043c72fcc34Sopenharmony_ci {"force-frequency", 0, NULL, 'X'}, 1044c72fcc34Sopenharmony_ci {"scale", 1, NULL, 'S'}, 1045c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 1046c72fcc34Sopenharmony_ci {"chmap", 1, NULL, 'm'}, 1047c72fcc34Sopenharmony_ci#endif 1048c72fcc34Sopenharmony_ci {NULL, 0, NULL, 0 }, 1049c72fcc34Sopenharmony_ci }; 1050c72fcc34Sopenharmony_ci 1051c72fcc34Sopenharmony_ci#ifdef ENABLE_NLS 1052c72fcc34Sopenharmony_ci setlocale(LC_ALL, ""); 1053c72fcc34Sopenharmony_ci textdomain(PACKAGE); 1054c72fcc34Sopenharmony_ci#endif 1055c72fcc34Sopenharmony_ci 1056c72fcc34Sopenharmony_ci snd_pcm_hw_params_alloca(&hwparams); 1057c72fcc34Sopenharmony_ci snd_pcm_sw_params_alloca(&swparams); 1058c72fcc34Sopenharmony_ci 1059c72fcc34Sopenharmony_ci nloops = 0; 1060c72fcc34Sopenharmony_ci morehelp = 0; 1061c72fcc34Sopenharmony_ci 1062c72fcc34Sopenharmony_ci printf("\nspeaker-test %s\n\n", SND_UTIL_VERSION_STR); 1063c72fcc34Sopenharmony_ci while (1) { 1064c72fcc34Sopenharmony_ci int c; 1065c72fcc34Sopenharmony_ci 1066c72fcc34Sopenharmony_ci if ((c = getopt_long(argc, argv, "hD:r:c:f:F:b:p:P:t:l:s:w:W:d:XS:" 1067c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 1068c72fcc34Sopenharmony_ci "m:" 1069c72fcc34Sopenharmony_ci#endif 1070c72fcc34Sopenharmony_ci , long_option, NULL)) < 0) 1071c72fcc34Sopenharmony_ci break; 1072c72fcc34Sopenharmony_ci 1073c72fcc34Sopenharmony_ci switch (c) { 1074c72fcc34Sopenharmony_ci case 'h': 1075c72fcc34Sopenharmony_ci morehelp++; 1076c72fcc34Sopenharmony_ci break; 1077c72fcc34Sopenharmony_ci case 'D': 1078c72fcc34Sopenharmony_ci device = strdup(optarg); 1079c72fcc34Sopenharmony_ci break; 1080c72fcc34Sopenharmony_ci case 'F': 1081c72fcc34Sopenharmony_ci format = snd_pcm_format_value(optarg); 1082c72fcc34Sopenharmony_ci for (fmt = supported_formats; *fmt >= 0; fmt++) 1083c72fcc34Sopenharmony_ci if (*fmt == format) 1084c72fcc34Sopenharmony_ci break; 1085c72fcc34Sopenharmony_ci if (*fmt < 0) { 1086c72fcc34Sopenharmony_ci fprintf(stderr, "Format %s is not supported...\n", snd_pcm_format_name(format)); 1087c72fcc34Sopenharmony_ci exit(EXIT_FAILURE); 1088c72fcc34Sopenharmony_ci } 1089c72fcc34Sopenharmony_ci break; 1090c72fcc34Sopenharmony_ci case 'r': 1091c72fcc34Sopenharmony_ci rate = atoi(optarg); 1092c72fcc34Sopenharmony_ci rate = rate < 4000 ? 4000 : rate; 1093c72fcc34Sopenharmony_ci rate = rate > 768000 ? 768000 : rate; 1094c72fcc34Sopenharmony_ci break; 1095c72fcc34Sopenharmony_ci case 'c': 1096c72fcc34Sopenharmony_ci channels = atoi(optarg); 1097c72fcc34Sopenharmony_ci channels = channels < 1 ? 1 : channels; 1098c72fcc34Sopenharmony_ci channels = channels > 1024 ? 1024 : channels; 1099c72fcc34Sopenharmony_ci break; 1100c72fcc34Sopenharmony_ci case 'f': 1101c72fcc34Sopenharmony_ci freq = atof(optarg); 1102c72fcc34Sopenharmony_ci break; 1103c72fcc34Sopenharmony_ci case 'b': 1104c72fcc34Sopenharmony_ci buffer_time = atoi(optarg); 1105c72fcc34Sopenharmony_ci buffer_time = buffer_time > 100000000 ? 100000000 : buffer_time; 1106c72fcc34Sopenharmony_ci break; 1107c72fcc34Sopenharmony_ci case 'p': 1108c72fcc34Sopenharmony_ci period_time = atoi(optarg); 1109c72fcc34Sopenharmony_ci period_time = period_time > 100000000 ? 100000000 : period_time; 1110c72fcc34Sopenharmony_ci break; 1111c72fcc34Sopenharmony_ci case 'P': 1112c72fcc34Sopenharmony_ci nperiods = atoi(optarg); 1113c72fcc34Sopenharmony_ci if (nperiods < 2 || nperiods > 1024) { 1114c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid number of periods %d\n"), nperiods); 1115c72fcc34Sopenharmony_ci exit(1); 1116c72fcc34Sopenharmony_ci } 1117c72fcc34Sopenharmony_ci break; 1118c72fcc34Sopenharmony_ci case 't': 1119c72fcc34Sopenharmony_ci if (*optarg == 'p') 1120c72fcc34Sopenharmony_ci test_type = TEST_PINK_NOISE; 1121c72fcc34Sopenharmony_ci else if (*optarg == 's') { 1122c72fcc34Sopenharmony_ci if (optarg[1] == 'i') 1123c72fcc34Sopenharmony_ci test_type = TEST_SINE; 1124c72fcc34Sopenharmony_ci else if (optarg[1] == 't') 1125c72fcc34Sopenharmony_ci test_type = TEST_ST2095_NOISE; 1126c72fcc34Sopenharmony_ci else { 1127c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid test type %s\n"), optarg); 1128c72fcc34Sopenharmony_ci exit(1); 1129c72fcc34Sopenharmony_ci } 1130c72fcc34Sopenharmony_ci } else if (*optarg == 'w') 1131c72fcc34Sopenharmony_ci test_type = TEST_WAV; 1132c72fcc34Sopenharmony_ci else if (*optarg == 't') 1133c72fcc34Sopenharmony_ci test_type = TEST_PATTERN; 1134c72fcc34Sopenharmony_ci else if (isdigit(*optarg)) { 1135c72fcc34Sopenharmony_ci test_type = atoi(optarg); 1136c72fcc34Sopenharmony_ci if (test_type < TEST_PINK_NOISE || test_type > TEST_PATTERN) { 1137c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid test type %s\n"), optarg); 1138c72fcc34Sopenharmony_ci exit(1); 1139c72fcc34Sopenharmony_ci } 1140c72fcc34Sopenharmony_ci } else { 1141c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid test type %s\n"), optarg); 1142c72fcc34Sopenharmony_ci exit(1); 1143c72fcc34Sopenharmony_ci } 1144c72fcc34Sopenharmony_ci break; 1145c72fcc34Sopenharmony_ci case 'l': 1146c72fcc34Sopenharmony_ci nloops = atoi(optarg); 1147c72fcc34Sopenharmony_ci break; 1148c72fcc34Sopenharmony_ci case 's': 1149c72fcc34Sopenharmony_ci speaker = atoi(optarg); 1150c72fcc34Sopenharmony_ci speaker = speaker < 1 ? 0 : speaker; 1151c72fcc34Sopenharmony_ci speakeroptset = 1; 1152c72fcc34Sopenharmony_ci break; 1153c72fcc34Sopenharmony_ci case 'w': 1154c72fcc34Sopenharmony_ci given_test_wav_file = optarg; 1155c72fcc34Sopenharmony_ci break; 1156c72fcc34Sopenharmony_ci case 'W': 1157c72fcc34Sopenharmony_ci wav_file_dir = optarg; 1158c72fcc34Sopenharmony_ci break; 1159c72fcc34Sopenharmony_ci case 'd': 1160c72fcc34Sopenharmony_ci debug = 1; 1161c72fcc34Sopenharmony_ci break; 1162c72fcc34Sopenharmony_ci case 'X': 1163c72fcc34Sopenharmony_ci force_frequency = 1; 1164c72fcc34Sopenharmony_ci break; 1165c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 1166c72fcc34Sopenharmony_ci case 'm': 1167c72fcc34Sopenharmony_ci chmap = optarg; 1168c72fcc34Sopenharmony_ci break; 1169c72fcc34Sopenharmony_ci#endif 1170c72fcc34Sopenharmony_ci case 'S': 1171c72fcc34Sopenharmony_ci generator_scale = atoi(optarg) / 100.0; 1172c72fcc34Sopenharmony_ci break; 1173c72fcc34Sopenharmony_ci default: 1174c72fcc34Sopenharmony_ci fprintf(stderr, _("Unknown option '%c'\n"), c); 1175c72fcc34Sopenharmony_ci exit(EXIT_FAILURE); 1176c72fcc34Sopenharmony_ci break; 1177c72fcc34Sopenharmony_ci } 1178c72fcc34Sopenharmony_ci } 1179c72fcc34Sopenharmony_ci 1180c72fcc34Sopenharmony_ci if (morehelp) { 1181c72fcc34Sopenharmony_ci help(); 1182c72fcc34Sopenharmony_ci exit(EXIT_SUCCESS); 1183c72fcc34Sopenharmony_ci } 1184c72fcc34Sopenharmony_ci 1185c72fcc34Sopenharmony_ci if (speakeroptset) { 1186c72fcc34Sopenharmony_ci speaker = speaker > channels ? 0 : speaker; 1187c72fcc34Sopenharmony_ci if (speaker==0) { 1188c72fcc34Sopenharmony_ci fprintf(stderr, _("Invalid parameter for -s option.\n")); 1189c72fcc34Sopenharmony_ci exit(EXIT_FAILURE); 1190c72fcc34Sopenharmony_ci } 1191c72fcc34Sopenharmony_ci } 1192c72fcc34Sopenharmony_ci 1193c72fcc34Sopenharmony_ci if (!force_frequency) { 1194c72fcc34Sopenharmony_ci freq = freq < 30.0 ? 30.0 : freq; 1195c72fcc34Sopenharmony_ci freq = freq > 8000.0 ? 8000.0 : freq; 1196c72fcc34Sopenharmony_ci } else { 1197c72fcc34Sopenharmony_ci freq = freq < 1.0 ? 1.0 : freq; 1198c72fcc34Sopenharmony_ci } 1199c72fcc34Sopenharmony_ci 1200c72fcc34Sopenharmony_ci if (test_type == TEST_WAV) 1201c72fcc34Sopenharmony_ci format = SND_PCM_FORMAT_S16_LE; /* fixed format */ 1202c72fcc34Sopenharmony_ci 1203c72fcc34Sopenharmony_ci printf(_("Playback device is %s\n"), device); 1204c72fcc34Sopenharmony_ci printf(_("Stream parameters are %iHz, %s, %i channels\n"), rate, snd_pcm_format_name(format), channels); 1205c72fcc34Sopenharmony_ci switch (test_type) { 1206c72fcc34Sopenharmony_ci case TEST_ST2095_NOISE: 1207c72fcc34Sopenharmony_ci printf(_("Using SMPTE ST-2095 -18.5dB AES FS band-limited pink noise\n")); 1208c72fcc34Sopenharmony_ci break; 1209c72fcc34Sopenharmony_ci case TEST_PINK_NOISE: 1210c72fcc34Sopenharmony_ci printf(_("Using 16 octaves of pink noise\n")); 1211c72fcc34Sopenharmony_ci break; 1212c72fcc34Sopenharmony_ci case TEST_SINE: 1213c72fcc34Sopenharmony_ci printf(_("Sine wave rate is %.4fHz\n"), freq); 1214c72fcc34Sopenharmony_ci break; 1215c72fcc34Sopenharmony_ci case TEST_WAV: 1216c72fcc34Sopenharmony_ci printf(_("WAV file(s)\n")); 1217c72fcc34Sopenharmony_ci break; 1218c72fcc34Sopenharmony_ci 1219c72fcc34Sopenharmony_ci } 1220c72fcc34Sopenharmony_ci 1221c72fcc34Sopenharmony_ci signal(SIGINT, signal_handler); 1222c72fcc34Sopenharmony_ci signal(SIGTERM, signal_handler); 1223c72fcc34Sopenharmony_ci signal(SIGABRT, signal_handler); 1224c72fcc34Sopenharmony_ci 1225c72fcc34Sopenharmony_ci if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { 1226c72fcc34Sopenharmony_ci printf(_("Playback open error: %d,%s\n"), err,snd_strerror(err)); 1227c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1228c72fcc34Sopenharmony_ci } 1229c72fcc34Sopenharmony_ci pcm_handle = handle; 1230c72fcc34Sopenharmony_ci 1231c72fcc34Sopenharmony_ci if ((err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { 1232c72fcc34Sopenharmony_ci printf(_("Setting of hwparams failed: %s\n"), snd_strerror(err)); 1233c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1234c72fcc34Sopenharmony_ci } 1235c72fcc34Sopenharmony_ci if ((err = set_swparams(handle, swparams)) < 0) { 1236c72fcc34Sopenharmony_ci printf(_("Setting of swparams failed: %s\n"), snd_strerror(err)); 1237c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1238c72fcc34Sopenharmony_ci } 1239c72fcc34Sopenharmony_ci 1240c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 1241c72fcc34Sopenharmony_ci err = config_chmap(handle, chmap); 1242c72fcc34Sopenharmony_ci if (err < 0) 1243c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1244c72fcc34Sopenharmony_ci#endif 1245c72fcc34Sopenharmony_ci 1246c72fcc34Sopenharmony_ci if (debug) { 1247c72fcc34Sopenharmony_ci snd_output_t *log; 1248c72fcc34Sopenharmony_ci err = snd_output_stdio_attach(&log, stderr, 0); 1249c72fcc34Sopenharmony_ci if (err >= 0) { 1250c72fcc34Sopenharmony_ci snd_pcm_dump(handle, log); 1251c72fcc34Sopenharmony_ci snd_output_close(log); 1252c72fcc34Sopenharmony_ci } 1253c72fcc34Sopenharmony_ci } 1254c72fcc34Sopenharmony_ci 1255c72fcc34Sopenharmony_ci frames = malloc(snd_pcm_frames_to_bytes(handle, period_size)); 1256c72fcc34Sopenharmony_ci if (frames == NULL) { 1257c72fcc34Sopenharmony_ci fprintf(stderr, _("No enough memory\n")); 1258c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1259c72fcc34Sopenharmony_ci } 1260c72fcc34Sopenharmony_ci 1261c72fcc34Sopenharmony_ci init_loop(); 1262c72fcc34Sopenharmony_ci 1263c72fcc34Sopenharmony_ci if (speaker==0) { 1264c72fcc34Sopenharmony_ci 1265c72fcc34Sopenharmony_ci if (test_type == TEST_WAV) { 1266c72fcc34Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 1267c72fcc34Sopenharmony_ci if (setup_wav_file(get_speaker_channel(chn)) < 0) 1268c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1269c72fcc34Sopenharmony_ci } 1270c72fcc34Sopenharmony_ci } 1271c72fcc34Sopenharmony_ci 1272c72fcc34Sopenharmony_ci for (n = 0; (! nloops || n < nloops) && !in_aborting; n++) { 1273c72fcc34Sopenharmony_ci 1274c72fcc34Sopenharmony_ci gettimeofday(&tv1, NULL); 1275c72fcc34Sopenharmony_ci for(chn = 0; chn < channels; chn++) { 1276c72fcc34Sopenharmony_ci int channel = get_speaker_channel(chn); 1277c72fcc34Sopenharmony_ci printf(" %d - %s\n", channel, get_channel_name(channel)); 1278c72fcc34Sopenharmony_ci 1279c72fcc34Sopenharmony_ci err = write_loop(handle, channel, ((rate*3)/period_size), frames); 1280c72fcc34Sopenharmony_ci 1281c72fcc34Sopenharmony_ci if (err < 0) { 1282c72fcc34Sopenharmony_ci fprintf(stderr, _("Transfer failed: %s\n"), snd_strerror(err)); 1283c72fcc34Sopenharmony_ci prg_exit(EXIT_SUCCESS); 1284c72fcc34Sopenharmony_ci } 1285c72fcc34Sopenharmony_ci } 1286c72fcc34Sopenharmony_ci gettimeofday(&tv2, NULL); 1287c72fcc34Sopenharmony_ci time1 = (double)tv1.tv_sec + ((double)tv1.tv_usec / 1000000.0); 1288c72fcc34Sopenharmony_ci time2 = (double)tv2.tv_sec + ((double)tv2.tv_usec / 1000000.0); 1289c72fcc34Sopenharmony_ci time3 = time2 - time1; 1290c72fcc34Sopenharmony_ci printf(_("Time per period = %lf\n"), time3 ); 1291c72fcc34Sopenharmony_ci } 1292c72fcc34Sopenharmony_ci } else { 1293c72fcc34Sopenharmony_ci chn = get_speaker_channel(speaker - 1); 1294c72fcc34Sopenharmony_ci 1295c72fcc34Sopenharmony_ci if (test_type == TEST_WAV) { 1296c72fcc34Sopenharmony_ci if (setup_wav_file(chn) < 0) 1297c72fcc34Sopenharmony_ci prg_exit(EXIT_FAILURE); 1298c72fcc34Sopenharmony_ci } 1299c72fcc34Sopenharmony_ci 1300c72fcc34Sopenharmony_ci printf(" - %s\n", get_channel_name(chn)); 1301c72fcc34Sopenharmony_ci err = write_loop(handle, chn, ((rate*5)/period_size), frames); 1302c72fcc34Sopenharmony_ci 1303c72fcc34Sopenharmony_ci if (err < 0) { 1304c72fcc34Sopenharmony_ci fprintf(stderr, _("Transfer failed: %s\n"), snd_strerror(err)); 1305c72fcc34Sopenharmony_ci } 1306c72fcc34Sopenharmony_ci } 1307c72fcc34Sopenharmony_ci 1308c72fcc34Sopenharmony_ci snd_pcm_drain(handle); 1309c72fcc34Sopenharmony_ci 1310c72fcc34Sopenharmony_ci free(frames); 1311c72fcc34Sopenharmony_ci#ifdef CONFIG_SUPPORT_CHMAP 1312c72fcc34Sopenharmony_ci free(ordered_channels); 1313c72fcc34Sopenharmony_ci#endif 1314c72fcc34Sopenharmony_ci 1315c72fcc34Sopenharmony_ci return prg_exit(EXIT_SUCCESS); 1316c72fcc34Sopenharmony_ci} 1317