Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm using OpenAL to play sounds. I'm trying to implement a fire-and-forget play function that takes a buffer ID and assigns it to a source from a pool I have previously allocated, and plays it. However, there is a problem with object lifetimes.

In OpenGL, delete functions either automatically unbind things (e.g. textures), or automatically deletes the thing when it eventually is unbound (e.g. shaders) and so it's usually easy to manage deletion. However alDeleteBuffers instead simply fails with AL_INVALID_OPERATION if the buffer is still bound to a source.

Is there an idiomatic way to "delete" OpenAL buffers that allows them to finish playing, and then automatically unbinds and really them? Do I need to tie buffer management more deeply into the source pool (e.g. deleting a buffer requires checking all the allocated sources also)?

Similarly, is there an idiomatic way to unbind (but not delete) buffers when they are finished playing? It would be nice if, when I was looking for a free source, I only needed to see if a buffer was attached at all and not bother checking the source state.

(I'm using C++, although approaches for C are also fine. Approaches assuming a GCd language and using finalizers are probably not applicable.)

share|improve this question
    
If you still need an answer, I used a garbage collection method in Gorgon engine: sf.net/p/gorgon-ge –  Cem Kalyoncu Dec 28 '12 at 5:07

1 Answer 1

Before deleting a buffer you must unbind it from each source that uses it (ex: alSourcei(mSourceId, AL_BUFFER, NULL); or delete all sources which are bound to the buffer.

You need to keep track of the length of each of your sounds to release them upon completions. You can do this using a structure for each source to keep the sound length and the time played (updated each game tick). Ex:

struct AudioVoice
{
    ALuint          mSourceId;
    ALuint          mMsDuration;
    ALuint          mMsPlayed;
};

If you use a component based system you can periodically check all running sources for completion and do the unbind/source delete there.

If you don't keep track of the play/pause changes in your code you will also want to check if the sources are playing before increasing the played time.

ALint sourceState;
alGetSourcei(mSourceId, AL_SOURCE_STATE, &sourceState);
if (sourceState == AL_PLAYING) { /* increase played time */  }

If you want to keep track of the sources bound to a buffer you can use a structure with the id of your buffer and a vector linking to the source structures this way you can even interrupt all sources which are bound to a buffer you need to release ASAP. Ex:

struct AudioData
{
    RKuint                      mMsDuration;
    ALuint                      mSourceId;
    std::vector<AudioVoice*>    mVoices;
};

This should be enough to get you on the right track. I can't give you more detailed code from my projects as they heavily rely on macros and hand made RTTI mechanisms.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.