mirror of
https://git.FreeBSD.org/ports.git
synced 2024-12-26 05:02:18 +00:00
82848e9a9f
<machine/soundcard.h> and fix build on -current.
578 lines
15 KiB
Plaintext
578 lines
15 KiB
Plaintext
--- audio-voxware.cc.orig Fri Apr 26 05:22:37 1996
|
|
+++ audio-voxware.cc Sat May 10 00:15:51 2003
|
|
@@ -1,4 +1,6 @@
|
|
/*
|
|
+ * Modifications (C) 1997-1998 by Luigi Rizzo and others.
|
|
+ *
|
|
* Copyright (c) 1991-1993 Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
@@ -33,31 +35,43 @@
|
|
static const char rcsid[] =
|
|
"@(#) $Header: audio-voxware.cc,v 1.10 96/04/26 05:22:05 van Exp $ (LBL)";
|
|
|
|
-#include <string.h>
|
|
-#include <sys/fcntl.h>
|
|
-#include <errno.h>
|
|
-#if defined(sco) || defined(__bsdi__)
|
|
-#include <sys/socket.h>
|
|
-#endif
|
|
-#if defined(__FreeBSD__)
|
|
-#include <sys/types.h>
|
|
-#include <sys/uio.h>
|
|
-#include <unistd.h>
|
|
-#include <machine/soundcard.h>
|
|
+
|
|
+/*
|
|
+ * Full Duplex audio module for the new sound driver and full duplex
|
|
+ * cards. Luigi Rizzo, from original sources supplied by Amancio Hasty.
|
|
+ *
|
|
+ * This includes some enhancements:
|
|
+ * - the audio device to use can be in the AUDIODEV env. variable.
|
|
+ * It can be either a unit number or a full pathname;
|
|
+ * - use whatever format is available from the card (included split
|
|
+ * format e.g. for the sb16);
|
|
+ * - limit the maximum size of the playout queue to approx 4 frames;
|
|
+ * this is necessary if the write channel is slower than expected;
|
|
+ * the fix is based on two new ioctls, AIOGCAP and AIONWRITE,
|
|
+ * but the code should compile with the old driver as well.
|
|
+ */
|
|
+
|
|
+#if !defined(__FreeBSD__) || (__FreeBSD__ < 4)
|
|
+#include <osfcn.h>
|
|
#else
|
|
-#include <sys/soundcard.h>
|
|
+#include <fcntl.h>
|
|
#endif
|
|
+#include <sys/soundcard.h>
|
|
#include "audio.h"
|
|
+#include "mulaw.h"
|
|
#include "Tcl.h"
|
|
|
|
#define ULAW_ZERO 0x7f
|
|
+
|
|
+/* for use in the Voxware driver */
|
|
#define ABUFLOG2 8
|
|
-#define ABUFLEN (1 << ABUFLOG2)
|
|
#define NFRAG 5
|
|
|
|
-class VoxWareAudio : public Audio {
|
|
+extern const u_char lintomulawX[];
|
|
+
|
|
+class VoxWare : public Audio {
|
|
public:
|
|
- VoxWareAudio();
|
|
+ VoxWare();
|
|
virtual int FrameReady();
|
|
virtual u_char* Read();
|
|
virtual void Write(u_char *);
|
|
@@ -66,163 +80,415 @@
|
|
virtual void OutputPort(int);
|
|
virtual void InputPort(int);
|
|
virtual void Obtain();
|
|
+ virtual void Release();
|
|
virtual void RMute();
|
|
virtual void RUnmute();
|
|
virtual int HalfDuplex() const;
|
|
protected:
|
|
+ int ext_fd; /* source for external file */
|
|
|
|
- u_char* readptr;
|
|
- u_char* readbufend;
|
|
u_char* readbuf;
|
|
+ u_short *s16_buf;
|
|
+
|
|
+ int play_fmt ;
|
|
+ int is_half_duplex ;
|
|
+
|
|
+ // new sound driver
|
|
+ int rec_fmt ; /* the sb16 has split format... */
|
|
+ snd_capabilities soundcaps;
|
|
|
|
- u_char* ubufptr;
|
|
- u_char* ubufend;
|
|
- u_char* ubuf;
|
|
-
|
|
- u_char* writeptr;
|
|
- u_char* writebufend;
|
|
- u_char* writebuf;
|
|
};
|
|
|
|
-static class VoxWareAudioMatcher : public Matcher {
|
|
+static class VoxWareMatcher : public Matcher {
|
|
public:
|
|
- VoxWareAudioMatcher() : Matcher("audio") {}
|
|
+ VoxWareMatcher() : Matcher("audio") {}
|
|
TclObject* match(const char* fmt) {
|
|
if (strcmp(fmt, "voxware") == 0)
|
|
- return (new VoxWareAudio);
|
|
- else
|
|
+ return (new VoxWare);
|
|
return (0);
|
|
}
|
|
-} voxware_audio_matcher;
|
|
+} linux_audio_matcher;
|
|
|
|
-VoxWareAudio::VoxWareAudio()
|
|
+VoxWare::VoxWare()
|
|
{
|
|
- readbuf = new u_char[ABUFLEN];
|
|
- readptr = readbufend = readbuf + ABUFLEN;
|
|
+ readbuf = new u_char[blksize];
|
|
+ s16_buf = new u_short[blksize];
|
|
|
|
- writeptr = writebuf = new u_char[ABUFLEN];
|
|
- writebufend = writebuf + ABUFLEN;
|
|
+ memset(readbuf, ULAW_ZERO, blksize);
|
|
|
|
- ubufptr = ubuf = new u_char[blksize];
|
|
- ubufend = ubuf + blksize;
|
|
- memset(ubuf, ULAW_ZERO, blksize);
|
|
+ ext_fd = -1 ; /* no external audio */
|
|
+ iports = 4; /* number of input ports */
|
|
}
|
|
|
|
-int VoxWareAudio::HalfDuplex() const
|
|
+void
|
|
+VoxWare::Obtain()
|
|
{
|
|
- /*XXX change this if full duplex audio device available*/
|
|
- return 1;
|
|
-}
|
|
+ char *thedev;
|
|
+ char buf[64];
|
|
+ int d = -1;
|
|
|
|
-void VoxWareAudio::Obtain()
|
|
-{
|
|
if (HaveAudio())
|
|
abort();
|
|
-
|
|
- fd = open("/dev/audio", O_RDWR|O_NDELAY);
|
|
+ is_half_duplex = 0 ;
|
|
+ /*
|
|
+ * variable AUDIODEV has the name of the audio device.
|
|
+ * With the new audio driver, the main device can also control
|
|
+ * the mixer, so there is no need to carry two descriptors around.
|
|
+ */
|
|
+ thedev=getenv("AUDIODEV");
|
|
+ if (thedev==NULL)
|
|
+ thedev="/dev/audio";
|
|
+ else if ( thedev[0] >= '0' && thedev[0] <= '9' ) {
|
|
+ d = atoi(thedev);
|
|
+ sprintf(buf,"/dev/audio%d", d);
|
|
+ thedev = buf ;
|
|
+ }
|
|
+ fd = open(thedev, O_RDWR );
|
|
if (fd >= 0) {
|
|
- int on = 1;
|
|
- ioctl(fd, FIONBIO, &on);
|
|
+ int i = -1 ;
|
|
+ u_long fmt = 0 ;
|
|
+ int rate = 8000 ;
|
|
+
|
|
+ snd_chan_param pa;
|
|
+ struct snd_size sz;
|
|
+ i = ioctl(fd, AIOGCAP, &soundcaps);
|
|
+ fmt = soundcaps.formats ; /* can be invalid, check later */
|
|
+
|
|
+ play_fmt = AFMT_MU_LAW ;
|
|
+ rec_fmt = AFMT_MU_LAW ;
|
|
+
|
|
+ if (i == -1 ) { /* setup code for old voxware driver */
|
|
+ i = ioctl(fd, SNDCTL_DSP_GETFMTS, &fmt);
|
|
+ fmt &= AFMT_MU_LAW ; /* only use mu-law */
|
|
+ fmt |= AFMT_FULLDUPLEX ;
|
|
+ if ( i < 0 ) { /* even voxware driver failed, try with pcaudio */
|
|
+ fmt = AFMT_MU_LAW | AFMT_WEIRD ;
|
|
+ }
|
|
+ }
|
|
+ switch (soundcaps.formats & (AFMT_FULLDUPLEX | AFMT_WEIRD)) {
|
|
+ case AFMT_FULLDUPLEX :
|
|
+ /*
|
|
+ * this entry for cards with decent full duplex. Use s16
|
|
+ * preferably (some are broken in ulaw) or ulaw or u8 otherwise.
|
|
+ */
|
|
+ if (fmt & AFMT_S16_LE)
|
|
+ play_fmt = rec_fmt = AFMT_S16_LE ;
|
|
+ else if (soundcaps.formats & AFMT_MU_LAW)
|
|
+ play_fmt = rec_fmt = AFMT_MU_LAW ;
|
|
+ else if (soundcaps.formats & AFMT_U8)
|
|
+ play_fmt = rec_fmt = AFMT_U8 ;
|
|
+ else {
|
|
+ printf("sorry, no supported formats\n");
|
|
+ close(fd);
|
|
+ fd = -1 ;
|
|
+ return;
|
|
+ }
|
|
+ break ;
|
|
+ case AFMT_FULLDUPLEX | AFMT_WEIRD :
|
|
+ /* this is the sb16... */
|
|
+ if (fmt & AFMT_S16_LE) {
|
|
+ play_fmt = AFMT_U8 ;
|
|
+ rec_fmt = AFMT_S16_LE;
|
|
+ } else {
|
|
+ printf("sorry, no supported formats\n");
|
|
+ close(fd);
|
|
+ fd = -1 ;
|
|
+ return;
|
|
+ }
|
|
+ break ;
|
|
+ default :
|
|
+ printf("sorry don't know how to deal with this card\n");
|
|
+ close (fd);
|
|
+ fd = -1;
|
|
+ return;
|
|
+ }
|
|
|
|
- int frag = (NFRAG << 16) | ABUFLOG2;
|
|
- ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
|
|
-#ifdef fullduplex
|
|
+ pa.play_format = play_fmt ;
|
|
+ pa.rec_format = rec_fmt ;
|
|
+ pa.play_rate = pa.rec_rate = rate ;
|
|
+ ioctl(fd, AIOSFMT, &pa); /* if this fails, also AIOSSIZE will.. */
|
|
+ sz.play_size = (play_fmt == AFMT_S16_LE) ? 2*blksize : blksize;
|
|
+ sz.rec_size = (rec_fmt == AFMT_S16_LE) ? 2*blksize : blksize;
|
|
+ i = ioctl(fd, AIOSSIZE, &sz);
|
|
+
|
|
+ /*
|
|
+ * Set the line input level to 0 to avoid loopback if the mic
|
|
+ * is connected to the line-in port (e.g. through an echo
|
|
+ * canceller).
|
|
+ */
|
|
+ int v = 0;
|
|
+ (void)ioctl(fd, MIXER_WRITE(SOUND_MIXER_LINE), &v);
|
|
+ // restore hardware settings in case some other vat changed them
|
|
+ InputPort(iport);
|
|
+ SetRGain(rgain);
|
|
+ SetPGain(pgain);
|
|
+
|
|
+ if ( i < 0 ) { // if AIOSSIZE fails, maybe this is a Voxware driver
|
|
+ ioctl(fd, SNDCTL_DSP_SPEED, &rate);
|
|
+ ioctl(fd, SNDCTL_DSP_SETFMT, &play_fmt); // same for play/rec
|
|
+ d = (play_fmt == AFMT_S16_LE) ? 2*blksize : blksize;
|
|
+ ioctl(fd, SNDCTL_DSP_SETBLKSIZE, &d);
|
|
+ read(fd, &i, 1); /* dummy read to start read engine */
|
|
+ }
|
|
Audio::Obtain();
|
|
-#else
|
|
- notify();
|
|
-#endif
|
|
+ } else {
|
|
+ fprintf(stderr, "failed to open rw...\n");
|
|
+ fd = open(thedev, O_WRONLY );
|
|
+ fprintf(stderr, "open wronly returns %d\n", fd);
|
|
+ is_half_duplex = 1 ;
|
|
+ play_fmt = rec_fmt = AFMT_MU_LAW ;
|
|
+ notify(); /* XXX */
|
|
}
|
|
}
|
|
|
|
-void VoxWareAudio::Write(u_char *cp)
|
|
+/*
|
|
+ * note: HalfDuplex() uses a modified function of the new driver,
|
|
+ * which will return AFMT_FULLDUPLEX set in SNDCTL_DSP_GETFMTS
|
|
+ * for full-duplex devices. In the old driver this was 0 so
|
|
+ * the default is to use half-duplex for them. Note also that I have
|
|
+ * not tested half-duplex operation.
|
|
+ */
|
|
+int
|
|
+VoxWare::HalfDuplex() const
|
|
{
|
|
- if (HaveAudio() && (rmute & 1) != 0) {
|
|
- register u_char *cpend = cp + blksize;
|
|
- register u_char *wbuf = writeptr;
|
|
- register u_char *wend = writebufend;
|
|
- for ( ; cp < cpend; cp += 4) {
|
|
- wbuf[0] = cp[0];
|
|
- wbuf[1] = cp[1];
|
|
- wbuf[2] = cp[2];
|
|
- wbuf[3] = cp[3];
|
|
- wbuf += 4;
|
|
- if (wbuf >= wend) {
|
|
- wbuf = writebuf;
|
|
- if (write(fd, (char*)wbuf, ABUFLEN) != ABUFLEN)
|
|
- perror("aud write");
|
|
- }
|
|
- }
|
|
- writeptr = wbuf;
|
|
+ int i, probed_duplex = 0;
|
|
+
|
|
+ /* newpcm style */
|
|
+#ifdef SNDCTL_DSP_GETCAPS
|
|
+ ioctl(fd, SNDCTL_DSP_GETCAPS, &i);
|
|
+ probed_duplex |= (i & DSP_CAP_DUPLEX);
|
|
+#endif /* SNDCTL_DSP_GETCAPS */
|
|
+
|
|
+ /* pcm style */
|
|
+#ifdef SNDCTL_DSP_GETFMTS
|
|
+ ioctl(fd, SNDCTL_DSP_GETFMTS, &i);
|
|
+ probed_duplex |= (i & AFMT_FULLDUPLEX);
|
|
+#endif /* SNDCTL_DSP_GETFMTS */
|
|
+
|
|
+ if (is_half_duplex || (probed_duplex == 0)) {
|
|
+ fprintf(stderr, "HalfDuplex returns 1\n");
|
|
+ return 1 ;
|
|
}
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
-int VoxWareAudio::FrameReady()
|
|
+void VoxWare::Release()
|
|
{
|
|
- if ((rmute & 1) == 0) {
|
|
- register u_char* cp = ubufptr;
|
|
- register u_char* cpend = ubufend;
|
|
- register u_char* rbuf = readptr;
|
|
- register u_char* rend = readbufend;
|
|
-
|
|
- for ( ; cp < cpend; cp += 4) {
|
|
- if (rbuf >= rend) {
|
|
- rbuf = readbuf;
|
|
- int cc = read(fd, (char*)rbuf, ABUFLEN);
|
|
- if (cc <= 0) {
|
|
- ubufptr = cp;
|
|
- readbufend = rbuf;
|
|
- if (cc == -1 && errno != EAGAIN) {
|
|
- Release();
|
|
- Obtain();
|
|
- }
|
|
- return (0);
|
|
+ if (HaveAudio()) {
|
|
+ Audio::Release();
|
|
}
|
|
- readbufend = rend = rbuf + cc;
|
|
}
|
|
- cp[0] = rbuf[0];
|
|
- cp[1] = rbuf[1];
|
|
- cp[2] = rbuf[2];
|
|
- cp[3] = rbuf[3];
|
|
- rbuf += 4;
|
|
+
|
|
+void VoxWare::Write(u_char *cp)
|
|
+{
|
|
+ int i = blksize, l;
|
|
+ if (play_fmt == AFMT_S16_LE) {
|
|
+ for (i=0; i< blksize; i++)
|
|
+ s16_buf[i] = mulawtolin[cp[i]] ;
|
|
+ cp = (u_char *)s16_buf;
|
|
+ i = 2 *blksize ;
|
|
+ } else if (play_fmt == AFMT_S8) {
|
|
+ for (i=0; i< blksize; i++) {
|
|
+ int x = mulawtolin[cp[i]] ;
|
|
+ x = (x >> 8 ) & 0xff;
|
|
+ cp[i] = (u_char)x ;
|
|
+ }
|
|
+ i = blksize ;
|
|
+ } else if (play_fmt == AFMT_U8) {
|
|
+ for (i=0; i< blksize; i++) {
|
|
+ int x = mulawtolin[cp[i]] ;
|
|
+ /*
|
|
+ * when translating to 8-bit formats, it would be useful to
|
|
+ * implement AGC to avoid loss of resolution in the conversion.
|
|
+ * This code is still incomplete...
|
|
+ */
|
|
+#if 0 /* AGC -- still not complete... */
|
|
+ static int peak = 0;
|
|
+ if (x < 0) x = -x ;
|
|
+ if (x > peak) peak = ( peak*16 + x - peak ) / 16 ;
|
|
+ else peak = ( peak*8192 + x - peak ) / 8192 ;
|
|
+ if (peak < 128) peak = 128 ;
|
|
+ /* at this point peak is in the range 128..32k
|
|
+ * samples can be scaled and clipped consequently.
|
|
+ */
|
|
+ x = x * 32768/peak ;
|
|
+ if (x > 32767) x = 32767;
|
|
+ else if (x < -32768) x = -32768;
|
|
+#endif
|
|
+ x = (x >> 8 ) & 0xff;
|
|
+ x = (x ^ 0x80) & 0xff ;
|
|
+ cp[i] = (u_char)x ;
|
|
+ }
|
|
+ i = blksize ;
|
|
+ }
|
|
+#if 0
|
|
+ // this code is meant to keep the queue short.
|
|
+ int r, queued;
|
|
+ r = ioctl(fd, AIONWRITE, &queued);
|
|
+ queued = soundcaps.bufsize - queued ;
|
|
+ if (play_fmt == AFMT_S16_LE) {
|
|
+ if (queued > 8*blksize)
|
|
+ i -= 8 ;
|
|
+ } else {
|
|
+ if (queued > 4*blksize)
|
|
+ i -= 4 ;
|
|
}
|
|
- readptr = rbuf;
|
|
+#endif
|
|
+ for ( ; i > 0 ; i -= l) {
|
|
+ l = write(fd, cp, i);
|
|
+ cp += l;
|
|
}
|
|
- return (1);
|
|
}
|
|
|
|
-u_char* VoxWareAudio::Read()
|
|
+u_char* VoxWare::Read()
|
|
{
|
|
- u_char* cp = ubuf;
|
|
- ubufptr = cp;
|
|
- return (cp);
|
|
+ u_char* cp;
|
|
+ int l=0, l0 = blksize, i = blksize;
|
|
+
|
|
+ cp = readbuf;
|
|
+
|
|
+ if (rec_fmt == AFMT_S16_LE) {
|
|
+ cp = (u_char *)s16_buf;
|
|
+ l0 = i = 2 *blksize ;
|
|
+ }
|
|
+ for ( ; i > 0 ; i -= l ) {
|
|
+ l = read(fd, cp, i);
|
|
+ if (l<0) break;
|
|
+ cp += l ;
|
|
+ }
|
|
+ if (rec_fmt == AFMT_S16_LE) {
|
|
+ for (i=0; i< blksize; i++) {
|
|
+#if 1 /* remove DC component... */
|
|
+ static int smean = 0 ; /* smoothed mean to remove DC */
|
|
+ int dif = ((short) s16_buf[i]) - (smean >> 13) ;
|
|
+ smean += dif ;
|
|
+ readbuf[i] = lintomulawX[ dif & 0x1ffff ] ;
|
|
+#else
|
|
+ readbuf[i] = lintomulaw[ s16_buf[i] ] ;
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+ else if (rec_fmt == AFMT_S8) {
|
|
+ for (i=0; i< blksize; i++)
|
|
+ readbuf[i] = lintomulaw[ readbuf[i]<<8 ] ;
|
|
+ }
|
|
+ else if (rec_fmt == AFMT_U8) {
|
|
+ for (i=0; i< blksize; i++)
|
|
+ readbuf[i] = lintomulaw[ (readbuf[i]<<8) ^ 0x8000 ] ;
|
|
+ }
|
|
+ if (iport == 3) {
|
|
+ l = read(ext_fd, readbuf, blksize);
|
|
+ if (l < blksize) {
|
|
+ lseek(ext_fd, (off_t) 0, 0);
|
|
+ read(ext_fd, readbuf+l, blksize - l);
|
|
+ }
|
|
+ }
|
|
+ return readbuf;
|
|
}
|
|
|
|
-void VoxWareAudio::SetRGain(int level)
|
|
+/*
|
|
+ * should check that I HaveAudio() before trying to set gain.
|
|
+ *
|
|
+ * In most mixer devices, there is only a master volume control on
|
|
+ * the capture channel, so the following code does not really work
|
|
+ * as expected. The only (partial) exception is the MIC line, where
|
|
+ * there is generally a 20dB boost which can be enabled or not
|
|
+ * depending on the type of device.
|
|
+ */
|
|
+void VoxWare::SetRGain(int level)
|
|
{
|
|
+ double x = level;
|
|
+ level = (int) (x/2.56);
|
|
+ int foo = (level<<8) | level;
|
|
+ if (!HaveAudio())
|
|
+ Obtain();
|
|
+ switch (iport) {
|
|
+ case 2:
|
|
+ case 1:
|
|
+ break;
|
|
+ case 0:
|
|
+ if (ioctl(fd, MIXER_WRITE(SOUND_MIXER_MIC), &foo) == -1)
|
|
+ printf("failed to set mic volume \n");
|
|
+ break;
|
|
+ }
|
|
+ /* IGAIN tends to be found on SB-like mixers, RECLEV on AC97 */
|
|
+ if ((ioctl(fd, MIXER_WRITE(SOUND_MIXER_IGAIN), &foo) == -1) &&
|
|
+ (ioctl(fd, MIXER_WRITE(SOUND_MIXER_RECLEV), &foo) == -1))
|
|
+ printf("failed set input line volume \n");
|
|
rgain = level;
|
|
}
|
|
|
|
-void VoxWareAudio::SetPGain(int level)
|
|
+void VoxWare::SetPGain(int level)
|
|
{
|
|
+ float x = level;
|
|
+ level = (int) (x/2.56);
|
|
+ int foo = (level<<8) | level;
|
|
+ if (ioctl(fd, MIXER_WRITE(SOUND_MIXER_PCM), &foo) == -1) {
|
|
+ printf("failed to output level %d \n", level);
|
|
+ }
|
|
pgain = level;
|
|
}
|
|
|
|
-void VoxWareAudio::OutputPort(int p)
|
|
+void VoxWare::OutputPort(int p)
|
|
{
|
|
oport = p;
|
|
}
|
|
|
|
-void VoxWareAudio::InputPort(int p)
|
|
+void VoxWare::InputPort(int p)
|
|
{
|
|
+ int src = 0;
|
|
+
|
|
+ if (ext_fd >= 0 && p != 3) {
|
|
+ close(ext_fd);
|
|
+ ext_fd = -1 ;
|
|
+ }
|
|
+
|
|
+ switch(p) {
|
|
+ case 3:
|
|
+ if (ext_fd == -1)
|
|
+ ext_fd = open(ext_fname, 0);
|
|
+ if (ext_fd != -1)
|
|
+ lseek(ext_fd, (off_t) 0, 0);
|
|
+ break;
|
|
+ case 2:
|
|
+ src = 1 << SOUND_MIXER_LINE;
|
|
+ break;
|
|
+ case 1: /* cd ... */
|
|
+ src = 1 << SOUND_MIXER_CD;
|
|
+ break;
|
|
+ case 0 :
|
|
+ src = 1 << SOUND_MIXER_MIC;
|
|
+ break;
|
|
+ }
|
|
+ if ( ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &src) == -1 ) {
|
|
+ printf("failed to select input \n");
|
|
+ p = 0;
|
|
+ }
|
|
iport = p;
|
|
}
|
|
|
|
-void VoxWareAudio::RMute()
|
|
+void VoxWare::RMute()
|
|
{
|
|
rmute |= 1;
|
|
}
|
|
|
|
-void VoxWareAudio::RUnmute()
|
|
+void VoxWare::RUnmute()
|
|
{
|
|
rmute &=~ 1;
|
|
}
|
|
+
|
|
+/*
|
|
+ * FrameReady must return 0 every so often, or the system will keep
|
|
+ * processing mike data and not other events.
|
|
+ */
|
|
+int VoxWare::FrameReady()
|
|
+{
|
|
+ int i, l = 0;
|
|
+ int lim = blksize;
|
|
+
|
|
+ i = ioctl(fd, FIONREAD, &l );
|
|
+ if (rec_fmt == AFMT_S16_LE) lim = 2*blksize;
|
|
+ return (l >= lim) ? 1 : 0 ;
|
|
+}
|
|
+/*** end of file ***/
|