On Fri, Apr 30, 2010 at 08:30:09AM +0000, Jacob Meuser wrote: > faking an mmap()d DMA buffer isn't exactly trivial. not really sure > why the Id people thought they would always be able to use mmap(). > we don't support mmap() on azalia, uaudio, mavb, audioce, the macppc > i2s drivers, and probably more. > > this works best for me on an azalia by using 'aucat -l -b 2048 -z 1024'. > with just 'aucat -l', it doesn't seem to work very well. > > it works pretty well without aucat, but sometimes the audio just drops > out. no idea why.
this version works much better. plain 'aucat -l' ends up with too large of a block size, but e.g. 'aucat -l -z 512' works like a charm. -- [email protected] SDF Public Access UNIX System - http://sdf.lonestar.org Index: Makefile =================================================================== RCS file: /cvs/ports/games/quake/Makefile,v retrieving revision 1.27 diff -N -u -p Makefile --- Makefile 15 Apr 2010 14:11:01 -0000 1.27 +++ Makefile 30 Apr 2010 11:09:52 -0000 @@ -6,7 +6,7 @@ CATEGORIES= games FULLPKGNAME-server= quakeworld-server-20000101p6p0 FULLPKGPATH-server= games/quake,-server -PKGNAME-main= quake-20000101p8 +PKGNAME-main= quake-20000101p9 DISTNAME= quake-v6-bsd-kame PATCHFILES= quake6-00-v6-20000202b.diff.gz:0 PATCH_DIST_STRIP= -p1 Index: files/snd_openbsd.c =================================================================== RCS file: /cvs/ports/games/quake/files/snd_openbsd.c,v retrieving revision 1.1.1.1 diff -N -u -p files/snd_openbsd.c --- files/snd_openbsd.c 3 Aug 2001 13:02:16 -0000 1.1.1.1 +++ files/snd_openbsd.c 30 Apr 2010 11:09:52 -0000 @@ -1,176 +1,228 @@ /* -Copyright (C) 1996-1997 Id Software, Inc. + * Copyright (c) 2010 Jacob Meuser <[email protected]> + * + * 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. + */ -This program 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 2 -of the License, or (at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ #include "quakedef.h" +#include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> -#include <sys/types.h> -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_MMAN_H -# include <sys/mman.h> -#endif -# include <sys/audioio.h> +#include <poll.h> +#include <errno.h> -static int audio_fd; -static int snd_inited; +#include <sndio.h> -static int tryrates[] = { 11025, 22051, 44100, 8000 }; +static struct sio_hdl *hdl; +static qboolean snd_inited; +static long long realpos, last_realpos; +static long long writtentime; +static int wbufp; +static int bround; -qboolean SNDDMA_Init(void) -{ +unsigned char *dma_buffer; +size_t dma_buffer_size; - int rc; - int fmt; - int tmp; - int i; - char *s; - audio_info_t info; - int caps; - snd_inited = 0; +static void +onmove(void *addr, int delta) +{ + realpos += delta; +} -// open /dev/dsp, confirm capability to mmap, and get size of dma buffer +qboolean +SNDDMA_Init(void) +{ + struct sio_par par; + char *s; + int i, todo; - // XXX Must open audio Read-Write for now for dma to work !!! - audio_fd = open("/dev/audio", O_RDWR); - if (audio_fd < 0) - { - perror("/dev/audio"); - Con_Printf("Could not open /dev/audio\n"); - return 0; + if (snd_inited == true) { + Con_Printf("Sound already inited\n"); + return false; } - - if (ioctl(audio_fd, AUDIO_GETPROPS, &caps)==-1) - { - perror("/dev/audio"); - Con_Printf("Sound driver does not understand GETPROPS\n"); - close(audio_fd); - return 0; + hdl = sio_open(NULL, SIO_PLAY, 0); + if (hdl == NULL) { + Con_Printf("Could not open sndio device\n"); + return false; } - if (!(caps & AUDIO_PROP_MMAP)) - { - Con_Printf("Sorry but your soundcard doesn't support mmap\n"); - close(audio_fd); - return 0; - } - shm = &sn; - shm->splitbuffer = 0; + shm->splitbuffer = 0; -// set sample bits & speed - - shm->samplebits = 16; - shm->speed = 11025; - s = getenv("QUAKE_SOUND_CHANNELS"); - if (s) shm->channels = atoi(s); + s = getenv("QUAKE_SOUND_CHANNELS"); + if (s) + shm->channels = atoi(s); else if ((i = COM_CheckParm("-sndmono")) != 0) shm->channels = 1; else if ((i = COM_CheckParm("-sndstereo")) != 0) shm->channels = 2; - else shm->channels = 2; + else + shm->channels = 2; + sio_initpar(&par); + par.rate = 11025; + par.bits = 16; + par.sig = 1; + par.le = SIO_LE_NATIVE; + par.pchan = shm->channels; + par.round = 512; + par.appbufsz = par.round * 4; - AUDIO_INITINFO(&info); - info.play.precision = shm->samplebits; - info.play.sample_rate = 11025; - info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; - info.play.channels = shm->channels; - if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1) { - Con_Printf("Bad encoding size\n"); - close(audio_fd); - return 0; - } - ioctl(audio_fd, AUDIO_GETINFO, &info); - shm->speed = info.play.sample_rate; + if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) { + Con_Printf("Error setting audio parameters\n"); + sio_close(hdl); + return false; + } - shm->samples = info.play.buffer_size / (shm->samplebits/8); - shm->submission_chunk = 1; + if ((par.pchan != 1 && par.pchan != 2) || + (par.bits != 16 || par.sig != 1)) { + Con_Printf("Could not set appropriate audio parameters\n"); + sio_close(hdl); + return false; + } -// memory map the dma buffer + bround = par.round; -// XXX This is absurd but dma does not work if not mmapped read/write. - shm->buffer = (unsigned char *) mmap(NULL, info.play.buffer_size, - PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0); - -// if (!shm->buffer || shm->buffer == (unsigned char *)-1) - if (shm->buffer == MAP_FAILED) - { - perror("/dev/audio"); - Con_Printf("Could not mmap /dev/audio\n"); - close(audio_fd); - return 0; + shm->speed = par.rate; + shm->channels = par.pchan; + shm->samplebits = par.bits; + + shm->samples = par.appbufsz * par.pchan; + dma_buffer_size = shm->samples * shm->samplebits / 8; + dma_buffer = calloc(1, dma_buffer_size); + if (dma_buffer == NULL) { + Con_Printf("Could not allocate audio ring buffer\n"); + return false; } + shm->buffer = dma_buffer; + realpos = last_realpos = 0; + sio_onmove(hdl, onmove, NULL); + + if (!sio_start(hdl)) { + Con_Printf("Could not start audio\n"); + sio_close(hdl); + return false; + } + + /* quake won't start writing until we do ... */ + todo = par.bufsz * par.pchan * par.bps; + while (todo) { + i = sio_write(hdl, dma_buffer, min(dma_buffer_size, todo)); + todo -= i; + } + + shm->submission_chunk = 1; + shm->soundalive = true; shm->samplepos = 0; + writtentime = 0; + wbufp = 0; - snd_inited = 1; - return 1; + snd_inited = true; + return true; } -int SNDDMA_GetDMAPos(void) +void +SNDDMA_Shutdown(void) { + if (snd_inited == true) { + sio_close(hdl); + snd_inited = false; + } + free(dma_buffer); +} - audio_offset_t count; +int +SNDDMA_GetDMAPos(void) +{ + struct pollfd pfd; + int n, add; - if (!snd_inited) return 0; + if (!snd_inited) + return (0); - if (ioctl(audio_fd, AUDIO_GETOOFFS, &count)==-1) - { - perror("/dev/audio"); - Con_Printf("Uh, sound dead.\n"); - close(audio_fd); - snd_inited = 0; - return 0; - } -// shm->samplepos = (count.bytes / (shm->samplebits / 8)) & (shm->samples-1); -// fprintf(stderr, "%d \r", count.ptr); - shm->samplepos = count.offset / (shm->samplebits / 8); + n = sio_pollfd(hdl, &pfd, POLLOUT); + while (poll(&pfd, n, 0) < 0 && errno == EINTR) + ; + sio_revents(hdl, &pfd); - return shm->samplepos; + /* Add a block, because quake wants the block to write to, not + * the one just consumed. However, make sure not to report that + * we've moved exactly a multiple of the buffer size, because + * that would look like we didn't move at all ... + */ + if ((realpos > last_realpos) && + ((realpos - last_realpos) % (shm->samples / shm->channels) == 0)) + add = 0; + else + add = bround; + n = ((realpos + add) * shm->channels) % shm->samples; + +#ifdef DEBUG + printf("realpos=%lld writtentime=%lld paintedtime=%lld n=%d samples=%d\n", + realpos, writtentime, (long long)paintedtime, n, shm->samples); +#endif + + last_realpos = realpos; + + return n; } -void SNDDMA_Shutdown(void) +void +SNDDMA_Submit(void) { - if (snd_inited) - { - close(audio_fd); - snd_inited = 0; - } -} + int frsize, bframes, nframes, bytes, ret; -/* -============== -SNDDMA_Submit + frsize = shm->channels * (shm->samplebits / 8); + bframes = dma_buffer_size / frsize; -Send sound to device if buffer isn't really the dma buffer -=============== -*/ -void SNDDMA_Submit(void) -{ -} + /* must have started over */ + if (paintedtime < writtentime) + wbufp = 0; + /* Number of frames to write. `paintedtime' is the number of + * frames quake has written. Do not write more than the + * number of frames between the position of the last samples we + * wrote and the end of the buffer, of course. + */ + nframes = min(paintedtime - writtentime, bframes - wbufp); + + if (!nframes) + return; + + /* Writing one block at a time helps avoid chances of wrapping + * the buffer between calls and otherwise keeps nice alignment. + */ + if (nframes > bround) + nframes = bround; + + bytes = nframes * frsize; + ret = sio_write(hdl, &dma_buffer[wbufp * frsize], bytes); + if (ret < bytes) + printf("audio can't keep up: %d of %d\n", ret, bytes); + + nframes = ret / frsize; + + writtentime += nframes; + wbufp += nframes; + + if (wbufp >= bframes) + wbufp = 0; +}
