fixed #17395: OpenAL A003 error if doing AL invocation before alcMakeContextCurrent(s_ALContext); (#17492)

Pause director if Audio Session is still in interrupted state, resume director in interrupted ended.
This commit is contained in:
James Chen 2017-03-14 13:56:12 +08:00 committed by minggo
parent 769f7830f0
commit b842202541
1 changed files with 68 additions and 20 deletions

View File

@ -79,8 +79,9 @@ void AudioEngineInterruptionListenerCallback(void* user_data, UInt32 interruptio
if (self = [super init]) if (self = [super init])
{ {
if ([[[UIDevice currentDevice] systemVersion] intValue] > 5) { if ([[[UIDevice currentDevice] systemVersion] intValue] > 5) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:UIApplicationWillResignActiveNotification object:nil];
} }
// only enable it on iOS. Disable it on tvOS // only enable it on iOS. Disable it on tvOS
// AudioSessionInitialize removed from tvOS // AudioSessionInitialize removed from tvOS
@ -95,37 +96,83 @@ void AudioEngineInterruptionListenerCallback(void* user_data, UInt32 interruptio
-(void)handleInterruption:(NSNotification*)notification -(void)handleInterruption:(NSNotification*)notification
{ {
static bool isAudioSessionInterrupted = false;
static bool resumeOnBecomingActive = false; static bool resumeOnBecomingActive = false;
static bool pauseOnResignActive = false;
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) { if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification])
{
NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue]; NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
if (reason == AVAudioSessionInterruptionTypeBegan) { if (reason == AVAudioSessionInterruptionTypeBegan)
alcMakeContextCurrent(NULL); {
isAudioSessionInterrupted = true;
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive)
{
ALOGD("AVAudioSessionInterruptionTypeBegan, application != UIApplicationStateActive, alcMakeContextCurrent(nullptr)");
alcMakeContextCurrent(nullptr);
}
else
{
ALOGD("AVAudioSessionInterruptionTypeBegan, application == UIApplicationStateActive, pauseOnResignActive = true");
pauseOnResignActive = true;
}
} }
if (reason == AVAudioSessionInterruptionTypeEnded) { if (reason == AVAudioSessionInterruptionTypeEnded)
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) { {
isAudioSessionInterrupted = false;
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
{
ALOGD("AVAudioSessionInterruptionTypeEnded, application == UIApplicationStateActive, alcMakeContextCurrent(s_ALContext)");
NSError *error = nil; NSError *error = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&error]; [[AVAudioSession sharedInstance] setActive:YES error:&error];
alcMakeContextCurrent(s_ALContext); alcMakeContextCurrent(s_ALContext);
} else { if (Director::getInstance()->isPaused())
{
ALOGD("AVAudioSessionInterruptionTypeEnded, director was paused, try to resume it.");
Director::getInstance()->resume();
}
}
else
{
ALOGD("AVAudioSessionInterruptionTypeEnded, application != UIApplicationStateActive, resumeOnBecomingActive = true");
resumeOnBecomingActive = true; resumeOnBecomingActive = true;
} }
} }
} }
else if ([notification.name isEqualToString:UIApplicationWillResignActiveNotification])
if ([notification.name isEqualToString:UIApplicationDidBecomeActiveNotification] && resumeOnBecomingActive) { {
resumeOnBecomingActive = false; ALOGD("UIApplicationWillResignActiveNotification");
NSError *error = nil; if (pauseOnResignActive)
BOOL success = [[AVAudioSession sharedInstance] {
setCategory: AVAudioSessionCategoryAmbient pauseOnResignActive = false;
error: &error]; ALOGD("UIApplicationWillResignActiveNotification, alcMakeContextCurrent(nullptr)");
if (!success) { alcMakeContextCurrent(nullptr);
ALOGE("Fail to set audio session."); }
return; }
else if ([notification.name isEqualToString:UIApplicationDidBecomeActiveNotification])
{
ALOGD("UIApplicationDidBecomeActiveNotification");
if (resumeOnBecomingActive)
{
resumeOnBecomingActive = false;
ALOGD("UIApplicationDidBecomeActiveNotification, alcMakeContextCurrent(s_ALContext)");
NSError *error = nil;
BOOL success = [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: &error];
if (!success) {
ALOGE("Fail to set audio session.");
return;
}
[[AVAudioSession sharedInstance] setActive:YES error:&error];
alcMakeContextCurrent(s_ALContext);
}
else if (isAudioSessionInterrupted)
{
ALOGD("Audio session is still interrupted, pause director!");
Director::getInstance()->pause();
} }
[[AVAudioSession sharedInstance] setActive:YES error:&error];
alcMakeContextCurrent(s_ALContext);
} }
} }
@ -133,6 +180,7 @@ void AudioEngineInterruptionListenerCallback(void* user_data, UInt32 interruptio
{ {
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
[super dealloc]; [super dealloc];
} }