1*88447a05SGarrett D'Amore /* 2*88447a05SGarrett D'Amore * CDDL HEADER START 3*88447a05SGarrett D'Amore * 4*88447a05SGarrett D'Amore * The contents of this file are subject to the terms of the 5*88447a05SGarrett D'Amore * Common Development and Distribution License (the "License"). 6*88447a05SGarrett D'Amore * You may not use this file except in compliance with the License. 7*88447a05SGarrett D'Amore * 8*88447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*88447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 10*88447a05SGarrett D'Amore * See the License for the specific language governing permissions 11*88447a05SGarrett D'Amore * and limitations under the License. 12*88447a05SGarrett D'Amore * 13*88447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 14*88447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*88447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 16*88447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 17*88447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 18*88447a05SGarrett D'Amore * 19*88447a05SGarrett D'Amore * CDDL HEADER END 20*88447a05SGarrett D'Amore */ 21*88447a05SGarrett D'Amore /* 22*88447a05SGarrett D'Amore * Copyright (C) 4Front Technologies 1996-2008. 23*88447a05SGarrett D'Amore * 24*88447a05SGarrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25*88447a05SGarrett D'Amore * Use is subject to license terms. 26*88447a05SGarrett D'Amore */ 27*88447a05SGarrett D'Amore /* 28*88447a05SGarrett D'Amore * This program is a general purpose test facility for audio output. 29*88447a05SGarrett D'Amore * It does not test record. 30*88447a05SGarrett D'Amore * 31*88447a05SGarrett D'Amore * The wavedata.c and wavedata.h files contain the actual samples compressed 32*88447a05SGarrett D'Amore * using the MS ADPCM algorithm. 33*88447a05SGarrett D'Amore */ 34*88447a05SGarrett D'Amore 35*88447a05SGarrett D'Amore #include <stdio.h> 36*88447a05SGarrett D'Amore #include <stdlib.h> 37*88447a05SGarrett D'Amore #include <unistd.h> 38*88447a05SGarrett D'Amore #include <fcntl.h> 39*88447a05SGarrett D'Amore #include <string.h> 40*88447a05SGarrett D'Amore #include <errno.h> 41*88447a05SGarrett D'Amore #include <unistd.h> 42*88447a05SGarrett D'Amore #include <sys/time.h> 43*88447a05SGarrett D'Amore #include <sys/ioctl.h> 44*88447a05SGarrett D'Amore #include <sys/utsname.h> 45*88447a05SGarrett D'Amore #include <sys/soundcard.h> 46*88447a05SGarrett D'Amore #include <inttypes.h> 47*88447a05SGarrett D'Amore #include <locale.h> 48*88447a05SGarrett D'Amore 49*88447a05SGarrett D'Amore #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 50*88447a05SGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 51*88447a05SGarrett D'Amore #endif 52*88447a05SGarrett D'Amore 53*88447a05SGarrett D'Amore #define _(s) gettext(s) 54*88447a05SGarrett D'Amore 55*88447a05SGarrett D'Amore /* 56*88447a05SGarrett D'Amore * Channel selectors 57*88447a05SGarrett D'Amore */ 58*88447a05SGarrett D'Amore #define CH_LEFT (1 << 0) 59*88447a05SGarrett D'Amore #define CH_RIGHT (1 << 1) 60*88447a05SGarrett D'Amore #define CH_LREAR4 (1 << 2) /* quadraphonic */ 61*88447a05SGarrett D'Amore #define CH_RREAR4 (1 << 3) /* quadraphonic */ 62*88447a05SGarrett D'Amore #define CH_CENTER (1 << 2) 63*88447a05SGarrett D'Amore #define CH_LFE (1 << 3) 64*88447a05SGarrett D'Amore #define CH_LSURR (1 << 4) 65*88447a05SGarrett D'Amore #define CH_RSURR (1 << 5) 66*88447a05SGarrett D'Amore #define CH_LREAR (1 << 6) 67*88447a05SGarrett D'Amore #define CH_RREAR (1 << 7) 68*88447a05SGarrett D'Amore #define CH_STEREO (CH_LEFT|CH_RIGHT) 69*88447a05SGarrett D'Amore #define CH_4 (CH_STEREO | CH_LREAR4 | CH_RREAR4) 70*88447a05SGarrett D'Amore #define CH_5 (CH_STEREO | CH_CENTER | CH_LSURR | CH_RSURR) 71*88447a05SGarrett D'Amore #define CH_7 (CH_5 | CH_LREAR | CH_RREAR) 72*88447a05SGarrett D'Amore 73*88447a05SGarrett D'Amore typedef struct chancfg { 74*88447a05SGarrett D'Amore int mask; 75*88447a05SGarrett D'Amore const char *name; 76*88447a05SGarrett D'Amore unsigned flags; 77*88447a05SGarrett D'Amore int16_t *data; 78*88447a05SGarrett D'Amore int len; 79*88447a05SGarrett D'Amore } chancfg_t; 80*88447a05SGarrett D'Amore 81*88447a05SGarrett D'Amore typedef struct testcfg { 82*88447a05SGarrett D'Amore int nchan; 83*88447a05SGarrett D'Amore chancfg_t *tests[16]; 84*88447a05SGarrett D'Amore } testcfg_t; 85*88447a05SGarrett D'Amore 86*88447a05SGarrett D'Amore #define CFLAG_LFE 0x1 /* lfe channel - not full range */ 87*88447a05SGarrett D'Amore 88*88447a05SGarrett D'Amore /* 89*88447a05SGarrett D'Amore * TRANSLATION_NOTE : The following strings are displayed during progress. 90*88447a05SGarrett D'Amore * Its important for alignment that they have the same displayed length. 91*88447a05SGarrett D'Amore */ 92*88447a05SGarrett D'Amore #define NM_LEFT "\t<left> ................" 93*88447a05SGarrett D'Amore #define NM_RIGHT "\t<right> ..............." 94*88447a05SGarrett D'Amore #define NM_LREAR "\t<left rear> ..........." 95*88447a05SGarrett D'Amore #define NM_RREAR "\t<right rear> .........." 96*88447a05SGarrett D'Amore #define NM_LSIDE "\t<left side> ..........." 97*88447a05SGarrett D'Amore #define NM_RSIDE "\t<right side> .........." 98*88447a05SGarrett D'Amore #define NM_CENTER "\t<center> .............." 99*88447a05SGarrett D'Amore #define NM_LFE "\t<lfe> ................." 100*88447a05SGarrett D'Amore #define NM_STEREO "\t<stereo> .............." 101*88447a05SGarrett D'Amore #define NM_40 "\t<4.0 surround> ........" 102*88447a05SGarrett D'Amore #define NM_50 "\t<5.0 surround> ........" 103*88447a05SGarrett D'Amore #define NM_70 "\t<7.0 surround> ........" 104*88447a05SGarrett D'Amore 105*88447a05SGarrett D'Amore chancfg_t ch_left = { CH_LEFT, NM_LEFT, 0 }; 106*88447a05SGarrett D'Amore chancfg_t ch_right = { CH_RIGHT, NM_RIGHT, 0 }; 107*88447a05SGarrett D'Amore chancfg_t ch_stereo = { CH_STEREO, NM_STEREO, 0 }; 108*88447a05SGarrett D'Amore 109*88447a05SGarrett D'Amore chancfg_t ch_center = { CH_CENTER, NM_CENTER, 0 }; 110*88447a05SGarrett D'Amore chancfg_t ch_lfe = { CH_LFE, NM_LFE, CFLAG_LFE }; 111*88447a05SGarrett D'Amore 112*88447a05SGarrett D'Amore chancfg_t ch_lsurr_4 = { (1 << 2), NM_LREAR, 0 }; 113*88447a05SGarrett D'Amore chancfg_t ch_rsurr_4 = { (1 << 3), NM_RREAR, 0 }; 114*88447a05SGarrett D'Amore chancfg_t ch_4 = { CH_4, NM_40, 0 }; 115*88447a05SGarrett D'Amore 116*88447a05SGarrett D'Amore chancfg_t ch_lsurr_5 = { CH_LSURR, NM_LREAR, 0 }; 117*88447a05SGarrett D'Amore chancfg_t ch_rsurr_5 = { CH_RSURR, NM_RREAR, 0 }; 118*88447a05SGarrett D'Amore chancfg_t ch_5 = { CH_5, NM_50, 0 }; 119*88447a05SGarrett D'Amore 120*88447a05SGarrett D'Amore chancfg_t ch_lsurr_7 = { CH_LSURR, NM_LSIDE, 0 }; 121*88447a05SGarrett D'Amore chancfg_t ch_rsurr_7 = { CH_RSURR, NM_RSIDE, 0 }; 122*88447a05SGarrett D'Amore chancfg_t ch_lrear_7 = { CH_LREAR, NM_LREAR, 0 }; 123*88447a05SGarrett D'Amore chancfg_t ch_rrear_7 = { CH_RREAR, NM_RREAR, 0 }; 124*88447a05SGarrett D'Amore chancfg_t ch_7 = { CH_7, NM_70, 0 }; 125*88447a05SGarrett D'Amore 126*88447a05SGarrett D'Amore testcfg_t test_stereo = { 127*88447a05SGarrett D'Amore 2, { &ch_left, &ch_right, &ch_stereo, NULL } 128*88447a05SGarrett D'Amore }; 129*88447a05SGarrett D'Amore 130*88447a05SGarrett D'Amore testcfg_t test_quad = { 131*88447a05SGarrett D'Amore 4, { &ch_left, &ch_right, &ch_stereo, 132*88447a05SGarrett D'Amore &ch_lsurr_4, &ch_rsurr_4, &ch_4, NULL } 133*88447a05SGarrett D'Amore }; 134*88447a05SGarrett D'Amore 135*88447a05SGarrett D'Amore testcfg_t test_51 = { 136*88447a05SGarrett D'Amore 6, { &ch_left, &ch_right, &ch_stereo, 137*88447a05SGarrett D'Amore &ch_lsurr_5, &ch_rsurr_5, &ch_center, &ch_lfe, &ch_5, NULL } 138*88447a05SGarrett D'Amore }; 139*88447a05SGarrett D'Amore 140*88447a05SGarrett D'Amore testcfg_t test_71 = { 141*88447a05SGarrett D'Amore 8, { &ch_left, &ch_right, &ch_stereo, 142*88447a05SGarrett D'Amore &ch_lsurr_7, &ch_rsurr_7, &ch_lrear_7, &ch_rrear_7, 143*88447a05SGarrett D'Amore &ch_center, &ch_lfe, &ch_7, NULL } 144*88447a05SGarrett D'Amore }; 145*88447a05SGarrett D'Amore 146*88447a05SGarrett D'Amore /* 147*88447a05SGarrett D'Amore * uncompress_wave() is defined in wavedata.c. It expands the audio 148*88447a05SGarrett D'Amore * samples stored in wavedata.h and returns the lenghth of the 149*88447a05SGarrett D'Amore * uncompressed version in bytes. 150*88447a05SGarrett D'Amore * 151*88447a05SGarrett D'Amore * The uncompressed wave data format is 16 bit (native) stereo 152*88447a05SGarrett D'Amore * recorded at 48000 Hz. 153*88447a05SGarrett D'Amore */ 154*88447a05SGarrett D'Amore extern int uncompress_wave(short *outbuf); 155*88447a05SGarrett D'Amore 156*88447a05SGarrett D'Amore static int data_len; 157*88447a05SGarrett D'Amore 158*88447a05SGarrett D'Amore #define MAXDEVICE 64 159*88447a05SGarrett D'Amore extern void describe_error(int); 160*88447a05SGarrett D'Amore 161*88447a05SGarrett D'Amore #define SAMPLE_RATE 48000 162*88447a05SGarrett D'Amore 163*88447a05SGarrett D'Amore /* 164*88447a05SGarrett D'Amore * Operating mode flags (set from the command line). 165*88447a05SGarrett D'Amore */ 166*88447a05SGarrett D'Amore #define TF_LOOP 0x00000010 /* Loop until interrupted */ 167*88447a05SGarrett D'Amore 168*88447a05SGarrett D'Amore static int mixerfd; 169*88447a05SGarrett D'Amore static int num_devices_tested = 0; 170*88447a05SGarrett D'Amore 171*88447a05SGarrett D'Amore static short *sample_buf; 172*88447a05SGarrett D'Amore 173*88447a05SGarrett D'Amore void 174*88447a05SGarrett D'Amore prepare(testcfg_t *tcfg) 175*88447a05SGarrett D'Amore { 176*88447a05SGarrett D'Amore int nsamples; 177*88447a05SGarrett D'Amore int i; 178*88447a05SGarrett D'Amore chancfg_t *ccfg; 179*88447a05SGarrett D'Amore if ((sample_buf = malloc(2000000)) == NULL) { 180*88447a05SGarrett D'Amore perror("malloc"); 181*88447a05SGarrett D'Amore exit(-1); 182*88447a05SGarrett D'Amore } 183*88447a05SGarrett D'Amore 184*88447a05SGarrett D'Amore data_len = uncompress_wave(sample_buf); 185*88447a05SGarrett D'Amore nsamples = (data_len / sizeof (int16_t)) / 2; 186*88447a05SGarrett D'Amore 187*88447a05SGarrett D'Amore for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) { 188*88447a05SGarrett D'Amore int16_t *src, *dst; 189*88447a05SGarrett D'Amore int ch; 190*88447a05SGarrett D'Amore int samp; 191*88447a05SGarrett D'Amore 192*88447a05SGarrett D'Amore src = sample_buf; 193*88447a05SGarrett D'Amore 194*88447a05SGarrett D'Amore if (ccfg->flags != CFLAG_LFE) { 195*88447a05SGarrett D'Amore ccfg->len = nsamples * tcfg->nchan * sizeof (int16_t); 196*88447a05SGarrett D'Amore ccfg->data = malloc(ccfg->len); 197*88447a05SGarrett D'Amore if ((dst = ccfg->data) == NULL) { 198*88447a05SGarrett D'Amore perror("malloc"); 199*88447a05SGarrett D'Amore exit(-1); 200*88447a05SGarrett D'Amore } 201*88447a05SGarrett D'Amore for (samp = 0; samp < nsamples; samp++) { 202*88447a05SGarrett D'Amore for (ch = 0; ch < tcfg->nchan; ch++) { 203*88447a05SGarrett D'Amore *dst = ((1U << ch) & ccfg->mask) ? 204*88447a05SGarrett D'Amore *src : 0; 205*88447a05SGarrett D'Amore dst++; 206*88447a05SGarrett D'Amore } 207*88447a05SGarrett D'Amore src += 2; 208*88447a05SGarrett D'Amore } 209*88447a05SGarrett D'Amore } else { 210*88447a05SGarrett D'Amore /* Skip LFE for now */ 211*88447a05SGarrett D'Amore ccfg->len = 0; 212*88447a05SGarrett D'Amore } 213*88447a05SGarrett D'Amore } 214*88447a05SGarrett D'Amore } 215*88447a05SGarrett D'Amore 216*88447a05SGarrett D'Amore /* 217*88447a05SGarrett D'Amore * The testdsp() routine checks the capabilities of a given audio device number 218*88447a05SGarrett D'Amore * (parameter n) and decides if the test sound needs to be played. 219*88447a05SGarrett D'Amore */ 220*88447a05SGarrett D'Amore 221*88447a05SGarrett D'Amore /*ARGSUSED*/ 222*88447a05SGarrett D'Amore int 223*88447a05SGarrett D'Amore testdsp(int hd, int flags, testcfg_t *tcfg) 224*88447a05SGarrett D'Amore { 225*88447a05SGarrett D'Amore float ratio; 226*88447a05SGarrett D'Amore struct timeval t1, t2; 227*88447a05SGarrett D'Amore unsigned long t; 228*88447a05SGarrett D'Amore int sample_rate; 229*88447a05SGarrett D'Amore int delay; 230*88447a05SGarrett D'Amore long long total_bytes = 0; 231*88447a05SGarrett D'Amore unsigned int tmp, caps; 232*88447a05SGarrett D'Amore int i; 233*88447a05SGarrett D'Amore chancfg_t *ccfg; 234*88447a05SGarrett D'Amore 235*88447a05SGarrett D'Amore caps = 0; 236*88447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_GETCAPS, &caps) == -1) { 237*88447a05SGarrett D'Amore perror("SNDCTL_DSP_GETCAPS"); 238*88447a05SGarrett D'Amore return (-1); 239*88447a05SGarrett D'Amore } 240*88447a05SGarrett D'Amore 241*88447a05SGarrett D'Amore /* 242*88447a05SGarrett D'Amore * Setup the sample format. Since OSS will support AFMT_S16_NE 243*88447a05SGarrett D'Amore * regardless of the device we do not need to support any 244*88447a05SGarrett D'Amore * other formats. 245*88447a05SGarrett D'Amore */ 246*88447a05SGarrett D'Amore 247*88447a05SGarrett D'Amore tmp = AFMT_S16_NE; 248*88447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_SETFMT, &tmp) == -1 || tmp != AFMT_S16_NE) { 249*88447a05SGarrett D'Amore (void) printf(_("Device doesn't support native 16-bit PCM\n")); 250*88447a05SGarrett D'Amore return (-1); 251*88447a05SGarrett D'Amore } 252*88447a05SGarrett D'Amore 253*88447a05SGarrett D'Amore /* 254*88447a05SGarrett D'Amore * Setup the device for channels. Once again we can simply 255*88447a05SGarrett D'Amore * assume that stereo will always work before OSS takes care 256*88447a05SGarrett D'Amore * of this by emulation if necessary. 257*88447a05SGarrett D'Amore */ 258*88447a05SGarrett D'Amore tmp = tcfg->nchan; 259*88447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_CHANNELS, &tmp) == -1 || tmp != tcfg->nchan) { 260*88447a05SGarrett D'Amore (void) printf(_("The device doesn't support %d channels\n"), 261*88447a05SGarrett D'Amore tcfg->nchan); 262*88447a05SGarrett D'Amore return (-2); 263*88447a05SGarrett D'Amore } 264*88447a05SGarrett D'Amore 265*88447a05SGarrett D'Amore /* 266*88447a05SGarrett D'Amore * Set up the sample rate. 267*88447a05SGarrett D'Amore */ 268*88447a05SGarrett D'Amore 269*88447a05SGarrett D'Amore tmp = SAMPLE_RATE; 270*88447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_SPEED, &tmp) == -1) { 271*88447a05SGarrett D'Amore perror("SNDCTL_DSP_SPEED"); 272*88447a05SGarrett D'Amore return (-3); 273*88447a05SGarrett D'Amore } 274*88447a05SGarrett D'Amore 275*88447a05SGarrett D'Amore sample_rate = tmp; 276*88447a05SGarrett D'Amore if (sample_rate != SAMPLE_RATE) { 277*88447a05SGarrett D'Amore (void) printf(_("The device doesn't support %d Hz\n"), 278*88447a05SGarrett D'Amore SAMPLE_RATE); 279*88447a05SGarrett D'Amore return (-3); 280*88447a05SGarrett D'Amore } 281*88447a05SGarrett D'Amore (void) printf("\n"); 282*88447a05SGarrett D'Amore 283*88447a05SGarrett D'Amore /* 284*88447a05SGarrett D'Amore * This program will measure the real sampling rate by 285*88447a05SGarrett D'Amore * computing the total time required to play the sample. 286*88447a05SGarrett D'Amore * 287*88447a05SGarrett D'Amore * This is not terribly presice with short test sounds but it 288*88447a05SGarrett D'Amore * can be used to detect if the sampling rate badly 289*88447a05SGarrett D'Amore * wrong. Errors of few percents is more likely to be caused 290*88447a05SGarrett D'Amore * by poor accuracy of the system clock rather than problems 291*88447a05SGarrett D'Amore * with the sampling rate. 292*88447a05SGarrett D'Amore */ 293*88447a05SGarrett D'Amore (void) gettimeofday(&t1, NULL); 294*88447a05SGarrett D'Amore 295*88447a05SGarrett D'Amore for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) { 296*88447a05SGarrett D'Amore (void) fputs(_(ccfg->name), stdout); 297*88447a05SGarrett D'Amore (void) fflush(stdout); 298*88447a05SGarrett D'Amore if (ccfg->flags & CFLAG_LFE) { 299*88447a05SGarrett D'Amore (void) printf(_("SKIPPED\n")); 300*88447a05SGarrett D'Amore continue; 301*88447a05SGarrett D'Amore } 302*88447a05SGarrett D'Amore 303*88447a05SGarrett D'Amore if (write(hd, ccfg->data, ccfg->len) < 0) { 304*88447a05SGarrett D'Amore (void) printf(_("ERROR: %s\n"), 305*88447a05SGarrett D'Amore strerror(errno)); 306*88447a05SGarrett D'Amore return (-3); 307*88447a05SGarrett D'Amore } 308*88447a05SGarrett D'Amore (void) printf(_("OK\n")); 309*88447a05SGarrett D'Amore total_bytes += ccfg->len; 310*88447a05SGarrett D'Amore } 311*88447a05SGarrett D'Amore 312*88447a05SGarrett D'Amore (void) gettimeofday(&t2, NULL); 313*88447a05SGarrett D'Amore delay = 0; 314*88447a05SGarrett D'Amore (void) ioctl(hd, SNDCTL_DSP_GETODELAY, &delay); /* Ignore errors */ 315*88447a05SGarrett D'Amore 316*88447a05SGarrett D'Amore /* 317*88447a05SGarrett D'Amore * Perform the time computations using milliseconds. 318*88447a05SGarrett D'Amore */ 319*88447a05SGarrett D'Amore 320*88447a05SGarrett D'Amore t = t2.tv_sec - t1.tv_sec; 321*88447a05SGarrett D'Amore t *= 1000; 322*88447a05SGarrett D'Amore 323*88447a05SGarrett D'Amore t += t2.tv_usec / 1000; 324*88447a05SGarrett D'Amore t -= t1.tv_usec / 1000; 325*88447a05SGarrett D'Amore 326*88447a05SGarrett D'Amore total_bytes -= delay; 327*88447a05SGarrett D'Amore total_bytes *= 1000; 328*88447a05SGarrett D'Amore 329*88447a05SGarrett D'Amore total_bytes /= t; 330*88447a05SGarrett D'Amore total_bytes /= (tcfg->nchan * sizeof (int16_t)); 331*88447a05SGarrett D'Amore 332*88447a05SGarrett D'Amore ratio = ((float)total_bytes / (float)sample_rate) * 100.0; 333*88447a05SGarrett D'Amore (void) printf(_("\t<measured sample rate %8.2f Hz (%4.2f%%)>\n"), 334*88447a05SGarrett D'Amore (float)sample_rate * ratio / 100.0, ratio - 100.0); 335*88447a05SGarrett D'Amore num_devices_tested++; 336*88447a05SGarrett D'Amore 337*88447a05SGarrett D'Amore return (1); 338*88447a05SGarrett D'Amore } 339*88447a05SGarrett D'Amore 340*88447a05SGarrett D'Amore static int 341*88447a05SGarrett D'Amore find_num_devices(void) 342*88447a05SGarrett D'Amore { 343*88447a05SGarrett D'Amore oss_sysinfo info; 344*88447a05SGarrett D'Amore struct utsname un; 345*88447a05SGarrett D'Amore /* 346*88447a05SGarrett D'Amore * Find out the number of available audio devices by calling 347*88447a05SGarrett D'Amore * SNDCTL_SYSINFO. 348*88447a05SGarrett D'Amore */ 349*88447a05SGarrett D'Amore 350*88447a05SGarrett D'Amore if (ioctl(mixerfd, SNDCTL_SYSINFO, &info) == -1) { 351*88447a05SGarrett D'Amore if (errno == ENXIO) { 352*88447a05SGarrett D'Amore (void) fprintf(stderr, 353*88447a05SGarrett D'Amore _("No supported sound hardware detected.\n")); 354*88447a05SGarrett D'Amore exit(-1); 355*88447a05SGarrett D'Amore } else { 356*88447a05SGarrett D'Amore perror("SNDCTL_SYSINFO"); 357*88447a05SGarrett D'Amore (void) printf(_("Cannot get system information.\n")); 358*88447a05SGarrett D'Amore exit(-1); 359*88447a05SGarrett D'Amore } 360*88447a05SGarrett D'Amore } 361*88447a05SGarrett D'Amore (void) printf(_("Sound subsystem and version: %s %s (0x%08X)\n"), 362*88447a05SGarrett D'Amore info.product, info.version, info.versionnum); 363*88447a05SGarrett D'Amore 364*88447a05SGarrett D'Amore if (uname(&un) != -1) 365*88447a05SGarrett D'Amore (void) printf(_("Platform: %s %s %s %s\n"), 366*88447a05SGarrett D'Amore un.sysname, un.release, un.version, un.machine); 367*88447a05SGarrett D'Amore 368*88447a05SGarrett D'Amore return (info.numaudios); 369*88447a05SGarrett D'Amore } 370*88447a05SGarrett D'Amore 371*88447a05SGarrett D'Amore /* 372*88447a05SGarrett D'Amore * The test_device() routine checks certain information about the device 373*88447a05SGarrett D'Amore * and calls testdsp() to play the test sound. 374*88447a05SGarrett D'Amore */ 375*88447a05SGarrett D'Amore 376*88447a05SGarrett D'Amore int 377*88447a05SGarrett D'Amore test_device(char *dn, int flags, testcfg_t *tcfg) 378*88447a05SGarrett D'Amore { 379*88447a05SGarrett D'Amore oss_audioinfo ainfo; 380*88447a05SGarrett D'Amore int code; 381*88447a05SGarrett D'Amore int fd; 382*88447a05SGarrett D'Amore 383*88447a05SGarrett D'Amore fd = open(dn, O_WRONLY, 0); 384*88447a05SGarrett D'Amore if (fd == -1) { 385*88447a05SGarrett D'Amore int err = errno; 386*88447a05SGarrett D'Amore perror(dn); 387*88447a05SGarrett D'Amore errno = err; 388*88447a05SGarrett D'Amore describe_error(errno); 389*88447a05SGarrett D'Amore return (0); 390*88447a05SGarrett D'Amore } 391*88447a05SGarrett D'Amore 392*88447a05SGarrett D'Amore ainfo.dev = -1; 393*88447a05SGarrett D'Amore if (ioctl(fd, SNDCTL_AUDIOINFO, &ainfo) == -1) { 394*88447a05SGarrett D'Amore perror("SNDCTL_AUDIOINFO"); 395*88447a05SGarrett D'Amore (void) close(fd); 396*88447a05SGarrett D'Amore return (1); 397*88447a05SGarrett D'Amore } 398*88447a05SGarrett D'Amore 399*88447a05SGarrett D'Amore (void) printf(_("\n*** Scanning sound adapter #%d ***\n"), 400*88447a05SGarrett D'Amore ainfo.card_number); 401*88447a05SGarrett D'Amore 402*88447a05SGarrett D'Amore (void) printf(_("%s (audio engine %d): %s\n"), ainfo.devnode, ainfo.dev, 403*88447a05SGarrett D'Amore ainfo.name); 404*88447a05SGarrett D'Amore 405*88447a05SGarrett D'Amore if (!ainfo.enabled) { 406*88447a05SGarrett D'Amore (void) printf(_(" - Device not present - Skipping\n")); 407*88447a05SGarrett D'Amore (void) close(fd); 408*88447a05SGarrett D'Amore return (1); 409*88447a05SGarrett D'Amore } 410*88447a05SGarrett D'Amore 411*88447a05SGarrett D'Amore if (!(ainfo.caps & PCM_CAP_OUTPUT)) { 412*88447a05SGarrett D'Amore (void) printf(_(" - Skipping input only device\n")); 413*88447a05SGarrett D'Amore (void) close(fd); 414*88447a05SGarrett D'Amore return (1); 415*88447a05SGarrett D'Amore } 416*88447a05SGarrett D'Amore 417*88447a05SGarrett D'Amore (void) printf(_(" - Performing audio playback test... ")); 418*88447a05SGarrett D'Amore (void) fflush(stdout); 419*88447a05SGarrett D'Amore 420*88447a05SGarrett D'Amore code = testdsp(fd, flags, tcfg); 421*88447a05SGarrett D'Amore (void) close(fd); 422*88447a05SGarrett D'Amore 423*88447a05SGarrett D'Amore return (code == 1); 424*88447a05SGarrett D'Amore } 425*88447a05SGarrett D'Amore 426*88447a05SGarrett D'Amore void 427*88447a05SGarrett D'Amore describe_error(int err) 428*88447a05SGarrett D'Amore { 429*88447a05SGarrett D'Amore switch (err) { 430*88447a05SGarrett D'Amore case ENODEV: 431*88447a05SGarrett D'Amore (void) fprintf(stderr, 432*88447a05SGarrett D'Amore _("The device file was found in /dev but\n" 433*88447a05SGarrett D'Amore "the driver was not loaded.\n")); 434*88447a05SGarrett D'Amore break; 435*88447a05SGarrett D'Amore 436*88447a05SGarrett D'Amore case ENXIO: 437*88447a05SGarrett D'Amore (void) fprintf(stderr, 438*88447a05SGarrett D'Amore _("There are no sound devices available.\n" 439*88447a05SGarrett D'Amore "The most likely reason is that the device you have\n" 440*88447a05SGarrett D'Amore "is malfunctioning or it's not supported.\n" 441*88447a05SGarrett D'Amore "It's also possible that you are trying to use the wrong " 442*88447a05SGarrett D'Amore "device file.\n")); 443*88447a05SGarrett D'Amore break; 444*88447a05SGarrett D'Amore 445*88447a05SGarrett D'Amore case ENOSPC: 446*88447a05SGarrett D'Amore (void) fprintf(stderr, 447*88447a05SGarrett D'Amore _("Your system cannot allocate memory for the device\n" 448*88447a05SGarrett D'Amore "buffers. Reboot your machine and try again.\n")); 449*88447a05SGarrett D'Amore break; 450*88447a05SGarrett D'Amore 451*88447a05SGarrett D'Amore case ENOENT: 452*88447a05SGarrett D'Amore (void) fprintf(stderr, 453*88447a05SGarrett D'Amore _("The device file is missing from /dev.\n")); 454*88447a05SGarrett D'Amore break; 455*88447a05SGarrett D'Amore 456*88447a05SGarrett D'Amore 457*88447a05SGarrett D'Amore case EBUSY: 458*88447a05SGarrett D'Amore (void) fprintf(stderr, 459*88447a05SGarrett D'Amore _("The device is busy. There is some other application\n" 460*88447a05SGarrett D'Amore "using it.\n")); 461*88447a05SGarrett D'Amore break; 462*88447a05SGarrett D'Amore 463*88447a05SGarrett D'Amore default: 464*88447a05SGarrett D'Amore break; 465*88447a05SGarrett D'Amore } 466*88447a05SGarrett D'Amore } 467*88447a05SGarrett D'Amore 468*88447a05SGarrett D'Amore int 469*88447a05SGarrett D'Amore main(int argc, char *argv[]) 470*88447a05SGarrett D'Amore { 471*88447a05SGarrett D'Amore int t, i; 472*88447a05SGarrett D'Amore int maxdev; 473*88447a05SGarrett D'Amore int flags = 0; 474*88447a05SGarrett D'Amore int status = 0; 475*88447a05SGarrett D'Amore int numdev; 476*88447a05SGarrett D'Amore extern int optind; 477*88447a05SGarrett D'Amore testcfg_t *tcfg; 478*88447a05SGarrett D'Amore 479*88447a05SGarrett D'Amore (void) setlocale(LC_ALL, ""); 480*88447a05SGarrett D'Amore (void) textdomain(TEXT_DOMAIN); 481*88447a05SGarrett D'Amore 482*88447a05SGarrett D'Amore tcfg = &test_stereo; 483*88447a05SGarrett D'Amore 484*88447a05SGarrett D'Amore /* 485*88447a05SGarrett D'Amore * Simple command line switch handling. 486*88447a05SGarrett D'Amore */ 487*88447a05SGarrett D'Amore 488*88447a05SGarrett D'Amore while ((i = getopt(argc, argv, "l2457")) != EOF) { 489*88447a05SGarrett D'Amore switch (i) { 490*88447a05SGarrett D'Amore case 'l': 491*88447a05SGarrett D'Amore flags |= TF_LOOP; 492*88447a05SGarrett D'Amore break; 493*88447a05SGarrett D'Amore case '2': 494*88447a05SGarrett D'Amore tcfg = &test_stereo; 495*88447a05SGarrett D'Amore break; 496*88447a05SGarrett D'Amore case '4': 497*88447a05SGarrett D'Amore tcfg = &test_quad; 498*88447a05SGarrett D'Amore break; 499*88447a05SGarrett D'Amore case '5': 500*88447a05SGarrett D'Amore tcfg = &test_51; 501*88447a05SGarrett D'Amore break; 502*88447a05SGarrett D'Amore case '7': 503*88447a05SGarrett D'Amore tcfg = &test_71; 504*88447a05SGarrett D'Amore break; 505*88447a05SGarrett D'Amore default: 506*88447a05SGarrett D'Amore (void) printf(_("Usage: %s [options...] [device]\n" 507*88447a05SGarrett D'Amore " -2 Stereo test\n" 508*88447a05SGarrett D'Amore " -4 Quadraphonic 4.0 test\n" 509*88447a05SGarrett D'Amore " -5 Surround 5.1 test\n" 510*88447a05SGarrett D'Amore " -7 Surround 7.1 test\n" 511*88447a05SGarrett D'Amore " -l Loop test\n"), argv[0]); 512*88447a05SGarrett D'Amore exit(-1); 513*88447a05SGarrett D'Amore } 514*88447a05SGarrett D'Amore } 515*88447a05SGarrett D'Amore 516*88447a05SGarrett D'Amore /* 517*88447a05SGarrett D'Amore * Open the mixer device used for calling SNDCTL_SYSINFO and 518*88447a05SGarrett D'Amore * SNDCTL_AUDIOINFO. 519*88447a05SGarrett D'Amore */ 520*88447a05SGarrett D'Amore if ((mixerfd = open("/dev/mixer", O_RDWR, 0)) == -1) { 521*88447a05SGarrett D'Amore int err = errno; 522*88447a05SGarrett D'Amore perror("/dev/mixer"); 523*88447a05SGarrett D'Amore errno = err; 524*88447a05SGarrett D'Amore describe_error(errno); 525*88447a05SGarrett D'Amore exit(-1); 526*88447a05SGarrett D'Amore } 527*88447a05SGarrett D'Amore 528*88447a05SGarrett D'Amore prepare(tcfg); /* Prepare the wave data */ 529*88447a05SGarrett D'Amore 530*88447a05SGarrett D'Amore /* 531*88447a05SGarrett D'Amore * Enumerate all devices and play the test sounds. 532*88447a05SGarrett D'Amore */ 533*88447a05SGarrett D'Amore maxdev = find_num_devices(); 534*88447a05SGarrett D'Amore if (maxdev < 1) { 535*88447a05SGarrett D'Amore (void) printf(_("\n*** No audio hardware available ***\n")); 536*88447a05SGarrett D'Amore exit(-1); 537*88447a05SGarrett D'Amore } 538*88447a05SGarrett D'Amore 539*88447a05SGarrett D'Amore numdev = (argc - optind); 540*88447a05SGarrett D'Amore do { 541*88447a05SGarrett D'Amore char *dn; 542*88447a05SGarrett D'Amore oss_audioinfo ainfo; 543*88447a05SGarrett D'Amore 544*88447a05SGarrett D'Amore if (numdev > 0) { 545*88447a05SGarrett D'Amore for (t = 0; t < numdev; t++) { 546*88447a05SGarrett D'Amore dn = argv[optind + t]; 547*88447a05SGarrett D'Amore if (!test_device(dn, flags, tcfg)) 548*88447a05SGarrett D'Amore status++; 549*88447a05SGarrett D'Amore } 550*88447a05SGarrett D'Amore } else { 551*88447a05SGarrett D'Amore for (t = 0; t < maxdev; t++) { 552*88447a05SGarrett D'Amore ainfo.dev = t; 553*88447a05SGarrett D'Amore if (ioctl(mixerfd, SNDCTL_AUDIOINFO, 554*88447a05SGarrett D'Amore &ainfo) == -1) { 555*88447a05SGarrett D'Amore perror("SNDCTL_AUDIOINFO"); 556*88447a05SGarrett D'Amore status++; 557*88447a05SGarrett D'Amore continue; 558*88447a05SGarrett D'Amore } 559*88447a05SGarrett D'Amore dn = ainfo.devnode; 560*88447a05SGarrett D'Amore if (!test_device(dn, flags, tcfg)) 561*88447a05SGarrett D'Amore status++; 562*88447a05SGarrett D'Amore } 563*88447a05SGarrett D'Amore } 564*88447a05SGarrett D'Amore 565*88447a05SGarrett D'Amore if (status == 0) 566*88447a05SGarrett D'Amore (void) printf(_("\n*** All tests completed OK ***\n")); 567*88447a05SGarrett D'Amore else 568*88447a05SGarrett D'Amore (void) printf(_("\n*** Errors were detected ***\n")); 569*88447a05SGarrett D'Amore 570*88447a05SGarrett D'Amore } while (flags & TF_LOOP); 571*88447a05SGarrett D'Amore 572*88447a05SGarrett D'Amore (void) close(mixerfd); 573*88447a05SGarrett D'Amore 574*88447a05SGarrett D'Amore return (status); 575*88447a05SGarrett D'Amore } 576