Subject: lib/34822: libossaudio ignores mixer class
To: None <lib-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <svs+pr@grep.ru>
List: netbsd-bugs
Date: 10/15/2006 01:00:00
>Number:         34822
>Category:       lib
>Synopsis:       libossaudio ignores mixer class
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Oct 15 01:00:00 +0000 2006
>Originator:     svs+pr@grep.ru
>Release:        NetBSD 3.0.1_STABLE
>Organization:
>Environment:
	
	
>Description:
If an audio driver uses 'record.master' to control record gain
(see PR 34821), libossaudio (and compat/ossaudio) may map it to
SOUND_MIXER_VOLUME, which is wrong.

>How-To-Repeat:
	
>Fix:
	
--- lib/libossaudio/ossaudio.c	1 Jun 2005 11:22:18 -0000	1.20
+++ lib/libossaudio/ossaudio.c	14 Oct 2006 22:17:21 -0000
@@ -456,7 +456,8 @@
 	int done;
 	dev_t dev;
 	int16_t devmap[SOUND_MIXER_NRDEVICES],
-	        rdevmap[NETBSD_MAXDEVS];
+	        rdevmap[NETBSD_MAXDEVS],
+		mclass[4];
 	char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
 	int enum2opaque[NETBSD_MAXDEVS];
         u_long devmask, recmask, stereomask;
@@ -509,6 +510,11 @@
 	return (m);
 }
 
+#define	_MIXER_CLASS_INPUTS	0
+#define	_MIXER_CLASS_OUTPUTS	1
+#define	_MIXER_CLASS_RECORD	2
+#define	_MIXER_CLASS_MONITOR	3
+
 /*
  * Collect the audio device information to allow faster
  * emulation of the Linux mixer ioctls.  Cache the information
@@ -521,30 +527,27 @@
 	mixer_devinfo_t mi;
 	int i, j, e;
 	static struct {
-		char *name;
+		int class;
+		const char *name;
 		int code;
 	} *dp, devs[] = {
-		{ AudioNmicrophone,	SOUND_MIXER_MIC },
-		{ AudioNline,		SOUND_MIXER_LINE },
-		{ AudioNcd,		SOUND_MIXER_CD },
-		{ AudioNdac,		SOUND_MIXER_PCM },
-		{ AudioNaux,		SOUND_MIXER_LINE1 },
-		{ AudioNrecord,		SOUND_MIXER_IMIX },
-		{ AudioNmaster,		SOUND_MIXER_VOLUME },
-		{ AudioNtreble,		SOUND_MIXER_TREBLE },
-		{ AudioNbass,		SOUND_MIXER_BASS },
-		{ AudioNspeaker,	SOUND_MIXER_SPEAKER },
-/*		{ AudioNheadphone,	?? },*/
-		{ AudioNoutput,		SOUND_MIXER_OGAIN },
-		{ AudioNinput,		SOUND_MIXER_IGAIN },
-/*		{ AudioNmaster,		SOUND_MIXER_SPEAKER },*/
-/*		{ AudioNstereo,		?? },*/
-/*		{ AudioNmono,		?? },*/
-		{ AudioNfmsynth,	SOUND_MIXER_SYNTH },
-/*		{ AudioNwave,		SOUND_MIXER_PCM },*/
-		{ AudioNmidi,		SOUND_MIXER_SYNTH },
-/*		{ AudioNmixerout,	?? },*/
-		{ 0, -1 }
+		{ _MIXER_CLASS_INPUTS, AudioNmicrophone,	SOUND_MIXER_MIC },
+		{ _MIXER_CLASS_INPUTS, AudioNline,		SOUND_MIXER_LINE },
+		{ _MIXER_CLASS_INPUTS, AudioNcd,		SOUND_MIXER_CD },
+		{ _MIXER_CLASS_INPUTS, AudioNdac,		SOUND_MIXER_PCM },
+		{ _MIXER_CLASS_INPUTS, AudioNaux,		SOUND_MIXER_LINE1 },
+		{ _MIXER_CLASS_INPUTS, AudioNspeaker,		SOUND_MIXER_SPEAKER },
+		{ _MIXER_CLASS_INPUTS, AudioNfmsynth,		SOUND_MIXER_SYNTH },
+		{ _MIXER_CLASS_INPUTS, AudioNmidi,		SOUND_MIXER_SYNTH },
+		{ _MIXER_CLASS_MONITOR, AudioNmaster,		SOUND_MIXER_VOLUME },
+		{ _MIXER_CLASS_OUTPUTS, AudioNmaster,		SOUND_MIXER_VOLUME },
+		{ _MIXER_CLASS_OUTPUTS, AudioNtreble,		SOUND_MIXER_TREBLE },
+		{ _MIXER_CLASS_OUTPUTS, AudioNbass,		SOUND_MIXER_BASS },
+		{ _MIXER_CLASS_RECORD, AudioNmaster,		SOUND_MIXER_IMIX },
+		{ _MIXER_CLASS_RECORD, AudioNrecord,		SOUND_MIXER_IMIX },
+		{ _MIXER_CLASS_RECORD, AudioNoutput,		SOUND_MIXER_OGAIN },
+		{ _MIXER_CLASS_RECORD, AudioNinput,		SOUND_MIXER_IGAIN },
+		{ 0, 0, -1 }
 	};
 	static struct audiodevinfo devcache = { 0 };
 	struct audiodevinfo *di = &devcache;
@@ -577,16 +580,33 @@
 		mi.index = i;
 		if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
 			break;
+		if (mi.type == AUDIO_MIXER_CLASS) {
+			if (strcmp(mi.label.name, AudioCinputs) == 0)
+				di->mclass[_MIXER_CLASS_INPUTS] = i;
+			if (strcmp(mi.label.name, AudioCoutputs) == 0)
+				di->mclass[_MIXER_CLASS_OUTPUTS] = i;
+			if (strcmp(mi.label.name, AudioCmonitor) == 0)
+				di->mclass[_MIXER_CLASS_MONITOR] = i;
+			if (strcmp(mi.label.name, AudioCrecord) == 0)
+				di->mclass[_MIXER_CLASS_RECORD] = i;
+		}
+	}
+	for(i = 0; i < NETBSD_MAXDEVS; i++) {
+		mi.index = i;
+		if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
+			break;
 		switch(mi.type) {
 		case AUDIO_MIXER_VALUE:
 			for(dp = devs; dp->name; dp++) {
-				if (strcmp(dp->name, mi.label.name) == 0)
+				if (strcmp(dp->name, mi.label.name) == 0
+				    && di->mclass[dp->class] == mi.mixer_class)
 					break;
 				dlen = strlen(dp->name);
 				mlen = strlen(mi.label.name);
 				if (dlen < mlen
 				    && mi.label.name[mlen-dlen-1] == '.'
-				    && strcmp(dp->name, mi.label.name + mlen - dlen) == 0)
+				    && strcmp(dp->name, mi.label.name + mlen - dlen) == 0
+				    && di->mclass[dp->class] == mi.mixer_class)
 					break;
 			}
 			if (dp->code >= 0) {
--- sys/compat/ossaudio/ossaudio.c	3 Sep 2006 20:58:26 -0000	1.53
+++ sys/compat/ossaudio/ossaudio.c	14 Oct 2006 23:18:05 -0000
@@ -536,7 +536,8 @@
 	int done;
 	dev_t dev;
 	int16_t devmap[OSS_SOUND_MIXER_NRDEVICES],
-	        rdevmap[NETBSD_MAXDEVS];
+	        rdevmap[NETBSD_MAXDEVS],
+	        mclass[4];
 	char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
 	int enum2opaque[NETBSD_MAXDEVS];
         u_long devmask, recmask, stereomask;
@@ -588,6 +589,11 @@
 	return (m);
 }
 
+#define	_MIXER_CLASS_INPUTS	0
+#define	_MIXER_CLASS_OUTPUTS	1
+#define	_MIXER_CLASS_RECORD	2
+#define	_MIXER_CLASS_MONITOR	3
+
 /*
  * Collect the audio device information to allow faster
  * emulation of the Linux mixer ioctls.  Cache the information
@@ -602,30 +608,27 @@
 	mixer_devinfo_t mi;
 	int i, j, e;
 	static const struct {
+		int class;
 		const char *name;
 		int code;
 	} *dp, devs[] = {
-		{ AudioNmicrophone,	OSS_SOUND_MIXER_MIC },
-		{ AudioNline,		OSS_SOUND_MIXER_LINE },
-		{ AudioNcd,		OSS_SOUND_MIXER_CD },
-		{ AudioNdac,		OSS_SOUND_MIXER_PCM },
-		{ AudioNaux,		OSS_SOUND_MIXER_LINE1 },
-		{ AudioNrecord,		OSS_SOUND_MIXER_IMIX },
-		{ AudioNmaster,		OSS_SOUND_MIXER_VOLUME },
-		{ AudioNtreble,		OSS_SOUND_MIXER_TREBLE },
-		{ AudioNbass,		OSS_SOUND_MIXER_BASS },
-		{ AudioNspeaker,	OSS_SOUND_MIXER_SPEAKER },
-/*		{ AudioNheadphone,	?? },*/
-		{ AudioNoutput,		OSS_SOUND_MIXER_OGAIN },
-		{ AudioNinput,		OSS_SOUND_MIXER_IGAIN },
-/*		{ AudioNmaster,		OSS_SOUND_MIXER_SPEAKER },*/
-/*		{ AudioNstereo,		?? },*/
-/*		{ AudioNmono,		?? },*/
-		{ AudioNfmsynth,	OSS_SOUND_MIXER_SYNTH },
-/*		{ AudioNwave,		OSS_SOUND_MIXER_PCM },*/
-		{ AudioNmidi,		OSS_SOUND_MIXER_SYNTH },
-/*		{ AudioNmixerout,	?? },*/
-		{ 0, -1 }
+ 		{ _MIXER_CLASS_INPUTS, AudioNmicrophone,	OSS_SOUND_MIXER_MIC },
+ 		{ _MIXER_CLASS_INPUTS, AudioNline,		OSS_SOUND_MIXER_LINE },
+ 		{ _MIXER_CLASS_INPUTS, AudioNcd,		OSS_SOUND_MIXER_CD },
+ 		{ _MIXER_CLASS_INPUTS, AudioNdac,		OSS_SOUND_MIXER_PCM },
+ 		{ _MIXER_CLASS_INPUTS, AudioNaux,		OSS_SOUND_MIXER_LINE1 },
+ 		{ _MIXER_CLASS_INPUTS, AudioNspeaker,		OSS_SOUND_MIXER_SPEAKER },
+ 		{ _MIXER_CLASS_INPUTS, AudioNfmsynth,		OSS_SOUND_MIXER_SYNTH },
+ 		{ _MIXER_CLASS_INPUTS, AudioNmidi,		OSS_SOUND_MIXER_SYNTH },
+ 		{ _MIXER_CLASS_MONITOR, AudioNmaster,		OSS_SOUND_MIXER_VOLUME },
+ 		{ _MIXER_CLASS_OUTPUTS, AudioNmaster,		OSS_SOUND_MIXER_VOLUME },
+ 		{ _MIXER_CLASS_OUTPUTS, AudioNtreble,		OSS_SOUND_MIXER_TREBLE },
+ 		{ _MIXER_CLASS_OUTPUTS, AudioNbass,		OSS_SOUND_MIXER_BASS },
+ 		{ _MIXER_CLASS_RECORD, AudioNmaster,		OSS_SOUND_MIXER_IMIX },
+ 		{ _MIXER_CLASS_RECORD, AudioNrecord,		OSS_SOUND_MIXER_IMIX },
+ 		{ _MIXER_CLASS_RECORD, AudioNoutput,		OSS_SOUND_MIXER_OGAIN },
+ 		{ _MIXER_CLASS_RECORD, AudioNinput,		OSS_SOUND_MIXER_IGAIN },
+ 		{ 0, 0, -1 }
 	};
 	int (*ioctlf)(struct file *, u_long, void *, struct lwp *) =
 	    fp->f_ops->fo_ioctl;
@@ -665,16 +668,33 @@
 		mi.index = i;
 		if (ioctlf(fp, AUDIO_MIXER_DEVINFO, (caddr_t)&mi, l) < 0)
 			break;
+		if (mi.type == AUDIO_MIXER_CLASS) {
+			if (strcmp(mi.label.name, AudioCinputs) == 0)
+				di->mclass[_MIXER_CLASS_INPUTS] = i;
+			if (strcmp(mi.label.name, AudioCoutputs) == 0)
+				di->mclass[_MIXER_CLASS_OUTPUTS] = i;
+			if (strcmp(mi.label.name, AudioCmonitor) == 0)
+				di->mclass[_MIXER_CLASS_MONITOR] = i;
+			if (strcmp(mi.label.name, AudioCrecord) == 0)
+				di->mclass[_MIXER_CLASS_RECORD] = i;
+		}
+	}
+	for(i = 0; i < NETBSD_MAXDEVS; i++) {
+		mi.index = i;
+		if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
+			break;
 		switch(mi.type) {
 		case AUDIO_MIXER_VALUE:
 			for(dp = devs; dp->name; dp++) {
-				if (strcmp(dp->name, mi.label.name) == 0)
+				if (strcmp(dp->name, mi.label.name) == 0
+				    && di->mclass[dp->class] == mi.mixer_class)
 					break;
 				dlen = strlen(dp->name);
 				mlen = strlen(mi.label.name);
 				if (dlen < mlen
 				    && mi.label.name[mlen-dlen-1] == '.'
-				    && strcmp(dp->name, mi.label.name + mlen - dlen) == 0)
+				    && strcmp(dp->name, mi.label.name + mlen - dlen) == 0
+				    && di->mclass[dp->class] == mi.mixer_class)
 					break;
 			}
 			if (dp->code >= 0) {

>Unformatted: