xref: /illumos-gate/usr/src/cmd/audio/audiotest/audiotest.c (revision a33ad26ef1f3b7a3fcf2fad564e6bd3798fdcbae)
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