$OpenBSD: patch-libao2_ao_sun_c,v 1.2 2006/07/19 21:40:47 robert Exp $
--- libao2/ao_sun.c.orig	Sun Jun 11 20:35:42 2006
+++ libao2/ao_sun.c	Thu Jul  6 00:08:11 2006
@@ -65,7 +65,57 @@ static enum {
 } enable_sample_timing;
 
 
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+int sun_mixer_get_dev(int fd, int *dev, char *id)
+{
+	mixer_devinfo_t info;
 
+	for (info.index = 0; ioctl(fd, AUDIO_MIXER_DEVINFO, &info) >= 0;
+	     info.index++) {
+		if (!strcmp(id, info.label.name)) {
+			*dev = info.index;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int sun_get_volume(int fd, int *l, int *r)
+{
+	mixer_ctrl_t mixer;
+
+	if (sun_mixer_get_dev(fd, &mixer.dev, "master") < 0)
+		return -1;
+
+	mixer.type = AUDIO_MIXER_VALUE;
+	mixer.un.value.num_channels = 2;
+	if (ioctl(fd, AUDIO_MIXER_READ, &mixer) < 0)
+		return -1;
+	*l = mixer.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
+	*r = mixer.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
+
+	return 0;
+}
+
+int sun_set_volume(int fd, int l, int r)
+{
+	mixer_ctrl_t mixer;
+
+	if (sun_mixer_get_dev(fd, &mixer.dev, "master") < 0)
+		return -1;
+
+	mixer.type = AUDIO_MIXER_VALUE;
+	mixer.un.value.num_channels = 2;
+	mixer.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
+	mixer.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
+
+	if (ioctl(fd, AUDIO_MIXER_WRITE, &mixer) < 0)
+		return -1;
+
+	return 0;
+}
+#endif
+
 // convert an OSS audio format specification into a sun audio encoding
 static int af2sunfmt(int format)
 {
@@ -365,13 +415,21 @@ static void setup_device_paths()
 	    audio_dev = "/dev/audio";
     }
 
+#if defined(__OpenBSD__) || defined(__NetBSD__)
     if (sun_mixer_device == NULL) {
+	if (mixer_device == NULL)
+	    mixer_device = strdup("/dev/mixer");
+	sun_mixer_device = mixer_device;
+    }
+#else
+    if (sun_mixer_device == NULL) {
 	if ((sun_mixer_device = mixer_device) == NULL || !sun_mixer_device[0]) {
 	    sun_mixer_device = malloc(strlen(audio_dev) + 4);
 	    strcpy(sun_mixer_device, audio_dev);
 	    strcat(sun_mixer_device, "ctl");
 	}
     }
+#endif
 
     if (ao_subdevice) audio_dev = ao_subdevice;
 }
@@ -395,6 +453,14 @@ static int control(int cmd,void *arg){
 	if ( fd != -1 )
 	{
 	    ao_control_vol_t *vol = (ao_control_vol_t *)arg;
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+	    int r, l;
+	    if (sun_get_volume(fd, &r, &l) < 0) {
+		    close(fd);
+		    goto cgerr;
+	    }
+	    vol->right = vol->left = (float)(r * 100. / AUDIO_MAX_GAIN);
+#else
 	    float volume;
 	    struct audio_info info;
 	    ioctl( fd,AUDIO_GETINFO,&info);
@@ -409,9 +475,11 @@ static int control(int cmd,void *arg){
 							/ AUDIO_MID_BALANCE;
 		vol->right = volume;
 	    }
+#endif
 	    close( fd );
 	    return CONTROL_OK;
-	}	
+	}
+cgerr:
 	return CONTROL_ERROR;
     }
     case AOCONTROL_SET_VOLUME:
@@ -422,10 +490,18 @@ static int control(int cmd,void *arg){
 	if ( !sun_mixer_device )    /* control function is used before init? */
 	    setup_device_paths();
 
-	fd=open( sun_mixer_device,O_RDONLY );
+	fd=open( sun_mixer_device,O_RDWR );
 	if ( fd != -1 )
 	{
 	    struct audio_info info;
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+	    int r;
+	    r = (int)(vol->right * AUDIO_MAX_GAIN / 100);
+	    if (sun_set_volume(fd, r, r) < 0) {
+		    close(fd);
+		    goto cserr;
+	    }
+#else
 	    float volume;
 	    AUDIO_INITINFO(&info);
 	    volume = vol->right > vol->left ? vol->right : vol->left;
@@ -440,9 +516,11 @@ static int control(int cmd,void *arg){
 	    info.output_muted = (volume == 0);
 #endif
 	    ioctl( fd,AUDIO_SETINFO,&info );
+#endif
 	    close( fd );
 	    return CONTROL_OK;
-	}	
+	}
+cserr:
 	return CONTROL_ERROR;
     }
     }
