Mercurial > fife-parpg
diff ext/openal-soft/Alc/ALc.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ext/openal-soft/Alc/ALc.c Sun Jun 29 18:44:17 2008 +0000 @@ -0,0 +1,1265 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005 + +#include "config.h" + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include <ctype.h> +#include "alMain.h" +#include "alSource.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alThunk.h" +#include "alSource.h" +#include "alExtension.h" +#include "alAuxEffectSlot.h" +#include "bs2b.h" + +/////////////////////////////////////////////////////// +// DEBUG INFORMATION + +char _alDebug[256]; + +/////////////////////////////////////////////////////// + + +#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +static struct { + const char *name; + void (*Init)(BackendFuncs*); + BackendFuncs Funcs; +} BackendList[] = { +#ifdef HAVE_ALSA + { "alsa", alc_alsa_init, EmptyFuncs }, +#endif +#ifdef HAVE_OSS + { "oss", alc_oss_init, EmptyFuncs }, +#endif +#ifdef HAVE_DSOUND + { "dsound", alcDSoundInit, EmptyFuncs }, +#endif +#ifdef HAVE_WINMM + { "winmm", alcWinMMInit, EmptyFuncs }, +#endif + + { "wave", alc_wave_init, EmptyFuncs }, + + { NULL, NULL, EmptyFuncs } +}; +#undef EmptyFuncs + +/////////////////////////////////////////////////////// + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + +/////////////////////////////////////////////////////// +// STRING and EXTENSIONS + +typedef struct ALCfunction_struct +{ + ALCchar *funcName; + ALvoid *address; +} ALCfunction; + +static ALCfunction alcFunctions[] = { + { "alcCreateContext", (ALvoid *) alcCreateContext }, + { "alcMakeContextCurrent", (ALvoid *) alcMakeContextCurrent }, + { "alcProcessContext", (ALvoid *) alcProcessContext }, + { "alcSuspendContext", (ALvoid *) alcSuspendContext }, + { "alcDestroyContext", (ALvoid *) alcDestroyContext }, + { "alcGetCurrentContext", (ALvoid *) alcGetCurrentContext }, + { "alcGetContextsDevice", (ALvoid *) alcGetContextsDevice }, + { "alcOpenDevice", (ALvoid *) alcOpenDevice }, + { "alcCloseDevice", (ALvoid *) alcCloseDevice }, + { "alcGetError", (ALvoid *) alcGetError }, + { "alcIsExtensionPresent", (ALvoid *) alcIsExtensionPresent }, + { "alcGetProcAddress", (ALvoid *) alcGetProcAddress }, + { "alcGetEnumValue", (ALvoid *) alcGetEnumValue }, + { "alcGetString", (ALvoid *) alcGetString }, + { "alcGetIntegerv", (ALvoid *) alcGetIntegerv }, + { "alcCaptureOpenDevice", (ALvoid *) alcCaptureOpenDevice }, + { "alcCaptureCloseDevice", (ALvoid *) alcCaptureCloseDevice }, + { "alcCaptureStart", (ALvoid *) alcCaptureStart }, + { "alcCaptureStop", (ALvoid *) alcCaptureStop }, + { "alcCaptureSamples", (ALvoid *) alcCaptureSamples }, + { NULL, (ALvoid *) NULL } +}; + +static ALenums enumeration[]={ + // Types + { (ALchar *)"ALC_INVALID", ALC_INVALID }, + { (ALchar *)"ALC_FALSE", ALC_FALSE }, + { (ALchar *)"ALC_TRUE", ALC_TRUE }, + + // ALC Properties + { (ALchar *)"ALC_MAJOR_VERSION", ALC_MAJOR_VERSION }, + { (ALchar *)"ALC_MINOR_VERSION", ALC_MINOR_VERSION }, + { (ALchar *)"ALC_ATTRIBUTES_SIZE", ALC_ATTRIBUTES_SIZE }, + { (ALchar *)"ALC_ALL_ATTRIBUTES", ALC_ALL_ATTRIBUTES }, + { (ALchar *)"ALC_DEFAULT_DEVICE_SPECIFIER", ALC_DEFAULT_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_DEVICE_SPECIFIER", ALC_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_ALL_DEVICES_SPECIFIER", ALC_ALL_DEVICES_SPECIFIER }, + { (ALchar *)"ALC_DEFAULT_ALL_DEVICES_SPECIFIER", ALC_DEFAULT_ALL_DEVICES_SPECIFIER }, + { (ALchar *)"ALC_EXTENSIONS", ALC_EXTENSIONS }, + { (ALchar *)"ALC_FREQUENCY", ALC_FREQUENCY }, + { (ALchar *)"ALC_REFRESH", ALC_REFRESH }, + { (ALchar *)"ALC_SYNC", ALC_SYNC }, + { (ALchar *)"ALC_MONO_SOURCES", ALC_MONO_SOURCES }, + { (ALchar *)"ALC_STEREO_SOURCES", ALC_STEREO_SOURCES }, + { (ALchar *)"ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER}, + { (ALchar *)"ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES }, + + // EFX Properties + { (ALchar *)"ALC_EFX_MAJOR_VERSION", ALC_EFX_MAJOR_VERSION }, + { (ALchar *)"ALC_EFX_MINOR_VERSION", ALC_EFX_MINOR_VERSION }, + { (ALchar *)"ALC_MAX_AUXILIARY_SENDS", ALC_MAX_AUXILIARY_SENDS }, + + // ALC Error Message + { (ALchar *)"ALC_NO_ERROR", ALC_NO_ERROR }, + { (ALchar *)"ALC_INVALID_DEVICE", ALC_INVALID_DEVICE }, + { (ALchar *)"ALC_INVALID_CONTEXT", ALC_INVALID_CONTEXT }, + { (ALchar *)"ALC_INVALID_ENUM", ALC_INVALID_ENUM }, + { (ALchar *)"ALC_INVALID_VALUE", ALC_INVALID_VALUE }, + { (ALchar *)"ALC_OUT_OF_MEMORY", ALC_OUT_OF_MEMORY }, + { (ALchar *)NULL, (ALenum)0 } +}; +// Error strings +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; + +// Context strings +static ALCchar alcDeviceList[2048]; +static ALCchar alcAllDeviceList[2048]; +static ALCchar alcCaptureDeviceList[2048]; +// Default is always the first in the list +static ALCchar *alcDefaultDeviceSpecifier = alcDeviceList; +static ALCchar *alcDefaultAllDeviceSpecifier = alcAllDeviceList; +static ALCchar *alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList; + + +static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_EFX"; +static ALCint alcMajorVersion = 1; +static ALCint alcMinorVersion = 1; + +static ALCint alcEFXMajorVersion = 1; +static ALCint alcEFXMinorVersion = 0; + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// Global Variables + +static ALCdevice *g_pDeviceList = NULL; +static ALCuint g_ulDeviceCount = 0; + +// Context List +static ALCcontext *g_pContextList = NULL; +static ALCuint g_ulContextCount = 0; + +// Context Error +static ALCenum g_eLastContextError = ALC_NO_ERROR; + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Related helper functions + +static void InitAL(void) +{ + static int done = 0; + if(!done) + { + int i; + const char *devs, *str; + + done = 1; + + InitializeCriticalSection(&_alMutex); + ALTHUNK_INIT(); + ReadALConfig(); + + devs = GetConfigValue(NULL, "drivers", ""); + if(devs[0]) + { + int n; + size_t len; + const char *next = devs; + + i = 0; + + do { + devs = next; + next = strchr(devs, ','); + + if(!devs[0] || devs[0] == ',') + continue; + + len = (next ? ((size_t)(next-devs)) : strlen(devs)); + for(n = i;BackendList[n].Init;n++) + { + if(len == strlen(BackendList[n].name) && + strncmp(BackendList[n].name, devs, len) == 0) + { + const char *name = BackendList[i].name; + void (*Init)(BackendFuncs*) = BackendList[i].Init; + + BackendList[i].name = BackendList[n].name; + BackendList[i].Init = BackendList[n].Init; + + BackendList[n].name = name; + BackendList[n].Init = Init; + + i++; + } + } + } while(next++); + + BackendList[i].name = NULL; + BackendList[i].Init = NULL; + } + + for(i = 0;BackendList[i].Init;i++) + BackendList[i].Init(&BackendList[i].Funcs); + + str = GetConfigValue(NULL, "stereodup", "false"); + DuplicateStereo = (strcasecmp(str, "true") == 0 || + strcasecmp(str, "yes") == 0 || + strcasecmp(str, "on") == 0 || + atoi(str) != 0); + } +} + +ALCchar *AppendDeviceList(char *name) +{ + static size_t pos; + ALCchar *ret = alcDeviceList+pos; + if(pos >= sizeof(alcDeviceList)) + { + AL_PRINT("Not enough room to add %s!\n", name); + return alcDeviceList + sizeof(alcDeviceList) - 1; + } + pos += snprintf(alcDeviceList+pos, sizeof(alcDeviceList)-pos-1, "%s", name) + 1; + return ret; +} + +ALCchar *AppendAllDeviceList(char *name) +{ + static size_t pos; + ALCchar *ret = alcAllDeviceList+pos; + if(pos >= sizeof(alcAllDeviceList)) + { + AL_PRINT("Not enough room to add %s!\n", name); + return alcAllDeviceList + sizeof(alcAllDeviceList) - 1; + } + pos += snprintf(alcAllDeviceList+pos, sizeof(alcAllDeviceList)-pos-1, "%s", name) + 1; + return ret; +} + +ALCchar *AppendCaptureDeviceList(char *name) +{ + static size_t pos; + ALCchar *ret = alcCaptureDeviceList+pos; + if(pos >= sizeof(alcCaptureDeviceList)) + { + AL_PRINT("Not enough room to add %s!\n", name); + return alcCaptureDeviceList + sizeof(alcCaptureDeviceList) - 1; + } + pos += snprintf(alcCaptureDeviceList+pos, sizeof(alcCaptureDeviceList)-pos-1, "%s", name) + 1; + return ret; +} + +/* + IsContext + + Check pContext is a valid Context pointer +*/ +static ALCboolean IsContext(ALCcontext *pContext) +{ + ALCcontext *pTempContext; + + pTempContext = g_pContextList; + while (pTempContext && pTempContext != pContext) + pTempContext = pTempContext->next; + + return (pTempContext ? ALC_TRUE : ALC_FALSE); +} + + +/* + SetALCError + + Store latest ALC Error +*/ +ALCvoid SetALCError(ALenum errorCode) +{ + g_eLastContextError = errorCode; +} + + +/* + SuspendContext + + Thread-safe entry +*/ +ALCvoid SuspendContext(ALCcontext *pContext) +{ + (void)pContext; + EnterCriticalSection(&_alMutex); +} + + +/* + ProcessContext + + Thread-safe exit +*/ +ALCvoid ProcessContext(ALCcontext *pContext) +{ + (void)pContext; + LeaveCriticalSection(&_alMutex); +} + + +/* + InitContext + + Initialize Context variables +*/ +static ALvoid InitContext(ALCcontext *pContext) +{ + int level; + + //Initialise listener + pContext->Listener.Gain = 1.0f; + pContext->Listener.MetersPerUnit = 1.0f; + pContext->Listener.Position[0] = 0.0f; + pContext->Listener.Position[1] = 0.0f; + pContext->Listener.Position[2] = 0.0f; + pContext->Listener.Velocity[0] = 0.0f; + pContext->Listener.Velocity[1] = 0.0f; + pContext->Listener.Velocity[2] = 0.0f; + pContext->Listener.Forward[0] = 0.0f; + pContext->Listener.Forward[1] = 0.0f; + pContext->Listener.Forward[2] = -1.0f; + pContext->Listener.Up[0] = 0.0f; + pContext->Listener.Up[1] = 1.0f; + pContext->Listener.Up[2] = 0.0f; + + //Validate pContext + pContext->LastError = AL_NO_ERROR; + pContext->InUse = AL_FALSE; + + //Set output format + pContext->Frequency = pContext->Device->Frequency; + + //Set globals + pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; + pContext->DopplerFactor = 1.0f; + pContext->DopplerVelocity = 1.0f; + pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + + pContext->lNumStereoSources = 1; + pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources; + + strcpy(pContext->ExtensionList, "AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic"); + + level = GetConfigValueInt(NULL, "cf_level", 0); + if(level > 0 && level <= 6) + { + pContext->bs2b = calloc(1, sizeof(*pContext->bs2b)); + bs2b_set_srate(pContext->bs2b, pContext->Frequency); + bs2b_set_level(pContext->bs2b, level); + } +} + + +/* + ExitContext + + Clean up Context, destroy any remaining Sources +*/ +static ALCvoid ExitContext(ALCcontext *pContext) +{ + //Invalidate context + pContext->LastError = AL_NO_ERROR; + pContext->InUse = AL_FALSE; + + free(pContext->bs2b); + pContext->bs2b = NULL; +} + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Functions calls + + +// This should probably move to another c file but for now ... +ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + ALCboolean DeviceFound = ALC_FALSE; + ALCdevice *pDevice = NULL; + ALCint i; + + InitAL(); + + if(deviceName && !deviceName[0]) + deviceName = NULL; + + pDevice = malloc(sizeof(ALCdevice)); + if (pDevice) + { + if (SampleSize > 0) + { + //Initialise device structure + memset(pDevice, 0, sizeof(ALCdevice)); + + //Validate device + pDevice->IsCaptureDevice = AL_TRUE; + + pDevice->Frequency = frequency; + pDevice->Format = format; + + for(i = 0;BackendList[i].Init;i++) + { + pDevice->Funcs = &BackendList[i].Funcs; + if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize)) + { + SuspendContext(NULL); + pDevice->next = g_pDeviceList; + g_pDeviceList = pDevice; + g_ulDeviceCount++; + ProcessContext(NULL); + + DeviceFound = ALC_TRUE; + break; + } + } + } + else + SetALCError(ALC_INVALID_VALUE); + + if(!DeviceFound) + { + free(pDevice); + pDevice = NULL; + } + } + else + SetALCError(ALC_OUT_OF_MEMORY); + + return pDevice; +} + +ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice(ALCdevice *pDevice) +{ + ALCboolean bReturn = ALC_FALSE; + ALCdevice **list; + + if ((pDevice)&&(pDevice->IsCaptureDevice)) + { + SuspendContext(NULL); + + list = &g_pDeviceList; + while(*list != pDevice) + list = &(*list)->next; + + *list = (*list)->next; + g_ulDeviceCount--; + + ProcessContext(NULL); + + ALCdevice_CloseCapture(pDevice); + free(pDevice); + + bReturn = ALC_TRUE; + } + else + SetALCError(ALC_INVALID_DEVICE); + + return bReturn; +} + +ALCAPI void ALCAPIENTRY alcCaptureStart(ALCdevice *pDevice) +{ + if ((pDevice)&&(pDevice->IsCaptureDevice)) + ALCdevice_StartCapture(pDevice); + else + SetALCError(ALC_INVALID_DEVICE); +} + +ALCAPI void ALCAPIENTRY alcCaptureStop(ALCdevice *pDevice) +{ + if ((pDevice)&&(pDevice->IsCaptureDevice)) + ALCdevice_StopCapture(pDevice); + else + SetALCError(ALC_INVALID_DEVICE); +} + +ALCAPI void ALCAPIENTRY alcCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCsizei lSamples) +{ + if ((pDevice) && (pDevice->IsCaptureDevice)) + ALCdevice_CaptureSamples(pDevice, pBuffer, lSamples); + else + SetALCError(ALC_INVALID_DEVICE); +} + +/* + alcGetError + + Return last ALC generated error code +*/ +ALCAPI ALCenum ALCAPIENTRY alcGetError(ALCdevice *device) +{ + ALCenum errorCode; + + (void)device; + + errorCode = g_eLastContextError; + g_eLastContextError = ALC_NO_ERROR; + return errorCode; +} + + +/* + alcSuspendContext + + Not functional +*/ +ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext *pContext) +{ + // Not a lot happens here ! + (void)pContext; +} + + +/* + alcProcessContext + + Not functional +*/ +ALCAPI ALCvoid ALCAPIENTRY alcProcessContext(ALCcontext *pContext) +{ + // Not a lot happens here ! + (void)pContext; +} + + +/* + alcGetString + + Returns information about the Device, and error strings +*/ +ALCAPI const ALCchar* ALCAPIENTRY alcGetString(ALCdevice *pDevice,ALCenum param) +{ + const ALCchar *value = NULL; + + InitAL(); + + switch (param) + { + case ALC_NO_ERROR: + value = alcNoError; + break; + + case ALC_INVALID_ENUM: + value = alcErrInvalidEnum; + break; + + case ALC_INVALID_VALUE: + value = alcErrInvalidValue; + break; + + case ALC_INVALID_DEVICE: + value = alcErrInvalidDevice; + break; + + case ALC_INVALID_CONTEXT: + value = alcErrInvalidContext; + break; + + case ALC_OUT_OF_MEMORY: + value = alcErrOutOfMemory; + break; + + case ALC_DEFAULT_DEVICE_SPECIFIER: + value = alcDefaultDeviceSpecifier; + break; + + case ALC_DEVICE_SPECIFIER: + if (pDevice) + value = pDevice->szDeviceName; + else + value = alcDeviceList; + break; + + case ALC_ALL_DEVICES_SPECIFIER: + value = alcAllDeviceList; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + value = alcDefaultAllDeviceSpecifier; + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + if (pDevice) + value = pDevice->szDeviceName; + else + value = alcCaptureDeviceList; + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + value = alcCaptureDefaultDeviceSpecifier; + break; + + case ALC_EXTENSIONS: + value = alcExtensionList; + break; + + default: + SetALCError(ALC_INVALID_ENUM); + break; + } + + return value; +} + + +/* + alcGetIntegerv + + Returns information about the Device and the version of Open AL +*/ +ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data) +{ + InitAL(); + + if ((device)&&(device->IsCaptureDevice)) + { + SuspendContext(NULL); + + // Capture device + switch (param) + { + case ALC_CAPTURE_SAMPLES: + if ((size) && (data)) + *data = ALCdevice_AvailableSamples(device); + else + SetALCError(ALC_INVALID_VALUE); + break; + + default: + SetALCError(ALC_INVALID_ENUM); + break; + } + + ProcessContext(NULL); + } + else + { + if(data) + { + // Playback Device + switch (param) + { + case ALC_MAJOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcMajorVersion; + break; + + case ALC_MINOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcMinorVersion; + break; + + case ALC_EFX_MAJOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcEFXMajorVersion; + break; + + case ALC_EFX_MINOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcEFXMinorVersion; + break; + + case ALC_MAX_AUXILIARY_SENDS: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = MAX_SENDS; + break; + + case ALC_ATTRIBUTES_SIZE: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = 12; + break; + + case ALC_ALL_ATTRIBUTES: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if (size < 7) + SetALCError(ALC_INVALID_VALUE); + else + { + int i = 0; + + data[i++] = ALC_FREQUENCY; + data[i++] = device->Frequency; + + data[i++] = ALC_REFRESH; + data[i++] = device->Frequency / device->UpdateSize; + + data[i++] = ALC_SYNC; + data[i++] = ALC_FALSE; + + SuspendContext(NULL); + if(device->Context && size >= 12) + { + data[i++] = ALC_MONO_SOURCES; + data[i++] = device->Context->lNumMonoSources; + + data[i++] = ALC_STEREO_SOURCES; + data[i++] = device->Context->lNumStereoSources; + + data[i++] = ALC_MAX_AUXILIARY_SENDS; + data[i++] = MAX_SENDS; + } + ProcessContext(NULL); + + data[i++] = 0; + } + break; + + case ALC_FREQUENCY: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Frequency; + break; + + case ALC_REFRESH: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Frequency / device->UpdateSize; + break; + + case ALC_SYNC: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = ALC_FALSE; + break; + + case ALC_MONO_SOURCES: + if(!device || !device->Context) + SetALCError(ALC_INVALID_DEVICE); + else if (size != 1) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Context->lNumMonoSources; + break; + + case ALC_STEREO_SOURCES: + if(!device || !device->Context) + SetALCError(ALC_INVALID_DEVICE); + else if (size != 1) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Context->lNumStereoSources; + break; + + default: + SetALCError(ALC_INVALID_ENUM); + break; + } + } + else if(size) + SetALCError(ALC_INVALID_VALUE); + } + + return; +} + + +/* + alcIsExtensionPresent + + Determines if there is support for a particular extension +*/ +ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) +{ + ALCboolean bResult = ALC_FALSE; + + (void)device; + + if (extName) + { + const char *ptr; + size_t len; + + len = strlen(extName); + ptr = alcExtensionList; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + { + bResult = ALC_TRUE; + break; + } + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + } + else + SetALCError(ALC_INVALID_VALUE); + + return bResult; +} + + +/* + alcGetProcAddress + + Retrieves the function address for a particular extension function +*/ +ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) +{ + ALCvoid *pFunction = NULL; + ALsizei i = 0; + + (void)device; + + if (funcName) + { + while(alcFunctions[i].funcName && + strcmp(alcFunctions[i].funcName,funcName) != 0) + i++; + pFunction = alcFunctions[i].address; + } + else + SetALCError(ALC_INVALID_VALUE); + + return pFunction; +} + + +/* + alcGetEnumValue + + Get the value for a particular ALC Enumerated Value +*/ +ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) +{ + ALsizei i = 0; + ALCenum val; + + (void)device; + + while ((enumeration[i].enumName)&&(strcmp(enumeration[i].enumName,enumName))) + i++; + val = enumeration[i].value; + + if(!enumeration[i].enumName) + SetALCError(ALC_INVALID_VALUE); + + return val; +} + + +/* + alcCreateContext + + Create and attach a Context to a particular Device. +*/ +ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) +{ + ALCcontext *ALContext = NULL; + ALuint ulAttributeIndex, ulRequestedStereoSources; + + if ((device)&&(!device->IsCaptureDevice)) + { + // Reset Context Last Error code + g_eLastContextError = ALC_NO_ERROR; + + // Current implementation only allows one Context per Device + if(!device->Context) + { + ALContext = calloc(1, sizeof(ALCcontext)); + if(!ALContext) + { + SetALCError(ALC_OUT_OF_MEMORY); + return NULL; + } + + ALContext->Device = device; + InitContext(ALContext); + + device->Context = ALContext; + + SuspendContext(NULL); + + ALContext->next = g_pContextList; + g_pContextList = ALContext; + g_ulContextCount++; + + ProcessContext(NULL); + + // Check for Voice Count attributes + if (attrList) + { + ulAttributeIndex = 0; + while ((ulAttributeIndex < 10) && (attrList[ulAttributeIndex])) + { + if (attrList[ulAttributeIndex] == ALC_STEREO_SOURCES) + { + ulRequestedStereoSources = attrList[ulAttributeIndex + 1]; + + if (ulRequestedStereoSources > ALContext->Device->MaxNoOfSources) + ulRequestedStereoSources = ALContext->Device->MaxNoOfSources; + + ALContext->lNumStereoSources = ulRequestedStereoSources; + ALContext->lNumMonoSources = ALContext->Device->MaxNoOfSources - ALContext->lNumStereoSources; + break; + } + + ulAttributeIndex += 2; + } + } + } + else + { + SetALCError(ALC_INVALID_VALUE); + ALContext = NULL; + } + } + else + SetALCError(ALC_INVALID_DEVICE); + + return ALContext; +} + + +/* + alcDestroyContext + + Remove a Context +*/ +ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context) +{ + ALCcontext **list; + + InitAL(); + + // Lock context list + SuspendContext(NULL); + + if (IsContext(context)) + { + // Lock context + SuspendContext(context); + + ReleaseALSources(context); + ReleaseALAuxiliaryEffectSlots(context); + + context->Device->Context = NULL; + + list = &g_pContextList; + while(*list != context) + list = &(*list)->next; + + *list = (*list)->next; + g_ulContextCount--; + + // Unlock context + ProcessContext(context); + + ExitContext(context); + + // Free memory (MUST do this after ProcessContext) + memset(context, 0, sizeof(ALCcontext)); + free(context); + } + else + SetALCError(ALC_INVALID_CONTEXT); + + ProcessContext(NULL); +} + + +/* + alcGetCurrentContext + + Returns the currently active Context +*/ +ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext(ALCvoid) +{ + ALCcontext *pContext = NULL; + + InitAL(); + + SuspendContext(NULL); + + pContext = g_pContextList; + while ((pContext) && (!pContext->InUse)) + pContext = pContext->next; + + ProcessContext(NULL); + + return pContext; +} + + +/* + alcGetContextsDevice + + Returns the Device that a particular Context is attached to +*/ +ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *pContext) +{ + ALCdevice *pDevice = NULL; + + InitAL(); + + SuspendContext(NULL); + if (IsContext(pContext)) + pDevice = pContext->Device; + else + SetALCError(ALC_INVALID_CONTEXT); + ProcessContext(NULL); + + return pDevice; +} + + +/* + alcMakeContextCurrent + + Makes the given Context the active Context +*/ +ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + ALCcontext *ALContext; + ALboolean bReturn = AL_TRUE; + + InitAL(); + + SuspendContext(NULL); + + // context must be a valid Context or NULL + if ((IsContext(context)) || (context == NULL)) + { + if ((ALContext=alcGetCurrentContext())) + { + SuspendContext(ALContext); + ALContext->InUse=AL_FALSE; + ProcessContext(ALContext); + } + + if ((ALContext=context) && (ALContext->Device)) + { + SuspendContext(ALContext); + ALContext->InUse=AL_TRUE; + ProcessContext(ALContext); + } + } + else + { + SetALCError(ALC_INVALID_CONTEXT); + bReturn = AL_FALSE; + } + + ProcessContext(NULL); + + return bReturn; +} + + +/* + alcOpenDevice + + Open the Device specified. +*/ +ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName) +{ + ALboolean bDeviceFound = AL_FALSE; + ALCdevice *device; + ALint i; + + InitAL(); + + if(deviceName && !deviceName[0]) + deviceName = NULL; + + device = malloc(sizeof(ALCdevice)); + if (device) + { + const char *fmt; + + //Initialise device structure + memset(device, 0, sizeof(ALCdevice)); + + //Validate device + device->IsCaptureDevice = AL_FALSE; + + //Set output format + device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE); + if((ALint)device->Frequency <= 0) + device->Frequency = SWMIXER_OUTPUT_RATE; + + fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16"); + if(fmt[0]) + device->Format = alGetEnumValue(fmt); + + if(!aluChannelsFromFormat(device->Format)) + device->Format = AL_FORMAT_STEREO16; + + device->UpdateSize = GetConfigValueInt(NULL, "refresh", 8192); + if((ALint)device->UpdateSize <= 0) + device->UpdateSize = 8192; + + device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256); + if((ALint)device->MaxNoOfSources <= 0) + device->MaxNoOfSources = 256; + + // Find a playback device to open + for(i = 0;BackendList[i].Init;i++) + { + device->Funcs = &BackendList[i].Funcs; + if(ALCdevice_OpenPlayback(device, deviceName)) + { + SuspendContext(NULL); + device->next = g_pDeviceList; + g_pDeviceList = device; + g_ulDeviceCount++; + ProcessContext(NULL); + + bDeviceFound = AL_TRUE; + break; + } + } + + if (!bDeviceFound) + { + // No suitable output device found + free(device); + device = NULL; + } + } + + return device; +} + + +/* + alcCloseDevice + + Close the specified Device +*/ +ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice *pDevice) +{ + ALCboolean bReturn = ALC_FALSE; + ALCdevice **list; + + if ((pDevice)&&(!pDevice->IsCaptureDevice)) + { + SuspendContext(NULL); + + list = &g_pDeviceList; + while(*list != pDevice) + list = &(*list)->next; + + *list = (*list)->next; + g_ulDeviceCount--; + + ProcessContext(NULL); + + if(pDevice->Context) + alcDestroyContext(pDevice->Context); + ALCdevice_ClosePlayback(pDevice); + + //Release device structure + memset(pDevice, 0, sizeof(ALCdevice)); + free(pDevice); + + bReturn = ALC_TRUE; + } + else + SetALCError(ALC_INVALID_DEVICE); + + return bReturn; +} + + +ALCvoid ReleaseALC(ALCvoid) +{ +#ifdef _DEBUG + if(g_ulContextCount > 0) + AL_PRINT("exit() %u device(s) and %u context(s) NOT deleted\n", g_ulDeviceCount, g_ulContextCount); +#endif + + while(g_pDeviceList) + { + if(g_pDeviceList->IsCaptureDevice) + alcCaptureCloseDevice(g_pDeviceList); + else + alcCloseDevice(g_pDeviceList); + } +} + +///////////////////////////////////////////////////////