19484Sgarrett.damore@Sun.COM /* 29484Sgarrett.damore@Sun.COM * CDDL HEADER START 39484Sgarrett.damore@Sun.COM * 49484Sgarrett.damore@Sun.COM * The contents of this file are subject to the terms of the 59484Sgarrett.damore@Sun.COM * Common Development and Distribution License (the "License"). 69484Sgarrett.damore@Sun.COM * You may not use this file except in compliance with the License. 79484Sgarrett.damore@Sun.COM * 89484Sgarrett.damore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99484Sgarrett.damore@Sun.COM * or http://www.opensolaris.org/os/licensing. 109484Sgarrett.damore@Sun.COM * See the License for the specific language governing permissions 119484Sgarrett.damore@Sun.COM * and limitations under the License. 129484Sgarrett.damore@Sun.COM * 139484Sgarrett.damore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 149484Sgarrett.damore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159484Sgarrett.damore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 169484Sgarrett.damore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 179484Sgarrett.damore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 189484Sgarrett.damore@Sun.COM * 199484Sgarrett.damore@Sun.COM * CDDL HEADER END 209484Sgarrett.damore@Sun.COM */ 219484Sgarrett.damore@Sun.COM /* 229484Sgarrett.damore@Sun.COM * Copyright (C) 4Front Technologies 1996-2008. 239484Sgarrett.damore@Sun.COM * 24*11936Sgdamore@opensolaris.org * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 259484Sgarrett.damore@Sun.COM * Use is subject to license terms. 269484Sgarrett.damore@Sun.COM */ 279484Sgarrett.damore@Sun.COM /* 289484Sgarrett.damore@Sun.COM * This program is a general purpose test facility for audio output. 299484Sgarrett.damore@Sun.COM * It does not test record. 309484Sgarrett.damore@Sun.COM * 319484Sgarrett.damore@Sun.COM * The wavedata.c and wavedata.h files contain the actual samples compressed 329484Sgarrett.damore@Sun.COM * using the MS ADPCM algorithm. 339484Sgarrett.damore@Sun.COM */ 349484Sgarrett.damore@Sun.COM 359484Sgarrett.damore@Sun.COM #include <stdio.h> 369484Sgarrett.damore@Sun.COM #include <stdlib.h> 379484Sgarrett.damore@Sun.COM #include <unistd.h> 389484Sgarrett.damore@Sun.COM #include <fcntl.h> 399484Sgarrett.damore@Sun.COM #include <string.h> 409484Sgarrett.damore@Sun.COM #include <errno.h> 419484Sgarrett.damore@Sun.COM #include <unistd.h> 429484Sgarrett.damore@Sun.COM #include <sys/time.h> 439484Sgarrett.damore@Sun.COM #include <sys/ioctl.h> 449484Sgarrett.damore@Sun.COM #include <sys/utsname.h> 459484Sgarrett.damore@Sun.COM #include <sys/soundcard.h> 469484Sgarrett.damore@Sun.COM #include <inttypes.h> 479484Sgarrett.damore@Sun.COM #include <locale.h> 489484Sgarrett.damore@Sun.COM 499484Sgarrett.damore@Sun.COM #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 509484Sgarrett.damore@Sun.COM #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 519484Sgarrett.damore@Sun.COM #endif 529484Sgarrett.damore@Sun.COM 539484Sgarrett.damore@Sun.COM #define _(s) gettext(s) 549484Sgarrett.damore@Sun.COM 559484Sgarrett.damore@Sun.COM /* 569484Sgarrett.damore@Sun.COM * Channel selectors 579484Sgarrett.damore@Sun.COM */ 589484Sgarrett.damore@Sun.COM #define CH_LEFT (1 << 0) 599484Sgarrett.damore@Sun.COM #define CH_RIGHT (1 << 1) 609484Sgarrett.damore@Sun.COM #define CH_LREAR4 (1 << 2) /* quadraphonic */ 619484Sgarrett.damore@Sun.COM #define CH_RREAR4 (1 << 3) /* quadraphonic */ 629484Sgarrett.damore@Sun.COM #define CH_CENTER (1 << 2) 639484Sgarrett.damore@Sun.COM #define CH_LFE (1 << 3) 649484Sgarrett.damore@Sun.COM #define CH_LSURR (1 << 4) 659484Sgarrett.damore@Sun.COM #define CH_RSURR (1 << 5) 669484Sgarrett.damore@Sun.COM #define CH_LREAR (1 << 6) 679484Sgarrett.damore@Sun.COM #define CH_RREAR (1 << 7) 689484Sgarrett.damore@Sun.COM #define CH_STEREO (CH_LEFT|CH_RIGHT) 699484Sgarrett.damore@Sun.COM #define CH_4 (CH_STEREO | CH_LREAR4 | CH_RREAR4) 709484Sgarrett.damore@Sun.COM #define CH_5 (CH_STEREO | CH_CENTER | CH_LSURR | CH_RSURR) 719484Sgarrett.damore@Sun.COM #define CH_7 (CH_5 | CH_LREAR | CH_RREAR) 729484Sgarrett.damore@Sun.COM 739484Sgarrett.damore@Sun.COM typedef struct chancfg { 749484Sgarrett.damore@Sun.COM int mask; 759484Sgarrett.damore@Sun.COM const char *name; 769484Sgarrett.damore@Sun.COM unsigned flags; 779484Sgarrett.damore@Sun.COM int16_t *data; 789484Sgarrett.damore@Sun.COM int len; 799484Sgarrett.damore@Sun.COM } chancfg_t; 809484Sgarrett.damore@Sun.COM 819484Sgarrett.damore@Sun.COM typedef struct testcfg { 829484Sgarrett.damore@Sun.COM int nchan; 839484Sgarrett.damore@Sun.COM chancfg_t *tests[16]; 849484Sgarrett.damore@Sun.COM } testcfg_t; 859484Sgarrett.damore@Sun.COM 869484Sgarrett.damore@Sun.COM #define CFLAG_LFE 0x1 /* lfe channel - not full range */ 879484Sgarrett.damore@Sun.COM 889484Sgarrett.damore@Sun.COM /* 899484Sgarrett.damore@Sun.COM * TRANSLATION_NOTE : The following strings are displayed during progress. 909484Sgarrett.damore@Sun.COM * Its important for alignment that they have the same displayed length. 919484Sgarrett.damore@Sun.COM */ 929484Sgarrett.damore@Sun.COM #define NM_LEFT "\t<left> ................" 939484Sgarrett.damore@Sun.COM #define NM_RIGHT "\t<right> ..............." 949484Sgarrett.damore@Sun.COM #define NM_LREAR "\t<left rear> ..........." 959484Sgarrett.damore@Sun.COM #define NM_RREAR "\t<right rear> .........." 969484Sgarrett.damore@Sun.COM #define NM_LSIDE "\t<left side> ..........." 979484Sgarrett.damore@Sun.COM #define NM_RSIDE "\t<right side> .........." 989484Sgarrett.damore@Sun.COM #define NM_CENTER "\t<center> .............." 999484Sgarrett.damore@Sun.COM #define NM_LFE "\t<lfe> ................." 1009484Sgarrett.damore@Sun.COM #define NM_STEREO "\t<stereo> .............." 1019484Sgarrett.damore@Sun.COM #define NM_40 "\t<4.0 surround> ........" 1029484Sgarrett.damore@Sun.COM #define NM_50 "\t<5.0 surround> ........" 1039484Sgarrett.damore@Sun.COM #define NM_70 "\t<7.0 surround> ........" 1049484Sgarrett.damore@Sun.COM 1059484Sgarrett.damore@Sun.COM chancfg_t ch_left = { CH_LEFT, NM_LEFT, 0 }; 1069484Sgarrett.damore@Sun.COM chancfg_t ch_right = { CH_RIGHT, NM_RIGHT, 0 }; 1079484Sgarrett.damore@Sun.COM chancfg_t ch_stereo = { CH_STEREO, NM_STEREO, 0 }; 1089484Sgarrett.damore@Sun.COM 1099484Sgarrett.damore@Sun.COM chancfg_t ch_center = { CH_CENTER, NM_CENTER, 0 }; 1109484Sgarrett.damore@Sun.COM chancfg_t ch_lfe = { CH_LFE, NM_LFE, CFLAG_LFE }; 1119484Sgarrett.damore@Sun.COM 1129484Sgarrett.damore@Sun.COM chancfg_t ch_lsurr_4 = { (1 << 2), NM_LREAR, 0 }; 1139484Sgarrett.damore@Sun.COM chancfg_t ch_rsurr_4 = { (1 << 3), NM_RREAR, 0 }; 1149484Sgarrett.damore@Sun.COM chancfg_t ch_4 = { CH_4, NM_40, 0 }; 1159484Sgarrett.damore@Sun.COM 1169484Sgarrett.damore@Sun.COM chancfg_t ch_lsurr_5 = { CH_LSURR, NM_LREAR, 0 }; 1179484Sgarrett.damore@Sun.COM chancfg_t ch_rsurr_5 = { CH_RSURR, NM_RREAR, 0 }; 1189484Sgarrett.damore@Sun.COM chancfg_t ch_5 = { CH_5, NM_50, 0 }; 1199484Sgarrett.damore@Sun.COM 1209484Sgarrett.damore@Sun.COM chancfg_t ch_lsurr_7 = { CH_LSURR, NM_LSIDE, 0 }; 1219484Sgarrett.damore@Sun.COM chancfg_t ch_rsurr_7 = { CH_RSURR, NM_RSIDE, 0 }; 1229484Sgarrett.damore@Sun.COM chancfg_t ch_lrear_7 = { CH_LREAR, NM_LREAR, 0 }; 1239484Sgarrett.damore@Sun.COM chancfg_t ch_rrear_7 = { CH_RREAR, NM_RREAR, 0 }; 1249484Sgarrett.damore@Sun.COM chancfg_t ch_7 = { CH_7, NM_70, 0 }; 1259484Sgarrett.damore@Sun.COM 1269484Sgarrett.damore@Sun.COM testcfg_t test_stereo = { 1279484Sgarrett.damore@Sun.COM 2, { &ch_left, &ch_right, &ch_stereo, NULL } 1289484Sgarrett.damore@Sun.COM }; 1299484Sgarrett.damore@Sun.COM 1309484Sgarrett.damore@Sun.COM testcfg_t test_quad = { 1319484Sgarrett.damore@Sun.COM 4, { &ch_left, &ch_right, &ch_stereo, 1329484Sgarrett.damore@Sun.COM &ch_lsurr_4, &ch_rsurr_4, &ch_4, NULL } 1339484Sgarrett.damore@Sun.COM }; 1349484Sgarrett.damore@Sun.COM 1359484Sgarrett.damore@Sun.COM testcfg_t test_51 = { 1369484Sgarrett.damore@Sun.COM 6, { &ch_left, &ch_right, &ch_stereo, 1379484Sgarrett.damore@Sun.COM &ch_lsurr_5, &ch_rsurr_5, &ch_center, &ch_lfe, &ch_5, NULL } 1389484Sgarrett.damore@Sun.COM }; 1399484Sgarrett.damore@Sun.COM 1409484Sgarrett.damore@Sun.COM testcfg_t test_71 = { 1419484Sgarrett.damore@Sun.COM 8, { &ch_left, &ch_right, &ch_stereo, 1429484Sgarrett.damore@Sun.COM &ch_lsurr_7, &ch_rsurr_7, &ch_lrear_7, &ch_rrear_7, 1439484Sgarrett.damore@Sun.COM &ch_center, &ch_lfe, &ch_7, NULL } 1449484Sgarrett.damore@Sun.COM }; 1459484Sgarrett.damore@Sun.COM 1469484Sgarrett.damore@Sun.COM /* 1479484Sgarrett.damore@Sun.COM * uncompress_wave() is defined in wavedata.c. It expands the audio 1489484Sgarrett.damore@Sun.COM * samples stored in wavedata.h and returns the lenghth of the 1499484Sgarrett.damore@Sun.COM * uncompressed version in bytes. 1509484Sgarrett.damore@Sun.COM * 1519484Sgarrett.damore@Sun.COM * The uncompressed wave data format is 16 bit (native) stereo 1529484Sgarrett.damore@Sun.COM * recorded at 48000 Hz. 1539484Sgarrett.damore@Sun.COM */ 1549484Sgarrett.damore@Sun.COM extern int uncompress_wave(short *outbuf); 1559484Sgarrett.damore@Sun.COM 1569484Sgarrett.damore@Sun.COM static int data_len; 1579484Sgarrett.damore@Sun.COM 1589484Sgarrett.damore@Sun.COM #define MAXDEVICE 64 1599484Sgarrett.damore@Sun.COM extern void describe_error(int); 1609484Sgarrett.damore@Sun.COM 1619484Sgarrett.damore@Sun.COM #define SAMPLE_RATE 48000 1629484Sgarrett.damore@Sun.COM 1639484Sgarrett.damore@Sun.COM /* 1649484Sgarrett.damore@Sun.COM * Operating mode flags (set from the command line). 1659484Sgarrett.damore@Sun.COM */ 1669484Sgarrett.damore@Sun.COM #define TF_LOOP 0x00000010 /* Loop until interrupted */ 1679484Sgarrett.damore@Sun.COM 1689484Sgarrett.damore@Sun.COM static int mixerfd; 1699484Sgarrett.damore@Sun.COM static int num_devices_tested = 0; 1709484Sgarrett.damore@Sun.COM 1719484Sgarrett.damore@Sun.COM static short *sample_buf; 1729484Sgarrett.damore@Sun.COM 1739484Sgarrett.damore@Sun.COM void 1749484Sgarrett.damore@Sun.COM prepare(testcfg_t *tcfg) 1759484Sgarrett.damore@Sun.COM { 1769484Sgarrett.damore@Sun.COM int nsamples; 1779484Sgarrett.damore@Sun.COM int i; 1789484Sgarrett.damore@Sun.COM chancfg_t *ccfg; 1799484Sgarrett.damore@Sun.COM if ((sample_buf = malloc(2000000)) == NULL) { 1809484Sgarrett.damore@Sun.COM perror("malloc"); 1819484Sgarrett.damore@Sun.COM exit(-1); 1829484Sgarrett.damore@Sun.COM } 1839484Sgarrett.damore@Sun.COM 1849484Sgarrett.damore@Sun.COM data_len = uncompress_wave(sample_buf); 1859484Sgarrett.damore@Sun.COM nsamples = (data_len / sizeof (int16_t)) / 2; 1869484Sgarrett.damore@Sun.COM 1879484Sgarrett.damore@Sun.COM for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) { 1889484Sgarrett.damore@Sun.COM int16_t *src, *dst; 1899484Sgarrett.damore@Sun.COM int ch; 1909484Sgarrett.damore@Sun.COM int samp; 1919484Sgarrett.damore@Sun.COM 1929484Sgarrett.damore@Sun.COM src = sample_buf; 1939484Sgarrett.damore@Sun.COM 1949484Sgarrett.damore@Sun.COM if (ccfg->flags != CFLAG_LFE) { 1959484Sgarrett.damore@Sun.COM ccfg->len = nsamples * tcfg->nchan * sizeof (int16_t); 1969484Sgarrett.damore@Sun.COM ccfg->data = malloc(ccfg->len); 1979484Sgarrett.damore@Sun.COM if ((dst = ccfg->data) == NULL) { 1989484Sgarrett.damore@Sun.COM perror("malloc"); 1999484Sgarrett.damore@Sun.COM exit(-1); 2009484Sgarrett.damore@Sun.COM } 2019484Sgarrett.damore@Sun.COM for (samp = 0; samp < nsamples; samp++) { 2029484Sgarrett.damore@Sun.COM for (ch = 0; ch < tcfg->nchan; ch++) { 2039484Sgarrett.damore@Sun.COM *dst = ((1U << ch) & ccfg->mask) ? 2049484Sgarrett.damore@Sun.COM *src : 0; 2059484Sgarrett.damore@Sun.COM dst++; 2069484Sgarrett.damore@Sun.COM } 2079484Sgarrett.damore@Sun.COM src += 2; 2089484Sgarrett.damore@Sun.COM } 2099484Sgarrett.damore@Sun.COM } else { 2109484Sgarrett.damore@Sun.COM /* Skip LFE for now */ 2119484Sgarrett.damore@Sun.COM ccfg->len = 0; 2129484Sgarrett.damore@Sun.COM } 2139484Sgarrett.damore@Sun.COM } 2149484Sgarrett.damore@Sun.COM } 2159484Sgarrett.damore@Sun.COM 2169484Sgarrett.damore@Sun.COM /* 2179484Sgarrett.damore@Sun.COM * The testdsp() routine checks the capabilities of a given audio device number 2189484Sgarrett.damore@Sun.COM * (parameter n) and decides if the test sound needs to be played. 2199484Sgarrett.damore@Sun.COM */ 2209484Sgarrett.damore@Sun.COM 2219484Sgarrett.damore@Sun.COM /*ARGSUSED*/ 2229484Sgarrett.damore@Sun.COM int 2239484Sgarrett.damore@Sun.COM testdsp(int hd, int flags, testcfg_t *tcfg) 2249484Sgarrett.damore@Sun.COM { 2259484Sgarrett.damore@Sun.COM float ratio; 2269484Sgarrett.damore@Sun.COM struct timeval t1, t2; 2279484Sgarrett.damore@Sun.COM unsigned long t; 2289484Sgarrett.damore@Sun.COM int sample_rate; 2299484Sgarrett.damore@Sun.COM int delay; 2309484Sgarrett.damore@Sun.COM long long total_bytes = 0; 2319484Sgarrett.damore@Sun.COM unsigned int tmp, caps; 2329484Sgarrett.damore@Sun.COM int i; 2339484Sgarrett.damore@Sun.COM chancfg_t *ccfg; 2349484Sgarrett.damore@Sun.COM 2359484Sgarrett.damore@Sun.COM caps = 0; 2369484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_GETCAPS, &caps) == -1) { 2379484Sgarrett.damore@Sun.COM perror("SNDCTL_DSP_GETCAPS"); 2389484Sgarrett.damore@Sun.COM return (-1); 2399484Sgarrett.damore@Sun.COM } 2409484Sgarrett.damore@Sun.COM 2419484Sgarrett.damore@Sun.COM /* 2429484Sgarrett.damore@Sun.COM * Setup the sample format. Since OSS will support AFMT_S16_NE 2439484Sgarrett.damore@Sun.COM * regardless of the device we do not need to support any 2449484Sgarrett.damore@Sun.COM * other formats. 2459484Sgarrett.damore@Sun.COM */ 2469484Sgarrett.damore@Sun.COM 2479484Sgarrett.damore@Sun.COM tmp = AFMT_S16_NE; 2489484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_SETFMT, &tmp) == -1 || tmp != AFMT_S16_NE) { 2499484Sgarrett.damore@Sun.COM (void) printf(_("Device doesn't support native 16-bit PCM\n")); 2509484Sgarrett.damore@Sun.COM return (-1); 2519484Sgarrett.damore@Sun.COM } 2529484Sgarrett.damore@Sun.COM 2539484Sgarrett.damore@Sun.COM /* 2549484Sgarrett.damore@Sun.COM * Setup the device for channels. Once again we can simply 2559484Sgarrett.damore@Sun.COM * assume that stereo will always work before OSS takes care 2569484Sgarrett.damore@Sun.COM * of this by emulation if necessary. 2579484Sgarrett.damore@Sun.COM */ 2589484Sgarrett.damore@Sun.COM tmp = tcfg->nchan; 2599484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_CHANNELS, &tmp) == -1 || tmp != tcfg->nchan) { 2609484Sgarrett.damore@Sun.COM (void) printf(_("The device doesn't support %d channels\n"), 2619484Sgarrett.damore@Sun.COM tcfg->nchan); 2629484Sgarrett.damore@Sun.COM return (-2); 2639484Sgarrett.damore@Sun.COM } 2649484Sgarrett.damore@Sun.COM 2659484Sgarrett.damore@Sun.COM /* 2669484Sgarrett.damore@Sun.COM * Set up the sample rate. 2679484Sgarrett.damore@Sun.COM */ 2689484Sgarrett.damore@Sun.COM 2699484Sgarrett.damore@Sun.COM tmp = SAMPLE_RATE; 2709484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_SPEED, &tmp) == -1) { 2719484Sgarrett.damore@Sun.COM perror("SNDCTL_DSP_SPEED"); 2729484Sgarrett.damore@Sun.COM return (-3); 2739484Sgarrett.damore@Sun.COM } 2749484Sgarrett.damore@Sun.COM 2759484Sgarrett.damore@Sun.COM sample_rate = tmp; 2769484Sgarrett.damore@Sun.COM if (sample_rate != SAMPLE_RATE) { 2779484Sgarrett.damore@Sun.COM (void) printf(_("The device doesn't support %d Hz\n"), 2789484Sgarrett.damore@Sun.COM SAMPLE_RATE); 2799484Sgarrett.damore@Sun.COM return (-3); 2809484Sgarrett.damore@Sun.COM } 2819484Sgarrett.damore@Sun.COM (void) printf("\n"); 2829484Sgarrett.damore@Sun.COM 2839484Sgarrett.damore@Sun.COM /* 2849484Sgarrett.damore@Sun.COM * This program will measure the real sampling rate by 2859484Sgarrett.damore@Sun.COM * computing the total time required to play the sample. 2869484Sgarrett.damore@Sun.COM * 2879484Sgarrett.damore@Sun.COM * This is not terribly presice with short test sounds but it 2889484Sgarrett.damore@Sun.COM * can be used to detect if the sampling rate badly 2899484Sgarrett.damore@Sun.COM * wrong. Errors of few percents is more likely to be caused 2909484Sgarrett.damore@Sun.COM * by poor accuracy of the system clock rather than problems 2919484Sgarrett.damore@Sun.COM * with the sampling rate. 2929484Sgarrett.damore@Sun.COM */ 2939484Sgarrett.damore@Sun.COM (void) gettimeofday(&t1, NULL); 2949484Sgarrett.damore@Sun.COM 2959484Sgarrett.damore@Sun.COM for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) { 2969484Sgarrett.damore@Sun.COM (void) fputs(_(ccfg->name), stdout); 2979484Sgarrett.damore@Sun.COM (void) fflush(stdout); 2989484Sgarrett.damore@Sun.COM if (ccfg->flags & CFLAG_LFE) { 2999484Sgarrett.damore@Sun.COM (void) printf(_("SKIPPED\n")); 3009484Sgarrett.damore@Sun.COM continue; 3019484Sgarrett.damore@Sun.COM } 3029484Sgarrett.damore@Sun.COM 3039484Sgarrett.damore@Sun.COM if (write(hd, ccfg->data, ccfg->len) < 0) { 3049484Sgarrett.damore@Sun.COM (void) printf(_("ERROR: %s\n"), 3059484Sgarrett.damore@Sun.COM strerror(errno)); 3069484Sgarrett.damore@Sun.COM return (-3); 3079484Sgarrett.damore@Sun.COM } 3089484Sgarrett.damore@Sun.COM (void) printf(_("OK\n")); 3099484Sgarrett.damore@Sun.COM total_bytes += ccfg->len; 3109484Sgarrett.damore@Sun.COM } 3119484Sgarrett.damore@Sun.COM 3129484Sgarrett.damore@Sun.COM (void) gettimeofday(&t2, NULL); 3139484Sgarrett.damore@Sun.COM delay = 0; 3149484Sgarrett.damore@Sun.COM (void) ioctl(hd, SNDCTL_DSP_GETODELAY, &delay); /* Ignore errors */ 3159484Sgarrett.damore@Sun.COM 3169484Sgarrett.damore@Sun.COM /* 3179484Sgarrett.damore@Sun.COM * Perform the time computations using milliseconds. 3189484Sgarrett.damore@Sun.COM */ 3199484Sgarrett.damore@Sun.COM 3209484Sgarrett.damore@Sun.COM t = t2.tv_sec - t1.tv_sec; 3219484Sgarrett.damore@Sun.COM t *= 1000; 3229484Sgarrett.damore@Sun.COM 3239484Sgarrett.damore@Sun.COM t += t2.tv_usec / 1000; 3249484Sgarrett.damore@Sun.COM t -= t1.tv_usec / 1000; 3259484Sgarrett.damore@Sun.COM 3269484Sgarrett.damore@Sun.COM total_bytes -= delay; 3279484Sgarrett.damore@Sun.COM total_bytes *= 1000; 3289484Sgarrett.damore@Sun.COM 3299484Sgarrett.damore@Sun.COM total_bytes /= t; 3309484Sgarrett.damore@Sun.COM total_bytes /= (tcfg->nchan * sizeof (int16_t)); 3319484Sgarrett.damore@Sun.COM 3329484Sgarrett.damore@Sun.COM ratio = ((float)total_bytes / (float)sample_rate) * 100.0; 3339484Sgarrett.damore@Sun.COM (void) printf(_("\t<measured sample rate %8.2f Hz (%4.2f%%)>\n"), 3349484Sgarrett.damore@Sun.COM (float)sample_rate * ratio / 100.0, ratio - 100.0); 3359484Sgarrett.damore@Sun.COM num_devices_tested++; 3369484Sgarrett.damore@Sun.COM 3379484Sgarrett.damore@Sun.COM return (1); 3389484Sgarrett.damore@Sun.COM } 3399484Sgarrett.damore@Sun.COM 3409484Sgarrett.damore@Sun.COM static int 3419484Sgarrett.damore@Sun.COM find_num_devices(void) 3429484Sgarrett.damore@Sun.COM { 3439484Sgarrett.damore@Sun.COM oss_sysinfo info; 3449484Sgarrett.damore@Sun.COM struct utsname un; 3459484Sgarrett.damore@Sun.COM /* 3469484Sgarrett.damore@Sun.COM * Find out the number of available audio devices by calling 3479484Sgarrett.damore@Sun.COM * SNDCTL_SYSINFO. 3489484Sgarrett.damore@Sun.COM */ 3499484Sgarrett.damore@Sun.COM 3509484Sgarrett.damore@Sun.COM if (ioctl(mixerfd, SNDCTL_SYSINFO, &info) == -1) { 3519484Sgarrett.damore@Sun.COM if (errno == ENXIO) { 3529484Sgarrett.damore@Sun.COM (void) fprintf(stderr, 3539484Sgarrett.damore@Sun.COM _("No supported sound hardware detected.\n")); 3549484Sgarrett.damore@Sun.COM exit(-1); 3559484Sgarrett.damore@Sun.COM } else { 3569484Sgarrett.damore@Sun.COM perror("SNDCTL_SYSINFO"); 3579484Sgarrett.damore@Sun.COM (void) printf(_("Cannot get system information.\n")); 3589484Sgarrett.damore@Sun.COM exit(-1); 3599484Sgarrett.damore@Sun.COM } 3609484Sgarrett.damore@Sun.COM } 3619484Sgarrett.damore@Sun.COM (void) printf(_("Sound subsystem and version: %s %s (0x%08X)\n"), 3629484Sgarrett.damore@Sun.COM info.product, info.version, info.versionnum); 3639484Sgarrett.damore@Sun.COM 3649484Sgarrett.damore@Sun.COM if (uname(&un) != -1) 3659484Sgarrett.damore@Sun.COM (void) printf(_("Platform: %s %s %s %s\n"), 3669484Sgarrett.damore@Sun.COM un.sysname, un.release, un.version, un.machine); 3679484Sgarrett.damore@Sun.COM 3689484Sgarrett.damore@Sun.COM return (info.numaudios); 3699484Sgarrett.damore@Sun.COM } 3709484Sgarrett.damore@Sun.COM 3719484Sgarrett.damore@Sun.COM /* 3729484Sgarrett.damore@Sun.COM * The test_device() routine checks certain information about the device 3739484Sgarrett.damore@Sun.COM * and calls testdsp() to play the test sound. 3749484Sgarrett.damore@Sun.COM */ 3759484Sgarrett.damore@Sun.COM 3769484Sgarrett.damore@Sun.COM int 3779484Sgarrett.damore@Sun.COM test_device(char *dn, int flags, testcfg_t *tcfg) 3789484Sgarrett.damore@Sun.COM { 3799484Sgarrett.damore@Sun.COM oss_audioinfo ainfo; 3809484Sgarrett.damore@Sun.COM int code; 3819484Sgarrett.damore@Sun.COM int fd; 3829484Sgarrett.damore@Sun.COM 3839484Sgarrett.damore@Sun.COM fd = open(dn, O_WRONLY, 0); 3849484Sgarrett.damore@Sun.COM if (fd == -1) { 3859484Sgarrett.damore@Sun.COM int err = errno; 3869484Sgarrett.damore@Sun.COM perror(dn); 3879484Sgarrett.damore@Sun.COM errno = err; 3889484Sgarrett.damore@Sun.COM describe_error(errno); 389*11936Sgdamore@opensolaris.org return (-1); 3909484Sgarrett.damore@Sun.COM } 3919484Sgarrett.damore@Sun.COM 3929484Sgarrett.damore@Sun.COM ainfo.dev = -1; 3939484Sgarrett.damore@Sun.COM if (ioctl(fd, SNDCTL_AUDIOINFO, &ainfo) == -1) { 3949484Sgarrett.damore@Sun.COM perror("SNDCTL_AUDIOINFO"); 3959484Sgarrett.damore@Sun.COM (void) close(fd); 396*11936Sgdamore@opensolaris.org return (-1); 3979484Sgarrett.damore@Sun.COM } 3989484Sgarrett.damore@Sun.COM 3999484Sgarrett.damore@Sun.COM (void) printf(_("\n*** Scanning sound adapter #%d ***\n"), 4009484Sgarrett.damore@Sun.COM ainfo.card_number); 4019484Sgarrett.damore@Sun.COM 4029484Sgarrett.damore@Sun.COM (void) printf(_("%s (audio engine %d): %s\n"), ainfo.devnode, ainfo.dev, 4039484Sgarrett.damore@Sun.COM ainfo.name); 4049484Sgarrett.damore@Sun.COM 4059484Sgarrett.damore@Sun.COM if (!ainfo.enabled) { 4069484Sgarrett.damore@Sun.COM (void) printf(_(" - Device not present - Skipping\n")); 4079484Sgarrett.damore@Sun.COM (void) close(fd); 408*11936Sgdamore@opensolaris.org return (0); 4099484Sgarrett.damore@Sun.COM } 4109484Sgarrett.damore@Sun.COM 4119484Sgarrett.damore@Sun.COM if (!(ainfo.caps & PCM_CAP_OUTPUT)) { 4129484Sgarrett.damore@Sun.COM (void) printf(_(" - Skipping input only device\n")); 4139484Sgarrett.damore@Sun.COM (void) close(fd); 414*11936Sgdamore@opensolaris.org return (0); 4159484Sgarrett.damore@Sun.COM } 4169484Sgarrett.damore@Sun.COM 4179484Sgarrett.damore@Sun.COM (void) printf(_(" - Performing audio playback test... ")); 4189484Sgarrett.damore@Sun.COM (void) fflush(stdout); 4199484Sgarrett.damore@Sun.COM 4209484Sgarrett.damore@Sun.COM code = testdsp(fd, flags, tcfg); 4219484Sgarrett.damore@Sun.COM (void) close(fd); 422*11936Sgdamore@opensolaris.org if (code < 0) { 423*11936Sgdamore@opensolaris.org return (code); 424*11936Sgdamore@opensolaris.org } 4259484Sgarrett.damore@Sun.COM 4269484Sgarrett.damore@Sun.COM return (code == 1); 4279484Sgarrett.damore@Sun.COM } 4289484Sgarrett.damore@Sun.COM 4299484Sgarrett.damore@Sun.COM void 4309484Sgarrett.damore@Sun.COM describe_error(int err) 4319484Sgarrett.damore@Sun.COM { 4329484Sgarrett.damore@Sun.COM switch (err) { 4339484Sgarrett.damore@Sun.COM case ENODEV: 4349484Sgarrett.damore@Sun.COM (void) fprintf(stderr, 4359484Sgarrett.damore@Sun.COM _("The device file was found in /dev but\n" 4369484Sgarrett.damore@Sun.COM "the driver was not loaded.\n")); 4379484Sgarrett.damore@Sun.COM break; 4389484Sgarrett.damore@Sun.COM 4399484Sgarrett.damore@Sun.COM case ENXIO: 4409484Sgarrett.damore@Sun.COM (void) fprintf(stderr, 4419484Sgarrett.damore@Sun.COM _("There are no sound devices available.\n" 4429484Sgarrett.damore@Sun.COM "The most likely reason is that the device you have\n" 4439484Sgarrett.damore@Sun.COM "is malfunctioning or it's not supported.\n" 4449484Sgarrett.damore@Sun.COM "It's also possible that you are trying to use the wrong " 4459484Sgarrett.damore@Sun.COM "device file.\n")); 4469484Sgarrett.damore@Sun.COM break; 4479484Sgarrett.damore@Sun.COM 4489484Sgarrett.damore@Sun.COM case ENOSPC: 4499484Sgarrett.damore@Sun.COM (void) fprintf(stderr, 4509484Sgarrett.damore@Sun.COM _("Your system cannot allocate memory for the device\n" 4519484Sgarrett.damore@Sun.COM "buffers. Reboot your machine and try again.\n")); 4529484Sgarrett.damore@Sun.COM break; 4539484Sgarrett.damore@Sun.COM 4549484Sgarrett.damore@Sun.COM case ENOENT: 4559484Sgarrett.damore@Sun.COM (void) fprintf(stderr, 4569484Sgarrett.damore@Sun.COM _("The device file is missing from /dev.\n")); 4579484Sgarrett.damore@Sun.COM break; 4589484Sgarrett.damore@Sun.COM 4599484Sgarrett.damore@Sun.COM 4609484Sgarrett.damore@Sun.COM case EBUSY: 4619484Sgarrett.damore@Sun.COM (void) fprintf(stderr, 4629484Sgarrett.damore@Sun.COM _("The device is busy. There is some other application\n" 4639484Sgarrett.damore@Sun.COM "using it.\n")); 4649484Sgarrett.damore@Sun.COM break; 4659484Sgarrett.damore@Sun.COM 4669484Sgarrett.damore@Sun.COM default: 4679484Sgarrett.damore@Sun.COM break; 4689484Sgarrett.damore@Sun.COM } 4699484Sgarrett.damore@Sun.COM } 4709484Sgarrett.damore@Sun.COM 4719484Sgarrett.damore@Sun.COM int 4729484Sgarrett.damore@Sun.COM main(int argc, char *argv[]) 4739484Sgarrett.damore@Sun.COM { 4749484Sgarrett.damore@Sun.COM int t, i; 4759484Sgarrett.damore@Sun.COM int maxdev; 4769484Sgarrett.damore@Sun.COM int flags = 0; 4779484Sgarrett.damore@Sun.COM int status = 0; 478*11936Sgdamore@opensolaris.org int errors = 0; 4799484Sgarrett.damore@Sun.COM int numdev; 4809484Sgarrett.damore@Sun.COM extern int optind; 4819484Sgarrett.damore@Sun.COM testcfg_t *tcfg; 4829484Sgarrett.damore@Sun.COM 4839484Sgarrett.damore@Sun.COM (void) setlocale(LC_ALL, ""); 4849484Sgarrett.damore@Sun.COM (void) textdomain(TEXT_DOMAIN); 4859484Sgarrett.damore@Sun.COM 4869484Sgarrett.damore@Sun.COM tcfg = &test_stereo; 4879484Sgarrett.damore@Sun.COM 4889484Sgarrett.damore@Sun.COM /* 4899484Sgarrett.damore@Sun.COM * Simple command line switch handling. 4909484Sgarrett.damore@Sun.COM */ 4919484Sgarrett.damore@Sun.COM 4929484Sgarrett.damore@Sun.COM while ((i = getopt(argc, argv, "l2457")) != EOF) { 4939484Sgarrett.damore@Sun.COM switch (i) { 4949484Sgarrett.damore@Sun.COM case 'l': 4959484Sgarrett.damore@Sun.COM flags |= TF_LOOP; 4969484Sgarrett.damore@Sun.COM break; 4979484Sgarrett.damore@Sun.COM case '2': 4989484Sgarrett.damore@Sun.COM tcfg = &test_stereo; 4999484Sgarrett.damore@Sun.COM break; 5009484Sgarrett.damore@Sun.COM case '4': 5019484Sgarrett.damore@Sun.COM tcfg = &test_quad; 5029484Sgarrett.damore@Sun.COM break; 5039484Sgarrett.damore@Sun.COM case '5': 5049484Sgarrett.damore@Sun.COM tcfg = &test_51; 5059484Sgarrett.damore@Sun.COM break; 5069484Sgarrett.damore@Sun.COM case '7': 5079484Sgarrett.damore@Sun.COM tcfg = &test_71; 5089484Sgarrett.damore@Sun.COM break; 5099484Sgarrett.damore@Sun.COM default: 5109484Sgarrett.damore@Sun.COM (void) printf(_("Usage: %s [options...] [device]\n" 5119484Sgarrett.damore@Sun.COM " -2 Stereo test\n" 5129484Sgarrett.damore@Sun.COM " -4 Quadraphonic 4.0 test\n" 5139484Sgarrett.damore@Sun.COM " -5 Surround 5.1 test\n" 5149484Sgarrett.damore@Sun.COM " -7 Surround 7.1 test\n" 5159484Sgarrett.damore@Sun.COM " -l Loop test\n"), argv[0]); 5169484Sgarrett.damore@Sun.COM exit(-1); 5179484Sgarrett.damore@Sun.COM } 5189484Sgarrett.damore@Sun.COM } 5199484Sgarrett.damore@Sun.COM 5209484Sgarrett.damore@Sun.COM /* 5219484Sgarrett.damore@Sun.COM * Open the mixer device used for calling SNDCTL_SYSINFO and 5229484Sgarrett.damore@Sun.COM * SNDCTL_AUDIOINFO. 5239484Sgarrett.damore@Sun.COM */ 5249484Sgarrett.damore@Sun.COM if ((mixerfd = open("/dev/mixer", O_RDWR, 0)) == -1) { 5259484Sgarrett.damore@Sun.COM int err = errno; 5269484Sgarrett.damore@Sun.COM perror("/dev/mixer"); 5279484Sgarrett.damore@Sun.COM errno = err; 5289484Sgarrett.damore@Sun.COM describe_error(errno); 5299484Sgarrett.damore@Sun.COM exit(-1); 5309484Sgarrett.damore@Sun.COM } 5319484Sgarrett.damore@Sun.COM 5329484Sgarrett.damore@Sun.COM prepare(tcfg); /* Prepare the wave data */ 5339484Sgarrett.damore@Sun.COM 5349484Sgarrett.damore@Sun.COM /* 5359484Sgarrett.damore@Sun.COM * Enumerate all devices and play the test sounds. 5369484Sgarrett.damore@Sun.COM */ 5379484Sgarrett.damore@Sun.COM maxdev = find_num_devices(); 5389484Sgarrett.damore@Sun.COM if (maxdev < 1) { 5399484Sgarrett.damore@Sun.COM (void) printf(_("\n*** No audio hardware available ***\n")); 5409484Sgarrett.damore@Sun.COM exit(-1); 5419484Sgarrett.damore@Sun.COM } 5429484Sgarrett.damore@Sun.COM 5439484Sgarrett.damore@Sun.COM numdev = (argc - optind); 5449484Sgarrett.damore@Sun.COM do { 5459484Sgarrett.damore@Sun.COM char *dn; 5469484Sgarrett.damore@Sun.COM oss_audioinfo ainfo; 547*11936Sgdamore@opensolaris.org int rv; 5489484Sgarrett.damore@Sun.COM 549*11936Sgdamore@opensolaris.org status = 0; 5509484Sgarrett.damore@Sun.COM if (numdev > 0) { 5519484Sgarrett.damore@Sun.COM for (t = 0; t < numdev; t++) { 5529484Sgarrett.damore@Sun.COM dn = argv[optind + t]; 553*11936Sgdamore@opensolaris.org rv = test_device(dn, flags, tcfg); 554*11936Sgdamore@opensolaris.org if (rv < 0) { 555*11936Sgdamore@opensolaris.org errors++; 556*11936Sgdamore@opensolaris.org } else if (rv) { 5579484Sgarrett.damore@Sun.COM status++; 558*11936Sgdamore@opensolaris.org } 5599484Sgarrett.damore@Sun.COM } 5609484Sgarrett.damore@Sun.COM } else { 5619484Sgarrett.damore@Sun.COM for (t = 0; t < maxdev; t++) { 5629484Sgarrett.damore@Sun.COM ainfo.dev = t; 5639484Sgarrett.damore@Sun.COM if (ioctl(mixerfd, SNDCTL_AUDIOINFO, 5649484Sgarrett.damore@Sun.COM &ainfo) == -1) { 5659484Sgarrett.damore@Sun.COM perror("SNDCTL_AUDIOINFO"); 5669484Sgarrett.damore@Sun.COM status++; 5679484Sgarrett.damore@Sun.COM continue; 5689484Sgarrett.damore@Sun.COM } 5699484Sgarrett.damore@Sun.COM dn = ainfo.devnode; 570*11936Sgdamore@opensolaris.org rv = test_device(dn, flags, tcfg); 571*11936Sgdamore@opensolaris.org if (rv < 0) { 572*11936Sgdamore@opensolaris.org errors++; 573*11936Sgdamore@opensolaris.org } else if (rv) { 5749484Sgarrett.damore@Sun.COM status++; 575*11936Sgdamore@opensolaris.org } 5769484Sgarrett.damore@Sun.COM } 5779484Sgarrett.damore@Sun.COM } 5789484Sgarrett.damore@Sun.COM 579*11936Sgdamore@opensolaris.org if (errors == 0) 5809484Sgarrett.damore@Sun.COM (void) printf(_("\n*** All tests completed OK ***\n")); 5819484Sgarrett.damore@Sun.COM else 5829484Sgarrett.damore@Sun.COM (void) printf(_("\n*** Errors were detected ***\n")); 5839484Sgarrett.damore@Sun.COM 584*11936Sgdamore@opensolaris.org } while (status && (flags & TF_LOOP)); 5859484Sgarrett.damore@Sun.COM 5869484Sgarrett.damore@Sun.COM (void) close(mixerfd); 5879484Sgarrett.damore@Sun.COM 5889484Sgarrett.damore@Sun.COM return (status); 5899484Sgarrett.damore@Sun.COM } 590