mirror of https://github.com/encounter/SDL.git
Handle audio interruptions on iOS/tvOS. Fixes bugs 2569 and 2960.
This commit is contained in:
parent
8f8f225b3f
commit
f0fca2880f
|
@ -34,6 +34,7 @@
|
||||||
#include <CoreServices/CoreServices.h>
|
#include <CoreServices/CoreServices.h>
|
||||||
#else
|
#else
|
||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
#import <UIKit/UIApplication.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <AudioToolbox/AudioToolbox.h>
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
|
@ -56,6 +57,9 @@ struct SDL_PrivateAudioData
|
||||||
SDL_atomic_t shutdown;
|
SDL_atomic_t shutdown;
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
AudioDeviceID deviceID;
|
AudioDeviceID deviceID;
|
||||||
|
#else
|
||||||
|
SDL_bool interrupted;
|
||||||
|
CFTypeRef interruption_listener;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -273,10 +273,58 @@ static int open_playback_devices = 0;
|
||||||
static int open_capture_devices = 0;
|
static int open_capture_devices = 0;
|
||||||
|
|
||||||
#if !MACOSX_COREAUDIO
|
#if !MACOSX_COREAUDIO
|
||||||
static BOOL update_audio_session()
|
|
||||||
|
static void interruption_begin(_THIS)
|
||||||
|
{
|
||||||
|
if (this != NULL && this->hidden->audioQueue != NULL) {
|
||||||
|
this->hidden->interrupted = SDL_TRUE;
|
||||||
|
AudioQueuePause(this->hidden->audioQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void interruption_end(_THIS)
|
||||||
|
{
|
||||||
|
if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL
|
||||||
|
&& this->hidden->interrupted) {
|
||||||
|
this->hidden->interrupted = SDL_FALSE;
|
||||||
|
AudioQueueStart(this->hidden->audioQueue, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface SDLInterruptionListener : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, assign) SDL_AudioDevice *device;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SDLInterruptionListener
|
||||||
|
|
||||||
|
- (void)audioSessionInterruption:(NSNotification *)note
|
||||||
|
{
|
||||||
|
@synchronized (self) {
|
||||||
|
NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
|
||||||
|
if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
|
||||||
|
interruption_begin(self.device);
|
||||||
|
} else {
|
||||||
|
interruption_end(self.device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationBecameActive:(NSNotification *)note
|
||||||
|
{
|
||||||
|
@synchronized (self) {
|
||||||
|
interruption_end(self.device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
static BOOL update_audio_session(_THIS, SDL_bool open)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||||
|
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||||
NSString *category;
|
NSString *category;
|
||||||
NSError *err = nil;
|
NSError *err = nil;
|
||||||
|
|
||||||
|
@ -291,6 +339,12 @@ static BOOL update_audio_session()
|
||||||
category = AVAudioSessionCategoryAmbient;
|
category = AVAudioSessionCategoryAmbient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (![session setCategory:category error:&err]) {
|
||||||
|
NSString *desc = err.description;
|
||||||
|
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
if (open_playback_devices + open_capture_devices == 1) {
|
if (open_playback_devices + open_capture_devices == 1) {
|
||||||
if (![session setActive:YES error:&err]) {
|
if (![session setActive:YES error:&err]) {
|
||||||
NSString *desc = err.description;
|
NSString *desc = err.description;
|
||||||
|
@ -301,10 +355,38 @@ static BOOL update_audio_session()
|
||||||
[session setActive:NO error:nil];
|
[session setActive:NO error:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![session setCategory:category error:&err]) {
|
if (open) {
|
||||||
NSString *desc = err.description;
|
SDLInterruptionListener *listener = [SDLInterruptionListener new];
|
||||||
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
|
listener.device = this;
|
||||||
return NO;
|
|
||||||
|
[center addObserver:listener
|
||||||
|
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:listener
|
||||||
|
selector:@selector(applicationBecameActive:)
|
||||||
|
name:UIApplicationDidBecomeActiveNotification
|
||||||
|
object:session];
|
||||||
|
|
||||||
|
[center addObserver:listener
|
||||||
|
selector:@selector(applicationBecameActive:)
|
||||||
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
|
object:session];
|
||||||
|
|
||||||
|
this->hidden->interruption_listener = CFBridgingRetain(listener);
|
||||||
|
} else {
|
||||||
|
if (this->hidden->interruption_listener != NULL) {
|
||||||
|
SDLInterruptionListener *listener = nil;
|
||||||
|
listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
|
||||||
|
@synchronized (listener) {
|
||||||
|
listener.device = NULL;
|
||||||
|
}
|
||||||
|
[center removeObserver:listener];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,6 +523,10 @@ COREAUDIO_CloseDevice(_THIS)
|
||||||
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !MACOSX_COREAUDIO
|
||||||
|
update_audio_session(this, SDL_FALSE);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (this->hidden->thread) {
|
if (this->hidden->thread) {
|
||||||
SDL_AtomicSet(&this->hidden->shutdown, 1);
|
SDL_AtomicSet(&this->hidden->shutdown, 1);
|
||||||
SDL_WaitThread(this->hidden->thread, NULL);
|
SDL_WaitThread(this->hidden->thread, NULL);
|
||||||
|
@ -468,10 +554,6 @@ COREAUDIO_CloseDevice(_THIS)
|
||||||
} else {
|
} else {
|
||||||
open_playback_devices--;
|
open_playback_devices--;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !MACOSX_COREAUDIO
|
|
||||||
update_audio_session();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MACOSX_COREAUDIO
|
#if MACOSX_COREAUDIO
|
||||||
|
@ -649,7 +731,7 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !MACOSX_COREAUDIO
|
#if !MACOSX_COREAUDIO
|
||||||
if (!update_audio_session()) {
|
if (!update_audio_session(this, SDL_TRUE)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue