Handling Audio Interruptions Without Losing Your Place

Spoken reading should survive the small interruptions that happen on a phone. The reader should not make someone start a long document again after a call, Siri request, or another audio app takes focus.

The problem

The first version could play and pause, but it did not own an audio session. An interruption could leave playback paused without a useful state or a reliable place to continue from.

// Before: playback had no interruption state
func play(_ utterance: AVSpeechUtterance) {
    synthesizer.speak(utterance)
}

// A call or Siri request could stop this without a saved resume path.

The change

SpeechService now configures a spoken playbackAVAudioSession and listens for iOS interruption notifications. When an interruption begins, it pauses at a word boundary, keeps the live character offset, and exposes anInterrupted state. It resumes only when iOS sends theshouldResume hint.

// After: pause at a word and resume only when iOS allows it
case .began:
    _ = synthesizer.pauseSpeaking(at: .word)
    isPaused = true
    isInterrupted = true

case .ended where options.contains(.shouldResume):
    activateAudioSession()
    _ = synthesizer.continueSpeaking()
    isInterrupted = false
Read aloudSystem interruptionPause at wordSave offsetResume when allowed

Result

The normal playback controls stay the same. The extra work appears only when the system takes over, which is the right outcome for this kind of reliability work. Background playback also has an explicit audio mode, as long as the app process is still alive.

← Back to all articles