Q:
Do I need to recreate my Audio Queue after receiving an interruption if I want to continue playback after the interruption?
A: While the topic of interruption handling is discussed in the Audio Session Programming Guide, developers should consider the following notes when working specifically with Audio Queue objects on iPhone OS 2 and iPhone OS 3.
iPhone OS 2.x
To support Audio Queue playback though an interruption event on iPhone OS 2.2.1 or earlier, applications will need to dispose of the currently playing Audio Queue object (by calling AudioQueueDispose ) when the AudioSessionInterruptionListener receives a kAudioSessionStartInterruption notification.
Once the interruption is over and the AudioSessionInterruptionListener receives the kAudioSessionEndInterruption notification, a new Audio Queue object can then be created and started.
Applications should save and restore any necessary state (eg. audio frame number) required to pick up playback from the point of interruption.
Listing 1: Generic audio session interruption handler iPhone OS 2.2.1 or earlier.
static void myInterruptionListener(void *inClientData, UInt32 inInterruptionState)
{
MyController *theController = (MyController *)inClientData;
[theController handleInteruption:inInterruptionState];
}
- (void)handleInterruption:(UInt32)inInterruptionState
{
// on interruption the running audio queue will stop itself and the audio session will go inactive
if (inInterruptionState == kAudioSessionBeginInterruption) {
// interruption detected!
// post a notification so we can update our UI
[[NSNotificationCenter defaultCenter] postNotificationName:@"playQueueStopped" object:self];
AudioQueueDispose(mPlaybackQueue, true);
mPlaybackQueue = NULL;
AudioFileClose(mAudioFile);
mAudioFile = 0;
mPlaybackWasInterrupted = YES;
} else if ((inInterruptionState == kAudioSessionEndInterruption) && mPlaybackWasInterupted) {
// we were playing back when we were interrupted, so reset and resume
// since we store the current playback audio frame in our controller object containing the queue
// playback will resume from where we stopped even though we are creating and starting a new queue
if (mPlaybackQueue == NULL) {
// call helper function to setup an audio queue for a given file
// resuming == true, so do not reset current packet number
mPlaybackQueue = SetupNewQueueForFile(mAudioFilePath, true);
if (mPlaybackQueue) {
UInt32 category = kAudioSessionCategory_MediaPlayback;
OSStatus result = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(category), &category);
if (result) printf("ERROR SETTING AUDIO CATEGORY!\n");
result = AudioSessionSetActive(true);
if (result) printf("ERROR SETTING AUDIO SESSION ACTIVE!\n");
result = AudioQueueStart(mPlaybackQueue, NULL);
if (result) printf("ERROR STARTING AUDIO QUEUE!\n");
// post a notification so we can update our UI
[[NSNotificationCenter defaultCenter] postNotificationName:@"playQueueResumed" object:self];
} else {
printf("ERROR CREATING AUDIO QUEUE!\n");
}
}
mPlaybackWasInterrupted = NO;
}
}
Back to Top
iPhone OS 3.0 or later
With the release of iPhone OS 3, applications may no longer need to dispose Audio Queue objects when the AudioSessionInterruptionListener receives a kAudioSessionStartInterruption notification. A playing Audio Queue will be paused as before and the application can update user interface elements if desired.
Once the interruption is over and the AudioSessionInterruptionListener receives the kAudioSessionEndInterruption notification, applications may now call AudioQueueStart to resume operation as expected.
IMPORTANT: There is a caveat with simply resuming playback after an interruption related to the use of the hardware codec for playback. Depending on the type of the interruption, the codec state may not survive through the interruption which may cause the Audio Queue object being used for playback to experience some packet loss if you just called AudioQueueStart to resume playback.
Applications may therefore decide to dispose of a playing Audio Queue and create a new Audio Queue object after receiving the kAudioSessionEndInterruption notification depending on the chosen hardware codec policy.
More information about the kAudioQueueProperty_HardwareCodecPolicy property can be found the the Audio Queue Services Reference or AudioToolbox/AudioQueue.h
Listing 2: Simplified interruption handler from the SpeakHere Sample, iPhone OS 3.0 or later.
void interruptionListener(void *inClientData, UInt32 inInterruptionState)
{
SpeakHereController *THIS = (SpeakHereController*)inClientData;
if (inInterruptionState == kAudioSessionBeginInterruption) {
if (THIS->recorder->IsRunning()) {
// if we were recording stop now
[THIS stopRecord];
} else if (THIS->player->IsRunning()) {
// the queue will stop itself on interruption, we just need to update the UI
[[NSNotificationCenter defaultCenter] postNotificationName:@"playbackQueueStopped" object:THIS];
THIS->playbackWasInterrupted = YES;
}
} else if ((inInterruptionState == kAudioSessionEndInterruption) && THIS->playbackWasInterrupted) {
// if we were playing when interrupted, resume playing and update UI
printf("Resuming Queue\n");
THIS->player->StartQueue(true);
[[NSNotificationCenter defaultCenter] postNotificationName:@"playbackQueueResumed" object:THIS];
THIS->playbackWasInterrupted = NO;
}
}
Note: See the Audio Session Services Reference or AudioToolbox/AudioServices.h for information about the AudioSession APIs.
Back to Top
Document Revision History
Date |
Notes |
2009-06-17 |
Updated for 3.0 |
2008-08-14 |
New document that describes how to handle an interruption when playing back audio using an Audio Queue. |
|