--- linux/src/al_ext.c 2004-07-20 11:59:00.000000000 +0100 +++ linux/src/al_ext.c 2004-07-25 13:44:41.000000000 +0100 @@ -993,5 +993,9 @@ return ALC_TRUE; } + if(ustrcmp("ALC_CAPTURE_SAMPLES", ename) == 0) { + return 0x312; + } + return 0; } --- linux/src/al_main.c 2004-07-20 11:58:58.000000000 +0100 +++ linux/src/al_main.c 2004-07-25 13:44:41.000000000 +0100 @@ -137,6 +137,7 @@ #ifdef CAPTURE_SUPPORT _alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_capture" ); + _alRegisterExtensionGroup( (const ALubyte*) "ALC_EXT_capture" ); #endif /* CAPTURE_SUPPORT */ #endif /* BUILTIN_EXT_LOKI */ --- linux/src/alc/alc_context.c 2004-07-20 11:58:58.000000000 +0100 +++ linux/src/alc/alc_context.c 2004-07-25 13:47:18.000000000 +0100 @@ -1526,6 +1526,8 @@ return deviceHandle->cc; } +ALint __alcGetAvailableSamples(ALvoid); + void alcGetIntegerv( ALCdevice *deviceHandle, ALCenum token, ALCsizei size , ALCint *dest ) { @@ -1547,6 +1549,9 @@ time. Check size */ + case 0x312: /*ALC_CAPTURE_SAMPLES:*/ + *dest = __alcGetAvailableSamples(); + break; case ALC_MAJOR_VERSION: *dest = 1; break; --- linux/src/extensions/al_ext_capture.c 2004-07-20 11:59:00.000000000 +0100 +++ linux/src/extensions/al_ext_capture.c 2004-07-25 13:44:41.000000000 +0100 @@ -45,6 +45,11 @@ AL_EXT_PAIR(alCaptureStop_EXT), AL_EXT_PAIR(alCaptureGetData_EXT), AL_EXT_PAIR(alCaptureDestroy_EXT), + AL_EXT_PAIR(alcCaptureOpenDevice), + AL_EXT_PAIR(alcCaptureCloseDevice), + AL_EXT_PAIR(alcCaptureStart), + AL_EXT_PAIR(alcCaptureStop), + AL_EXT_PAIR(alcCaptureSamples), { NULL, NULL } }; @@ -72,8 +77,8 @@ return; } -ALboolean alCaptureInit_EXT( UNUSED(ALenum format), - UNUSED(ALuint rate), +ALboolean alCaptureInit_EXT( ALenum format, + ALuint rate, UNUSED(ALsizei bufferSize) ) { ALuint cid; @@ -89,9 +94,26 @@ capture_device = cc->read_device; if ( capture_device == NULL ) { char spec[1024]; - char *fmt="'( (direction \"read\") (sampling-rate %d))"; + int speakers; + char *fmt="'( (direction \"read\") (sampling-rate %d) (speaker-num %d) )"; - sprintf(spec, fmt, rate); + switch (format) { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + default: + speakers = 1; + break; + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + speakers = 2; + break; + case AL_FORMAT_QUAD8_LOKI: + case AL_FORMAT_QUAD16_LOKI: + speakers = 4; + break; + } + + sprintf(spec, fmt, rate, speakers); capture_device = alcOpenDevice((ALubyte *)spec); if ( capture_device ) { _alcSetContext(NULL, cid, capture_device); @@ -171,14 +193,16 @@ format, dev->format, samples); size *= (_al_formatbits(dev->format) / 8); - if ( n > (ALsizei)size ) + if ( n > (ALsizei)size ) temp = malloc( n ); else temp = malloc( size ); if ( size > 0 ) { size = _alcDeviceRead(cid, temp, size); + } + if ( size > 0 ) { temp = _alBufferCanonizeData(dev->format, temp, size, @@ -189,8 +213,8 @@ AL_TRUE); } else { /* Hmm, zero size in record.. */ - memset(temp, 0, n); - size = n; + /*memset(temp, 0, n);*/ + size = 0; } if(temp == NULL) { fprintf(stderr, "could not canonize data\n"); @@ -203,3 +227,228 @@ } return size; } + + +/* Hacked in ALC_EXT_capture support. --ryan. */ +/* This doesn't support multiple devices, device enumeration, or capture */ +/* devices seperate from an existing context. How painful. */ + +/* ring buffer functionality... */ + +typedef struct +{ + ALubyte *buffer; + ALsizei size; + ALsizei write; + ALsizei read; + ALsizei used; +} __ALRingBuffer; + +static ALboolean __alRingBufferInit(__ALRingBuffer *ring, ALsizei size); +static ALvoid __alRingBufferShutdown(__ALRingBuffer *ring); +static ALsizei __alRingBufferSize(__ALRingBuffer *ring); +static ALvoid __alRingBufferPut(__ALRingBuffer *ring, ALubyte *data, ALsizei size); +static ALsizei __alRingBufferGet(__ALRingBuffer *ring, ALubyte *data, ALsizei size); + +static __ALRingBuffer captureRing; + +static ALboolean __alRingBufferInit(__ALRingBuffer *ring, ALsizei size) +{ + ALubyte *ptr = (ALubyte *) realloc(ring->buffer, size); + if (ptr == NULL) + return(AL_FALSE); + + ring->buffer = ptr; + ring->size = size; + ring->write = 0; + ring->read = 0; + ring->used = 0; + return(AL_TRUE); +} /* __alRingBufferInit */ + +static ALvoid __alRingBufferShutdown(__ALRingBuffer *ring) +{ + free(ring->buffer); + ring->buffer = NULL; +} /* __alRingBufferShutdown */ + +static ALsizei __alRingBufferSize(__ALRingBuffer *ring) +{ + return(ring->used); +} /* __alRingBufferSize */ + +static ALvoid __alRingBufferPut(__ALRingBuffer *ring, ALubyte *data, ALsizei _size) +{ + register ALsizei size = _size; + register ALsizei cpy; + register ALsizei avail; + + if (!size) /* just in case... */ + return; + + /* Putting more data than ring buffer holds in total? Replace it all. */ + if (size > ring->size) + { + ring->write = 0; + ring->read = 0; + ring->used = ring->size; + memcpy(ring->buffer, data + (size - ring->size), ring->size); + return; + } /* if */ + + /* Buffer overflow? Push read pointer to oldest sample not overwritten. */ + avail = ring->size - ring->used; + if (size > avail) + { + ring->read += size - avail; + if (ring->read > ring->size) + ring->read -= ring->size; + } /* if */ + + /* Clip to end of buffer and copy first block... */ + cpy = ring->size - ring->write; + if (size < cpy) + cpy = size; + if (cpy) memcpy(ring->buffer + ring->write, data, cpy); + + /* Wrap around to front of ring buffer and copy remaining data... */ + avail = size - cpy; + if (avail) memcpy(ring->buffer, data + cpy, avail); + + /* Update write pointer... */ + ring->write += size; + if (ring->write > ring->size) + ring->write -= ring->size; + + ring->used += size; + if (ring->used > ring->size) + ring->used = ring->size; +} /* __alRingBufferPut */ + +static ALsizei __alRingBufferGet(__ALRingBuffer *ring, ALubyte *data, ALsizei _size) +{ + register ALsizei cpy; + register ALsizei size = _size; + register ALsizei avail = ring->used; + + /* Clamp amount to read to available data... */ + if (size > avail) + size = avail; + + /* Clip to end of buffer and copy first block... */ + cpy = ring->size - ring->read; + if (cpy > size) cpy = size; + if (cpy) memcpy(data, ring->buffer + ring->read, cpy); + + /* Wrap around to front of ring buffer and copy remaining data... */ + avail = size - cpy; + if (avail) memcpy(data + cpy, ring->buffer, avail); + + /* Update read pointer... */ + ring->read += size; + if (ring->read > ring->size) + ring->read -= ring->size; + + ring->used -= size; + + return(size); /* may have been clamped if there wasn't enough data... */ +} /* __alRingBufferGet */ + + +static ALenum captureFmt = AL_NONE; +static ALuint captureFreq = 0; +static ALint captureFmtSize = 0; + +ALCdevice *alcCaptureOpenDevice(const ALubyte *deviceName, + ALuint freq, ALenum fmt, + ALsizei bufsize) +{ + ALCdevice *retval; + AL_context *cc; + ALuint cid; + + if (deviceName != NULL) /* !!! FIXME */ + return NULL; + + switch (fmt) /* try to keep this sane for now... */ + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + break; /* okay format. */ + + default: + return(NULL); + } + + captureFmt = fmt; + captureFreq = freq; + captureFmtSize = (_al_formatbits(fmt) / 8); + if ((fmt == AL_FORMAT_STEREO8) || (fmt == AL_FORMAT_STEREO16)) + captureFmtSize *= 2; + + bufsize *= captureFmtSize; + + if (!__alRingBufferInit(&captureRing, bufsize)) + return NULL; + + if (!alCaptureInit_EXT(fmt, freq, bufsize)) + return NULL; + + cid = _alcCCId; + _alcLockContext( cid ); + cc = _alcGetContext(cid); + retval = cc->read_device; + retval->cc = cc; + _alcUnlockContext( cid ); + + fprintf(stderr, "WARNING: ALC_EXT_capture is subject to change!\n"); + + return(retval); +} + +ALvoid alcCaptureCloseDevice(ALCdevice *dev) +{ + if (dev == NULL) + return; + + alCaptureDestroy_EXT(); + __alRingBufferShutdown(&captureRing); +} + +ALvoid alcCaptureStart(void) +{ + alCaptureStart_EXT(); +} + +ALvoid alcCaptureStop(void) +{ + alCaptureStop_EXT(); +} + +/* !!! FIXME: Not ideal; reads samples in ALC_CAPTURE_SAMPLES query */ +/* !!! FIXME: should query hardware here and do read in alcCaptureSamples() */ +ALint __alcGetAvailableSamples(ALvoid) +{ + static ALubyte buf[2048]; + ALsizei got; + + while ((got = alCaptureGetData_EXT(buf, sizeof (buf), + captureFmt, captureFreq)) > 0) + __alRingBufferPut(&captureRing, buf, got); + + /*printf("got %d have %d\n", (int) got, (int) (__alRingBufferSize(&captureRing) / captureFmtSize));*/ + + return(__alRingBufferSize(&captureRing) / captureFmtSize); +} + + +ALvoid alcCaptureSamples(UNUSED(ALCdevice *device), ALvoid *buf, ALsizei samps) +{ + if ((__alRingBufferSize(&captureRing) / captureFmtSize) < samps) + return; /* !!! FIXME: This is an error condition! */ + + __alRingBufferGet(&captureRing, buf, samps * captureFmtSize); +} + --- linux/src/extensions/al_ext_capture.h 2004-07-20 11:59:00.000000000 +0100 +++ linux/src/extensions/al_ext_capture.h 2004-07-25 13:44:41.000000000 +0100 @@ -13,6 +13,16 @@ #include +ALCdevice *alcCaptureOpenDevice(const ALubyte *deviceName, + ALuint freq, ALenum fmt, + ALsizei bufsize); +ALvoid alcCaptureCloseDevice(ALCdevice *dev); +ALvoid alcCaptureStart(void); +ALvoid alcCaptureStop(void); +ALint __alcGetAvailableSamples(ALvoid); +ALvoid alcCaptureSamples(ALCdevice *device, ALvoid *buf, ALsizei samps); + + /* * alInitCapture( void ) * @@ -38,7 +48,12 @@ AL_EXT_PAIR(alCaptureStart_EXT), \ AL_EXT_PAIR(alCaptureStop_EXT), \ AL_EXT_PAIR(alCaptureGetData_EXT), \ - AL_EXT_PAIR(alCaptureDestroy_EXT) \ + AL_EXT_PAIR(alCaptureDestroy_EXT), \ + AL_EXT_PAIR(alcCaptureOpenDevice), \ + AL_EXT_PAIR(alcCaptureCloseDevice), \ + AL_EXT_PAIR(alcCaptureStart), \ + AL_EXT_PAIR(alcCaptureStop), \ + AL_EXT_PAIR(alcCaptureSamples) \ /* initialization and destruction functions */