How do you completely remove and release memory of an OpenAL sound file?
Asked Answered
S

3

7

I have a small level based iPhone app. I need to load and release sound files for each level. Everything works fine with my openAL SoundManager except releasing sounds.

At first, when I remove a sound, it seems to do what it is meant to do – it removes the sound and I can’t access it again unless I reload it. BUT, when I test my apps dealloc’s with ‘Instruments’ it doesn’t show any deallocation. It doesn’t seem to free up the memory. So, when you move from level to level, it doesn't take long for the memory to run out and the app to crash.

I get this error in console:

Program received signal: “0”. warning: check_safe_call: could not restore current frame kill quit

This is how I load the sounds -

- (void)loadSoundWithKey:(NSString*)aSoundKey fileName:(NSString*)aFileName fileExt:(NSString*)aFileExt {
// Check to make sure that a sound with the same key does not already exist
NSNumber *numVal = [soundLibrary objectForKey:aSoundKey];
// If the key is found log it and finish
if(numVal != nil) {
    NSLog(@"WARNING - SoundManager: Sound key '%@' already exists.", aSoundKey);
    return;
}
    NSUInteger bufferID;
// Generate a buffer within OpenAL for this sound
alGenBuffers(1, &bufferID);
// Set up the variables which are going to be used to hold the format
// size and frequency of the sound file we are loading
ALenum  error = AL_NO_ERROR;
ALenum  format;
ALsizei size;
ALsizei freq;
ALvoid *data;
NSBundle *bundle = [NSBundle mainBundle];
// Get the audio data from the file which has been passed in
CFURLRef fileURL = (CFURLRef)[[NSURL fileURLWithPath:[bundle pathForResource:aFileName ofType:aFileExt]] retain];
if (fileURL)
{   
    data = MyGetOpenALAudioData(fileURL, &size, &format, &freq);
    CFRelease(fileURL);
    if((error = alGetError()) != AL_NO_ERROR) {
        NSLog(@"ERROR - SoundManager: Error loading sound: %x\n", error);
        exit(1);
    }
    // Use the static buffer data API
    alBufferDataStaticProc(bufferID, format, data, size, freq);
    if((error = alGetError()) != AL_NO_ERROR) {
        NSLog(@"ERROR - SoundManager: Error attaching audio to buffer: %x\n", error);
    }       
}
else
{
    NSLog(@"ERROR - SoundManager: Could not find file '%@.%@'", aFileName, aFileExt);
    data = NULL;
}

// Place the buffer ID into the sound library against |aSoundKey|
[soundLibrary setObject:[NSNumber numberWithUnsignedInt:bufferID] forKey:aSoundKey];
if(DEBUG) NSLog(@"INFO - SoundManager: Loaded sound with key '%@' into buffer '%d'", aSoundKey, bufferID);

}

And this is how I am trying to remove/release. But it still seems to retain the memory of the sound file -

- (void)removeSoundWithKey:(NSString*)aSoundKey {
// Find the buffer which has been linked to the sound key provided
NSNumber *numVal = [soundLibrary objectForKey:aSoundKey];
// If the key is not found log it and finish
if(numVal == nil) {
    NSLog(@"WARNING - SoundManager: No sound with key '%@' was found so cannot be removed", aSoundKey);
    return;
}    
// Get the buffer number form the sound library so that the sound buffer can be released
NSUInteger bufferID = [numVal unsignedIntValue];
alDeleteBuffers(1, &bufferID);
[soundLibrary removeObjectForKey:aSoundKey];
if(DEBUG) NSLog(@"INFO - SoundManager: Removed sound with key '%@'", aSoundKey);

}

Can anyone think of away to completely remove every trace of my sound file (with the ability to load it again)?

Thank you very much!

Shere answered 10/1, 2010 at 3:28 Comment(2)
Hi, Several views but no answers yet?... If you look at this code and can't see anything wrong with it, please say so. Then it might lead me to think that my problem isn't with my buffers not releasing memory. ThanksShere
alBufferDataStatic is a "sharp knife" with a bunch of hidden caveats. I recommend watching this video: youtu.be/6QQAzhwalPIRhythmist
S
5

If anyone is interested... my problem was resolved by changing the alBufferDataStaticProc to alBufferData. Then adding if(data) free(data); See below.

Thanks for your help.

alBufferData(bufferID, format, data, size, freq);
    if((error = alGetError()) != AL_NO_ERROR) {
        NSLog(@"ERROR - SoundManager: Error attaching audio to buffer: %x\n", error);
    }
    if (data) 
        free(data);
}else{
    NSLog(@"ERROR - SoundManager: Could not find file '%@.%@'", fileName, fileType);
    data = NULL;
Shere answered 30/1, 2010 at 23:0 Comment(1)
Actually, this didn't work for me, but it helped a lot on finding the issue. All I needed to do, from using the same apple example, was adding if (device != NULL) [self teardownOpenAL]; before [self initOpenAL];Tentacle
T
2

This is a sum up of what I did "to completely remove every trace of my sound file (with the ability to load it again)" using the same apple example and some openAL documentation:

if (device != NULL)
    [self teardownOpenAL];
[self initOpenAL];
alSourcePlay(source);

The main addition here is that if, which in my case I actually added into teardownOpenAL.

Tentacle answered 10/1, 2011 at 14:18 Comment(0)
L
0

Not familiar with the specialities with OpenAL for iPhone, but here is my rough guess:

Is the buffer still attached to an OpenAL source, i.e. have you called alSourcei(..., AL_BUFFER, ...) or alSourceQueueBuffers between the loading and the release? If that is the case you might need to run alSourcei(..., AL_BUFFER, NULL) or alSourceUnqueueBuffers before deleting the buffer.

Try checking for OpenAL errors (alGetErrors) after you called alDeleteBuffers.

Levitus answered 18/1, 2010 at 16:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.