Skip to content

Commit

Permalink
Merge pull request #10481 from KentuckyCompass/ios-audio-fix
Browse files Browse the repository at this point in the history
iOS: handle audio session interruptions and improve micro-stutter
  • Loading branch information
hrydgard committed Dec 31, 2017
2 parents 8e1ab3f + ca5758f commit e82237b
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 153 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ elseif(IOS)
ios/AppDelegate.h ios/AppDelegate.h
ios/ViewController.mm ios/ViewController.mm
ios/ViewController.h ios/ViewController.h
ios/iOSCoreAudio.cpp ios/iOSCoreAudio.mm
ios/iOSCoreAudio.h ios/iOSCoreAudio.h
ios/PPSSPPUIApplication.h ios/PPSSPPUIApplication.h
ios/PPSSPPUIApplication.mm ios/PPSSPPUIApplication.mm
Expand All @@ -681,7 +681,7 @@ elseif(IOS)
ios/iCade/iCadeReaderView.h ios/iCade/iCadeReaderView.h
ios/iCade/iCadeReaderView.m ios/iCade/iCadeReaderView.m
ios/iCade/iCadeState.h) ios/iCade/iCadeState.h)
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL") set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation")
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework") if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController") set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
endif() endif()
Expand Down
10 changes: 8 additions & 2 deletions Core/System.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ void Audio_Init() {
} }
} }


void Audio_Shutdown() {
if (audioInitialized) {
audioInitialized = false;
host->ShutdownSound();
}
}

bool IsOnSeparateCPUThread() { bool IsOnSeparateCPUThread() {
if (cpuThread != nullptr) { if (cpuThread != nullptr) {
return cpuThreadID == std::this_thread::get_id(); return cpuThreadID == std::this_thread::get_id();
Expand Down Expand Up @@ -290,8 +297,7 @@ void CPU_Shutdown() {
__KernelShutdown(); __KernelShutdown();
HLEShutdown(); HLEShutdown();
if (coreParameter.enableSound) { if (coreParameter.enableSound) {
host->ShutdownSound(); Audio_Shutdown();
audioInitialized = false; // deleted in ShutdownSound
} }
pspFileSystem.Shutdown(); pspFileSystem.Shutdown();
mipsr4k.Shutdown(); mipsr4k.Shutdown();
Expand Down
1 change: 1 addition & 0 deletions Core/System.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ void PSP_RunLoopFor(int cycles);
void Core_UpdateDebugStats(bool collectStats); void Core_UpdateDebugStats(bool collectStats);


void Audio_Init(); void Audio_Init();
void Audio_Shutdown();


bool IsOnSeparateCPUThread(); bool IsOnSeparateCPUThread();
bool IsAudioInitialised(); bool IsAudioInitialised();
Expand Down
89 changes: 88 additions & 1 deletion ios/AppDelegate.mm
Original file line number Original file line Diff line number Diff line change
@@ -1,21 +1,108 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "ViewController.h" #import "ViewController.h"
#import "base/NativeApp.h" #import "base/NativeApp.h"
#import "Core/System.h"
#import "Core/Config.h"
#import "Common/Log.h"

#import <AVFoundation/AVFoundation.h>


@implementation AppDelegate @implementation AppDelegate

// This will be called when the user receives and dismisses a phone call
// or other interruption to the audio session
// Registered in application:didFinishLaunchingWithOptions:
// for AVAudioSessionInterruptionNotification
-(void) handleAudioSessionInterruption:(NSNotification *)notification {
NSNumber *interruptionType = notification.userInfo[AVAudioSessionInterruptionTypeKey];

// Sanity check in case it's somehow not an NSNumber
if (![interruptionType respondsToSelector:@selector(unsignedIntegerValue)]) {
return; // Lets not crash
}

switch ([interruptionType unsignedIntegerValue]) {
case AVAudioSessionInterruptionTypeBegan:
INFO_LOG(SYSTEM, "ios audio session interruption beginning");
if (g_Config.bEnableSound) {
Audio_Shutdown();
}
break;

case AVAudioSessionInterruptionTypeEnded:
INFO_LOG(SYSTEM, "ios audio session interruption ending");
if (g_Config.bEnableSound) {
/*
* Only try to reinit audio if in the foreground, otherwise
* it may fail. Instead, trust that applicationDidBecomeActive
* will do it later.
*/
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
Audio_Init();
}
}
break;

default:
break;
};
}

// This will be called when the iOS's shared media process was reset
// Registered in application:didFinishLaunchingWithOptions:
// for AVAudioSessionMediaServicesWereResetNotification
-(void) handleMediaServicesWereReset:(NSNotification *)notification {
INFO_LOG(SYSTEM, "ios media services were reset - reinitializing audio");

/*
When media services were reset, Apple recommends:
1) Dispose of orphaned audio objects (such as players, recorders,
converters, or audio queues) and create new ones
2) Reset any internal audio states being tracked, including all
properties of AVAudioSession
3) When appropriate, reactivate the AVAudioSession instance using the
setActive:error: method
We accomplish this by shutting down and reinitializing audio
*/

if (g_Config.bEnableSound) {
Audio_Shutdown();
Audio_Init();
}
}

-(BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -(BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] init]; self.viewController = [[ViewController alloc] init];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMediaServicesWereReset:) name:AVAudioSessionMediaServicesWereResetNotification object:nil];

self.window.rootViewController = self.viewController; self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible]; [self.window makeKeyAndVisible];

return YES; return YES;
} }


-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

-(void) applicationWillResignActive:(UIApplication *)application { -(void) applicationWillResignActive:(UIApplication *)application {
if (g_Config.bEnableSound) {
Audio_Shutdown();
}

NativeMessageReceived("lost_focus", ""); NativeMessageReceived("lost_focus", "");
} }


-(void) applicationDidBecomeActive:(UIApplication *)application { -(void) applicationDidBecomeActive:(UIApplication *)application {
if (g_Config.bEnableSound) {
Audio_Init();
}

NativeMessageReceived("got_focus", ""); NativeMessageReceived("got_focus", "");
} }
@end
@end
148 changes: 0 additions & 148 deletions ios/iOSCoreAudio.cpp

This file was deleted.

Loading

0 comments on commit e82237b

Please sign in to comment.