AudioSessionInitialize Workarounds

Yesterday I decided to go after one of my audio bugs by take a look how AVAudioPlayer does it right, and I discovered a little thing about Audio Session.
Here are two workarounds for AudioSessionInitialize.
I never liked AudioSessionInitialize because you can set the InterruptionListener and it’s ClientData just once:
* Discussion
* Your application must call this function before making any other Audio
* Session Services calls. You may activate and deactivate your audio session
* as needed (see AudioSessionSetActive), but should initialize it only once.
*/
OSStatus AudioSessionInitialize (
CFRunLoopRef inRunLoop,
CFStringRef inRunLoopMode,
AudioSessionInterruptionListener inInterruptionListener,
void *inClientData
);
So you need a helper class like this where you have to set the active AudioPlayer:
void interruptionListenerCallback (
void *inUserData,
UInt32 interruptionState
) {
AudioInterruptionListener *listener = (AudioInterruptionListener *) inUserData;
DoItYourselfPlayer *player = listener.doItYourselfPlayer;
if (!player)
return;
if (interruptionState == kAudioSessionBeginInterruption) {
[player performSelectorOnMainThread:@selector(audioStreamPlayerBeginInterruption)
withObject:nil
waitUntilDone:YES];
} else if ((interruptionState == kAudioSessionEndInterruption)) {
[player performSelectorOnMainThread:@selector(audioStreamPlayerEndInterruption)
withObject:nil
waitUntilDone:YES];
}
}
@implementation AudioInterruptionListener
static AudioInterruptionListener *sharedAudioInterruptionListener;
@synthesize doItYourselfPlayer;
+ (void)initialize {
if (!sharedAudioInterruptionListener) {
sharedAudioInterruptionListener = [[AudioInterruptionListener alloc] init];
AudioSessionInitialize (
NULL,
NULL,
interruptionListenerCallback,
sharedAudioInterruptionListener
);
}
}
+ (AudioInterruptionListener *)sharedAudioInterruptionListener
{
return sharedAudioInterruptionListener;
}
@end
This is fine, but I was no big fan of this helper class when I wrote it.
AVAudioPlayer works without such helper class, but how? Well don’t do this at home, because ‘intr’ is not documented in “Audio Session Services Property Identifiers.”, but you can also add an InterruptionListener with AudioSessionAddPropertyListener, the code should look something along this lines:
pthread_once(&interruptionListenerOneTimeInit, interruptionListenerInit);
…
AudioSessionAddPropertyListener(’intr’, interruptionListenerCallback, self);
}
- (void)stop {
AudioSessionRemovePropertyListenerWithUserData(’intr’, interruptionListenerCallback, self);
…
}
#pragma mark -
#pragma mark Audio Session Implementations
pthread_once_t interruptionListenerOneTimeInit = PTHREAD_ONCE_INIT;
void interruptionListenerInit(void)
{
AudioSessionInitialize(NULL, NULL, NULL, NULL);
}
void interruptionListenerCallback (
void *inClientData,
AudioSessionPropertyID inID,
UInt32 inDataSize,
const void *inData
) {
DoItYourselfPlayer *player = inClientData;
if (inID == ‘intr’) {
UInt32 *interruptionState = (UInt32 *)inData;
if (*interruptionState == kAudioSessionBeginInterruption) {
[player performSelectorOnMainThread:@selector(audioStreamPlayerBeginInterruption)
withObject:nil
waitUntilDone:YES];
} else if (*interruptionState == kAudioSessionEndInterruption) {
[player performSelectorOnMainThread:@selector(audioStreamPlayerEndInterruption)
withObject:nil
waitUntilDone:YES];
}
}
}
}
If you agree that Apple should expose this functionality to third parties, please submit a duplicate for Radar ID# 6467253.
Happy Holidays hacking!

