Commit ff53521bc6776350aa286bd58f5a1b4e6ce8433d

Sam Lantinga 2020-06-04T12:26:57

Fixed Bluetooth audio output on Apple TV

diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m
index b8d786d..83250a4 100644
--- a/src/audio/coreaudio/SDL_coreaudio.m
+++ b/src/audio/coreaudio/SDL_coreaudio.m
@@ -291,34 +291,34 @@ static BOOL session_active = NO;
 
 static void pause_audio_devices()
 {
-	int i;
-
-	if (!open_devices) {
-		return;
-	}
-
-	for (i = 0; i < num_open_devices; ++i) {
-		SDL_AudioDevice *device = open_devices[i];
-		if (device->hidden->audioQueue && !device->hidden->interrupted) {
-			AudioQueuePause(device->hidden->audioQueue);
-		}
-	}
+    int i;
+
+    if (!open_devices) {
+        return;
+    }
+
+    for (i = 0; i < num_open_devices; ++i) {
+        SDL_AudioDevice *device = open_devices[i];
+        if (device->hidden->audioQueue && !device->hidden->interrupted) {
+            AudioQueuePause(device->hidden->audioQueue);
+        }
+    }
 }
 
 static void resume_audio_devices()
 {
-	int i;
-
-	if (!open_devices) {
-		return;
-	}
-
-	for (i = 0; i < num_open_devices; ++i) {
-		SDL_AudioDevice *device = open_devices[i];
-		if (device->hidden->audioQueue && !device->hidden->interrupted) {
-			AudioQueueStart(device->hidden->audioQueue, NULL);
-		}
-	}
+    int i;
+
+    if (!open_devices) {
+        return;
+    }
+
+    for (i = 0; i < num_open_devices; ++i) {
+        SDL_AudioDevice *device = open_devices[i];
+        if (device->hidden->audioQueue && !device->hidden->interrupted) {
+            AudioQueueStart(device->hidden->audioQueue, NULL);
+        }
+    }
 }
 
 static void interruption_begin(_THIS)
@@ -406,26 +406,29 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
         if (category == AVAudioSessionCategoryPlayAndRecord) {
             options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
         }
+#endif
         if (category == AVAudioSessionCategoryRecord ||
             category == AVAudioSessionCategoryPlayAndRecord) {
-            options |= AVAudioSessionCategoryOptionAllowBluetooth;
+            /* AVAudioSessionCategoryOptionAllowBluetooth isn't available in the SDK for
+               Apple TV but is still needed in order to output to Bluetooth devices.
+             */
+            options |= 0x4; /* AVAudioSessionCategoryOptionAllowBluetooth; */
         }
-#endif
         if (category == AVAudioSessionCategoryPlayAndRecord) {
             options |= AVAudioSessionCategoryOptionAllowBluetoothA2DP |
                        AVAudioSessionCategoryOptionAllowAirPlay;
         }
-		if (category == AVAudioSessionCategoryPlayback ||
-			category == AVAudioSessionCategoryPlayAndRecord) {
-			options |= AVAudioSessionCategoryOptionDuckOthers;
-		}
+        if (category == AVAudioSessionCategoryPlayback ||
+            category == AVAudioSessionCategoryPlayAndRecord) {
+            options |= AVAudioSessionCategoryOptionDuckOthers;
+        }
 
         if ([session respondsToSelector:@selector(setCategory:mode:options:error:)]) {
             if (![session.category isEqualToString:category] || session.categoryOptions != options) {
-				/* Stop the current session so we don't interrupt other application audio */
-				pause_audio_devices();
-				[session setActive:NO error:nil];
-				session_active = NO;
+                /* Stop the current session so we don't interrupt other application audio */
+                pause_audio_devices();
+                [session setActive:NO error:nil];
+                session_active = NO;
 
                 if (![session setCategory:category mode:mode options:options error:&err]) {
                     NSString *desc = err.description;
@@ -435,10 +438,10 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
             }
         } else {
             if (![session.category isEqualToString:category]) {
-				/* Stop the current session so we don't interrupt other application audio */
-				pause_audio_devices();
-				[session setActive:NO error:nil];
-				session_active = NO;
+                /* Stop the current session so we don't interrupt other application audio */
+                pause_audio_devices();
+                [session setActive:NO error:nil];
+                session_active = NO;
 
                 if (![session setCategory:category error:&err]) {
                     NSString *desc = err.description;
@@ -459,12 +462,12 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
                 SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String);
                 return NO;
             }
-			session_active = YES;
-			resume_audio_devices();
+            session_active = YES;
+            resume_audio_devices();
         } else if (!open_playback_devices && !open_capture_devices && session_active) {
-			pause_audio_devices();
+            pause_audio_devices();
             [session setActive:NO error:nil];
-			session_active = NO;
+            session_active = NO;
         }
 
         if (open) {
@@ -492,12 +495,12 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
 
             this->hidden->interruption_listener = CFBridgingRetain(listener);
         } else {
-			SDLInterruptionListener *listener = nil;
-			listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
-			[center removeObserver:listener];
-			@synchronized (listener) {
-				listener.device = NULL;
-			}
+            SDLInterruptionListener *listener = nil;
+            listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
+            [center removeObserver:listener];
+            @synchronized (listener) {
+                listener.device = NULL;
+            }
         }
     }
 
@@ -671,7 +674,7 @@ static void
 COREAUDIO_CloseDevice(_THIS)
 {
     const SDL_bool iscapture = this->iscapture;
-	int i;
+    int i;
 
 /* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
 /* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
@@ -691,19 +694,19 @@ COREAUDIO_CloseDevice(_THIS)
     update_audio_session(this, SDL_FALSE, SDL_TRUE);
 #endif
 
-	for (i = 0; i < num_open_devices; ++i) {
-		if (open_devices[i] == this) {
-			--num_open_devices;
-			if (i < num_open_devices) {
-				SDL_memmove(&open_devices[i], &open_devices[i+1], sizeof(open_devices[i])*(num_open_devices - i));
-			}
-			break;
-		}
-	}
-	if (num_open_devices == 0) {
-		SDL_free(open_devices);
-		open_devices = NULL;
-	}
+    for (i = 0; i < num_open_devices; ++i) {
+        if (open_devices[i] == this) {
+            --num_open_devices;
+            if (i < num_open_devices) {
+                SDL_memmove(&open_devices[i], &open_devices[i+1], sizeof(open_devices[i])*(num_open_devices - i));
+            }
+            break;
+        }
+    }
+    if (num_open_devices == 0) {
+        SDL_free(open_devices);
+        open_devices = NULL;
+    }
 
     /* if callback fires again, feed silence; don't call into the app. */
     SDL_AtomicSet(&this->paused, 1);
@@ -1009,7 +1012,7 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
     AudioStreamBasicDescription *strdesc;
     SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
     int valid_datatype = 0;
-	SDL_AudioDevice **new_open_devices;
+    SDL_AudioDevice **new_open_devices;
 
     /* Initialize all variables that we clean on shutdown */
     this->hidden = (struct SDL_PrivateAudioData *)
@@ -1027,11 +1030,11 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
         open_playback_devices++;
     }
 
-	new_open_devices = (SDL_AudioDevice **)SDL_realloc(open_devices, sizeof(open_devices[0]) * (num_open_devices + 1));
-	if (new_open_devices) {
-		open_devices = new_open_devices;
-		open_devices[num_open_devices++] = this;
-	}
+    new_open_devices = (SDL_AudioDevice **)SDL_realloc(open_devices, sizeof(open_devices[0]) * (num_open_devices + 1));
+    if (new_open_devices) {
+        open_devices = new_open_devices;
+        open_devices[num_open_devices++] = this;
+    }
 
 #if !MACOSX_COREAUDIO
     if (!update_audio_session(this, SDL_TRUE, SDL_TRUE)) {