2012-09-30 05:52:03 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
/* Modifified for FTEQW by Alf Schlichting, a.schlichting@lemarit.com */
|
|
|
|
/* note: this is for OpenBSD */
|
|
|
|
|
|
|
|
#include "quakedef.h"
|
|
|
|
#include "sound.h"
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <sndio.h>
|
|
|
|
|
|
|
|
struct sndio_private
|
|
|
|
{
|
|
|
|
struct sio_hdl *hdl;
|
|
|
|
|
|
|
|
unsigned char *dma_buffer;
|
|
|
|
size_t dma_buffer_size, dma_ptr;
|
|
|
|
};
|
|
|
|
|
2017-09-20 11:27:13 +00:00
|
|
|
static qboolean sndio_init(soundcardinfo_t *, const char *);
|
2012-09-30 05:52:03 +00:00
|
|
|
static void *sndio_lock(soundcardinfo_t *);
|
|
|
|
static void sndio_unlock(soundcardinfo_t *, void *);
|
|
|
|
static void sndio_shutdown(soundcardinfo_t *);
|
|
|
|
static unsigned int sndio_getdmapos(soundcardinfo_t *);
|
|
|
|
static void sndio_submit(soundcardinfo_t *, int, int);
|
|
|
|
static void sndio_setunderwater(soundcardinfo_t *sc, qboolean underwater); //simply a stub. Any ideas how to actually implement this properly?
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
static void sndio_setunderwater(soundcardinfo_t *sc, qboolean underwater) //simply a stub. Any ideas how to actually implement this properly?
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-09-20 11:27:13 +00:00
|
|
|
static qboolean sndio_init(soundcardinfo_t *sc, const char *cardname)
|
2012-09-30 05:52:03 +00:00
|
|
|
{
|
|
|
|
struct sndio_private *sp;
|
|
|
|
struct sio_par par;
|
|
|
|
unsigned samp_per_buf;
|
|
|
|
char *s;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Con_DPrintf("sndio_init called\n");
|
2017-09-20 11:27:13 +00:00
|
|
|
if (cardname && *cardname)
|
|
|
|
return false; //only support the default device for now.
|
2012-09-30 05:52:03 +00:00
|
|
|
|
|
|
|
sp = calloc(sizeof(struct sndio_private), 1);
|
|
|
|
if (sp == NULL)
|
|
|
|
{
|
|
|
|
Con_Printf("Could not get mem");
|
2017-09-20 11:27:13 +00:00
|
|
|
return false;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
Con_DPrintf("trying to open sp->hdl\n");
|
|
|
|
sp->hdl = sio_open(SIO_DEVANY, SIO_PLAY, 1);
|
|
|
|
if (sp->hdl == NULL)
|
|
|
|
{
|
|
|
|
Con_Printf("Could not open sndio device\n");
|
2017-09-20 11:27:13 +00:00
|
|
|
return false;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
Con_DPrintf("Opened sndio\n");
|
|
|
|
sc->GetDMAPos = sndio_getdmapos;
|
|
|
|
sc->Submit = sndio_submit;
|
|
|
|
sc->Shutdown = sndio_shutdown;
|
|
|
|
sc->Lock = sndio_lock;
|
|
|
|
sc->Unlock = sndio_unlock;
|
|
|
|
sc->SetWaterDistortion = sndio_setunderwater;
|
|
|
|
sc->handle = sp;
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
sio_initpar(&par);
|
|
|
|
par.rate = sc->sn.speed;
|
2017-09-20 11:27:13 +00:00
|
|
|
par.bits = (sc->sn.samplebytes==1)?8:16;
|
2012-09-30 05:52:03 +00:00
|
|
|
par.sig = 1;
|
|
|
|
par.le = SIO_LE_NATIVE;
|
|
|
|
par.pchan = sc->sn.numchannels;
|
|
|
|
par.appbufsz = par.rate / 20; /* 1/20 second latency */
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
if (!sio_setpar(sp->hdl, &par) || !sio_getpar(sp->hdl, &par))
|
|
|
|
{
|
|
|
|
Con_Printf("Error setting audio parameters\n");
|
|
|
|
sio_close(sp->hdl);
|
2017-09-20 11:27:13 +00:00
|
|
|
return false;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
if ((par.pchan != 1 && par.pchan != 2) ||
|
|
|
|
(par.bits != 16 || par.sig != 1))
|
|
|
|
{
|
|
|
|
Con_Printf("Could not set appropriate audio parameters\n");
|
|
|
|
sio_close(sp->hdl);
|
2017-09-20 11:27:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (par.bits == 16)
|
|
|
|
{
|
|
|
|
sc->sn.sampleformat = QSF_S16;
|
|
|
|
sc->sn.samplebytes = 2;
|
|
|
|
}
|
|
|
|
else if (par.bits == 8)
|
|
|
|
{
|
|
|
|
sc->sn.sampleformat = QSF_U8;
|
|
|
|
sc->sn.samplebytes = 1;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
/* sc->sn.speed = par.rate;
|
|
|
|
sc->sn.numchannels = par.pchan;
|
|
|
|
sc->sn.samplebits = par.bits;
|
|
|
|
*/
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
/*
|
|
|
|
* 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 <<= 1)
|
|
|
|
; /* nothing */
|
|
|
|
sc->sn.samples = i * par.pchan;
|
2017-09-20 11:27:13 +00:00
|
|
|
|
|
|
|
sp->dma_buffer_size = sc->sn.samples * sc->sn.samplebytes;
|
2012-09-30 05:52:03 +00:00
|
|
|
sc->sn.buffer = calloc(1, sp->dma_buffer_size);
|
|
|
|
if (sc->sn.buffer == NULL)
|
|
|
|
{
|
|
|
|
Con_Printf("Could not allocate audio ring buffer\n");
|
2017-09-20 11:27:13 +00:00
|
|
|
return false;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
dma_ptr = 0;
|
|
|
|
if (!sio_start(sp->hdl))
|
|
|
|
{
|
|
|
|
Con_Printf("Could not start audio\n");
|
|
|
|
sio_close(sp->hdl);
|
2017-09-20 11:27:13 +00:00
|
|
|
return false;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
sc->sn.samplepos = 0;
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
Con_DPrintf("sc->sn.speed = %d, par.rate = %d\n", sc->sn.speed, par.rate);
|
2017-09-20 11:27:13 +00:00
|
|
|
Con_DPrintf("sc->sn.samplebits = %d, par.bits = %d\n", sc->sn.samplebytes*8, par.bits);
|
2012-09-30 05:52:03 +00:00
|
|
|
Con_DPrintf("sc->sn.numchannels = %d, par.pchan = %d\n", sc->sn.numchannels, par.pchan);
|
|
|
|
Con_DPrintf("sc->sn.samples = %d, par.pchan = %d\n", sc->sn.samples, par.pchan);
|
|
|
|
Con_DPrintf("dma_buffer_size = %d\n", sp->dma_buffer_size);
|
2017-09-20 11:27:13 +00:00
|
|
|
return true;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
sndio_lock(soundcardinfo_t *sc, unsigned int *sampidx)
|
|
|
|
{
|
2017-09-20 11:27:13 +00:00
|
|
|
return sc->sn.buffer;
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sndio_unlock(soundcardinfo_t *sci, void *p)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sndio_shutdown(soundcardinfo_t *sc)
|
|
|
|
{
|
|
|
|
struct sndio_private *sp = sc->handle;
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
sio_close(sp->hdl);
|
|
|
|
free(sc->sn.buffer);
|
|
|
|
sc->sn.buffer = NULL;
|
|
|
|
*sc->name = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
sndio_getdmapos(soundcardinfo_t *sc)
|
|
|
|
{
|
|
|
|
struct sndio_private *sp = sc->handle;
|
2017-09-20 11:27:13 +00:00
|
|
|
sc->sn.samplepos = dma_ptr / sc->sn.samplebytes;
|
2012-09-30 05:52:03 +00:00
|
|
|
return sc->sn.samplepos;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sndio_submit(soundcardinfo_t *sc, int startcount, int endcount)
|
|
|
|
{
|
|
|
|
struct pollfd pfd;
|
|
|
|
struct sndio_private *sp = sc->handle;
|
|
|
|
size_t count, todo, avail;
|
|
|
|
int n;
|
2017-09-20 11:27:13 +00:00
|
|
|
|
2012-09-30 05:52:03 +00:00
|
|
|
n = sio_pollfd(sp->hdl, &pfd, POLLOUT);
|
|
|
|
while (poll(&pfd, n, 0) < 0 && errno == EINTR)
|
|
|
|
;
|
|
|
|
if (!(sio_revents(sp->hdl, &pfd) & POLLOUT))
|
|
|
|
return;
|
|
|
|
avail = sp->dma_buffer_size;
|
|
|
|
while (avail > 0)
|
|
|
|
{
|
|
|
|
todo = sp->dma_buffer_size - dma_ptr;
|
|
|
|
if (todo > avail)
|
|
|
|
todo = avail;
|
|
|
|
count = sio_write(sp->hdl, sc->sn.buffer + dma_ptr, todo);
|
|
|
|
if (count == 0)
|
|
|
|
break;
|
|
|
|
dma_ptr += count;
|
|
|
|
if (dma_ptr >= sp->dma_buffer_size)
|
|
|
|
dma_ptr -= sp->dma_buffer_size;
|
|
|
|
avail -= count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-20 11:27:13 +00:00
|
|
|
sounddriver_t SNDIO_AudioOutput =
|
|
|
|
{
|
|
|
|
"sndio",
|
|
|
|
sndio_init,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|