mirror of
https://github.com/love2d/love.git
synced 2026-08-19 20:19:42 +02:00
adds iOS audio interruption handling and recovery
This commit is contained in:
@@ -78,6 +78,12 @@ bool setAudioMixWithOthers(bool mixEnabled);
|
|||||||
**/
|
**/
|
||||||
bool hasBackgroundMusic();
|
bool hasBackgroundMusic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers notifications to handle and restore audio interruptions
|
||||||
|
**/
|
||||||
|
void initAudioSessionInterruptionHandler();
|
||||||
|
void destroyAudioSessionInterruptionHandler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the area in the window that is safe for UI to render to (not covered by
|
* Gets the area in the window that is safe for UI to render to (not covered by
|
||||||
* the status bar, notch, etc.)
|
* the status bar, notch, etc.)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#import <AudioToolbox/AudioServices.h>
|
#import <AudioToolbox/AudioServices.h>
|
||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
|
||||||
|
#include "modules/audio/Audio.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <SDL_events.h>
|
#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 love
|
||||||
{
|
{
|
||||||
namespace ios
|
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)
|
Rect getSafeArea(SDL_Window *window)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
|
|||||||
@@ -291,6 +291,12 @@ public:
|
|||||||
**/
|
**/
|
||||||
static bool setMixWithSystem(bool mix);
|
static bool setMixWithSystem(bool mix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause/resume audio context
|
||||||
|
*/
|
||||||
|
virtual void pauseContext() = 0;
|
||||||
|
virtual void resumeContext() = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static StringMap<DistanceModel, DISTANCE_MAX_ENUM>::Entry distanceModelEntries[];
|
static StringMap<DistanceModel, DISTANCE_MAX_ENUM>::Entry distanceModelEntries[];
|
||||||
|
|||||||
@@ -203,6 +203,15 @@ bool Audio::isEFXsupported() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::pauseContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::resumeContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // null
|
} // null
|
||||||
} // audio
|
} // audio
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ public:
|
|||||||
int getMaxSourceEffects() const;
|
int getMaxSourceEffects() const;
|
||||||
bool isEFXsupported() const;
|
bool isEFXsupported() const;
|
||||||
|
|
||||||
|
void pauseContext();
|
||||||
|
void resumeContext();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float volume;
|
float volume;
|
||||||
DistanceModel distanceModel;
|
DistanceModel distanceModel;
|
||||||
|
|||||||
@@ -26,6 +26,10 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#ifdef LOVE_IOS
|
||||||
|
#include "common/ios.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
@@ -189,10 +193,18 @@ Audio::Audio()
|
|||||||
|
|
||||||
poolThread = new PoolThread(pool);
|
poolThread = new PoolThread(pool);
|
||||||
poolThread->start();
|
poolThread->start();
|
||||||
|
|
||||||
|
#ifdef LOVE_IOS
|
||||||
|
love::ios::initAudioSessionInterruptionHandler();
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio::~Audio()
|
Audio::~Audio()
|
||||||
{
|
{
|
||||||
|
#ifdef LOVE_IOS
|
||||||
|
love::ios::destroyAudioSessionInterruptionHandler();
|
||||||
|
#endif
|
||||||
poolThread->setFinish();
|
poolThread->setFinish();
|
||||||
poolThread->wait();
|
poolThread->wait();
|
||||||
|
|
||||||
@@ -293,6 +305,17 @@ std::vector<love::audio::Source*> Audio::pause()
|
|||||||
return Source::pause(pool);
|
return Source::pause(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::pauseContext()
|
||||||
|
{
|
||||||
|
alcMakeContextCurrent(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::resumeContext()
|
||||||
|
{
|
||||||
|
if (context && alcGetCurrentContext() != context)
|
||||||
|
alcMakeContextCurrent(context);
|
||||||
|
}
|
||||||
|
|
||||||
void Audio::setVolume(float volume)
|
void Audio::setVolume(float volume)
|
||||||
{
|
{
|
||||||
alListenerf(AL_GAIN, volume);
|
alListenerf(AL_GAIN, volume);
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ public:
|
|||||||
void pause(love::audio::Source *source);
|
void pause(love::audio::Source *source);
|
||||||
void pause(const std::vector<love::audio::Source*> &sources);
|
void pause(const std::vector<love::audio::Source*> &sources);
|
||||||
std::vector<love::audio::Source*> pause();
|
std::vector<love::audio::Source*> pause();
|
||||||
|
void pauseContext();
|
||||||
|
void resumeContext();
|
||||||
void setVolume(float volume);
|
void setVolume(float volume);
|
||||||
float getVolume() const;
|
float getVolume() const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user