$NetBSD: patch-src_plugins_sun_ao__sun.c,v 1.3 2020/06/05 10:08:35 nia Exp $

- Fix device selection on NetBSD.
- Support 24-bit playback on NetBSD.

--- src/plugins/sun/ao_sun.c.orig	2016-11-14 08:03:30.000000000 +0000
+++ src/plugins/sun/ao_sun.c
@@ -78,6 +78,9 @@ typedef struct ao_sun_internal {
 	char *dev;
         int id;
 	int fd;
+	int linear24;
+	void *convbuf;
+	size_t convbuf_sz;
 } ao_sun_internal;
 
 
@@ -160,7 +163,11 @@ int ao_plugin_open(ao_device *device, ao
 
         if(internal->dev==NULL){
           char buf[80];
-          sprintf(buf,"/dev/sound/%d",internal->id);
+#ifndef __sun
+          snprintf(buf,sizeof(buf),"/dev/audio%d",internal->id);
+#else
+          snprintf(buf,sizeof(buf),"/dev/sound/%d",internal->id);
+#endif
           internal->dev=strdup(buf);
         }
 
@@ -172,7 +179,12 @@ int ao_plugin_open(ao_device *device, ao
 	info.mode = AUMODE_PLAY;
 #endif
 	info.play.encoding = AUDIO_ENCODING_SLINEAR;
-	info.play.precision = format->bits;
+	if (format->bits == 24) {
+		info.play.precision = 32;
+		internal->linear24 = 1;
+	} else {
+		info.play.precision = format->bits;
+	}
 	info.play.sample_rate = format->rate;
 	info.play.channels = device->output_channels;
 
@@ -198,8 +210,46 @@ int ao_plugin_play(ao_device *device, co
 		uint_32 num_bytes)
 {
 	ao_sun_internal *internal = (ao_sun_internal *) device->internal;
+	void *out;
+
+	/* convert 24-bit linear to 32-bit linear for NetBSD compat */
+	if (internal->linear24) {
+		unsigned char *srcp = (unsigned char *)output_samples;
+		size_t nsamples = num_bytes / 3;
+		size_t bufsz = nsamples * 4;
+		sint_32 *outp, temp;
+
+		if (internal->convbuf_sz < bufsz) {
+			internal->convbuf = realloc(internal->convbuf, bufsz);
+			if (!internal->convbuf)
+				return 1;
+			internal->convbuf_sz = bufsz;
+		}
+		outp = internal->convbuf;
+		if (device->driver_byte_format != AO_FMT_BIG) {
+			while (nsamples--) {
+				temp = (((sint_32)srcp[0]) << 8);
+				temp = temp | (((sint_32)srcp[1]) << 16);
+				temp = temp | (((sint_32)srcp[2]) << 24);
+				*(outp++) = temp;
+				srcp += 3;
+			}
+		} else {
+			while (nsamples--) {
+				temp = (((sint_32)srcp[0]) << 24);
+				temp = temp | (((sint_32)srcp[1]) << 16);
+				temp = temp | (((sint_32)srcp[2]) << 8);
+				*(outp++) = temp;
+				srcp += 3;
+			}
+		}
+		num_bytes = bufsz;
+		out = internal->convbuf;
+	} else {
+		out = (void *)output_samples;
+	}
 
-	if (write(internal->fd, output_samples, num_bytes) < 0)
+	if (write(internal->fd, out, num_bytes) < 0)
 		return 0;
 	else
 		return 1;
@@ -224,6 +274,7 @@ void ao_plugin_device_clear(ao_device *d
 
         if(internal->dev)
           free(internal->dev);
+	free(internal->convbuf);
 	free(internal);
         device->internal=NULL;
 }
