Restore game audio after OS events (dictation or siri) use audio

- Dictation reliable raises the handleAudioInterrupt notification, so that
  is used for disabling / enabling audio
- Siri sometimes doesn't raise the handleAudioInterrupt notification, so
  rely on applicationDidBecomeActive / applicationWillResignActive.
- Trial and error showed it is best to destroy and re-create the OS audio
  objects when audio is disabled / enabled.
This commit is contained in:
Scott Ludwig 2016-01-21 21:45:51 -08:00
parent 2a3ef9776d
commit f2d7002bc3
7 changed files with 54 additions and 30 deletions

View File

@ -2165,6 +2165,14 @@ bool Game::FilterEvent(Event *pevt)
case mpShowObjectivesEvent:
ShowObjectivesAction::OnMPShowObjectivesEvent(pevt->dw);
break;
case disableSoundEvent:
gsndm.SaveStateAndClear();
break;
case enableSoundEvent:
gsndm.RestoreState();
break;
}
return false;
@ -2201,7 +2209,9 @@ void Game::Suspend()
// Call host. This is a modal loop. When it returns, the game isn't
// paused anymore
gsndm.SaveStateAndClear();
HostSuspendModalLoop(pbmBack);
gsndm.RestoreState();
// Ok, invalidate everything so it all redraws

View File

@ -1789,6 +1789,8 @@ struct Event { // evt
#define checkGameOverEvent 0x6011
#define connectionCloseEvent 0x6012
#define showMessageEvent 0x6013
#define enableSoundEvent 0x6014
#define disableSoundEvent 0x6015
// gameOverEvent constants (placed in Event::dw)

View File

@ -156,6 +156,16 @@ bool ProcessMessage(base::Message *pmsg, Event *pevt)
pevt->ff = 0;
break;
case kidmDisableSound:
pevt->eType = disableSoundEvent;
pevt->ff = 0;
break;
case kidmEnableSound:
pevt->eType = enableSoundEvent;
pevt->ff = 0;
break;
default:
return false;
}

View File

@ -23,6 +23,8 @@ const int kidmAppSetFocus = 17;
const int kidmAppKillFocus = 18;
const int kidmAskStringEvent = 19;
const int kidmKeyDown = 20;
const int kidmEnableSound = 21;
const int kidmDisableSound = 22;
extern base::MessageQueue gmq;

View File

@ -1,5 +1,6 @@
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
#import <UIKit/UIWindow.h>
#import <UIKit/UIApplication.h>
@ -46,6 +47,27 @@ IPhoneAppDelegate *g_appDelegate;
{
}
- (void)handleAudioInterruption:(NSNotification *)notification
{
UInt8 type = [[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] intValue];
if (type == AVAudioSessionInterruptionTypeBegan) {
if (m_game_thread != NULL) {
m_game_thread->Post(kidmDisableSound, NULL);
}
}
if (type == AVAudioSessionInterruptionTypeEnded) {
NSError *error = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive:YES error:&error];
if (success) {
if (m_game_thread != NULL) {
m_game_thread->Post(kidmEnableSound, NULL);
}
} else {
NSLog(@"AVAudioSession setActive error %@", error);
}
}
}
- (void)allocPath:(char **)ppsz baseDir:(const char *)baseDir
subDir:(const char *)subDir
{
@ -171,6 +193,12 @@ IPhoneAppDelegate *g_appDelegate;
strcpy(m_pszUUID, pszUUID);
CFRelease(strUUID);
// Set up a notification to restore sound when interrupted
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(handleAudioInterruption:)
name: AVAudioSessionInterruptionNotification
object: nil];
// Spin off a thread to run the game
m_game_thread = new base::Thread();
m_game_thread->Start(wi::IPhone::GameThreadStart, NULL);

View File

@ -7,25 +7,6 @@
#include "criticalsection.h"
#include "iphone.h"
@interface AudioInterruptionHandler : NSObject
{
}
@end
@implementation AudioInterruptionHandler
- (void)handleInterruption:(NSNotification *)notification
{
UInt8 type = [[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] intValue];
if (type == AVAudioSessionInterruptionTypeEnded) {
NSError *error = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive:YES error:&error];
if (!success) {
NSLog(@"AVAudioSession setActive error %@", error);
}
}
}
@end
namespace wi {
#define kcBuffers 4
@ -91,9 +72,11 @@ IPhoneSoundDevice::IPhoneSoundDevice()
IPhoneSoundDevice::~IPhoneSoundDevice()
{
// This api deletes buffers too
if (m_haq != NULL) {
AudioQueueDispose(m_haq, true);
}
SetSoundServiceDevice(NULL);
}
bool IPhoneSoundDevice::Init()
@ -118,14 +101,6 @@ bool IPhoneSoundDevice::Init()
return false;
}
// Set up callback for turning on audio when an interruption ends
AudioInterruptionHandler *handler = [AudioInterruptionHandler alloc];
[[NSNotificationCenter defaultCenter] addObserver: handler
selector: @selector(handleInterruption:)
name: AVAudioSessionInterruptionNotification
object: session];
[handler release];
success = [session setActive:YES error:nil];
if (!success) {
return false;

View File

@ -122,9 +122,6 @@ bool SoundMgr::IsEnabled()
return false;
}
// Our game conflicts with OS audio on some devices like Clie. We try to detect these cases and turn audio
// completely off
void SoundMgr::RestoreState()
{
if (m_fStateSaved) {