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*12389SEdgar.Liu@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
259484Sgarrett.damore@Sun.COM */
269484Sgarrett.damore@Sun.COM /*
279484Sgarrett.damore@Sun.COM * This program is a general purpose test facility for audio output.
289484Sgarrett.damore@Sun.COM * It does not test record.
299484Sgarrett.damore@Sun.COM *
309484Sgarrett.damore@Sun.COM * The wavedata.c and wavedata.h files contain the actual samples compressed
319484Sgarrett.damore@Sun.COM * using the MS ADPCM algorithm.
329484Sgarrett.damore@Sun.COM */
339484Sgarrett.damore@Sun.COM
349484Sgarrett.damore@Sun.COM #include <stdio.h>
359484Sgarrett.damore@Sun.COM #include <stdlib.h>
369484Sgarrett.damore@Sun.COM #include <unistd.h>
379484Sgarrett.damore@Sun.COM #include <fcntl.h>
389484Sgarrett.damore@Sun.COM #include <string.h>
399484Sgarrett.damore@Sun.COM #include <errno.h>
409484Sgarrett.damore@Sun.COM #include <unistd.h>
419484Sgarrett.damore@Sun.COM #include <sys/time.h>
429484Sgarrett.damore@Sun.COM #include <sys/ioctl.h>
439484Sgarrett.damore@Sun.COM #include <sys/utsname.h>
449484Sgarrett.damore@Sun.COM #include <sys/soundcard.h>
459484Sgarrett.damore@Sun.COM #include <inttypes.h>
469484Sgarrett.damore@Sun.COM #include <locale.h>
479484Sgarrett.damore@Sun.COM
489484Sgarrett.damore@Sun.COM #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
499484Sgarrett.damore@Sun.COM #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
509484Sgarrett.damore@Sun.COM #endif
519484Sgarrett.damore@Sun.COM
529484Sgarrett.damore@Sun.COM #define _(s) gettext(s)
539484Sgarrett.damore@Sun.COM
549484Sgarrett.damore@Sun.COM /*
559484Sgarrett.damore@Sun.COM * Channel selectors
569484Sgarrett.damore@Sun.COM */
579484Sgarrett.damore@Sun.COM #define CH_LEFT (1 << 0)
589484Sgarrett.damore@Sun.COM #define CH_RIGHT (1 << 1)
599484Sgarrett.damore@Sun.COM #define CH_LREAR4 (1 << 2) /* quadraphonic */
609484Sgarrett.damore@Sun.COM #define CH_RREAR4 (1 << 3) /* quadraphonic */
619484Sgarrett.damore@Sun.COM #define CH_CENTER (1 << 2)
629484Sgarrett.damore@Sun.COM #define CH_LFE (1 << 3)
639484Sgarrett.damore@Sun.COM #define CH_LSURR (1 << 4)
649484Sgarrett.damore@Sun.COM #define CH_RSURR (1 << 5)
659484Sgarrett.damore@Sun.COM #define CH_LREAR (1 << 6)
669484Sgarrett.damore@Sun.COM #define CH_RREAR (1 << 7)
679484Sgarrett.damore@Sun.COM #define CH_STEREO (CH_LEFT|CH_RIGHT)
689484Sgarrett.damore@Sun.COM #define CH_4 (CH_STEREO | CH_LREAR4 | CH_RREAR4)
699484Sgarrett.damore@Sun.COM #define CH_5 (CH_STEREO | CH_CENTER | CH_LSURR | CH_RSURR)
709484Sgarrett.damore@Sun.COM #define CH_7 (CH_5 | CH_LREAR | CH_RREAR)
719484Sgarrett.damore@Sun.COM
729484Sgarrett.damore@Sun.COM typedef struct chancfg {
739484Sgarrett.damore@Sun.COM int mask;
749484Sgarrett.damore@Sun.COM const char *name;
759484Sgarrett.damore@Sun.COM unsigned flags;
769484Sgarrett.damore@Sun.COM int16_t *data;
779484Sgarrett.damore@Sun.COM int len;
789484Sgarrett.damore@Sun.COM } chancfg_t;
799484Sgarrett.damore@Sun.COM
809484Sgarrett.damore@Sun.COM typedef struct testcfg {
819484Sgarrett.damore@Sun.COM int nchan;
82*12389SEdgar.Liu@Sun.COM uint32_t rate;
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 = {
127*12389SEdgar.Liu@Sun.COM 2, 48000, { &ch_left, &ch_right, &ch_stereo, NULL }
1289484Sgarrett.damore@Sun.COM };
1299484Sgarrett.damore@Sun.COM
1309484Sgarrett.damore@Sun.COM testcfg_t test_quad = {
131*12389SEdgar.Liu@Sun.COM 4, 48000, { &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 = {
136*12389SEdgar.Liu@Sun.COM 6, 48000, { &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 = {
141*12389SEdgar.Liu@Sun.COM 8, 48000, { &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
prepare(testcfg_t * tcfg)1749484Sgarrett.damore@Sun.COM prepare(testcfg_t *tcfg)
1759484Sgarrett.damore@Sun.COM {
1769484Sgarrett.damore@Sun.COM int nsamples;
177*12389SEdgar.Liu@Sun.COM int i, j;
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;
191*12389SEdgar.Liu@Sun.COM int rate_multiple;
1929484Sgarrett.damore@Sun.COM
1939484Sgarrett.damore@Sun.COM src = sample_buf;
194*12389SEdgar.Liu@Sun.COM rate_multiple = tcfg->rate / 48000;
1959484Sgarrett.damore@Sun.COM
1969484Sgarrett.damore@Sun.COM if (ccfg->flags != CFLAG_LFE) {
197*12389SEdgar.Liu@Sun.COM ccfg->len = nsamples * tcfg->nchan *
198*12389SEdgar.Liu@Sun.COM sizeof (int16_t) * rate_multiple;
1999484Sgarrett.damore@Sun.COM ccfg->data = malloc(ccfg->len);
2009484Sgarrett.damore@Sun.COM if ((dst = ccfg->data) == NULL) {
2019484Sgarrett.damore@Sun.COM perror("malloc");
2029484Sgarrett.damore@Sun.COM exit(-1);
2039484Sgarrett.damore@Sun.COM }
2049484Sgarrett.damore@Sun.COM for (samp = 0; samp < nsamples; samp++) {
2059484Sgarrett.damore@Sun.COM for (ch = 0; ch < tcfg->nchan; ch++) {
206*12389SEdgar.Liu@Sun.COM for (j = 0; j < rate_multiple; j++) {
207*12389SEdgar.Liu@Sun.COM *dst = ((1U << ch) & ccfg->mask)
208*12389SEdgar.Liu@Sun.COM ? *src : 0;
209*12389SEdgar.Liu@Sun.COM dst++;
210*12389SEdgar.Liu@Sun.COM }
2119484Sgarrett.damore@Sun.COM }
2129484Sgarrett.damore@Sun.COM src += 2;
2139484Sgarrett.damore@Sun.COM }
2149484Sgarrett.damore@Sun.COM } else {
2159484Sgarrett.damore@Sun.COM /* Skip LFE for now */
2169484Sgarrett.damore@Sun.COM ccfg->len = 0;
2179484Sgarrett.damore@Sun.COM }
2189484Sgarrett.damore@Sun.COM }
2199484Sgarrett.damore@Sun.COM }
2209484Sgarrett.damore@Sun.COM
2219484Sgarrett.damore@Sun.COM /*
2229484Sgarrett.damore@Sun.COM * The testdsp() routine checks the capabilities of a given audio device number
2239484Sgarrett.damore@Sun.COM * (parameter n) and decides if the test sound needs to be played.
2249484Sgarrett.damore@Sun.COM */
2259484Sgarrett.damore@Sun.COM
2269484Sgarrett.damore@Sun.COM /*ARGSUSED*/
2279484Sgarrett.damore@Sun.COM int
testdsp(int hd,int flags,testcfg_t * tcfg)2289484Sgarrett.damore@Sun.COM testdsp(int hd, int flags, testcfg_t *tcfg)
2299484Sgarrett.damore@Sun.COM {
2309484Sgarrett.damore@Sun.COM float ratio;
2319484Sgarrett.damore@Sun.COM struct timeval t1, t2;
2329484Sgarrett.damore@Sun.COM unsigned long t;
2339484Sgarrett.damore@Sun.COM int sample_rate;
2349484Sgarrett.damore@Sun.COM int delay;
2359484Sgarrett.damore@Sun.COM long long total_bytes = 0;
2369484Sgarrett.damore@Sun.COM unsigned int tmp, caps;
2379484Sgarrett.damore@Sun.COM int i;
2389484Sgarrett.damore@Sun.COM chancfg_t *ccfg;
2399484Sgarrett.damore@Sun.COM
2409484Sgarrett.damore@Sun.COM caps = 0;
2419484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
2429484Sgarrett.damore@Sun.COM perror("SNDCTL_DSP_GETCAPS");
2439484Sgarrett.damore@Sun.COM return (-1);
2449484Sgarrett.damore@Sun.COM }
2459484Sgarrett.damore@Sun.COM
2469484Sgarrett.damore@Sun.COM /*
2479484Sgarrett.damore@Sun.COM * Setup the sample format. Since OSS will support AFMT_S16_NE
2489484Sgarrett.damore@Sun.COM * regardless of the device we do not need to support any
2499484Sgarrett.damore@Sun.COM * other formats.
2509484Sgarrett.damore@Sun.COM */
2519484Sgarrett.damore@Sun.COM tmp = AFMT_S16_NE;
2529484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_SETFMT, &tmp) == -1 || tmp != AFMT_S16_NE) {
2539484Sgarrett.damore@Sun.COM (void) printf(_("Device doesn't support native 16-bit PCM\n"));
2549484Sgarrett.damore@Sun.COM return (-1);
2559484Sgarrett.damore@Sun.COM }
2569484Sgarrett.damore@Sun.COM
2579484Sgarrett.damore@Sun.COM /*
2589484Sgarrett.damore@Sun.COM * Setup the device for channels. Once again we can simply
2599484Sgarrett.damore@Sun.COM * assume that stereo will always work before OSS takes care
2609484Sgarrett.damore@Sun.COM * of this by emulation if necessary.
2619484Sgarrett.damore@Sun.COM */
2629484Sgarrett.damore@Sun.COM tmp = tcfg->nchan;
2639484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_CHANNELS, &tmp) == -1 || tmp != tcfg->nchan) {
2649484Sgarrett.damore@Sun.COM (void) printf(_("The device doesn't support %d channels\n"),
2659484Sgarrett.damore@Sun.COM tcfg->nchan);
2669484Sgarrett.damore@Sun.COM return (-2);
2679484Sgarrett.damore@Sun.COM }
2689484Sgarrett.damore@Sun.COM
2699484Sgarrett.damore@Sun.COM /*
2709484Sgarrett.damore@Sun.COM * Set up the sample rate.
2719484Sgarrett.damore@Sun.COM */
272*12389SEdgar.Liu@Sun.COM tmp = tcfg->rate;
2739484Sgarrett.damore@Sun.COM if (ioctl(hd, SNDCTL_DSP_SPEED, &tmp) == -1) {
2749484Sgarrett.damore@Sun.COM perror("SNDCTL_DSP_SPEED");
2759484Sgarrett.damore@Sun.COM return (-3);
2769484Sgarrett.damore@Sun.COM }
2779484Sgarrett.damore@Sun.COM
2789484Sgarrett.damore@Sun.COM sample_rate = tmp;
279*12389SEdgar.Liu@Sun.COM if (sample_rate != tcfg->rate) {
2809484Sgarrett.damore@Sun.COM (void) printf(_("The device doesn't support %d Hz\n"),
281*12389SEdgar.Liu@Sun.COM tcfg->rate);
2829484Sgarrett.damore@Sun.COM return (-3);
2839484Sgarrett.damore@Sun.COM }
2849484Sgarrett.damore@Sun.COM (void) printf("\n");
2859484Sgarrett.damore@Sun.COM
2869484Sgarrett.damore@Sun.COM /*
2879484Sgarrett.damore@Sun.COM * This program will measure the real sampling rate by
2889484Sgarrett.damore@Sun.COM * computing the total time required to play the sample.
2899484Sgarrett.damore@Sun.COM *
2909484Sgarrett.damore@Sun.COM * This is not terribly presice with short test sounds but it
2919484Sgarrett.damore@Sun.COM * can be used to detect if the sampling rate badly
2929484Sgarrett.damore@Sun.COM * wrong. Errors of few percents is more likely to be caused
2939484Sgarrett.damore@Sun.COM * by poor accuracy of the system clock rather than problems
2949484Sgarrett.damore@Sun.COM * with the sampling rate.
2959484Sgarrett.damore@Sun.COM */
2969484Sgarrett.damore@Sun.COM (void) gettimeofday(&t1, NULL);
2979484Sgarrett.damore@Sun.COM
2989484Sgarrett.damore@Sun.COM for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) {
2999484Sgarrett.damore@Sun.COM (void) fputs(_(ccfg->name), stdout);
3009484Sgarrett.damore@Sun.COM (void) fflush(stdout);
3019484Sgarrett.damore@Sun.COM if (ccfg->flags & CFLAG_LFE) {
3029484Sgarrett.damore@Sun.COM (void) printf(_("SKIPPED\n"));
3039484Sgarrett.damore@Sun.COM continue;
3049484Sgarrett.damore@Sun.COM }
3059484Sgarrett.damore@Sun.COM
3069484Sgarrett.damore@Sun.COM if (write(hd, ccfg->data, ccfg->len) < 0) {
3079484Sgarrett.damore@Sun.COM (void) printf(_("ERROR: %s\n"),
3089484Sgarrett.damore@Sun.COM strerror(errno));
3099484Sgarrett.damore@Sun.COM return (-3);
3109484Sgarrett.damore@Sun.COM }
3119484Sgarrett.damore@Sun.COM (void) printf(_("OK\n"));
3129484Sgarrett.damore@Sun.COM total_bytes += ccfg->len;
3139484Sgarrett.damore@Sun.COM }
3149484Sgarrett.damore@Sun.COM
3159484Sgarrett.damore@Sun.COM (void) gettimeofday(&t2, NULL);
3169484Sgarrett.damore@Sun.COM delay = 0;
3179484Sgarrett.damore@Sun.COM (void) ioctl(hd, SNDCTL_DSP_GETODELAY, &delay); /* Ignore errors */
3189484Sgarrett.damore@Sun.COM
3199484Sgarrett.damore@Sun.COM /*
3209484Sgarrett.damore@Sun.COM * Perform the time computations using milliseconds.
3219484Sgarrett.damore@Sun.COM */
3229484Sgarrett.damore@Sun.COM
3239484Sgarrett.damore@Sun.COM t = t2.tv_sec - t1.tv_sec;
3249484Sgarrett.damore@Sun.COM t *= 1000;
3259484Sgarrett.damore@Sun.COM
3269484Sgarrett.damore@Sun.COM t += t2.tv_usec / 1000;
3279484Sgarrett.damore@Sun.COM t -= t1.tv_usec / 1000;
3289484Sgarrett.damore@Sun.COM
3299484Sgarrett.damore@Sun.COM total_bytes -= delay;
3309484Sgarrett.damore@Sun.COM total_bytes *= 1000;
3319484Sgarrett.damore@Sun.COM
3329484Sgarrett.damore@Sun.COM total_bytes /= t;
3339484Sgarrett.damore@Sun.COM total_bytes /= (tcfg->nchan * sizeof (int16_t));
3349484Sgarrett.damore@Sun.COM
3359484Sgarrett.damore@Sun.COM ratio = ((float)total_bytes / (float)sample_rate) * 100.0;
3369484Sgarrett.damore@Sun.COM (void) printf(_("\t<measured sample rate %8.2f Hz (%4.2f%%)>\n"),
3379484Sgarrett.damore@Sun.COM (float)sample_rate * ratio / 100.0, ratio - 100.0);
3389484Sgarrett.damore@Sun.COM num_devices_tested++;
3399484Sgarrett.damore@Sun.COM
3409484Sgarrett.damore@Sun.COM return (1);
3419484Sgarrett.damore@Sun.COM }
3429484Sgarrett.damore@Sun.COM
3439484Sgarrett.damore@Sun.COM static int
find_num_devices(void)3449484Sgarrett.damore@Sun.COM find_num_devices(void)
3459484Sgarrett.damore@Sun.COM {
3469484Sgarrett.damore@Sun.COM oss_sysinfo info;
3479484Sgarrett.damore@Sun.COM struct utsname un;
3489484Sgarrett.damore@Sun.COM /*
3499484Sgarrett.damore@Sun.COM * Find out the number of available audio devices by calling
3509484Sgarrett.damore@Sun.COM * SNDCTL_SYSINFO.
3519484Sgarrett.damore@Sun.COM */
3529484Sgarrett.damore@Sun.COM
3539484Sgarrett.damore@Sun.COM if (ioctl(mixerfd, SNDCTL_SYSINFO, &info) == -1) {
3549484Sgarrett.damore@Sun.COM if (errno == ENXIO) {
3559484Sgarrett.damore@Sun.COM (void) fprintf(stderr,
3569484Sgarrett.damore@Sun.COM _("No supported sound hardware detected.\n"));
3579484Sgarrett.damore@Sun.COM exit(-1);
3589484Sgarrett.damore@Sun.COM } else {
3599484Sgarrett.damore@Sun.COM perror("SNDCTL_SYSINFO");
3609484Sgarrett.damore@Sun.COM (void) printf(_("Cannot get system information.\n"));
3619484Sgarrett.damore@Sun.COM exit(-1);
3629484Sgarrett.damore@Sun.COM }
3639484Sgarrett.damore@Sun.COM }
3649484Sgarrett.damore@Sun.COM (void) printf(_("Sound subsystem and version: %s %s (0x%08X)\n"),
3659484Sgarrett.damore@Sun.COM info.product, info.version, info.versionnum);
3669484Sgarrett.damore@Sun.COM
3679484Sgarrett.damore@Sun.COM if (uname(&un) != -1)
3689484Sgarrett.damore@Sun.COM (void) printf(_("Platform: %s %s %s %s\n"),
3699484Sgarrett.damore@Sun.COM un.sysname, un.release, un.version, un.machine);
3709484Sgarrett.damore@Sun.COM
3719484Sgarrett.damore@Sun.COM return (info.numaudios);
3729484Sgarrett.damore@Sun.COM }
3739484Sgarrett.damore@Sun.COM
3749484Sgarrett.damore@Sun.COM /*
3759484Sgarrett.damore@Sun.COM * The test_device() routine checks certain information about the device
3769484Sgarrett.damore@Sun.COM * and calls testdsp() to play the test sound.
3779484Sgarrett.damore@Sun.COM */
3789484Sgarrett.damore@Sun.COM
3799484Sgarrett.damore@Sun.COM int
test_device(char * dn,int flags,testcfg_t * tcfg)3809484Sgarrett.damore@Sun.COM test_device(char *dn, int flags, testcfg_t *tcfg)
3819484Sgarrett.damore@Sun.COM {
3829484Sgarrett.damore@Sun.COM oss_audioinfo ainfo;
3839484Sgarrett.damore@Sun.COM int code;
3849484Sgarrett.damore@Sun.COM int fd;
3859484Sgarrett.damore@Sun.COM
3869484Sgarrett.damore@Sun.COM fd = open(dn, O_WRONLY, 0);
3879484Sgarrett.damore@Sun.COM if (fd == -1) {
3889484Sgarrett.damore@Sun.COM int err = errno;
3899484Sgarrett.damore@Sun.COM perror(dn);
3909484Sgarrett.damore@Sun.COM errno = err;
3919484Sgarrett.damore@Sun.COM describe_error(errno);
39211936Sgdamore@opensolaris.org return (-1);
3939484Sgarrett.damore@Sun.COM }
3949484Sgarrett.damore@Sun.COM
3959484Sgarrett.damore@Sun.COM ainfo.dev = -1;
3969484Sgarrett.damore@Sun.COM if (ioctl(fd, SNDCTL_AUDIOINFO, &ainfo) == -1) {
3979484Sgarrett.damore@Sun.COM perror("SNDCTL_AUDIOINFO");
3989484Sgarrett.damore@Sun.COM (void) close(fd);
39911936Sgdamore@opensolaris.org return (-1);
4009484Sgarrett.damore@Sun.COM }
4019484Sgarrett.damore@Sun.COM
4029484Sgarrett.damore@Sun.COM (void) printf(_("\n*** Scanning sound adapter #%d ***\n"),
4039484Sgarrett.damore@Sun.COM ainfo.card_number);
4049484Sgarrett.damore@Sun.COM
4059484Sgarrett.damore@Sun.COM (void) printf(_("%s (audio engine %d): %s\n"), ainfo.devnode, ainfo.dev,
4069484Sgarrett.damore@Sun.COM ainfo.name);
4079484Sgarrett.damore@Sun.COM
4089484Sgarrett.damore@Sun.COM if (!ainfo.enabled) {
4099484Sgarrett.damore@Sun.COM (void) printf(_(" - Device not present - Skipping\n"));
4109484Sgarrett.damore@Sun.COM (void) close(fd);
41111936Sgdamore@opensolaris.org return (0);
4129484Sgarrett.damore@Sun.COM }
4139484Sgarrett.damore@Sun.COM
4149484Sgarrett.damore@Sun.COM if (!(ainfo.caps & PCM_CAP_OUTPUT)) {
4159484Sgarrett.damore@Sun.COM (void) printf(_(" - Skipping input only device\n"));
4169484Sgarrett.damore@Sun.COM (void) close(fd);
41711936Sgdamore@opensolaris.org return (0);
4189484Sgarrett.damore@Sun.COM }
4199484Sgarrett.damore@Sun.COM
4209484Sgarrett.damore@Sun.COM (void) printf(_(" - Performing audio playback test... "));
4219484Sgarrett.damore@Sun.COM (void) fflush(stdout);
4229484Sgarrett.damore@Sun.COM
4239484Sgarrett.damore@Sun.COM code = testdsp(fd, flags, tcfg);
4249484Sgarrett.damore@Sun.COM (void) close(fd);
42511936Sgdamore@opensolaris.org if (code < 0) {
42611936Sgdamore@opensolaris.org return (code);
42711936Sgdamore@opensolaris.org }
4289484Sgarrett.damore@Sun.COM
4299484Sgarrett.damore@Sun.COM return (code == 1);
4309484Sgarrett.damore@Sun.COM }
4319484Sgarrett.damore@Sun.COM
4329484Sgarrett.damore@Sun.COM void
describe_error(int err)4339484Sgarrett.damore@Sun.COM describe_error(int err)
4349484Sgarrett.damore@Sun.COM {
4359484Sgarrett.damore@Sun.COM switch (err) {
4369484Sgarrett.damore@Sun.COM case ENODEV:
4379484Sgarrett.damore@Sun.COM (void) fprintf(stderr,
4389484Sgarrett.damore@Sun.COM _("The device file was found in /dev but\n"
4399484Sgarrett.damore@Sun.COM "the driver was not loaded.\n"));
4409484Sgarrett.damore@Sun.COM break;
4419484Sgarrett.damore@Sun.COM
4429484Sgarrett.damore@Sun.COM case ENXIO:
4439484Sgarrett.damore@Sun.COM (void) fprintf(stderr,
4449484Sgarrett.damore@Sun.COM _("There are no sound devices available.\n"
4459484Sgarrett.damore@Sun.COM "The most likely reason is that the device you have\n"
4469484Sgarrett.damore@Sun.COM "is malfunctioning or it's not supported.\n"
4479484Sgarrett.damore@Sun.COM "It's also possible that you are trying to use the wrong "
4489484Sgarrett.damore@Sun.COM "device file.\n"));
4499484Sgarrett.damore@Sun.COM break;
4509484Sgarrett.damore@Sun.COM
4519484Sgarrett.damore@Sun.COM case ENOSPC:
4529484Sgarrett.damore@Sun.COM (void) fprintf(stderr,
4539484Sgarrett.damore@Sun.COM _("Your system cannot allocate memory for the device\n"
4549484Sgarrett.damore@Sun.COM "buffers. Reboot your machine and try again.\n"));
4559484Sgarrett.damore@Sun.COM break;
4569484Sgarrett.damore@Sun.COM
4579484Sgarrett.damore@Sun.COM case ENOENT:
4589484Sgarrett.damore@Sun.COM (void) fprintf(stderr,
4599484Sgarrett.damore@Sun.COM _("The device file is missing from /dev.\n"));
4609484Sgarrett.damore@Sun.COM break;
4619484Sgarrett.damore@Sun.COM
4629484Sgarrett.damore@Sun.COM
4639484Sgarrett.damore@Sun.COM case EBUSY:
4649484Sgarrett.damore@Sun.COM (void) fprintf(stderr,
4659484Sgarrett.damore@Sun.COM _("The device is busy. There is some other application\n"
4669484Sgarrett.damore@Sun.COM "using it.\n"));
4679484Sgarrett.damore@Sun.COM break;
4689484Sgarrett.damore@Sun.COM
4699484Sgarrett.damore@Sun.COM default:
4709484Sgarrett.damore@Sun.COM break;
4719484Sgarrett.damore@Sun.COM }
4729484Sgarrett.damore@Sun.COM }
4739484Sgarrett.damore@Sun.COM
4749484Sgarrett.damore@Sun.COM int
main(int argc,char * argv[])4759484Sgarrett.damore@Sun.COM main(int argc, char *argv[])
4769484Sgarrett.damore@Sun.COM {
4779484Sgarrett.damore@Sun.COM int t, i;
4789484Sgarrett.damore@Sun.COM int maxdev;
4799484Sgarrett.damore@Sun.COM int flags = 0;
4809484Sgarrett.damore@Sun.COM int status = 0;
48111936Sgdamore@opensolaris.org int errors = 0;
4829484Sgarrett.damore@Sun.COM int numdev;
4839484Sgarrett.damore@Sun.COM extern int optind;
4849484Sgarrett.damore@Sun.COM testcfg_t *tcfg;
4859484Sgarrett.damore@Sun.COM
4869484Sgarrett.damore@Sun.COM (void) setlocale(LC_ALL, "");
4879484Sgarrett.damore@Sun.COM (void) textdomain(TEXT_DOMAIN);
4889484Sgarrett.damore@Sun.COM
4899484Sgarrett.damore@Sun.COM tcfg = &test_stereo;
4909484Sgarrett.damore@Sun.COM
4919484Sgarrett.damore@Sun.COM /*
4929484Sgarrett.damore@Sun.COM * Simple command line switch handling.
4939484Sgarrett.damore@Sun.COM */
4949484Sgarrett.damore@Sun.COM
495*12389SEdgar.Liu@Sun.COM while ((i = getopt(argc, argv, "l2457r:")) != EOF) {
4969484Sgarrett.damore@Sun.COM switch (i) {
4979484Sgarrett.damore@Sun.COM case 'l':
4989484Sgarrett.damore@Sun.COM flags |= TF_LOOP;
4999484Sgarrett.damore@Sun.COM break;
5009484Sgarrett.damore@Sun.COM case '2':
5019484Sgarrett.damore@Sun.COM tcfg = &test_stereo;
5029484Sgarrett.damore@Sun.COM break;
5039484Sgarrett.damore@Sun.COM case '4':
5049484Sgarrett.damore@Sun.COM tcfg = &test_quad;
5059484Sgarrett.damore@Sun.COM break;
5069484Sgarrett.damore@Sun.COM case '5':
5079484Sgarrett.damore@Sun.COM tcfg = &test_51;
5089484Sgarrett.damore@Sun.COM break;
5099484Sgarrett.damore@Sun.COM case '7':
5109484Sgarrett.damore@Sun.COM tcfg = &test_71;
5119484Sgarrett.damore@Sun.COM break;
512*12389SEdgar.Liu@Sun.COM case 'r':
513*12389SEdgar.Liu@Sun.COM tcfg->rate = atoi(optarg);
514*12389SEdgar.Liu@Sun.COM break;
5159484Sgarrett.damore@Sun.COM default:
5169484Sgarrett.damore@Sun.COM (void) printf(_("Usage: %s [options...] [device]\n"
5179484Sgarrett.damore@Sun.COM " -2 Stereo test\n"
5189484Sgarrett.damore@Sun.COM " -4 Quadraphonic 4.0 test\n"
5199484Sgarrett.damore@Sun.COM " -5 Surround 5.1 test\n"
5209484Sgarrett.damore@Sun.COM " -7 Surround 7.1 test\n"
521*12389SEdgar.Liu@Sun.COM " -r Sample Rate (48000|96000|192000)\n"
5229484Sgarrett.damore@Sun.COM " -l Loop test\n"), argv[0]);
5239484Sgarrett.damore@Sun.COM exit(-1);
5249484Sgarrett.damore@Sun.COM }
5259484Sgarrett.damore@Sun.COM }
5269484Sgarrett.damore@Sun.COM
5279484Sgarrett.damore@Sun.COM /*
5289484Sgarrett.damore@Sun.COM * Open the mixer device used for calling SNDCTL_SYSINFO and
5299484Sgarrett.damore@Sun.COM * SNDCTL_AUDIOINFO.
5309484Sgarrett.damore@Sun.COM */
5319484Sgarrett.damore@Sun.COM if ((mixerfd = open("/dev/mixer", O_RDWR, 0)) == -1) {
5329484Sgarrett.damore@Sun.COM int err = errno;
5339484Sgarrett.damore@Sun.COM perror("/dev/mixer");
5349484Sgarrett.damore@Sun.COM errno = err;
5359484Sgarrett.damore@Sun.COM describe_error(errno);
5369484Sgarrett.damore@Sun.COM exit(-1);
5379484Sgarrett.damore@Sun.COM }
5389484Sgarrett.damore@Sun.COM
5399484Sgarrett.damore@Sun.COM prepare(tcfg); /* Prepare the wave data */
5409484Sgarrett.damore@Sun.COM
5419484Sgarrett.damore@Sun.COM /*
5429484Sgarrett.damore@Sun.COM * Enumerate all devices and play the test sounds.
5439484Sgarrett.damore@Sun.COM */
5449484Sgarrett.damore@Sun.COM maxdev = find_num_devices();
5459484Sgarrett.damore@Sun.COM if (maxdev < 1) {
5469484Sgarrett.damore@Sun.COM (void) printf(_("\n*** No audio hardware available ***\n"));
5479484Sgarrett.damore@Sun.COM exit(-1);
5489484Sgarrett.damore@Sun.COM }
5499484Sgarrett.damore@Sun.COM
5509484Sgarrett.damore@Sun.COM numdev = (argc - optind);
5519484Sgarrett.damore@Sun.COM do {
5529484Sgarrett.damore@Sun.COM char *dn;
5539484Sgarrett.damore@Sun.COM oss_audioinfo ainfo;
55411936Sgdamore@opensolaris.org int rv;
5559484Sgarrett.damore@Sun.COM
55611936Sgdamore@opensolaris.org status = 0;
5579484Sgarrett.damore@Sun.COM if (numdev > 0) {
5589484Sgarrett.damore@Sun.COM for (t = 0; t < numdev; t++) {
5599484Sgarrett.damore@Sun.COM dn = argv[optind + t];
56011936Sgdamore@opensolaris.org rv = test_device(dn, flags, tcfg);
56111936Sgdamore@opensolaris.org if (rv < 0) {
56211936Sgdamore@opensolaris.org errors++;
56311936Sgdamore@opensolaris.org } else if (rv) {
5649484Sgarrett.damore@Sun.COM status++;
56511936Sgdamore@opensolaris.org }
5669484Sgarrett.damore@Sun.COM }
5679484Sgarrett.damore@Sun.COM } else {
5689484Sgarrett.damore@Sun.COM for (t = 0; t < maxdev; t++) {
5699484Sgarrett.damore@Sun.COM ainfo.dev = t;
5709484Sgarrett.damore@Sun.COM if (ioctl(mixerfd, SNDCTL_AUDIOINFO,
5719484Sgarrett.damore@Sun.COM &ainfo) == -1) {
5729484Sgarrett.damore@Sun.COM perror("SNDCTL_AUDIOINFO");
5739484Sgarrett.damore@Sun.COM status++;
5749484Sgarrett.damore@Sun.COM continue;
5759484Sgarrett.damore@Sun.COM }
5769484Sgarrett.damore@Sun.COM dn = ainfo.devnode;
57711936Sgdamore@opensolaris.org rv = test_device(dn, flags, tcfg);
57811936Sgdamore@opensolaris.org if (rv < 0) {
57911936Sgdamore@opensolaris.org errors++;
58011936Sgdamore@opensolaris.org } else if (rv) {
5819484Sgarrett.damore@Sun.COM status++;
58211936Sgdamore@opensolaris.org }
5839484Sgarrett.damore@Sun.COM }
5849484Sgarrett.damore@Sun.COM }
5859484Sgarrett.damore@Sun.COM
58611936Sgdamore@opensolaris.org if (errors == 0)
5879484Sgarrett.damore@Sun.COM (void) printf(_("\n*** All tests completed OK ***\n"));
5889484Sgarrett.damore@Sun.COM else
5899484Sgarrett.damore@Sun.COM (void) printf(_("\n*** Errors were detected ***\n"));
5909484Sgarrett.damore@Sun.COM
59111936Sgdamore@opensolaris.org } while (status && (flags & TF_LOOP));
5929484Sgarrett.damore@Sun.COM
5939484Sgarrett.damore@Sun.COM (void) close(mixerfd);
5949484Sgarrett.damore@Sun.COM
5959484Sgarrett.damore@Sun.COM return (status);
5969484Sgarrett.damore@Sun.COM }
597