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;
+}

Reply via email to