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.
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 recordingUIBackgroundModes: an array containingaudio
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 }
}
}