aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Weissflog <floooh@gmail.com>2021-02-16 20:29:19 +0100
committerAndre Weissflog <floooh@gmail.com>2021-02-16 20:30:31 +0100
commit83bf2da8fd24be7b6d9b0f3aaa52f901c922de64 (patch)
treee3a938b50ddeffef67fd91bfb1a840456400859e
parent8c2c4a891ea855d7259047eb195f1e041928e8d7 (diff)
sokol_audio.h: fix ARC vs non-ARC on iOS
-rw-r--r--sokol_audio.h64
1 files changed, 36 insertions, 28 deletions
diff --git a/sokol_audio.h b/sokol_audio.h
index f85f3d67..83d27e1d 100644
--- a/sokol_audio.h
+++ b/sokol_audio.h
@@ -41,7 +41,8 @@
- Windows: WASAPI
- Linux: ALSA (link with asound)
- - macOS/iOS: CoreAudio (link with AudioToolbox)
+ - macOS: CoreAudio (link with AudioToolbox)
+ - iOS: CoreAudio+AVAudioSession (link with AudioToolbox and AVFramework)
- emscripten: WebAudio with ScriptProcessorNode
- Android: OpenSLES (link with OpenSLES)
@@ -309,6 +310,7 @@
The CoreAudio backend is selected on macOS and iOS (__APPLE__ is defined).
Since the CoreAudio API is implemented in C (not Objective-C) on macOS the
implementation part of Sokol Audio can be included into a C source file.
+
However on iOS, Sokol Audio must be compiled as Objective-C due to it's
reliance on the AVAudioSession object.
@@ -513,9 +515,14 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
#elif defined(__APPLE__)
#include <TargetConditionals.h>
#include <AudioToolbox/AudioToolbox.h>
-#if TARGET_OS_IOS
- #include <AVFoundation/AVFoundation.h>
-#endif
+ #if TARGET_OS_IOS
+ #if !defined(__cplusplus)
+ #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields)
+ #error "sokol_audio.h on iOS requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)"
+ #endif
+ #endif
+ #include <AVFoundation/AVFoundation.h>
+ #endif
#elif (defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__)
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
@@ -603,9 +610,9 @@ typedef struct {
typedef struct {
AudioQueueRef ca_audio_queue;
-#if TARGET_OS_IOS
- void* ca_interruption_handler;
-#endif
+ #if TARGET_OS_IOS
+ id ca_interruption_handler;
+ #endif
} _saudio_backend_t;
/*=== ALSA BACKEND DECLARATIONS ==============================================*/
@@ -982,31 +989,33 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { };
#elif defined(__APPLE__)
#if TARGET_OS_IOS
-@interface _saudio_interruption_handler:NSObject {
-}
+#if __has_feature(objc_arc)
+#define _SAUDIO_OBJC_RELEASE(obj) { obj = nil; }
+#else
+#define _SAUDIO_OBJC_RELEASE(obj) { [obj release]; obj = nil; }
+#endif
+
+@interface _saudio_interruption_handler : NSObject { }
@end
@implementation _saudio_interruption_handler
--(id)init
-{
+-(id)init {
self = [super init];
AVAudioSession* session = [AVAudioSession sharedInstance];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:session];
return self;
}
--(void)dealloc
-{
+-(void)dealloc {
[self remove_handler];
+ [super dealloc];
}
--(void)remove_handler
-{
+-(void)remove_handler {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVAudioSessionInterruptionNotification" object:nil];
}
--(void)handle_interruption:(NSNotification*)notification
-{
+-(void)handle_interruption:(NSNotification*)notification {
AVAudioSession* session = [AVAudioSession sharedInstance];
SOKOL_ASSERT(session);
NSDictionary* dict = notification.userInfo;
@@ -1050,16 +1059,17 @@ _SOKOL_PRIVATE void _saudio_coreaudio_callback(void* user_data, AudioQueueRef qu
_SOKOL_PRIVATE bool _saudio_backend_init(void) {
SOKOL_ASSERT(0 == _saudio.backend.ca_audio_queue);
-#if TARGET_OS_IOS
+ #if TARGET_OS_IOS
/* activate audio session */
AVAudioSession* session = [AVAudioSession sharedInstance];
- SOKOL_ASSERT(session);
+ SOKOL_ASSERT(session != nil);
[session setCategory: AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
[session setActive:true error:nil];
/* create interruption handler */
- _saudio.backend.ca_interruption_handler = (__bridge_retained void*)[[_saudio_interruption_handler alloc] init];
-#endif
+ _saudio.backend.ca_interruption_handler = [[_saudio_interruption_handler alloc] init];
+ #endif
+
/* create an audio queue with fp32 samples */
AudioStreamBasicDescription fmt;
memset(&fmt, 0, sizeof(fmt));
@@ -1099,19 +1109,17 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
AudioQueueStop(_saudio.backend.ca_audio_queue, true);
AudioQueueDispose(_saudio.backend.ca_audio_queue, false);
_saudio.backend.ca_audio_queue = NULL;
-#if TARGET_OS_IOS
+ #if TARGET_OS_IOS
/* remove interruption handler */
- if (_saudio.backend.ca_interruption_handler != NULL) {
- _saudio_interruption_handler* interruption_handler = (__bridge_transfer _saudio_interruption_handler*)_saudio.backend.ca_interruption_handler;
- [interruption_handler remove_handler];
- _saudio.backend.ca_interruption_handler = NULL;
+ if (_saudio.backend.ca_interruption_handler != nil) {
+ [_saudio.backend.ca_interruption_handler remove_handler];
+ _SAUDIO_OBJC_RELEASE(_saudio.backend.ca_interruption_handler);
}
-
/* deactivate audio session */
AVAudioSession* session = [AVAudioSession sharedInstance];
SOKOL_ASSERT(session);
[session setActive:false error:nil];;
-#endif
+ #endif
}
/*=== ALSA BACKEND IMPLEMENTATION ============================================*/