Speech Recognition
Convert live speech and prerecorded audio to text. Targets modern on-device SpeechAnalyzer (iOS 26+) and legacy SFSpeechRecognizer (iOS 10+).
Contents
- Permissions & Audio Session
- Modern SpeechAnalyzer (iOS 26+)
- Legacy SFSpeechRecognizer
- On-Device Model Assets
- Common Mistakes
- Review Checklist
- References
Permissions & Audio Session
Add NSSpeechRecognitionUsageDescription and NSMicrophoneUsageDescription to Info.plist. Request speech and microphone authorization before starting recording:
import Speech
import AVFAudio
func requestPermissions() async -> Bool {
let speechAuthorized = await withCheckedContinuation { continuation in
SFSpeechRecognizer.requestAuthorization { status in
continuation.resume(returning: status == .authorized)
}
}
guard speechAuthorized else { return false }
return await AVAudioApplication.requestRecordPermission()
}
Modern SpeechAnalyzer (iOS 26+)
SpeechAnalyzer delivers modular, asynchronous streaming transcription using SpeechTranscriber:
import Speech
final class LiveTranscriber {
private var analyzer: SpeechAnalyzer?
private var transcriber: SpeechTranscriber?
func startTranscribing(format: AVAudioFormat) async throws {
let transcriber = SpeechTranscriber(locale: Locale(identifier: "en-US"), preset: .transcription)
let analyzer = SpeechAnalyzer(modules: [transcriber])
self.transcriber = transcriber
self.analyzer = analyzer
Task {
for try await result in transcriber.results {
let text = result.text
if result.isFinal {
print("Committed: \(text)")
} else {
print("Partial: \(text)")
}
}
}
try await analyzer.start(inputFormat: format)
}
func appendAudio(buffer: AVAudioPCMBuffer) {
analyzer?.append(buffer)
}
func stop() async throws {
try await analyzer?.finish()
}
}
Legacy SFSpeechRecognizer
For audio file transcription and backward compatibility:
func transcribeFile(url: URL) async throws -> String {
guard let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US")),
recognizer.isAvailable else {
throw SpeechError.unavailable
}
let request = SFSpeechURLRecognitionRequest(url: url)
request.requiresOnDeviceRecognition = true
return try await withCheckedThrowingContinuation { continuation in
recognizer.recognitionTask(with: request) { result, error in
if let error {
continuation.resume(throwing: error)
} else if let result, result.isFinal {
continuation.resume(returning: result.bestTranscription.formattedString)
}
}
}
}
On-Device Model Assets
Check asset installation or download language packs before recognition:
let status = await AssetInventory.status(for: .transcription, locale: Locale(identifier: "en-US"))
if status != .installed {
try await AssetInventory.download(for: .transcription, locale: Locale(identifier: "en-US"))
}
Common Mistakes
- Missing microphone usage description: Omitting
NSMicrophoneUsageDescriptioncrashes immediately when accessingAVAudioEngine. - Conflating partial and final results: Partial results update frequently; only commit text into data models when
result.isFinalis true. - Starting multiple concurrent recognition tasks: Always finish or cancel the previous task before launching a new recognition stream.
- Ignoring on-device fallback failures: If
requiresOnDeviceRecognitionis true, ensure model assets are installed viaAssetInventory. - Not stopping audio engine alongside recognition: Failing to halt
AVAudioEnginekeeps the microphone indicator active in the status bar.
Review Checklist
-
NSSpeechRecognitionUsageDescriptionandNSMicrophoneUsageDescriptionpresent in Info.plist - Speech recognition authorization requested and confirmed authorized
- Audio engine input nodes and tap callbacks cleaned up upon completion
-
SpeechAnalyzer(iOS 26+) used for modern streaming pipelines - Transient partial results visually distinguished from finalized transcripts
References
- SpeechAnalyzer pipelines, volatile results, and audio buffering: references/speechanalyzer-patterns.md
- Speech framework
- SpeechAnalyzer
- SpeechTranscriber
- SpeechTranscriber.Preset
- DictationTranscriber
- SpeechDetector
- SFSpeechRecognizer
- SFSpeechAudioBufferRecognitionRequest
- SFSpeechURLRecognitionRequest
- SFSpeechRecognitionResult
- SFSpeechRecognitionRequest
- AssetInventory
- Asking Permission to Use Speech Recognition
- Recognizing Speech in Live Audio
- Bring advanced speech-to-text to your app with SpeechAnalyzer