28

I have a performance-intensive iPhone game I would like to add sounds to. There seem to be about three main choices: (1) AVAudioPlayer, (2) Audio Queues and (3) OpenAL. I’d hate to write pages of low-level code just to play a sample, so that I would like to use AVAudioPlayer. The problem is that it seems to kill the performace – I’ve done a simple measuring using CFAbsoluteTimeGetCurrent and the play message seems to take somewhere from 9 to 30 ms to finish. That’s quite miserable, considering that 25 ms == 40 fps.

Of course there is the prepareToPlay method that should speed things up. That’s why I wrote a simple class that keeps several AVAudioPlayers at its disposal, prepares them beforehand and then plays the sample using the prepared player. No cigar, still it takes the ~20 ms I mentioned above.

Such performance is unusable for games, so what do you use to play sounds with a decent performance on iPhone? Am I doing something wrong with the AVAudioPlayer? Do you play sounds with Audio Queues? (I’ve written something akin to AVAudioPlayer before 2.2 came out and I would love to spare that experience.) Do you use OpenAL? If yes, is there a simple way to play sounds with OpenAL, or do you have to write pages of code?


Update: Yes, playing sounds with OpenAL is fairly simple.


zoul
  • 102,279
  • 44
  • 260
  • 354
  • What sound format do you use for Finch? I tried a 16-bit, 44.1kHz, PCM (uncompressed), .caf file and just got a hiss when I played the sound. – willc2 Jul 03 '09 at 14:31
  • It turns out OpenAL wants little-endian data. The converter app I use, only saves big-endian. Switched to afconvert until I can write a drag & drop converter. – willc2 Jul 03 '09 at 18:52
  • Does finch buffer audio files or should we explicitly buffer it. – arundevma Jul 13 '12 at 04:48
  • The whole audio buffer is sent to OpenAL before playing, so I think there’s little point in buffering on the calling side. – zoul Jul 13 '12 at 06:37
  • Are you sure you didn't mean ~200 ms? 20 ms is a very short amount and certainly good enough for game sounds... – Jocko Homo May 29 '13 at 18:29
  • @JockoHomo, I have initially discovered the lag because the sounds *felt* sluggish. Only after that I measured the delay and found out the number. Plus consider that 20 ms is all the time you’ve got to ship a single frame at 50 fps. It sucks to drop a frame each time you want to play a sound effect. – zoul May 30 '13 at 06:31
  • I use Finch in all my apps. Want to thank you by donating, do you have donate page. Thanks – GeneCode Apr 05 '20 at 09:27

5 Answers5

8

AVAudioPlayer is very marginal for game audio. Tackling AudioQueue or OpenAL by adapting one of the examples is definitely the way to go. latency is much more controllable that way.

Mark Bessey
  • 19,598
  • 4
  • 47
  • 69
  • 1
    AVAudioPlayer has improved greatly since 2009. – John Fricker Jan 31 '11 at 16:32
  • 5
    Hi I am from 2018 and `AVAudioPlayer` still drops frame rate if calling `play` or `setCurrentTime:0` repeatedly. `dispatch_async` does not help. `.caf` extension does not help either. – 5argon Apr 10 '18 at 20:44
7

If you're calling play on the main thread, try running it on a separate thread. What I ended up doing is:

#include <dispatch/dispatch.h>

dispatch_queue_t playQueue = dispatch_queue_create("com.example.playqueue", NULL);

AVAudioPlayer* player = ...
dispatch_async(playQueue, ^{
    [player play];
});

which fixed the worst of the framerate stuttering I was experiencing.

Ryan
  • 496
  • 6
  • 13
2

Use CocosDenshion – it’s free, easy, and works. It wraps AVAudioPlayer for background tracks and OpenAL for sounds.

zoul
  • 102,279
  • 44
  • 260
  • 354
2

I use OpenAL and the classes that came with the CrashLanding sample code. It's worked fine so far to play samples and play looped music all at the same time. I'm currently learning how to release the memory I've allocated for a sound (.wav file) when, for example, I want to play some intro music just once.

MrDatabase
  • 43,245
  • 41
  • 111
  • 153
  • 1
    I am scared of the audio code in Crash Landing, that’s why I was looking for an alternative. Wrapping up a simple OpenAL class was pretty easy after all – you can take a look at the code I wrote and see if it fits better than the sound engine from Crash Landing. – zoul Jun 30 '09 at 13:23
0

Do you want to check the buffering with the implementation you're using? It might be somehow related to the 20ms delay you're experiencing. i.e., try to play around with the buffer size.

SuPra
  • 8,488
  • 4
  • 37
  • 30
  • 1
    What kind of buffering? (Sorry if the question is not clear.) I’m currently using vanilla AVAudioPlayer, just with a wrapper that keeps several players at hand and each time some of them finishes, the wrapper calls the prepareToPlay method. – zoul Jun 12 '09 at 14:48
  • At some point, the audio data should be read into a buffer in order to be played out, look for that and try to adjust the buffer size. – SuPra Jun 12 '09 at 14:51
  • I just checked the API, and when you're initializing and you use initWithData, try to designate a memory buffer large enough. – SuPra Jun 12 '09 at 14:54
  • Ah-ha. I don’t think AVAudioPlayer lets you do that. The buffer size is most probably autodetected with respect to the data format and the first buffer is primed as you call prepareToPlay. – zoul Jun 12 '09 at 14:59
  • Hmm. That's a bad way of doing it if you're streaming the audio. Sorry I can't help you then. Wait for another response or try a different approach. An OpenAL treatment of the problem is here: http://www.gehacktes.net/2009/03/iphone-programming-part-6-multiple-sounds-with-openal/ – SuPra Jun 12 '09 at 15:10