$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 + * + * 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 . - -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 -#include -#include #include -#include -#include -#include -#include -#ifdef __linux__ // rb0101023 - guard this -#include -#endif -#ifdef __FreeBSD__ // rb0101023 - added -#include -#endif #include +#include +#include +#include +#include +#include +#include + #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) +{ }