AVAudioRecorder loses earlier audio after Siri with iOS 27 lifecycle notifications

I’m migrating to the new notifications described in Handling audio interruptions.

On an iPhone 14 running iOS 27.0.1 (24A446), I call pause() when the system deactivates the session. On .shouldResume, I await successful session.activate() and call record() on the same recorder. It returns true, but the saved file contains only the audio recorded after Siri.

To reproduce: record for five seconds, invoke and dismiss Siri, record for another five seconds, then stop and play. The earlier five seconds are missing. A legacy-notification control preserved both portions on the same phone.

Is another step required to preserve the recording with the new notifications, or is this a known issue? I found this similar report, although it uses the legacy API.

Minimal reproduction

Built with Xcode 27.1. Create a SwiftUI iOS app targeting iOS 27, replace its generated App.swift with the code below, and add these Info.plist entries:

  • NSMicrophoneUsageDescription: Test audio recording
  • UIBackgroundModes: an array containing audio
import SwiftUI
import AVFoundation

@main
struct RecorderReproApp: App {
    var body: some Scene { WindowGroup { RecorderReproView() } }
}

@MainActor
struct RecorderReproView: View {
    private let session = AVAudioSession.sharedInstance()
    private let file = URL.documentsDirectory.appendingPathComponent("recording.m4a")
    @State private var recorder: AVAudioRecorder?
    @State private var player: AVAudioPlayer?
    @State private var running = false
    @State private var interrupted = false
    @State private var status = "Ready"

    var body: some View {
        VStack(spacing: 24) {
            Button("Start") { Task { await start() } }.disabled(running)
            Button("Stop") {
                running = false
                interrupted = false
                recorder?.stop()
                status = file.path
            }.disabled(!running)
            Button("Play") {
                do {
                    player = try AVAudioPlayer(contentsOf: file)
                    status = "Saved duration: \(player!.duration) seconds"
                    player?.play()
                } catch { status = error.localizedDescription }
            }.disabled(running)
            Text(status)
        }
        .padding()
        .task {
            for await notification in NotificationCenter.default.notifications(
                named: AVAudioSession.didBecomeInactiveNotification, object: session
            ) {
                guard running,
                      let context = notification.userInfo?[AVAudioSession.deactivationContextKey]
                        as? AVAudioSession.DeactivationContext,
                      context.source == .system else { continue }
                recorder?.pause()
                interrupted = true
                status = "Interrupted"
            }
        }
        .task {
            for await notification in NotificationCenter.default.notifications(
                named: AVAudioSession.resumptionRecommendationNotification, object: session
            ) {
                guard running, interrupted,
                      let context = notification.userInfo?[AVAudioSession.resumptionContextKey]
                        as? AVAudioSession.ResumptionContext else { continue }
                guard context.recommendation == .shouldResume else {
                    interrupted = false
                    continue
                }
                do {
                    guard try await session.activate(), running, interrupted else { continue }
                    status = "Resumed: \(recorder!.record())"
                    interrupted = false
                } catch { status = error.localizedDescription }
            }
        }
    }

    private func start() async {
        guard await AVAudioApplication.requestRecordPermission() else { return }
        do {
            try session.setCategory(.playAndRecord)
            guard try await session.activate() else { return }
            recorder = try AVAudioRecorder(url: file, settings: [
                AVFormatIDKey: kAudioFormatMPEG4AAC_HE,
                AVSampleRateKey: 44_100,
                AVEncoderBitRateKey: 32_000,
                AVNumberOfChannelsKey: 2
            ])
            running = recorder!.record()
            status = "Recording: \(running)"
        } catch { status = error.localizedDescription }
    }
}