Technical Q&A QA1639

Audio Queue - Playing an Audio File Containing HE-AAC Encoded Audio

Q:  I'm trying to play an HE-AACv1 encoded audio file, but kAudioFilePropertyDataFormat reports the format as plain 'aac '. How do I retrieve the appropriate AudioStreamBasicDescription to configure the Audio Queue correctly?

A: I'm trying to play an HE-AACv1 encoded audio file, but kAudioFilePropertyDataFormat reports the format as plain 'aac '. How do I retrieve the appropriate AudioStreamBasicDescription to configure the Audio Queue correctly?

HE-AAC is a layered format and has at its core the base layer of AAC. The encoded data for a layered audio format can be made of several layers that could have different sample rates, different channel layouts and may be decoded to multiple destination formats. Any AAC decoder would be able to decode the AAC base layer of an HE-AAC bitstream.

The kAudioFilePropertyFormatList Property

Core Audio represents this layering through the notion of an audio format list containing one or more audio format list items, each item representing an available format of the encoded data in the file.

For example, a hypothetical file encoded as HE-AACv1 may return an audio format list containing two audio format list items, describing the available formats as:

In other words, the encoded data in the file may be rendered as either HE-AAC or AAC-LC.

The audio format list for an audio file is retrieved by calling AudioFileGetProperty using the kAudioFilePropertyFormatList property.

The kAudioFilePropertyFormatList property will return an array of AudioFormatListItem structures (declared in AudioToolbox/AudioFormat.h), one for each alternate format represented as a AudioStreamBasicDescription, AudioChannelLayoutTag pair.

/*!
    @struct		AudioFormatListItem
    @abstract   this struct is used as output from the kAudioFormatProperty_FormatList property
    @field      mASBD 
                    an AudioStreamBasicDescription
    @field      mChannelLayoutTag 
                    an AudioChannelLayoutTag
*/
struct AudioFormatListItem
{
    AudioStreamBasicDescription		mASBD;
    AudioChannelLayoutTag		mChannelLayoutTag;
};
typedef struct AudioFormatListItem AudioFormatListItem;

You could then choose the appropriate AudioStreamBasicDescription to use with AudioQueueNewOutput when creating a new Audio Queue object for playback.

The kAudioFormatProperty_FirstPlayableFormatFromList Property

Since platform capabilities can vary (HE-AAC decoding may be available on one platform but not on another), Core Audio also has the notion of a first playable format. The first playable format is the highest quality (or best) format the platform is capable of playing back as determined at run-time.

Use the AudioFormatGetProperty API with the kAudioFormatProperty_FirstPlayableFormatFromList property to retrieve an index value for the AudioFormatListItem in the audio format list array that describes the highest quality format the device is capable of playing back.

Here's the same audio format list from before with index values added.

Example

Listing 1 demonstrates how the kAudioFilePropertyFormatList and kAudioFormatProperty_FirstPlayableFormatFromList properties can be used together to easily retrieve the richest (or best) supported audio format description for playback.

Listing 1  

#include "CAStreamBasicDescription.h"

AudioFormatListItem GetFirstPlayableAudioFormatForFile(AudioFileID inFileID)
{
    AudioFormatListItem *formatListPtr = NULL;
    AudioFormatListItem formatItem = {0};
    UInt32 propertySize;

    OSStatus status = noErr;

    if (NULL == inFileID) return formatItem;

    status = AudioFileGetPropertyInfo(inFileID, kAudioFilePropertyFormatList, &propertySize, NULL);
    if (noErr == status) {

        // allocate memory for the format list items
        formatListPtr = (AudioFormatListItem *)malloc(propertySize);
        if (NULL == formatListPtr) return formatItem;

        // get the list of Audio Format List Item's
        status = AudioFileGetProperty(inFileID, kAudioFilePropertyFormatList, &propertySize, formatListPtr);
        if (noErr == status) {
            // print out some helpful information
            UInt32 numFormats = propertySize / sizeof(AudioFormatListItem);
            printf ("This file has a %d layered data format:\n", numFormats);
            for (unsigned int i = 0; i < numFormats; ++i) {
                CAStreamBasicDescription(formatListPtr[i].mASBD).Print();
            }

            UInt32 itemIndex;
            UInt32 indexSize = sizeof(itemIndex);

            // get the index number of the first playable format -- this index number will be for
            // the highest quality layer the platform is capable of playing
            status = AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList, propertySize,
                                            formatListPtr, &indexSize, &itemIndex);
            if (noErr == status) {
                printf ("Returning AudioFormatListItem at index %d.\n", itemIndex);
                // copy the format item at index we want returned
                formatItem =  formatListPtr[itemIndex];
            }
        }

        free(formatListPtr);
    }

    return formatItem;
}


Document Revision History


DateNotes
2009-04-21

First Version

 

New document that describes how to use the FormatList property to chose the richest available format for AQ playback.