iOS: Leave PlayAndRecord when a game stops recording

The session category was switched before the audio unit's input was
turned off, and iOS refuses ('!pri') to leave PlayAndRecord while the
input runs. So after a game used the microphone, the session stayed in
PlayAndRecord, ignoring the silent mode setting. Switch it while the
unit is stopped instead.

Also log the two setCategory failures separately, and the route's input.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-22 12:31:43 +02:00
1 parent f993f3b9b2
commit b8c9e82fe6
1 file changed
+12 -3
+12 -3
View File
@@ -65,7 +65,10 @@ void iOSCoreAudioUpdateSession() {
#else
// Hacky hack to force iOS to re-evaluate.
// Switching from CatogoryPlayback to CategoryPlayback with an option otherwise does nothing.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAudioProcessing error:&error];
NSError *hackError = nil;
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAudioProcessing error:&hackError]) {
NSLog(@"Switching to AudioProcessing failed: %@", hackError);
}
// Here, we apply the settings.
if (g_micEnabled) {
@@ -94,7 +97,7 @@ void iOSCoreAudioUpdateSession() {
#endif
if (error) {
NSLog(@"%@", error);
NSLog(@"Setting the audio session category failed: %@", error);
}
}
@@ -103,6 +106,9 @@ void iOSCoreAudioLogRoute(const char *reason) {
for (AVAudioSessionPortDescription *port in session.currentRoute.outputs) {
NSLog(@"Audio route (%s): %@ '%@' (category %@, options %d)", reason, port.portType, port.portName, session.category, (int)session.categoryOptions);
}
for (AVAudioSessionPortDescription *port in session.currentRoute.inputs) {
NSLog(@"Audio input (%s): %@ '%@'", reason, port.portType, port.portName);
}
}
void NativeMix(short *audio, int numSamples, int sampleRateHz, void *userdata);
@@ -317,14 +323,15 @@ void iOSCoreAudioShutdown()
// Brings the unit in line with g_micEnabled. Main thread.
static void UpdateMicrophone() {
iOSCoreAudioUpdateSession();
if (!audioInstance) {
// Sets up the session too.
iOSCoreAudioInit();
return;
}
if (!g_Config.bEnableSound && !g_micEnabled) {
// The unit was only running for the microphone.
iOSCoreAudioShutdown();
iOSCoreAudioUpdateSession();
return;
}
if (g_micEnabled == g_micInputOn && (!g_micEnabled || g_micSampleRate == g_micInputRate)) {
@@ -333,6 +340,8 @@ static void UpdateMicrophone() {
AudioOutputUnitStop(audioInstance);
AudioUnitUninitialize(audioInstance);
// Only with the unit stopped: iOS refuses (with '!pri') to leave PlayAndRecord while the input runs.
iOSCoreAudioUpdateSession();
ConfigureInput(audioInstance, g_micEnabled);
OSStatus err = AudioUnitInitialize(audioInstance);
if (err == noErr) {