diff options
author | Zack Middleton <zturtleman@gmail.com> | 2013-11-10 22:42:48 -0600 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2014-06-17 17:43:36 +0100 |
commit | f7e122a3f11830fa4c5e049296b31969d2964280 (patch) | |
tree | 956dd3a1644dbf9c49a7369ae35c3f99e96a881e /src/client/snd_openal.c | |
parent | a9f515331547b95d2c4813a57e89e8fbf66f161b (diff) |
Make OpenAL buffer management work on OS X
Don't assume we have unlimited OpenAL buffers.
Detach buffers from sources by setting AL_BUFFER to 0. Cannot delete buffers on OS X immediately after alSourceUnqueueBuffers.
Free unprocessed stream and music buffers.
Free unused sfx buffers when sound file exists and fails loading into OpenAL (though I haven't seen it fail).
Diffstat (limited to 'src/client/snd_openal.c')
-rw-r--r-- | src/client/snd_openal.c | 137 |
1 files changed, 105 insertions, 32 deletions
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c index b7ce3f0f..fa18f2dc 100644 --- a/src/client/snd_openal.c +++ b/src/client/snd_openal.c @@ -317,6 +317,44 @@ static qboolean S_AL_BufferEvict( void ) /* ================= +S_AL_GenBuffers +================= +*/ +static qboolean S_AL_GenBuffers(ALsizei numBuffers, ALuint *buffers, const char *name) +{ + ALenum error; + + S_AL_ClearError( qfalse ); + qalGenBuffers( numBuffers, buffers ); + error = qalGetError(); + + // If we ran out of buffers, start evicting the least recently used sounds + while( error == AL_INVALID_VALUE ) + { + if( !S_AL_BufferEvict( ) ) + { + Com_Printf( S_COLOR_RED "ERROR: Out of audio buffers\n"); + return qfalse; + } + + // Try again + S_AL_ClearError( qfalse ); + qalGenBuffers( numBuffers, buffers ); + error = qalGetError(); + } + + if( error != AL_NO_ERROR ) + { + Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n", + name, S_AL_ErrorMsg(error)); + return qfalse; + } + + return qtrue; +} + +/* +================= S_AL_BufferLoad ================= */ @@ -357,14 +395,10 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) format = S_AL_Format(info.width, info.channels); // Create a buffer - S_AL_ClearError( qfalse ); - qalGenBuffers(1, &curSfx->buffer); - if((error = qalGetError()) != AL_NO_ERROR) + if (!S_AL_GenBuffers(1, &curSfx->buffer, curSfx->filename)) { S_AL_BufferUseDefault(sfx); Hunk_FreeTempMemory(data); - Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n", - curSfx->filename, S_AL_ErrorMsg(error)); return; } @@ -386,6 +420,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) { if( !S_AL_BufferEvict( ) ) { + qalDeleteBuffers(1, &curSfx->buffer); S_AL_BufferUseDefault(sfx); Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", curSfx->filename); @@ -400,6 +435,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) // Some other error condition if(error != AL_NO_ERROR) { + qalDeleteBuffers(1, &curSfx->buffer); S_AL_BufferUseDefault(sfx); Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n", @@ -983,7 +1019,7 @@ static void S_AL_SrcKill(srcHandle_t src) curSource->isPlaying = qfalse; } - // Remove the buffer + // Detach any buffers qalSourcei(curSource->alSource, AL_BUFFER, 0); curSource->sfx = 0; @@ -1642,9 +1678,15 @@ ALuint S_AL_SrcGet(srcHandle_t src) //=========================================================================== +// Q3A cinematics use up to 12 buffers at once +#define MAX_STREAM_BUFFERS 20 + static srcHandle_t streamSourceHandles[MAX_RAW_STREAMS]; static qboolean streamPlaying[MAX_RAW_STREAMS]; static ALuint streamSources[MAX_RAW_STREAMS]; +static ALuint streamBuffers[MAX_RAW_STREAMS][MAX_STREAM_BUFFERS]; +static int streamNumBuffers[MAX_RAW_STREAMS]; +static int streamBufIndex[MAX_RAW_STREAMS]; /* ================= @@ -1702,6 +1744,9 @@ static void S_AL_AllocateStreamChannel(int stream, int entityNum) streamSourceHandles[stream] = cursrc; streamSources[stream] = alsrc; + + streamNumBuffers[stream] = 0; + streamBufIndex[stream] = 0; } /* @@ -1714,6 +1759,15 @@ static void S_AL_FreeStreamChannel( int stream ) if ((stream < 0) || (stream >= MAX_RAW_STREAMS)) return; + // Detach any buffers + qalSourcei(streamSources[stream], AL_BUFFER, 0); + + // Delete the buffers + if (streamNumBuffers[stream] > 0) { + qalDeleteBuffers(streamNumBuffers[stream], streamBuffers[stream]); + streamNumBuffers[stream] = 0; + } + // Release the output streamSource S_AL_SrcUnlock(streamSourceHandles[stream]); S_AL_SrcKill(streamSourceHandles[stream]); @@ -1729,6 +1783,7 @@ S_AL_RawSamples static void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum) { + int numBuffers; ALuint buffer; ALuint format; @@ -1750,8 +1805,40 @@ void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, } } - // Create a buffer, and stuff the data into it - qalGenBuffers(1, &buffer); + qalGetSourcei(streamSources[stream], AL_BUFFERS_QUEUED, &numBuffers); + + if (numBuffers == MAX_STREAM_BUFFERS) + { + Com_DPrintf(S_COLOR_RED"WARNING: Steam dropping raw samples, reached MAX_STREAM_BUFFERS\n"); + return; + } + + // Allocate a new AL buffer if needed + if (numBuffers == streamNumBuffers[stream]) + { + ALuint oldBuffers[MAX_STREAM_BUFFERS]; + int i; + + if (!S_AL_GenBuffers(1, &buffer, "stream")) + return; + + Com_Memcpy(oldBuffers, &streamBuffers[stream], sizeof (oldBuffers)); + + // Reorder buffer array in order of oldest to newest + for ( i = 0; i < streamNumBuffers[stream]; ++i ) + streamBuffers[stream][i] = oldBuffers[(streamBufIndex[stream] + i) % streamNumBuffers[stream]]; + + // Add the new buffer to end + streamBuffers[stream][streamNumBuffers[stream]] = buffer; + streamBufIndex[stream] = streamNumBuffers[stream]; + streamNumBuffers[stream]++; + } + + // Select next buffer in loop + buffer = streamBuffers[stream][ streamBufIndex[stream] ]; + streamBufIndex[stream] = (streamBufIndex[stream] + 1) % streamNumBuffers[stream]; + + // Fill buffer qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); // Shove the data onto the streamSource @@ -1781,13 +1868,12 @@ void S_AL_StreamUpdate( int stream ) if(streamSourceHandles[stream] == -1) return; - // Un-queue any buffers, and delete them + // Un-queue any buffers qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers ); while( numBuffers-- ) { ALuint buffer; qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer); - qalDeleteBuffers(1, &buffer); } // Start the streamSource playing if necessary @@ -1818,8 +1904,6 @@ S_AL_StreamDie static void S_AL_StreamDie( int stream ) { - int numBuffers; - if ((stream < 0) || (stream >= MAX_RAW_STREAMS)) return; @@ -1829,15 +1913,6 @@ void S_AL_StreamDie( int stream ) streamPlaying[stream] = qfalse; qalSourceStop(streamSources[stream]); - // Un-queue any buffers, and delete them - qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers ); - while( numBuffers-- ) - { - ALuint buffer; - qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer); - qalDeleteBuffers(1, &buffer); - } - S_AL_FreeStreamChannel(stream); } @@ -1929,22 +2004,17 @@ S_AL_StopBackgroundTrack static void S_AL_StopBackgroundTrack( void ) { - int numBuffers; - if(!musicPlaying) return; // Stop playing qalSourceStop(musicSource); - // Un-queue any buffers, and delete them - qalGetSourcei( musicSource, AL_BUFFERS_PROCESSED, &numBuffers ); - while( numBuffers-- ) - { - ALuint buffer; - qalSourceUnqueueBuffers(musicSource, 1, &buffer); - qalDeleteBuffers(1, &buffer); - } + // Detach any buffers + qalSourcei(musicSource, AL_BUFFER, 0); + + // Delete the buffers + qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers); // Free the musicSource S_AL_MusicSourceFree(); @@ -2077,7 +2147,8 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop ) } // Generate the musicBuffers - qalGenBuffers(NUM_MUSIC_BUFFERS, musicBuffers); + if (!S_AL_GenBuffers(NUM_MUSIC_BUFFERS, musicBuffers, "music")) + return; // Queue the musicBuffers up for(i = 0; i < NUM_MUSIC_BUFFERS; i++) @@ -2438,6 +2509,8 @@ qboolean S_AL_Init( soundInterface_t *si ) streamSourceHandles[i] = -1; streamPlaying[i] = qfalse; streamSources[i] = 0; + streamNumBuffers[i] = 0; + streamBufIndex[i] = 0; } // New console variables |