188447a05SGarrett D'Amore /*
288447a05SGarrett D'Amore * CDDL HEADER START
388447a05SGarrett D'Amore *
488447a05SGarrett D'Amore * The contents of this file are subject to the terms of the
588447a05SGarrett D'Amore * Common Development and Distribution License (the "License").
688447a05SGarrett D'Amore * You may not use this file except in compliance with the License.
788447a05SGarrett D'Amore *
888447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
1088447a05SGarrett D'Amore * See the License for the specific language governing permissions
1188447a05SGarrett D'Amore * and limitations under the License.
1288447a05SGarrett D'Amore *
1388447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
1488447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
1688447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
1788447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
1888447a05SGarrett D'Amore *
1988447a05SGarrett D'Amore * CDDL HEADER END
2088447a05SGarrett D'Amore */
2188447a05SGarrett D'Amore /*
2288447a05SGarrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
2388447a05SGarrett D'Amore *
24*a33ad26eSZhao Edgar Liu - Sun Microsystems * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2588447a05SGarrett D'Amore */
2688447a05SGarrett D'Amore /*
2788447a05SGarrett D'Amore * This program is a general purpose test facility for audio output.
2888447a05SGarrett D'Amore * It does not test record.
2988447a05SGarrett D'Amore *
3088447a05SGarrett D'Amore * The wavedata.c and wavedata.h files contain the actual samples compressed
3188447a05SGarrett D'Amore * using the MS ADPCM algorithm.
3288447a05SGarrett D'Amore */
3388447a05SGarrett D'Amore
3488447a05SGarrett D'Amore #include <stdio.h>
3588447a05SGarrett D'Amore #include <stdlib.h>
3688447a05SGarrett D'Amore #include <unistd.h>
3788447a05SGarrett D'Amore #include <fcntl.h>
3888447a05SGarrett D'Amore #include <string.h>
3988447a05SGarrett D'Amore #include <errno.h>
4088447a05SGarrett D'Amore #include <unistd.h>
4188447a05SGarrett D'Amore #include <sys/time.h>
4288447a05SGarrett D'Amore #include <sys/ioctl.h>
4388447a05SGarrett D'Amore #include <sys/utsname.h>
4488447a05SGarrett D'Amore #include <sys/soundcard.h>
4588447a05SGarrett D'Amore #include <inttypes.h>
4688447a05SGarrett D'Amore #include <locale.h>
4788447a05SGarrett D'Amore
4888447a05SGarrett D'Amore #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
4988447a05SGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
5088447a05SGarrett D'Amore #endif
5188447a05SGarrett D'Amore
5288447a05SGarrett D'Amore #define _(s) gettext(s)
5388447a05SGarrett D'Amore
5488447a05SGarrett D'Amore /*
5588447a05SGarrett D'Amore * Channel selectors
5688447a05SGarrett D'Amore */
5788447a05SGarrett D'Amore #define CH_LEFT (1 << 0)
5888447a05SGarrett D'Amore #define CH_RIGHT (1 << 1)
5988447a05SGarrett D'Amore #define CH_LREAR4 (1 << 2) /* quadraphonic */
6088447a05SGarrett D'Amore #define CH_RREAR4 (1 << 3) /* quadraphonic */
6188447a05SGarrett D'Amore #define CH_CENTER (1 << 2)
6288447a05SGarrett D'Amore #define CH_LFE (1 << 3)
6388447a05SGarrett D'Amore #define CH_LSURR (1 << 4)
6488447a05SGarrett D'Amore #define CH_RSURR (1 << 5)
6588447a05SGarrett D'Amore #define CH_LREAR (1 << 6)
6688447a05SGarrett D'Amore #define CH_RREAR (1 << 7)
6788447a05SGarrett D'Amore #define CH_STEREO (CH_LEFT|CH_RIGHT)
6888447a05SGarrett D'Amore #define CH_4 (CH_STEREO | CH_LREAR4 | CH_RREAR4)
6988447a05SGarrett D'Amore #define CH_5 (CH_STEREO | CH_CENTER | CH_LSURR | CH_RSURR)
7088447a05SGarrett D'Amore #define CH_7 (CH_5 | CH_LREAR | CH_RREAR)
7188447a05SGarrett D'Amore
7288447a05SGarrett D'Amore typedef struct chancfg {
7388447a05SGarrett D'Amore int mask;
7488447a05SGarrett D'Amore const char *name;
7588447a05SGarrett D'Amore unsigned flags;
7688447a05SGarrett D'Amore int16_t *data;
7788447a05SGarrett D'Amore int len;
7888447a05SGarrett D'Amore } chancfg_t;
7988447a05SGarrett D'Amore
8088447a05SGarrett D'Amore typedef struct testcfg {
8188447a05SGarrett D'Amore int nchan;
82*a33ad26eSZhao Edgar Liu - Sun Microsystems uint32_t rate;
8388447a05SGarrett D'Amore chancfg_t *tests[16];
8488447a05SGarrett D'Amore } testcfg_t;
8588447a05SGarrett D'Amore
8688447a05SGarrett D'Amore #define CFLAG_LFE 0x1 /* lfe channel - not full range */
8788447a05SGarrett D'Amore
8888447a05SGarrett D'Amore /*
8988447a05SGarrett D'Amore * TRANSLATION_NOTE : The following strings are displayed during progress.
9088447a05SGarrett D'Amore * Its important for alignment that they have the same displayed length.
9188447a05SGarrett D'Amore */
9288447a05SGarrett D'Amore #define NM_LEFT "\t<left> ................"
9388447a05SGarrett D'Amore #define NM_RIGHT "\t<right> ..............."
9488447a05SGarrett D'Amore #define NM_LREAR "\t<left rear> ..........."
9588447a05SGarrett D'Amore #define NM_RREAR "\t<right rear> .........."
9688447a05SGarrett D'Amore #define NM_LSIDE "\t<left side> ..........."
9788447a05SGarrett D'Amore #define NM_RSIDE "\t<right side> .........."
9888447a05SGarrett D'Amore #define NM_CENTER "\t<center> .............."
9988447a05SGarrett D'Amore #define NM_LFE "\t<lfe> ................."
10088447a05SGarrett D'Amore #define NM_STEREO "\t<stereo> .............."
10188447a05SGarrett D'Amore #define NM_40 "\t<4.0 surround> ........"
10288447a05SGarrett D'Amore #define NM_50 "\t<5.0 surround> ........"
10388447a05SGarrett D'Amore #define NM_70 "\t<7.0 surround> ........"
10488447a05SGarrett D'Amore
10588447a05SGarrett D'Amore chancfg_t ch_left = { CH_LEFT, NM_LEFT, 0 };
10688447a05SGarrett D'Amore chancfg_t ch_right = { CH_RIGHT, NM_RIGHT, 0 };
10788447a05SGarrett D'Amore chancfg_t ch_stereo = { CH_STEREO, NM_STEREO, 0 };
10888447a05SGarrett D'Amore
10988447a05SGarrett D'Amore chancfg_t ch_center = { CH_CENTER, NM_CENTER, 0 };
11088447a05SGarrett D'Amore chancfg_t ch_lfe = { CH_LFE, NM_LFE, CFLAG_LFE };
11188447a05SGarrett D'Amore
11288447a05SGarrett D'Amore chancfg_t ch_lsurr_4 = { (1 << 2), NM_LREAR, 0 };
11388447a05SGarrett D'Amore chancfg_t ch_rsurr_4 = { (1 << 3), NM_RREAR, 0 };
11488447a05SGarrett D'Amore chancfg_t ch_4 = { CH_4, NM_40, 0 };
11588447a05SGarrett D'Amore
11688447a05SGarrett D'Amore chancfg_t ch_lsurr_5 = { CH_LSURR, NM_LREAR, 0 };
11788447a05SGarrett D'Amore chancfg_t ch_rsurr_5 = { CH_RSURR, NM_RREAR, 0 };
11888447a05SGarrett D'Amore chancfg_t ch_5 = { CH_5, NM_50, 0 };
11988447a05SGarrett D'Amore
12088447a05SGarrett D'Amore chancfg_t ch_lsurr_7 = { CH_LSURR, NM_LSIDE, 0 };
12188447a05SGarrett D'Amore chancfg_t ch_rsurr_7 = { CH_RSURR, NM_RSIDE, 0 };
12288447a05SGarrett D'Amore chancfg_t ch_lrear_7 = { CH_LREAR, NM_LREAR, 0 };
12388447a05SGarrett D'Amore chancfg_t ch_rrear_7 = { CH_RREAR, NM_RREAR, 0 };
12488447a05SGarrett D'Amore chancfg_t ch_7 = { CH_7, NM_70, 0 };
12588447a05SGarrett D'Amore
12688447a05SGarrett D'Amore testcfg_t test_stereo = {
127*a33ad26eSZhao Edgar Liu - Sun Microsystems 2, 48000, { &ch_left, &ch_right, &ch_stereo, NULL }
12888447a05SGarrett D'Amore };
12988447a05SGarrett D'Amore
13088447a05SGarrett D'Amore testcfg_t test_quad = {
131*a33ad26eSZhao Edgar Liu - Sun Microsystems 4, 48000, { &ch_left, &ch_right, &ch_stereo,
13288447a05SGarrett D'Amore &ch_lsurr_4, &ch_rsurr_4, &ch_4, NULL }
13388447a05SGarrett D'Amore };
13488447a05SGarrett D'Amore
13588447a05SGarrett D'Amore testcfg_t test_51 = {
136*a33ad26eSZhao Edgar Liu - Sun Microsystems 6, 48000, { &ch_left, &ch_right, &ch_stereo,
13788447a05SGarrett D'Amore &ch_lsurr_5, &ch_rsurr_5, &ch_center, &ch_lfe, &ch_5, NULL }
13888447a05SGarrett D'Amore };
13988447a05SGarrett D'Amore
14088447a05SGarrett D'Amore testcfg_t test_71 = {
141*a33ad26eSZhao Edgar Liu - Sun Microsystems 8, 48000, { &ch_left, &ch_right, &ch_stereo,
14288447a05SGarrett D'Amore &ch_lsurr_7, &ch_rsurr_7, &ch_lrear_7, &ch_rrear_7,
14388447a05SGarrett D'Amore &ch_center, &ch_lfe, &ch_7, NULL }
14488447a05SGarrett D'Amore };
14588447a05SGarrett D'Amore
14688447a05SGarrett D'Amore /*
14788447a05SGarrett D'Amore * uncompress_wave() is defined in wavedata.c. It expands the audio
14888447a05SGarrett D'Amore * samples stored in wavedata.h and returns the lenghth of the
14988447a05SGarrett D'Amore * uncompressed version in bytes.
15088447a05SGarrett D'Amore *
15188447a05SGarrett D'Amore * The uncompressed wave data format is 16 bit (native) stereo
15288447a05SGarrett D'Amore * recorded at 48000 Hz.
15388447a05SGarrett D'Amore */
15488447a05SGarrett D'Amore extern int uncompress_wave(short *outbuf);
15588447a05SGarrett D'Amore
15688447a05SGarrett D'Amore static int data_len;
15788447a05SGarrett D'Amore
15888447a05SGarrett D'Amore #define MAXDEVICE 64
15988447a05SGarrett D'Amore extern void describe_error(int);
16088447a05SGarrett D'Amore
16188447a05SGarrett D'Amore #define SAMPLE_RATE 48000
16288447a05SGarrett D'Amore
16388447a05SGarrett D'Amore /*
16488447a05SGarrett D'Amore * Operating mode flags (set from the command line).
16588447a05SGarrett D'Amore */
16688447a05SGarrett D'Amore #define TF_LOOP 0x00000010 /* Loop until interrupted */
16788447a05SGarrett D'Amore
16888447a05SGarrett D'Amore static int mixerfd;
16988447a05SGarrett D'Amore static int num_devices_tested = 0;
17088447a05SGarrett D'Amore
17188447a05SGarrett D'Amore static short *sample_buf;
17288447a05SGarrett D'Amore
17388447a05SGarrett D'Amore void
prepare(testcfg_t * tcfg)17488447a05SGarrett D'Amore prepare(testcfg_t *tcfg)
17588447a05SGarrett D'Amore {
17688447a05SGarrett D'Amore int nsamples;
177*a33ad26eSZhao Edgar Liu - Sun Microsystems int i, j;
17888447a05SGarrett D'Amore chancfg_t *ccfg;
17988447a05SGarrett D'Amore if ((sample_buf = malloc(2000000)) == NULL) {
18088447a05SGarrett D'Amore perror("malloc");
18188447a05SGarrett D'Amore exit(-1);
18288447a05SGarrett D'Amore }
18388447a05SGarrett D'Amore
18488447a05SGarrett D'Amore data_len = uncompress_wave(sample_buf);
18588447a05SGarrett D'Amore nsamples = (data_len / sizeof (int16_t)) / 2;
18688447a05SGarrett D'Amore
18788447a05SGarrett D'Amore for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) {
18888447a05SGarrett D'Amore int16_t *src, *dst;
18988447a05SGarrett D'Amore int ch;
19088447a05SGarrett D'Amore int samp;
191*a33ad26eSZhao Edgar Liu - Sun Microsystems int rate_multiple;
19288447a05SGarrett D'Amore
19388447a05SGarrett D'Amore src = sample_buf;
194*a33ad26eSZhao Edgar Liu - Sun Microsystems rate_multiple = tcfg->rate / 48000;
19588447a05SGarrett D'Amore
19688447a05SGarrett D'Amore if (ccfg->flags != CFLAG_LFE) {
197*a33ad26eSZhao Edgar Liu - Sun Microsystems ccfg->len = nsamples * tcfg->nchan *
198*a33ad26eSZhao Edgar Liu - Sun Microsystems sizeof (int16_t) * rate_multiple;
19988447a05SGarrett D'Amore ccfg->data = malloc(ccfg->len);
20088447a05SGarrett D'Amore if ((dst = ccfg->data) == NULL) {
20188447a05SGarrett D'Amore perror("malloc");
20288447a05SGarrett D'Amore exit(-1);
20388447a05SGarrett D'Amore }
20488447a05SGarrett D'Amore for (samp = 0; samp < nsamples; samp++) {
20588447a05SGarrett D'Amore for (ch = 0; ch < tcfg->nchan; ch++) {
206*a33ad26eSZhao Edgar Liu - Sun Microsystems for (j = 0; j < rate_multiple; j++) {
207*a33ad26eSZhao Edgar Liu - Sun Microsystems *dst = ((1U << ch) & ccfg->mask)
208*a33ad26eSZhao Edgar Liu - Sun Microsystems ? *src : 0;
20988447a05SGarrett D'Amore dst++;
21088447a05SGarrett D'Amore }
211*a33ad26eSZhao Edgar Liu - Sun Microsystems }
21288447a05SGarrett D'Amore src += 2;
21388447a05SGarrett D'Amore }
21488447a05SGarrett D'Amore } else {
21588447a05SGarrett D'Amore /* Skip LFE for now */
21688447a05SGarrett D'Amore ccfg->len = 0;
21788447a05SGarrett D'Amore }
21888447a05SGarrett D'Amore }
21988447a05SGarrett D'Amore }
22088447a05SGarrett D'Amore
22188447a05SGarrett D'Amore /*
22288447a05SGarrett D'Amore * The testdsp() routine checks the capabilities of a given audio device number
22388447a05SGarrett D'Amore * (parameter n) and decides if the test sound needs to be played.
22488447a05SGarrett D'Amore */
22588447a05SGarrett D'Amore
22688447a05SGarrett D'Amore /*ARGSUSED*/
22788447a05SGarrett D'Amore int
testdsp(int hd,int flags,testcfg_t * tcfg)22888447a05SGarrett D'Amore testdsp(int hd, int flags, testcfg_t *tcfg)
22988447a05SGarrett D'Amore {
23088447a05SGarrett D'Amore float ratio;
23188447a05SGarrett D'Amore struct timeval t1, t2;
23288447a05SGarrett D'Amore unsigned long t;
23388447a05SGarrett D'Amore int sample_rate;
23488447a05SGarrett D'Amore int delay;
23588447a05SGarrett D'Amore long long total_bytes = 0;
23688447a05SGarrett D'Amore unsigned int tmp, caps;
23788447a05SGarrett D'Amore int i;
23888447a05SGarrett D'Amore chancfg_t *ccfg;
23988447a05SGarrett D'Amore
24088447a05SGarrett D'Amore caps = 0;
24188447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
24288447a05SGarrett D'Amore perror("SNDCTL_DSP_GETCAPS");
24388447a05SGarrett D'Amore return (-1);
24488447a05SGarrett D'Amore }
24588447a05SGarrett D'Amore
24688447a05SGarrett D'Amore /*
24788447a05SGarrett D'Amore * Setup the sample format. Since OSS will support AFMT_S16_NE
24888447a05SGarrett D'Amore * regardless of the device we do not need to support any
24988447a05SGarrett D'Amore * other formats.
25088447a05SGarrett D'Amore */
25188447a05SGarrett D'Amore tmp = AFMT_S16_NE;
25288447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_SETFMT, &tmp) == -1 || tmp != AFMT_S16_NE) {
25388447a05SGarrett D'Amore (void) printf(_("Device doesn't support native 16-bit PCM\n"));
25488447a05SGarrett D'Amore return (-1);
25588447a05SGarrett D'Amore }
25688447a05SGarrett D'Amore
25788447a05SGarrett D'Amore /*
25888447a05SGarrett D'Amore * Setup the device for channels. Once again we can simply
25988447a05SGarrett D'Amore * assume that stereo will always work before OSS takes care
26088447a05SGarrett D'Amore * of this by emulation if necessary.
26188447a05SGarrett D'Amore */
26288447a05SGarrett D'Amore tmp = tcfg->nchan;
26388447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_CHANNELS, &tmp) == -1 || tmp != tcfg->nchan) {
26488447a05SGarrett D'Amore (void) printf(_("The device doesn't support %d channels\n"),
26588447a05SGarrett D'Amore tcfg->nchan);
26688447a05SGarrett D'Amore return (-2);
26788447a05SGarrett D'Amore }
26888447a05SGarrett D'Amore
26988447a05SGarrett D'Amore /*
27088447a05SGarrett D'Amore * Set up the sample rate.
27188447a05SGarrett D'Amore */
272*a33ad26eSZhao Edgar Liu - Sun Microsystems tmp = tcfg->rate;
27388447a05SGarrett D'Amore if (ioctl(hd, SNDCTL_DSP_SPEED, &tmp) == -1) {
27488447a05SGarrett D'Amore perror("SNDCTL_DSP_SPEED");
27588447a05SGarrett D'Amore return (-3);
27688447a05SGarrett D'Amore }
27788447a05SGarrett D'Amore
27888447a05SGarrett D'Amore sample_rate = tmp;
279*a33ad26eSZhao Edgar Liu - Sun Microsystems if (sample_rate != tcfg->rate) {
28088447a05SGarrett D'Amore (void) printf(_("The device doesn't support %d Hz\n"),
281*a33ad26eSZhao Edgar Liu - Sun Microsystems tcfg->rate);
28288447a05SGarrett D'Amore return (-3);
28388447a05SGarrett D'Amore }
28488447a05SGarrett D'Amore (void) printf("\n");
28588447a05SGarrett D'Amore
28688447a05SGarrett D'Amore /*
28788447a05SGarrett D'Amore * This program will measure the real sampling rate by
28888447a05SGarrett D'Amore * computing the total time required to play the sample.
28988447a05SGarrett D'Amore *
29088447a05SGarrett D'Amore * This is not terribly presice with short test sounds but it
29188447a05SGarrett D'Amore * can be used to detect if the sampling rate badly
29288447a05SGarrett D'Amore * wrong. Errors of few percents is more likely to be caused
29388447a05SGarrett D'Amore * by poor accuracy of the system clock rather than problems
29488447a05SGarrett D'Amore * with the sampling rate.
29588447a05SGarrett D'Amore */
29688447a05SGarrett D'Amore (void) gettimeofday(&t1, NULL);
29788447a05SGarrett D'Amore
29888447a05SGarrett D'Amore for (i = 0; (ccfg = tcfg->tests[i]) != NULL; i++) {
29988447a05SGarrett D'Amore (void) fputs(_(ccfg->name), stdout);
30088447a05SGarrett D'Amore (void) fflush(stdout);
30188447a05SGarrett D'Amore if (ccfg->flags & CFLAG_LFE) {
30288447a05SGarrett D'Amore (void) printf(_("SKIPPED\n"));
30388447a05SGarrett D'Amore continue;
30488447a05SGarrett D'Amore }
30588447a05SGarrett D'Amore
30688447a05SGarrett D'Amore if (write(hd, ccfg->data, ccfg->len) < 0) {
30788447a05SGarrett D'Amore (void) printf(_("ERROR: %s\n"),
30888447a05SGarrett D'Amore strerror(errno));
30988447a05SGarrett D'Amore return (-3);
31088447a05SGarrett D'Amore }
31188447a05SGarrett D'Amore (void) printf(_("OK\n"));
31288447a05SGarrett D'Amore total_bytes += ccfg->len;
31388447a05SGarrett D'Amore }
31488447a05SGarrett D'Amore
31588447a05SGarrett D'Amore (void) gettimeofday(&t2, NULL);
31688447a05SGarrett D'Amore delay = 0;
31788447a05SGarrett D'Amore (void) ioctl(hd, SNDCTL_DSP_GETODELAY, &delay); /* Ignore errors */
31888447a05SGarrett D'Amore
31988447a05SGarrett D'Amore /*
32088447a05SGarrett D'Amore * Perform the time computations using milliseconds.
32188447a05SGarrett D'Amore */
32288447a05SGarrett D'Amore
32388447a05SGarrett D'Amore t = t2.tv_sec - t1.tv_sec;
32488447a05SGarrett D'Amore t *= 1000;
32588447a05SGarrett D'Amore
32688447a05SGarrett D'Amore t += t2.tv_usec / 1000;
32788447a05SGarrett D'Amore t -= t1.tv_usec / 1000;
32888447a05SGarrett D'Amore
32988447a05SGarrett D'Amore total_bytes -= delay;
33088447a05SGarrett D'Amore total_bytes *= 1000;
33188447a05SGarrett D'Amore
33288447a05SGarrett D'Amore total_bytes /= t;
33388447a05SGarrett D'Amore total_bytes /= (tcfg->nchan * sizeof (int16_t));
33488447a05SGarrett D'Amore
33588447a05SGarrett D'Amore ratio = ((float)total_bytes / (float)sample_rate) * 100.0;
33688447a05SGarrett D'Amore (void) printf(_("\t<measured sample rate %8.2f Hz (%4.2f%%)>\n"),
33788447a05SGarrett D'Amore (float)sample_rate * ratio / 100.0, ratio - 100.0);
33888447a05SGarrett D'Amore num_devices_tested++;
33988447a05SGarrett D'Amore
34088447a05SGarrett D'Amore return (1);
34188447a05SGarrett D'Amore }
34288447a05SGarrett D'Amore
34388447a05SGarrett D'Amore static int
find_num_devices(void)34488447a05SGarrett D'Amore find_num_devices(void)
34588447a05SGarrett D'Amore {
34688447a05SGarrett D'Amore oss_sysinfo info;
34788447a05SGarrett D'Amore struct utsname un;
34888447a05SGarrett D'Amore /*
34988447a05SGarrett D'Amore * Find out the number of available audio devices by calling
35088447a05SGarrett D'Amore * SNDCTL_SYSINFO.
35188447a05SGarrett D'Amore */
35288447a05SGarrett D'Amore
35388447a05SGarrett D'Amore if (ioctl(mixerfd, SNDCTL_SYSINFO, &info) == -1) {
35488447a05SGarrett D'Amore if (errno == ENXIO) {
35588447a05SGarrett D'Amore (void) fprintf(stderr,
35688447a05SGarrett D'Amore _("No supported sound hardware detected.\n"));
35788447a05SGarrett D'Amore exit(-1);
35888447a05SGarrett D'Amore } else {
35988447a05SGarrett D'Amore perror("SNDCTL_SYSINFO");
36088447a05SGarrett D'Amore (void) printf(_("Cannot get system information.\n"));
36188447a05SGarrett D'Amore exit(-1);
36288447a05SGarrett D'Amore }
36388447a05SGarrett D'Amore }
36488447a05SGarrett D'Amore (void) printf(_("Sound subsystem and version: %s %s (0x%08X)\n"),
36588447a05SGarrett D'Amore info.product, info.version, info.versionnum);
36688447a05SGarrett D'Amore
36788447a05SGarrett D'Amore if (uname(&un) != -1)
36888447a05SGarrett D'Amore (void) printf(_("Platform: %s %s %s %s\n"),
36988447a05SGarrett D'Amore un.sysname, un.release, un.version, un.machine);
37088447a05SGarrett D'Amore
37188447a05SGarrett D'Amore return (info.numaudios);
37288447a05SGarrett D'Amore }
37388447a05SGarrett D'Amore
37488447a05SGarrett D'Amore /*
37588447a05SGarrett D'Amore * The test_device() routine checks certain information about the device
37688447a05SGarrett D'Amore * and calls testdsp() to play the test sound.
37788447a05SGarrett D'Amore */
37888447a05SGarrett D'Amore
37988447a05SGarrett D'Amore int
test_device(char * dn,int flags,testcfg_t * tcfg)38088447a05SGarrett D'Amore test_device(char *dn, int flags, testcfg_t *tcfg)
38188447a05SGarrett D'Amore {
38288447a05SGarrett D'Amore oss_audioinfo ainfo;
38388447a05SGarrett D'Amore int code;
38488447a05SGarrett D'Amore int fd;
38588447a05SGarrett D'Amore
38688447a05SGarrett D'Amore fd = open(dn, O_WRONLY, 0);
38788447a05SGarrett D'Amore if (fd == -1) {
38888447a05SGarrett D'Amore int err = errno;
38988447a05SGarrett D'Amore perror(dn);
39088447a05SGarrett D'Amore errno = err;
39188447a05SGarrett D'Amore describe_error(errno);
39268c47f65SGarrett D'Amore return (-1);
39388447a05SGarrett D'Amore }
39488447a05SGarrett D'Amore
39588447a05SGarrett D'Amore ainfo.dev = -1;
39688447a05SGarrett D'Amore if (ioctl(fd, SNDCTL_AUDIOINFO, &ainfo) == -1) {
39788447a05SGarrett D'Amore perror("SNDCTL_AUDIOINFO");
39888447a05SGarrett D'Amore (void) close(fd);
39968c47f65SGarrett D'Amore return (-1);
40088447a05SGarrett D'Amore }
40188447a05SGarrett D'Amore
40288447a05SGarrett D'Amore (void) printf(_("\n*** Scanning sound adapter #%d ***\n"),
40388447a05SGarrett D'Amore ainfo.card_number);
40488447a05SGarrett D'Amore
40588447a05SGarrett D'Amore (void) printf(_("%s (audio engine %d): %s\n"), ainfo.devnode, ainfo.dev,
40688447a05SGarrett D'Amore ainfo.name);
40788447a05SGarrett D'Amore
40888447a05SGarrett D'Amore if (!ainfo.enabled) {
40988447a05SGarrett D'Amore (void) printf(_(" - Device not present - Skipping\n"));
41088447a05SGarrett D'Amore (void) close(fd);
41168c47f65SGarrett D'Amore return (0);
41288447a05SGarrett D'Amore }
41388447a05SGarrett D'Amore
41488447a05SGarrett D'Amore if (!(ainfo.caps & PCM_CAP_OUTPUT)) {
41588447a05SGarrett D'Amore (void) printf(_(" - Skipping input only device\n"));
41688447a05SGarrett D'Amore (void) close(fd);
41768c47f65SGarrett D'Amore return (0);
41888447a05SGarrett D'Amore }
41988447a05SGarrett D'Amore
42088447a05SGarrett D'Amore (void) printf(_(" - Performing audio playback test... "));
42188447a05SGarrett D'Amore (void) fflush(stdout);
42288447a05SGarrett D'Amore
42388447a05SGarrett D'Amore code = testdsp(fd, flags, tcfg);
42488447a05SGarrett D'Amore (void) close(fd);
42568c47f65SGarrett D'Amore if (code < 0) {
42668c47f65SGarrett D'Amore return (code);
42768c47f65SGarrett D'Amore }
42888447a05SGarrett D'Amore
42988447a05SGarrett D'Amore return (code == 1);
43088447a05SGarrett D'Amore }
43188447a05SGarrett D'Amore
43288447a05SGarrett D'Amore void
describe_error(int err)43388447a05SGarrett D'Amore describe_error(int err)
43488447a05SGarrett D'Amore {
43588447a05SGarrett D'Amore switch (err) {
43688447a05SGarrett D'Amore case ENODEV:
43788447a05SGarrett D'Amore (void) fprintf(stderr,
43888447a05SGarrett D'Amore _("The device file was found in /dev but\n"
43988447a05SGarrett D'Amore "the driver was not loaded.\n"));
44088447a05SGarrett D'Amore break;
44188447a05SGarrett D'Amore
44288447a05SGarrett D'Amore case ENXIO:
44388447a05SGarrett D'Amore (void) fprintf(stderr,
44488447a05SGarrett D'Amore _("There are no sound devices available.\n"
44588447a05SGarrett D'Amore "The most likely reason is that the device you have\n"
44688447a05SGarrett D'Amore "is malfunctioning or it's not supported.\n"
44788447a05SGarrett D'Amore "It's also possible that you are trying to use the wrong "
44888447a05SGarrett D'Amore "device file.\n"));
44988447a05SGarrett D'Amore break;
45088447a05SGarrett D'Amore
45188447a05SGarrett D'Amore case ENOSPC:
45288447a05SGarrett D'Amore (void) fprintf(stderr,
45388447a05SGarrett D'Amore _("Your system cannot allocate memory for the device\n"
45488447a05SGarrett D'Amore "buffers. Reboot your machine and try again.\n"));
45588447a05SGarrett D'Amore break;
45688447a05SGarrett D'Amore
45788447a05SGarrett D'Amore case ENOENT:
45888447a05SGarrett D'Amore (void) fprintf(stderr,
45988447a05SGarrett D'Amore _("The device file is missing from /dev.\n"));
46088447a05SGarrett D'Amore break;
46188447a05SGarrett D'Amore
46288447a05SGarrett D'Amore
46388447a05SGarrett D'Amore case EBUSY:
46488447a05SGarrett D'Amore (void) fprintf(stderr,
46588447a05SGarrett D'Amore _("The device is busy. There is some other application\n"
46688447a05SGarrett D'Amore "using it.\n"));
46788447a05SGarrett D'Amore break;
46888447a05SGarrett D'Amore
46988447a05SGarrett D'Amore default:
47088447a05SGarrett D'Amore break;
47188447a05SGarrett D'Amore }
47288447a05SGarrett D'Amore }
47388447a05SGarrett D'Amore
47488447a05SGarrett D'Amore int
main(int argc,char * argv[])47588447a05SGarrett D'Amore main(int argc, char *argv[])
47688447a05SGarrett D'Amore {
47788447a05SGarrett D'Amore int t, i;
47888447a05SGarrett D'Amore int maxdev;
47988447a05SGarrett D'Amore int flags = 0;
48088447a05SGarrett D'Amore int status = 0;
48168c47f65SGarrett D'Amore int errors = 0;
48288447a05SGarrett D'Amore int numdev;
48388447a05SGarrett D'Amore extern int optind;
48488447a05SGarrett D'Amore testcfg_t *tcfg;
48588447a05SGarrett D'Amore
48688447a05SGarrett D'Amore (void) setlocale(LC_ALL, "");
48788447a05SGarrett D'Amore (void) textdomain(TEXT_DOMAIN);
48888447a05SGarrett D'Amore
48988447a05SGarrett D'Amore tcfg = &test_stereo;
49088447a05SGarrett D'Amore
49188447a05SGarrett D'Amore /*
49288447a05SGarrett D'Amore * Simple command line switch handling.
49388447a05SGarrett D'Amore */
49488447a05SGarrett D'Amore
495*a33ad26eSZhao Edgar Liu - Sun Microsystems while ((i = getopt(argc, argv, "l2457r:")) != EOF) {
49688447a05SGarrett D'Amore switch (i) {
49788447a05SGarrett D'Amore case 'l':
49888447a05SGarrett D'Amore flags |= TF_LOOP;
49988447a05SGarrett D'Amore break;
50088447a05SGarrett D'Amore case '2':
50188447a05SGarrett D'Amore tcfg = &test_stereo;
50288447a05SGarrett D'Amore break;
50388447a05SGarrett D'Amore case '4':
50488447a05SGarrett D'Amore tcfg = &test_quad;
50588447a05SGarrett D'Amore break;
50688447a05SGarrett D'Amore case '5':
50788447a05SGarrett D'Amore tcfg = &test_51;
50888447a05SGarrett D'Amore break;
50988447a05SGarrett D'Amore case '7':
51088447a05SGarrett D'Amore tcfg = &test_71;
51188447a05SGarrett D'Amore break;
512*a33ad26eSZhao Edgar Liu - Sun Microsystems case 'r':
513*a33ad26eSZhao Edgar Liu - Sun Microsystems tcfg->rate = atoi(optarg);
514*a33ad26eSZhao Edgar Liu - Sun Microsystems break;
51588447a05SGarrett D'Amore default:
51688447a05SGarrett D'Amore (void) printf(_("Usage: %s [options...] [device]\n"
51788447a05SGarrett D'Amore " -2 Stereo test\n"
51888447a05SGarrett D'Amore " -4 Quadraphonic 4.0 test\n"
51988447a05SGarrett D'Amore " -5 Surround 5.1 test\n"
52088447a05SGarrett D'Amore " -7 Surround 7.1 test\n"
521*a33ad26eSZhao Edgar Liu - Sun Microsystems " -r Sample Rate (48000|96000|192000)\n"
52288447a05SGarrett D'Amore " -l Loop test\n"), argv[0]);
52388447a05SGarrett D'Amore exit(-1);
52488447a05SGarrett D'Amore }
52588447a05SGarrett D'Amore }
52688447a05SGarrett D'Amore
52788447a05SGarrett D'Amore /*
52888447a05SGarrett D'Amore * Open the mixer device used for calling SNDCTL_SYSINFO and
52988447a05SGarrett D'Amore * SNDCTL_AUDIOINFO.
53088447a05SGarrett D'Amore */
53188447a05SGarrett D'Amore if ((mixerfd = open("/dev/mixer", O_RDWR, 0)) == -1) {
53288447a05SGarrett D'Amore int err = errno;
53388447a05SGarrett D'Amore perror("/dev/mixer");
53488447a05SGarrett D'Amore errno = err;
53588447a05SGarrett D'Amore describe_error(errno);
53688447a05SGarrett D'Amore exit(-1);
53788447a05SGarrett D'Amore }
53888447a05SGarrett D'Amore
53988447a05SGarrett D'Amore prepare(tcfg); /* Prepare the wave data */
54088447a05SGarrett D'Amore
54188447a05SGarrett D'Amore /*
54288447a05SGarrett D'Amore * Enumerate all devices and play the test sounds.
54388447a05SGarrett D'Amore */
54488447a05SGarrett D'Amore maxdev = find_num_devices();
54588447a05SGarrett D'Amore if (maxdev < 1) {
54688447a05SGarrett D'Amore (void) printf(_("\n*** No audio hardware available ***\n"));
54788447a05SGarrett D'Amore exit(-1);
54888447a05SGarrett D'Amore }
54988447a05SGarrett D'Amore
55088447a05SGarrett D'Amore numdev = (argc - optind);
55188447a05SGarrett D'Amore do {
55288447a05SGarrett D'Amore char *dn;
55388447a05SGarrett D'Amore oss_audioinfo ainfo;
55468c47f65SGarrett D'Amore int rv;
55588447a05SGarrett D'Amore
55668c47f65SGarrett D'Amore status = 0;
55788447a05SGarrett D'Amore if (numdev > 0) {
55888447a05SGarrett D'Amore for (t = 0; t < numdev; t++) {
55988447a05SGarrett D'Amore dn = argv[optind + t];
56068c47f65SGarrett D'Amore rv = test_device(dn, flags, tcfg);
56168c47f65SGarrett D'Amore if (rv < 0) {
56268c47f65SGarrett D'Amore errors++;
56368c47f65SGarrett D'Amore } else if (rv) {
56488447a05SGarrett D'Amore status++;
56588447a05SGarrett D'Amore }
56668c47f65SGarrett D'Amore }
56788447a05SGarrett D'Amore } else {
56888447a05SGarrett D'Amore for (t = 0; t < maxdev; t++) {
56988447a05SGarrett D'Amore ainfo.dev = t;
57088447a05SGarrett D'Amore if (ioctl(mixerfd, SNDCTL_AUDIOINFO,
57188447a05SGarrett D'Amore &ainfo) == -1) {
57288447a05SGarrett D'Amore perror("SNDCTL_AUDIOINFO");
57388447a05SGarrett D'Amore status++;
57488447a05SGarrett D'Amore continue;
57588447a05SGarrett D'Amore }
57688447a05SGarrett D'Amore dn = ainfo.devnode;
57768c47f65SGarrett D'Amore rv = test_device(dn, flags, tcfg);
57868c47f65SGarrett D'Amore if (rv < 0) {
57968c47f65SGarrett D'Amore errors++;
58068c47f65SGarrett D'Amore } else if (rv) {
58188447a05SGarrett D'Amore status++;
58288447a05SGarrett D'Amore }
58388447a05SGarrett D'Amore }
58468c47f65SGarrett D'Amore }
58588447a05SGarrett D'Amore
58668c47f65SGarrett D'Amore if (errors == 0)
58788447a05SGarrett D'Amore (void) printf(_("\n*** All tests completed OK ***\n"));
58888447a05SGarrett D'Amore else
58988447a05SGarrett D'Amore (void) printf(_("\n*** Errors were detected ***\n"));
59088447a05SGarrett D'Amore
59168c47f65SGarrett D'Amore } while (status && (flags & TF_LOOP));
59288447a05SGarrett D'Amore
59388447a05SGarrett D'Amore (void) close(mixerfd);
59488447a05SGarrett D'Amore
59588447a05SGarrett D'Amore return (status);
59688447a05SGarrett D'Amore }
597