$OpenBSD$
--- src/unix/linux_snd.c.orig	Tue Aug 10 18:17:01 2010
+++ src/unix/linux_snd.c	Wed Aug 18 21:39:36 2010
@@ -1,309 +1,157 @@
 /*
-===========================================================================
+ * Copyright (c) 2010 Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
 
-Return to Castle Wolfenstein single player GPL Source Code
-Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
-This file is part of the Return to Castle Wolfenstein single player GPL Source Code (RTCW SP Source Code).  
-
-RTCW SP Source Code is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-RTCW SP Source Code is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
-
-In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code.  If not, please request a copy in writing from id Software at the address below.
-
-If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
-
-===========================================================================
-*/
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
 #include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/shm.h>
-#include <sys/wait.h>
-#ifdef __linux__ // rb0101023 - guard this
-#include <linux/soundcard.h>
-#endif
-#ifdef __FreeBSD__ // rb0101023 - added
-#include <sys/soundcard.h>
-#endif
 #include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <errno.h>
 
+#include <sndio.h>
+
 #include "../game/q_shared.h"
 #include "../client/snd_local.h"
 
-int audio_fd;
-int snd_inited = 0;
+static struct sio_hdl *hdl;
+static int snd_inited;
 
-cvar_t *sndbits;
-cvar_t *sndspeed;
-cvar_t *sndchannels;
+unsigned char *dma_buffer;
+size_t dma_buffer_size, dma_ptr;
 
-cvar_t *snddevice;
 
-/* Some devices may work only with 48000 */
-static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
-
-static qboolean use_custom_memset = qfalse;
-// show_bug.cgi?id=371
-void Snd_Memset( void* dest, const int val, const size_t count ) {
-	int *pDest;
-	int i, iterate;
-
-	if ( !use_custom_memset ) {
-		Com_Memset( dest,val,count );
-		return;
-	}
-	iterate = count / sizeof( int );
-	pDest = (int*)dest;
-	for ( i = 0; i < iterate; i++ )
-	{
-		pDest[i] = val;
-	}
-}
-
-qboolean SNDDMA_Init( void ) {
-	int rc;
-	int fmt;
-	int tmp;
+qboolean
+SNDDMA_Init(void)
+{
+	struct sio_par par;
 	int i;
-	// char *s; // bk001204 - unused
-	struct audio_buf_info info;
-	int caps;
-	extern uid_t saved_euid;
 
-	if ( snd_inited ) {
-		return 1;
-	}
+	if (snd_inited)
+		return qtrue;
 
-	if ( !snddevice ) {
-		sndbits = Cvar_Get( "sndbits", "16", CVAR_ARCHIVE );
-		sndspeed = Cvar_Get( "sndspeed", "0", CVAR_ARCHIVE );
-		sndchannels = Cvar_Get( "sndchannels", "2", CVAR_ARCHIVE );
-		snddevice = Cvar_Get( "snddevice", "/dev/dsp", CVAR_ARCHIVE );
+	hdl = sio_open(NULL, SIO_PLAY, 1);
+	if (hdl == NULL) {
+		Com_Printf("Could not open sndio device\n");
+		return qfalse;
 	}
 
-	// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
-	if ( !audio_fd ) {
-		seteuid( saved_euid );
+	sio_initpar(&par);
 
-		audio_fd = open( snddevice->string, O_RDWR );
+	par.bits = 16;
+	par.sig = 1;
+	par.pchan = 2;
+	par.rate = 44100;
+	par.le = SIO_LE_NATIVE;
+	par.appbufsz = par.rate / 10;	/* 1/10 second latency */
 
-		seteuid( getuid() );
-
-		if ( audio_fd < 0 ) {
-			perror( snddevice->string );
-			Com_Printf( "Could not open %s\n", snddevice->string );
-			return 0;
-		}
+	if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
+		Com_Printf("Error setting audio parameters\n");
+		sio_close(hdl);
+		return qfalse;
 	}
-
-	if ( ioctl( audio_fd, SNDCTL_DSP_GETCAPS, &caps ) == -1 ) {
-		perror( snddevice->string );
-		Com_Printf( "Sound driver too old\n" );
-		close( audio_fd );
-		return 0;
+	if ((par.pchan != 1 && par.pchan != 2) ||
+	    !((par.bits == 16 && par.sig == 1) ||
+	      (par.bits == 8 && par.sig == 0))) {
+		Com_Printf("Could not set appropriate audio parameters\n");
+		sio_close(hdl);
+		return qfalse;
 	}
-
-	if ( !( caps & DSP_CAP_TRIGGER ) || !( caps & DSP_CAP_MMAP ) ) {
-		Com_Printf( "Sorry but your soundcard can't do this\n" );
-		close( audio_fd );
-		return 0;
-	}
-
-
-	/* SNDCTL_DSP_GETOSPACE moved to be called later */
-
-	// set sample bits & speed
-	dma.samplebits = (int)sndbits->value;
-	if ( dma.samplebits != 16 && dma.samplebits != 8 ) {
-		ioctl( audio_fd, SNDCTL_DSP_GETFMTS, &fmt );
-		if ( fmt & AFMT_S16_LE ) {
-			dma.samplebits = 16;
-		} else if ( fmt & AFMT_U8 ) {
-			dma.samplebits = 8;
-		}
-	}
-
-	dma.speed = (int)sndspeed->value;
-	if ( !dma.speed ) {
-		for ( i = 0 ; i < sizeof( tryrates ) / 4 ; i++ )
-			if ( !ioctl( audio_fd, SNDCTL_DSP_SPEED, &tryrates[i] ) ) {
-				break;
-			}
-		dma.speed = tryrates[i];
-	}
-
-	dma.channels = (int)sndchannels->value;
-	if ( dma.channels < 1 || dma.channels > 2 ) {
-		dma.channels = 2;
-	}
-
-/*  mmap() call moved forward */
-
-	tmp = 0;
-	if ( dma.channels == 2 ) {
-		tmp = 1;
-	}
-	rc = ioctl( audio_fd, SNDCTL_DSP_STEREO, &tmp );
-	if ( rc < 0 ) {
-		perror( snddevice->string );
-		Com_Printf( "Could not set %s to stereo=%d", snddevice->string, dma.channels );
-		close( audio_fd );
-		return 0;
-	}
-
-	if ( tmp ) {
-		dma.channels = 2;
-	} else {
-		dma.channels = 1;
-	}
-
-	rc = ioctl( audio_fd, SNDCTL_DSP_SPEED, &dma.speed );
-	if ( rc < 0 ) {
-		perror( snddevice->string );
-		Com_Printf( "Could not set %s speed to %d", snddevice->string, dma.speed );
-		close( audio_fd );
-		return 0;
-	}
-
-	if ( dma.samplebits == 16 ) {
-		rc = AFMT_S16_LE;
-		rc = ioctl( audio_fd, SNDCTL_DSP_SETFMT, &rc );
-		if ( rc < 0 ) {
-			perror( snddevice->string );
-			Com_Printf( "Could not support 16-bit data.  Try 8-bit.\n" );
-			close( audio_fd );
-			return 0;
-		}
-	} else if ( dma.samplebits == 8 ) {
-		rc = AFMT_U8;
-		rc = ioctl( audio_fd, SNDCTL_DSP_SETFMT, &rc );
-		if ( rc < 0 ) {
-			perror( snddevice->string );
-			Com_Printf( "Could not support 8-bit data.\n" );
-			close( audio_fd );
-			return 0;
-		}
-	} else {
-		perror( snddevice->string );
-		Com_Printf( "%d-bit sound not supported.", dma.samplebits );
-		close( audio_fd );
-		return 0;
-	}
-
-	if ( ioctl( audio_fd, SNDCTL_DSP_GETOSPACE, &info ) == -1 ) {
-		perror( "GETOSPACE" );
-		Com_Printf( "Um, can't do GETOSPACE?\n" );
-		close( audio_fd );
-		return 0;
-	}
-
-	dma.samples = info.fragstotal * info.fragsize / ( dma.samplebits / 8 );
+	dma.speed = par.rate;
+	dma.channels = par.pchan;
+	dma.samplebits = par.bits;
 	dma.submission_chunk = 1;
 
-	// memory map the dma buffer
-	// TTimo PROT_READ
-	// show_bug.cgi?id=371
-	// checking Alsa bug, doesn't allow dma alloc with PROT_READ?
+	/*
+	 * find the smallest power of two larger than the buffer size
+	 * and use it as the internal buffer's size
+	 */
+	for (i = 1; i < par.appbufsz; i <<= 2)
+		; /* nothing */
+	dma.samples = i * par.pchan;
 
-	// 1-17-2002
-	// use local C implementation of memset in all cases
-	// propagated from MP code to be safe with sound stuff once and for all
-
-/*
-	if (!dma.buffer)
-		dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal
-			* info.fragsize, PROT_WRITE|PROT_READ, MAP_FILE|MAP_SHARED, audio_fd, 0);
-*/
-	dma.buffer = NULL;
-
-	if ( dma.buffer == NULL ) {
-//    Com_Printf("Could not mmap dma buffer PROT_WRITE|PROT_READ\n");
-//    Com_Printf("trying mmap PROT_WRITE (with associated better compatibility / less performance code)\n");
-		dma.buffer = (unsigned char *) mmap( NULL, info.fragstotal
-											 * info.fragsize, PROT_WRITE, MAP_FILE | MAP_SHARED, audio_fd, 0 );
-		// LordHavoc MAP_FAILED is a bad value to have outside init code
-		if (dma.buffer == MAP_FAILED)
-			dma.buffer = NULL;
-		// NOTE TTimo could add a variable to force using regular memset on systems that are known to be safe
-		use_custom_memset = qtrue;
+	dma_buffer_size = dma.samples * dma.samplebits / 8;
+	dma_buffer = calloc(1, dma_buffer_size);
+	if (dma_buffer == NULL) {
+		Com_Printf("Could not allocate audio ring buffer\n");
+		return qfalse;
 	}
-
-	if ( dma.buffer == NULL ) {
-		perror( snddevice->string );
-		Com_Printf( "Could not mmap %s\n", snddevice->string );
-		close( audio_fd );
-		return 0;
+	dma_ptr = 0;
+	dma.buffer = dma_buffer;
+	if (!sio_start(hdl)) {
+		Com_Printf("Could not start audio\n");
+		sio_close(hdl);
+		return qfalse;
 	}
 
-	// toggle the trigger & start her up
+	snd_inited = qtrue;
+	return qtrue;
+}
 
-	tmp = 0;
-	rc  = ioctl( audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp );
-	if ( rc < 0 ) {
-		perror( snddevice->string );
-		Com_Printf( "Could not toggle.\n" );
-		close( audio_fd );
-		return 0;
+void
+SNDDMA_Shutdown(void)
+{
+	if (snd_inited == qtrue) {
+		sio_close(hdl);
+		snd_inited = qfalse;
 	}
+	free(dma_buffer);
+}
 
-	tmp = PCM_ENABLE_OUTPUT;
-	rc = ioctl( audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp );
-	if ( rc < 0 ) {
-		perror( snddevice->string );
-		Com_Printf( "Could not toggle.\n" );
-		close( audio_fd );
+int
+SNDDMA_GetDMAPos(void)
+{
+	if (!snd_inited)
+		return (0);
 
-		return 0;
-	}
-
-	snd_inited = 1;
-	return 1;
+	return (dma_ptr / (dma.samplebits / 8));
 }
 
-int SNDDMA_GetDMAPos( void ) {
-	struct count_info count;
+void
+SNDDMA_Submit(void)
+{
+	struct pollfd pfd;
+	size_t count, todo, avail;
+	int n;
 
-	if ( !snd_inited ) {
-		return 0;
+	n = sio_pollfd(hdl, &pfd, POLLOUT);
+	while (poll(&pfd, n, 0) < 0 && errno == EINTR)
+		;
+	if (!(sio_revents(hdl, &pfd) & POLLOUT))
+		return;
+	avail = dma_buffer_size;
+	while (avail > 0) {
+		todo = dma_buffer_size - dma_ptr;
+		if (todo > avail)
+			todo = avail;
+		count = sio_write(hdl, dma_buffer + dma_ptr, todo);
+		if (count == 0)
+			break;
+		dma_ptr += count;
+		if (dma_ptr >= dma_buffer_size)
+			dma_ptr -= dma_buffer_size;
+		avail -= count;
 	}
-
-	if ( ioctl( audio_fd, SNDCTL_DSP_GETOPTR, &count ) == -1 ) {
-		perror( snddevice->string );
-		Com_Printf( "Uh, sound dead.\n" );
-		close( audio_fd );
-		snd_inited = 0;
-		return 0;
-	}
-	return count.ptr / ( dma.samplebits / 8 );
 }
 
-void SNDDMA_Shutdown( void ) {
-}
-
-/*
-==============
-SNDDMA_Submit
-
-Send sound to device if buffer isn't really the dma buffer
-===============
-*/
-void SNDDMA_Submit( void ) {
-}
-
-void SNDDMA_BeginPainting( void ) {
+void
+SNDDMA_BeginPainting(void)
+{
 }
