mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-28 11:57:24 +08:00
coreaudio: Always init/deinit session listener on iOS.
Previously, if UpdateAudioSession() failed on close--which it might if something strange has happened with the system's audio configuration--the listener wouldn't be deregistered, and would risk touching a free'd pointer if the app moved to or from the background afterwards, firing an event handler that should have been deregistered. Closes #15439.
This commit is contained in:
@@ -502,39 +502,6 @@ static bool UpdateAudioSession(SDL_AudioDevice *device, bool open, bool allow_pl
|
|||||||
[session setActive:NO error:nil];
|
[session setActive:NO error:nil];
|
||||||
session_active = false;
|
session_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (open) {
|
|
||||||
SDLInterruptionListener *listener = [SDLInterruptionListener new];
|
|
||||||
listener.device = device;
|
|
||||||
|
|
||||||
[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. */
|
|
||||||
// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications.
|
|
||||||
[center addObserver:listener
|
|
||||||
selector:@selector(applicationBecameActive:)
|
|
||||||
name:UIApplicationDidBecomeActiveNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
[center addObserver:listener
|
|
||||||
selector:@selector(applicationBecameActive:)
|
|
||||||
name:UIApplicationWillEnterForegroundNotification
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
device->hidden->interruption_listener = CFBridgingRetain(listener);
|
|
||||||
} else {
|
|
||||||
SDLInterruptionListener *listener = nil;
|
|
||||||
listener = (SDLInterruptionListener *)CFBridgingRelease(device->hidden->interruption_listener);
|
|
||||||
[center removeObserver:listener];
|
|
||||||
@synchronized(listener) {
|
|
||||||
listener.device = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -627,6 +594,17 @@ static void COREAUDIO_CloseDevice(SDL_AudioDevice *device)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MACOSX_COREAUDIO
|
||||||
|
if (device->hidden->interruption_listener) {
|
||||||
|
SDLInterruptionListener *listener = (SDLInterruptionListener *)CFBridgingRelease(device->hidden->interruption_listener);
|
||||||
|
device->hidden->interruption_listener = nil;
|
||||||
|
[center removeObserver:listener];
|
||||||
|
@synchronized(listener) {
|
||||||
|
listener.device = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// dispose of the audio queue before waiting on the thread, or it might stall for a long time!
|
// dispose of the audio queue before waiting on the thread, or it might stall for a long time!
|
||||||
if (device->hidden->audioQueue) {
|
if (device->hidden->audioQueue) {
|
||||||
AudioQueueFlush(device->hidden->audioQueue);
|
AudioQueueFlush(device->hidden->audioQueue);
|
||||||
@@ -998,6 +976,32 @@ static bool COREAUDIO_OpenDevice(SDL_AudioDevice *device)
|
|||||||
return SDL_SetError("%s", device->hidden->thread_error);
|
return SDL_SetError("%s", device->hidden->thread_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MACOSX_COREAUDIO
|
||||||
|
SDLInterruptionListener *listener = [SDLInterruptionListener new];
|
||||||
|
listener.device = device;
|
||||||
|
|
||||||
|
[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. */
|
||||||
|
// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications.
|
||||||
|
[center addObserver:listener
|
||||||
|
selector:@selector(applicationBecameActive:)
|
||||||
|
name:UIApplicationDidBecomeActiveNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
[center addObserver:listener
|
||||||
|
selector:@selector(applicationBecameActive:)
|
||||||
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
device->hidden->interruption_listener = CFBridgingRetain(listener);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (device->hidden->thread != NULL);
|
return (device->hidden->thread != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user