/** * 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 */ #include "config.h" #include #include #include #include "alMain.h" #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "alError.h" #include "alDatabuffer.h" #include "alThunk.h" #define LookupDatabuffer(m, k) ((ALdatabuffer*)LookupUIntMapKey(&(m), (k))) /* * alGenDatabuffersEXT(ALsizei n, ALuint *puiBuffers) * * Generates n AL Databuffers, and stores the Databuffers Names in the array pointed to by puiBuffers */ AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers) { ALCcontext *Context; ALsizei i=0; Context = GetContextSuspended(); if(!Context) return; /* Check that we are actually generation some Databuffers */ if(n < 0 || IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint))) alSetError(Context, AL_INVALID_VALUE); else { ALCdevice *device = Context->Device; ALenum err; /* Create all the new Databuffers */ while(i < n) { ALdatabuffer *buffer = calloc(1, sizeof(ALdatabuffer)); if(!buffer) { alSetError(Context, AL_OUT_OF_MEMORY); alDeleteDatabuffersEXT(i, puiBuffers); break; } buffer->databuffer = ALTHUNK_ADDENTRY(buffer); err = InsertUIntMapEntry(&device->DatabufferMap, buffer->databuffer, buffer); if(err != AL_NO_ERROR) { ALTHUNK_REMOVEENTRY(buffer->databuffer); memset(buffer, 0, sizeof(ALdatabuffer)); free(buffer); alSetError(Context, err); alDeleteDatabuffersEXT(i, puiBuffers); break; } puiBuffers[i++] = buffer->databuffer; buffer->state = UNMAPPED; } } ProcessContext(Context); } /* * alDatabeleteBuffersEXT(ALsizei n, ALuint *puiBuffers) * * Deletes the n AL Databuffers pointed to by puiBuffers */ AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *buffers) { ALCcontext *Context; ALCdevice *device; ALdatabuffer *ALBuf; ALboolean Failed; ALsizei i; Context = GetContextSuspended(); if(!Context) return; /* Check we are actually Deleting some Databuffers */ Failed = AL_TRUE; device = Context->Device; if(n < 0) alSetError(Context, AL_INVALID_VALUE); else { Failed = AL_FALSE; /* Check that all the databuffers are valid and can actually be * deleted */ for(i = 0;i < n;i++) { if(!buffers[i]) continue; /* Check for valid Buffer ID */ if((ALBuf=LookupDatabuffer(device->DatabufferMap, buffers[i])) == NULL) { /* Invalid Databuffer */ alSetError(Context, AL_INVALID_NAME); Failed = AL_TRUE; break; } else if(ALBuf->state != UNMAPPED) { /* Databuffer still in use, cannot be deleted */ alSetError(Context, AL_INVALID_OPERATION); Failed = AL_TRUE; break; } } } /* If all the Databuffers were valid (and unmapped), then we can delete them */ if(!Failed) { for(i = 0;i < n;i++) { if((ALBuf=LookupDatabuffer(device->DatabufferMap, buffers[i])) == NULL) continue; if(ALBuf == Context->SampleSource) Context->SampleSource = NULL; if(ALBuf == Context->SampleSink) Context->SampleSink = NULL; // Release the memory used to store audio data free(ALBuf->data); // Release buffer structure RemoveUIntMapKey(&device->DatabufferMap, ALBuf->databuffer); ALTHUNK_REMOVEENTRY(ALBuf->databuffer); memset(ALBuf, 0, sizeof(ALdatabuffer)); free(ALBuf); } } ProcessContext(Context); } /* * alIsDatabufferEXT(ALuint uiBuffer) * * Checks if ulBuffer is a valid Databuffer Name */ AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint buffer) { ALCcontext *Context; ALboolean result; ALCdevice *device; Context = GetContextSuspended(); if(!Context) return AL_FALSE; device = Context->Device; result = ((!buffer || LookupDatabuffer(device->DatabufferMap, buffer)) ? AL_TRUE : AL_FALSE); ProcessContext(Context); return result; } /* * alDatabufferDataEXT(ALuint buffer,ALvoid *data,ALsizei size,ALenum usage) * * Fill databuffer with data */ AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage) { ALCcontext *Context; ALdatabuffer *ALBuf; ALCdevice *Device; ALvoid *temp; Context = GetContextSuspended(); if(!Context) return; Device = Context->Device; if((ALBuf=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL) { if(ALBuf->state == UNMAPPED) { if(usage == AL_STREAM_WRITE_EXT || usage == AL_STREAM_READ_EXT || usage == AL_STREAM_COPY_EXT || usage == AL_STATIC_WRITE_EXT || usage == AL_STATIC_READ_EXT || usage == AL_STATIC_COPY_EXT || usage == AL_DYNAMIC_WRITE_EXT || usage == AL_DYNAMIC_READ_EXT || usage == AL_DYNAMIC_COPY_EXT) { if(size >= 0) { /* (Re)allocate data */ temp = realloc(ALBuf->data, size); if(temp) { ALBuf->data = temp; ALBuf->size = size; ALBuf->usage = usage; if(data) memcpy(ALBuf->data, data, size); } else alSetError(Context, AL_OUT_OF_MEMORY); } else alSetError(Context, AL_INVALID_VALUE); } else alSetError(Context, AL_INVALID_ENUM); } else alSetError(Context, AL_INVALID_OPERATION); } else alSetError(Context, AL_INVALID_NAME); ProcessContext(Context); } AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data) { ALCcontext *pContext; ALdatabuffer *pBuffer; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) { if(start >= 0 && length >= 0 && start+length <= pBuffer->size) { if(pBuffer->state == UNMAPPED) memcpy(pBuffer->data+start, data, length); else alSetError(pContext, AL_INVALID_OPERATION); } else alSetError(pContext, AL_INVALID_VALUE); } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data) { ALCcontext *pContext; ALdatabuffer *pBuffer; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) { if(start >= 0 && length >= 0 && start+length <= pBuffer->size) { if(pBuffer->state == UNMAPPED) memcpy(data, pBuffer->data+start, length); else alSetError(pContext, AL_INVALID_OPERATION); } else alSetError(pContext, AL_INVALID_VALUE); } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue) { ALCcontext *pContext; ALCdevice *Device; (void)flValue; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch(eParam) { default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues) { ALCcontext *pContext; ALCdevice *Device; (void)flValues; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch(eParam) { default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue) { ALCcontext *pContext; ALCdevice *Device; (void)lValue; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch(eParam) { default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues) { ALCcontext *pContext; ALCdevice *Device; (void)plValues; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch(eParam) { default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue) { ALCcontext *pContext; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; if(pflValue) { Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch(eParam) { default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); } else alSetError(pContext, AL_INVALID_VALUE); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues) { ALCcontext *pContext; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; if(pflValues) { Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch(eParam) { default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); } else alSetError(pContext, AL_INVALID_VALUE); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue) { ALCcontext *pContext; ALdatabuffer *pBuffer; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; if(plValue) { Device = pContext->Device; if((pBuffer=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL) { switch(eParam) { case AL_SIZE: *plValue = (ALint)pBuffer->size; break; default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); } else alSetError(pContext, AL_INVALID_VALUE); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues) { ALCcontext *pContext; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; if(plValues) { Device = pContext->Device; if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) { switch (eParam) { case AL_SIZE: alGetDatabufferiEXT(buffer, eParam, plValues); break; default: alSetError(pContext, AL_INVALID_ENUM); break; } } else alSetError(pContext, AL_INVALID_NAME); } else alSetError(pContext, AL_INVALID_VALUE); ProcessContext(pContext); } AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer) { ALCcontext *pContext; ALdatabuffer *pBuffer = NULL; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if(uiBuffer == 0 || (pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) { if(target == AL_SAMPLE_SOURCE_EXT) pContext->SampleSource = pBuffer; else if(target == AL_SAMPLE_SINK_EXT) pContext->SampleSink = pBuffer; else alSetError(pContext, AL_INVALID_VALUE); } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access) { ALCcontext *pContext; ALdatabuffer *pBuffer; ALvoid *ret = NULL; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return NULL; Device = pContext->Device; if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) { if(start >= 0 && length >= 0 && start+length <= pBuffer->size) { if(access == AL_READ_ONLY_EXT || access == AL_WRITE_ONLY_EXT || access == AL_READ_WRITE_EXT) { if(pBuffer->state == UNMAPPED) { ret = pBuffer->data + start; pBuffer->state = MAPPED; } else alSetError(pContext, AL_INVALID_OPERATION); } else alSetError(pContext, AL_INVALID_ENUM); } else alSetError(pContext, AL_INVALID_VALUE); } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); return ret; } AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer) { ALCcontext *pContext; ALdatabuffer *pBuffer; ALCdevice *Device; pContext = GetContextSuspended(); if(!pContext) return; Device = pContext->Device; if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) { if(pBuffer->state == MAPPED) pBuffer->state = UNMAPPED; else alSetError(pContext, AL_INVALID_OPERATION); } else alSetError(pContext, AL_INVALID_NAME); ProcessContext(pContext); } /* * ReleaseALDatabuffers() * * INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist */ ALvoid ReleaseALDatabuffers(ALCdevice *device) { ALsizei i; for(i = 0;i < device->DatabufferMap.size;i++) { ALdatabuffer *temp = device->DatabufferMap.array[i].value; device->DatabufferMap.array[i].value = NULL; // Release buffer data free(temp->data); // Release Buffer structure ALTHUNK_REMOVEENTRY(temp->databuffer); memset(temp, 0, sizeof(ALdatabuffer)); free(temp); } }