adds iOS audio interruption handling and recovery

This commit is contained in:
cigumo
2020-12-08 23:13:52 -03:00
parent 0b06d0d1f9
commit 74edaf8fba
7 changed files with 130 additions and 0 deletions
+81
View File
@@ -28,6 +28,8 @@
#import <AudioToolbox/AudioServices.h>
#import <AVFoundation/AVFoundation.h>
#include "modules/audio/Audio.h"
#include <vector>
#include <SDL_events.h>
@@ -200,6 +202,53 @@ static int dropFileEventFilter(void *userdata, SDL_Event *event)
}
}
@interface LoveAudioInterruptionListener : NSObject
@end
@implementation LoveAudioInterruptionListener
+ (id) shared
{
// thread-safe singleton
static dispatch_once_t pred = 0;
__strong static id _shared = nil;
dispatch_once(&pred, ^{
_shared = [[self alloc] init];
});
return _shared;
}
- (void)audioSessionInterruption:(NSNotification *)note
{
@synchronized (self) {
auto audio = love::Module::getInstance<love::audio::Audio>(love::Module::M_AUDIO);
if (!audio) {
NSLog(@"LoveAudioInterruptionListener could not get love audio module");
return;
}
NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
audio->pauseContext();
} else {
audio->resumeContext();
}
}
}
- (void)applicationBecameActive:(NSNotification *)note
{
@synchronized (self) {
auto audio = love::Module::getInstance<love::audio::Audio>(love::Module::M_AUDIO);
if (!audio) {
NSLog(@"ERROR:could not get love audio module");
return;
}
audio->resumeContext();
}
}
@end
namespace love
{
namespace ios
@@ -376,6 +425,38 @@ bool hasBackgroundMusic()
}
}
void initAudioSessionInterruptionHandler()
{
@autoreleasepool
{
AVAudioSession *session = [AVAudioSession sharedInstance];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:[LoveAudioInterruptionListener shared]
selector:@selector(audioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:session];
// An interruption end notification is not guaranteed to be sent if
// we were previously interrupted... resuming if needed when the app
// becomes active seems to be the way to go.
[center addObserver:[LoveAudioInterruptionListener shared]
selector:@selector(applicationBecameActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[center addObserver:[LoveAudioInterruptionListener shared]
selector:@selector(applicationBecameActive:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
}
void destroyAudioSessionInterruptionHandler()
{
[[NSNotificationCenter defaultCenter] removeObserver:[LoveAudioInterruptionListener shared]];
}
Rect getSafeArea(SDL_Window *window)
{
@autoreleasepool