Wednesday, October 21, 2009

Supporting AAC+ via the iPhone SDK

I've been asked a few times about how I've managed to support AAC+ v1 (also known as HE AAC v1) using the iPhone SDK. Even though AAC+ has been supported since iPhone OS 2.2, the process is not currently documented well at all in Apple's iPhone documentation. About 6 months ago, when I had a project requiring AAC+ support, I ended up using one of my iPhone Developer tech support credits to get an answer from Apple. Even then, the answer provided by Apple was fairly vague and it took a few more hours of tinkering for me to get things working.

Since it's apparently still not a well documented procedure, I figured I should share this information. I may be shooting myself in the foot competitively - AAC+ isn't something every radio app currently supports - but I do try to share with the developer community. AAC+ support isn't meant to be some secret feature usable only by some developers - it's officially supported by the SDK. It's just that the documentation is lacking.

This is not meant to be a full tutorial of using the iPhone SDK audio streams and queues. I am assuming you can already play standard audio streams in your app.

When you receive the audiostreamproperty notification for an AAC+ stream, initially the stream property will be AAC. You'll then need enumerate the kAudioFileStreamProperty_FormatList for that property. Retrieve the format list via a call to AudioFileStreamGetProperty(). Loop through the format list and if the stream is in AAC+ format one of the format IDs will be kAudioFormatMPEG4AAC_HE. This is the descriptor you'll need to use for AAC+ support when you call AudioQueueNewOutput().

This last point is key! You must use this new descriptor pulled out of the format list to create your audio queue. If you use the original descriptor, you will only be creating an AAC audio queue rather than an AAC+ one.

Oh, and don't expect this to work on the simulator. For some reason HE AAC is only supported on the real iPhone hardware - the simulator will never return a result of HE AAC - at least it didn't under 2.2.1. I haven't re-tested with any of the 3.x sims.

Also note that the SDK currently only supports AAC+ v1 with SBR (Spectral Band Replication). The PS (parametric stereo) feature of AAC+ v2 does not work and results in a mono audio playback. Also, the AAC+ support only works on OS 2.2 and higher.

Here's an example of how I detect the HE AAC descriptor in an audiostreamproperty notification handler . It's just a snippet of code taken out of context, but hopefully gives you an idea of how it is done:

AudioStreamBasicDescription asbd;
UInt32 asbdSize = sizeof(asbd);
UInt32 formatListSize;
Boolean writable;

err =
AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
if (err) { /* do something for an error */ }

err =
AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, &writable);
if (!err) {

        
// get the FormatList data
        void* formatListData = calloc(1, formatListSize);
        err =
AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, formatListData);
        
if (err) { PRINTERROR("get kAudioFilePropertyFormatList"); free(formatListData); ; }
        
        
// Scan through all the supported formats and look for HE AAC
        for (int x = 0; x < formatListSize; x += sizeof(AudioFormatListItem)){
                
AudioStreamBasicDescription *pasbd = formatListData + x;
        
                
if (pasbd->mFormatID == kAudioFormatMPEG4AAC_HE){
                        
NSLog(@“Found HE AAC!");
                        
// HE AAC isn't supported on the simulator for some reason
                        if (!TARGET_IPHONE_SIMULATOR){
                                
memcpy(&asbd, pasbd, sizeof(asbd));
                        }
                        
break;
                }                                
        }
        
free(formatListData);
}

All content copyright © 2009  Brian Stormont, unless otherwise noted.   All rights reserved.