OK, So, I just got an email from Ken, a dude who surfed across this OpenAL stuff on my blog, had some troubles, and asked me for help. He is having trouble unloading buffers and then re-using them again without getting some esoteric OpenAL errors.
So I went through the snippets he sent me very quickly and threw out some advice. Ken came back with a few more questions and I went over the code again and noticed this:
// use the static buffer data API alBufferDataStaticProc(buffer, format, data, size, freq);
Ah-HA! I said, that is probably your problem right there! alBufferDataStatic should be avoided unless you need it. When do you know if you will need it? Here is a rule of thumb: If you dont know the answer to that question then you dont need it.
(I don’t want to seem to be picking on Ken, this problem is so common that I decided I needed to do a post about it (similar to my rant about never using the sample code from Apple in a shipping app))
OK, so why do I think you should avoid it? I am sure you have heard that if you want the best performance then you should be using alBufferDataStatic() right?! No.
Well, what is alBufferDataStatic() anyway? alBufferDataStatic puts the onus of memory management for all your buffer data onto your code.
Let me repeat that: When using alBufferDataStatic() YOU are responsible for all the memory management.
That is it. That is your big performance boost.
Wait! Really? that is all it does?
The iPhone’s shared memory space and the way it handles memory and the way your app gets jettisoned if you use too much is a very unique situation. A situation that requires that you often have to really closely handle your memory. So! That means that if you are trying to squeeze every single last byte of memory out of the iPhone so that your fully immersive 3d first-person-shooter can keep a consistent 30FPS then you will probably want to spend a few weeks tweaking your sound code so that you have very close control of your memory at all times.
For the other %99.9999 percent of apps that might want to use OpenAL (even if you are using lots of sounds) you are just adding extra headaches to your code by using alBufferDataStatic(). Here is another rule of thumb: If you are not employing a developer whose sole job is to handle the sound code in your app, then you don’t need alBufferDataStatic().
Have a quick read of the technote that mentions alBufferDataStatic().
What does this really mean?
It means this: when you use alBufferData() you load your sound data into a local buffer (one that you have to malloc) then when you call alBufferData(), OpenAL copies all those bytes into it’s own buffer that it deals with. Then you free your local storage and OpenAL now owns that buffer. The downside: for a brief moment, you have 2 copies of your sound in memory. The upside: very very easy memory management.
If you are getting jettisoned right here, during this buffer copy, then you may need alBufferDataStatic(). But more likely you have done a crap job of handling your memory elsewhere. (also it is good to note that if you are loading big sounds into memory you are doing it wrong anyway, those big sounds should be streamed).
Ok, you are absolutely, positively sure that you need to manage your own sound memory? Maybe you should be using alBufferDataStatic(), but first: here is yet another rule of thumb: if you are reading this blog post to see if you need to use it; you don’t. go to your code right now and take it out. Just take it out.
Obviously I am being a bit hyperbolic in an attempt to make a point. I dont know about your code, but here is a small list of the most common bugs I find in my code:
- Forgot to release an object properly and it leaks and eventually my app is jettisoned
- Accidentally released an autoreleased object, causing a crash
- Accidentally released an object owned by some other object, causing it to crash much much later
- malloced some space and forgot to free it, causing a leak and eventual jettison
- freed some malloced space and then tried to use it, causing my app to go batshit crazy
The list goes on. But can you see a common thread? Memory. Why would I want to add yet more memory management responsibilities when I dont need it? Why do developers always insist on making their own lives so much more difficult than they have to?
Here are a few platitudes:
- Less code == Less bugs. More code == More bugs. Therefore Less Code is always better.
- Do not add any code you dont need right now. (this is very common, you think to yourself: Hmm I am already here in this object, and I could see that I might need a method that does X in the future so I will just write it now so I dont have to write it then. Wrong. In that ‘future’ when you do need it, it will need to do Y, not X and you will have to re-write it. Or, more likely you will never need a method that does X, and you just wasted a bunch of time and added more code
- Do not prematurely optimize. Get the code working first. Then go back and identify the places you need to smooth out. If you try to optimize as you go then you will end up spending all your time making that one method totally awesome (only to realize later that method only gets called once every few seconds, so really it could be the least efficient bit of code ever and nobody would ever notice.)
So, by using alBufferDataStatic() you are breaking all three of my lovely platitudes.
Dont do it.
You are only causing yourself grief and making your code buggy and shitty. Use alBufferData(). It works. It is easy. The highly experienced engineers who work on OpenAL have made sure that there are no memory issues with alBufferData(). If you decide to port your code, alBufferData() will still work! alBufferData() makes your breath smell minty! alBufferData() will totally pull chicks.
I have put OpenAL code into about 6 apps now. A few games and a few utilities. And one ‘sound board’ style app that played 32 sounds simultaneously (which was the max at the time, probably still is) and was able to handle gigantic sounds files (via streaming) without ever using alBufferDataStatic(). Was this some herculean task of super-awesome mad coding skillzzzz?
No. Just the opposite actually. I keep all my code as absolutely bare-minimum simple as I can.
Keep your code simple, don’t use stuff you don’t need.