SFSpeechRecognizer는 iOS 생태계에서 Apple의 기본 음성 인식 API입니다. 이 프레임워크는 Speech.framework를 통해 기기의 ASR 엔진에 대한 액세스를 제공하며, 실시간 스트리밍 전사 및 일회성 오디오 파일 인식을 지원합니다. SFSpeechRecognizer는 iOS 10+, macOS 10.15+, watchOS 6+ 및 tvOS 17+에서 사용할 수 있습니다. iOS 17에서 Apple은 인터넷 연결 없이 음성 인식을 가능하게 하는 완전한 온디바이스 모드를 추가했습니다. Apple Speech Documentation, 2025에 따르면, SFSpeechRecognizer는 200,000개 이상의 App Store 애플리케이션에서 사용되며 영어에서 7%의 WER로 하루에 수백만 건의 요청을 처리합니다.
핵심 사항
SFSpeechRecognizer는 특정 언어에 대한 음성 인식기를 나타내는 Speech.framework의 클래스입니다. Locale(ru_RU, en_US, zh_CN)로 초기화됩니다. SFSpeechRecognizer는 인식 요청(SFSpeechRecognitionRequest)을 관리하고 전사 및 메타데이터가 포함된 결과(SFSpeechRecognitionResult)를 반환합니다. 두 가지 유형의 요청을 지원합니다: SFSpeechAudioBufferRecognitionRequest(라이브 오디오 스트림) 및 SFSpeechURLRecognitionRequest(오디오 파일). 둘 다 SFTranscription을 반환합니다 — 대체 인식 가설의 배열입니다.
SFSpeechRecognitionResult에는 다음이 포함됩니다: bestTranscription(최상의 가설, SFTranscription), transcriptions(모든 대안), isFinal(최종/중간). SFTranscription에는 다음이 포함됩니다: formattedString(텍스트), segments(타임스탬프, 신뢰도, substringRange, alternativeSubstrings가 있는 SFTranscriptionSegment 배열). 각 세그먼트의 신뢰도(0..1) — 신뢰할 수 없는 부분을 필터링할 수 있습니다. Segments는 Speech.framework의 핵심 기능입니다: 신뢰도 점수와 함께 단어별 마크업을 제공합니다.
SFSpeechRecognizer 아키텍처: AVFoundation(오디오 캡처) → Audio Buffer → SFSpeechAudioBufferRecognitionRequest → SFSpeechRecognizer(ASR 엔진) → SFSpeechRecognitionResult → SFSpeechRecognitionTask(제어: cancel, finish, pause). Apple의 ASR 엔진은 하이브리드 아키텍처를 사용합니다: 온디바이스용 Conformer(인코더) + RNNT(디코더), 클라우드용 Transducer. 모델은 Apple Neural Engine(ANE)에 최적화되어 있습니다. A17 Pro에서 온디바이스 ASR은 RTF 0.3–0.6(실시간보다 빠름)으로 실행됩니다.
| 구성 요소 | 목적 | iOS 버전 |
|---|---|---|
| SFSpeechRecognizer | 기본 인식 클래스 | iOS 10+ |
| SFSpeechAudioBufferRecognitionRequest | 라이브 오디오 스트림 | iOS 10+ |
| SFSpeechURLRecognitionRequest | 오디오 파일(.wav, .m4a) | iOS 10+ |
| SFSpeechRecognitionTask | 요청 관리(cancel, finish) | iOS 10+ |
| 온디바이스 인식 | 오프라인 ASR | iOS 17+ |
| 결합 인식 | 하이브리드 온디바이스 + 클라우드 | iOS 17+ |
오디오 요구 사항: SFSpeechRecognizer는 LPCM(16kHz, 16bit, 모노) 또는 Opus(iOS 17+)를 허용합니다. AVFoundation은 모든 형식의 버퍼를 캡처할 수 있으며 요청이 자동으로 변환합니다. 최소 길이: 0.5초(무음 감지). 최대: 요청당 1분(클라우드) / 2분(온디바이스). 긴 전사의 경우 2–5초 오버랩으로 30–60초 청크로 오디오를 분할합니다.
사용자 권한: SFSpeechRecognizer에는 두 가지 명시적 권한이 필요합니다. NSMicrophoneUsageDescription(Privacy — Microphone Usage Description) — 마이크 액세스용. NSSpeechRecognitionUsageDescription(Privacy — Speech Recognition Usage Description) — 음성 인식 액세스용. 둘 다 사용자에게 이유를 설명하는 문자열입니다. SFSpeechRecognizer.requestAuthorization — 권한 대화상자를 표시합니다. 상태: notDetermined, denied, restricted, authorized. authorized 상태가 없으면 recognizer를 호출하면 오류 216(Speech framework error)이 반환됩니다.
가용성 확인: SFSpeechRecognizer.isAvailable — 현재 언어에 ASR을 사용할 수 있는지 확인합니다. iOS 16-에서는 isAvailable = false(인터넷 없음). iOS 17+에서는 온디바이스 언어의 경우 오프라인에서도 isAvailable = true. SFSpeechRecognizer.supportedLocales — 기기에서 지원하는 언어 목록을 가져오는 정적 메서드. 시작할 때마다 isAvailable을 확인하는 것이 좋습니다(사용자가 설정에서 Siri/받아쓰기를 비활성화할 수 있음). 가용성은 지역에 따라 다릅니다: 중국어 — 중국에서만, 아랍어 — UAE.
// SFSpeechRecognizer 설정
import Speech
SFSpeechRecognizer.requestAuthorization { status in
guard status == .authorized else { return }
}
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "ru_RU"))!
guard recognizer.isAvailable else {
print("ASR을 사용할 수 없습니다. 설정에서 Siri와 받아쓰기를 활성화하세요")
return
}
let request = SFSpeechAudioBufferRecognitionRequest()
request.requiresOnDeviceRecognition = true
오류 처리: SFSpeechRecognizer는 Error를 반환할 수 있는 completion handler와 함께 호출됩니다. 주요 오류: 203 — 인터넷 없음(클라우드, iOS 16-); 216 — 권한 없음(권한 없음); 301 — 오디오 오류(마이크/형식 문제); 401 — 서비스를 사용할 수 없음(서비스 과부하); 601 — 언어를 사용할 수 없음(기기에서 언어가 지원되지 않음). 온디바이스 iOS 17+의 주요 오류: 301(오디오), 601(언어). 항상 completion handler를 처리하세요 — 녹음 중 언제든지 오류가 발생할 수 있습니다.
라이브 ASR 파이프라인: AVAudioEngine(마이크 캡처) → installTap(오디오 버퍼) → request.append(buffer) → SFSpeechRecognizer → recognitionTask → delegate/resultHandler. AVAudioEngine은 낮은 지연 시간(마이크에서 버퍼까지 5–10ms)을 제공합니다. SFSpeechRecognitionDelegate: didHypothesizeTranscription(200–500ms마다 — 부분 텍스트), didFinishRecognition(최종 결과). Task.isFinishing — 인식이 완료되면 취소할 수 있습니다. 연속 인식(무한 받아쓰기)의 경우 isFinal 후에 새 작업을 만듭니다.
SFSpeechRecognitionTaskDelegate: 선택적 메서드. speechRecognitionDidDetectSpeech(음성 시작) — UI 표시용. didHypothesizeTranscription(중간 텍스트) — 말하는 동안 표시용. didFinishRecognition(최종 결과) — 텍스트 확정용. didFinishSuccessfully(성공/오류) — 완료용. didProcessAudio(오디오 버퍼 처리됨) — RMS 미터용. didHypothesizeTranscription을 구현하는 것이 좋습니다 — 사용자는 지연 없이 즉시 텍스트를 볼 수 있습니다. 최종 전사는 저장용입니다.
// 라이브 음성 인식
let audioEngine = AVAudioEngine()
let request = SFSpeechAudioBufferRecognitionRequest()
request.shouldReportPartialResults = true
recognitionTask = recognizer.recognitionTask(with: request) { result, error in
if let result = result {
textView.text = result.bestTranscription.formattedString
}
if error != nil || result?.isFinal == true {
audioEngine.stop()
request.endAudio()
}
}
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024,
format: recordingFormat) { buffer, _ in
request.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
연속 인식: “항상 듣기” 모드(음성 입력, 어시스턴트)의 경우 isFinal 후에 작업을 다시 시작해야 합니다. 루프 만들기: finishTask → request = SFSpeechAudioBufferRecognitionRequest() → recognitionTask = recognizer.recognitionTask(with: request). 간격을 피하려면 한 작업의 끝을 다음 시작과 겹치게 합니다(이전 작업이 끝나기 1–2초 전에 새 요청 시작). AVFoundation AVAudioSession — 동시 재생 및 녹음을 위해 .playAndRecord를 구성합니다. iOS 17+에서 온디바이스 연속 ASR은 시간당 2–5%의 배터리를 소비합니다(A15+).
SFSpeechURLRecognitionRequest — URL로 오디오 파일을 인식하기 위한 요청입니다. 지원 형식: .wav(16kHz, 16bit, 모노), .m4a(AAC), .mp4, .mov. 최대 길이: 클라우드 약 1분, 온디바이스 약 2분. 더 긴 파일의 경우 청크로 분할합니다(AVAssetExportSession + trim). SFSpeechURLRecognitionRequest는 스트리밍을 지원하지 않습니다(부분 결과 없음) — 최종 결과만. 파일로 부분 결과를 얻으려면 Audio Buffer Request로 변환합니다.
오디오 파일 전사 가져오기: SFSpeechRecognizer.recognitionTask(with: request) resultHandler. bestTranscription.formattedString을 추출합니다. 단어 수준 타임스탬프 — bestTranscription.segments의 segments(segment.duration, segment.timestamp, segment.substring). 세그먼트별 신뢰도 — 각 단어의 ASR 신뢰도(필터링에 사용). 대체 가설 — 신뢰도가 낮은 단어의 transcriptionFormatter 대안. 여러 화자가 있는 파일의 경우 SFSpeechRecognitionRequest는 여러 요청을 반환할 수 있습니다(화자당 하나, iOS 17+).
// 오디오 파일 전사
let audioURL = Bundle.main.url(forResource: "recording", withExtension: "m4a")!
let request = SFSpeechURLRecognitionRequest(url: audioURL)
request.requiresOnDeviceRecognition = true
recognizer.recognitionTask(with: request) { result, error in
guard let result = result, error == nil else {
print("오류: \(error?.localizedDescription ?? "unknown")")
return
}
let transcription = result.bestTranscription
let text = transcription.formattedString
let words = transcription.segments.map { segment in
Word(text: segment.substring,
start: segment.timestamp,
duration: segment.duration,
confidence: segment.confidence)
}
}
긴 오디오 파일 분할: 1분 이상 파일의 경우 2–3초 오버랩(스티칭)으로 30–60초 청크로 분할합니다. AVAssetExportSession + CMTimeRange — 청크 내보내기. 대안: UISelectionView(사용자가 세그먼트 선택). 전사 스티칭: 텍스트 연결, 오버랩으로 스티칭(이전 청크의 마지막 2–3단어를 다음 청크의 처음 2–3단어와 비교 — 중복 제거). Vosk와 Whisper는 긴 오디오를 기본적으로 지원하지만 SFSpeechRecognizer는 지원하지 않습니다. 긴 전사의 경우 Whisper(Core ML)를 권장합니다 — 길이 제한이 없습니다.
온디바이스 모드(iOS 17+): request.requiresOnDeviceRecognition = true. ASR이 Apple Neural Engine(ANE)에서 로컬로 실행됩니다. 장점: 인터넷 불필요, 개인정보 보호(오디오가 기기를 떠나지 않음), 무료, 낮은 지연 시간(RTF 0.3–0.6). 단점: 낮은 정확도(WER 12–14% vs 7–12%), 요청당 2분 제한, 제한된 언어 세트(60개 언어 모두 온디바이스 사용 가능하지 않음). 온디바이스 모델은 기기에서 약 50–100MB를 차지하며 첫 번째 요청 시 다운로드됩니다.
클라우드(iOS 16-): request.requiresOnDeviceRecognition = false(또는 매개변수 없음). Apple 서버의 ASR — 더 정확함(WER 7% EN, 12% RU), 더 많은 언어, 요청당 최대 1분. 인터넷(WiFi 또는 셀룰러) 필요. Apple은 클라우드 ASR에 대해 개발자에게 요금을 부과하지 않습니다(무료). 제한: 애플리케이션당 분당 1회 요청(지정되지 않음), 하지만 Apple은 프로덕션 규모에서 제한할 수 있습니다. 클라우드 ASR은 SLA 없이 최선의 품질을 제공합니다. 엔터프라이즈 앱의 경우 Google Cloud ASR 또는 Whisper(Core ML)를 사용하세요.
| 매개변수 | 온디바이스(iOS 17+) | 클라우드(iOS 10+) |
|---|---|---|
| 인터넷 필요 | 아니요 | 예 |
| WER (EN) | 10–12% | 7% |
| WER (RU) | 12–14% | 12% |
| 지연 시간(RTF) | 0.3–0.6 | 0.3–0.8(+네트워크) |
| 최대 길이 | 2분 | 1분 |
| 개인정보 보호 | 완전 | 오디오가 기기를 떠남 |
| 무료 | 예 | 예 |
결합 인식(iOS 17+): request.requiresOnDeviceRecognition = false(인터넷 있음, 클라우드), = true(오프라인, 폴백). Apple이 자동으로 모드를 선택합니다. 정확도가 중요한 앱: NetworkMonitor(NWPathMonitor) 확인 — 인터넷 있으면 클라우드, 없으면 온디바이스. 개인정보가 중요한 앱: 항상 온디바이스. 전사: 클라우드(더 정확). 음성 입력: 온디바이스(더 빠름). 결합 권장: 80% 클라우드, 20% 온디바이스 폴백.
사용자 정의 키보드에서 음성 입력 — SFSpeechRecognizer를 키보드 확장(iOS 10+)에 통합. 사용자가 마이크 버튼을 누르면 ASR이 음성을 텍스트로 변환하여 텍스트 필드에 삽입합니다. 요구 사항: 부분 결과(실시간 텍스트 확인), 온디바이스(키보드는 인터넷 없이 작동해야 함). SFSpeechRecognizer + AVSpeechSynthesizer — 음성 입력 + 음성 출력. iOS 17+에서 사용자 정의 키보드의 경우 온디바이스를 사용합니다. 키보드 확장 제한: AVAudioEngine을 사용할 수 있지만 시간 제한이 있습니다(백그라운드 실행 제한).
회의 및 강의 전사 — 오디오를 녹음하고 전사하는 앱(Otter.ai, Rev, Apple Voice Memos). SFSpeechURLRecognitionRequest가 .m4a 파일을 처리합니다. 긴 녹음(30–60분)의 경우 — Whisper Core ML(길이 제한 없음). 타임스탬프가 있는 SFSpeechRecognizer segments — 오디오와 텍스트 동기화용(재생 중 텍스트 강조). 세그먼트별 신뢰도 — 신뢰할 수 없는 부분 표시용(노란색 강조). 화자 분할(누가 말했는지) — Apple이 API를 제공하지 않으므로 서버에서 pyannote-audio + Whisper를 사용합니다.
iOS 앱에서 음성 명령 — SFSpeechRecognizer + VGS 프레임워크(Voice Grammar Services)로 명령 실행: “설정 열기”, “메시지 보내기”, “불 켜기”. 문법 기반 인식: SFSpeechRecognitionRequest contextualStrings = 명령 배열. 명령 인식 정확도가 95%로 향상됩니다(자유 형식 85% 대비). SFSpeechRecognitionTask.cancel — 명령 실행 후 중단. VGS + SFSpeechRecognizer + Shortcuts — UI를 작성하지 않고 사용자 정의 음성 명령. 접근성: Voice Control(내장) + SFSpeechRecognizer(사용자 정의 명령).
// 컨텍스트 문자열을 사용한 음성 명령
let request = SFSpeechAudioBufferRecognitionRequest()
request.requiresOnDeviceRecognition = true
request.shouldReportPartialResults = true
request.contextualStrings = ["open contacts", "send message",
"show notifications", "손전등 켜기"]
recognitionTask = recognizer.recognitionTask(with: request) { result, _ in
guard let text = result?.bestTranscription.formattedString.lowercased() else { return }
voiceCommands.first { text.contains($0) }.map { command in
DispatchQueue.main.async { self.executeCommand(command) }
recognitionTask?.cancel()
}
}
의료 및 법률 앱에서 받아쓰기 — SFSpeechRecognizer로 음성으로 구조화된 문서 만들기. 도메인 적응: 의료/법률 용어가 포함된 contextualStrings(500개 이상 구문). SFSpeechRecognitionRequest.customLmProbability — contextualStrings 영향(0.1–1.0). 의료 받아쓰기의 경우 온디바이스 사용(환자 데이터 개인정보 보호). 의료 데이터로 미세 조정된 Whisper — 기본 SFSpeechRecognizer의 12% 대신 WER 5%의 대안. HIPAA 규정 준수: 온디바이스 모드(데이터가 기기를 떠나지 않음). 약속 전사 — SFSpeechURLRecognitionRequest + 화자 타임스탬프가 있는 segments.
자주 묻는 질문
SFSpeechRecognizer는 iOS 10, macOS 10.15, watchOS 6 및 tvOS 17부터 사용할 수 있습니다. 온디바이스 모드는 iOS 17부터(requiresOnDeviceRecognition). iOS 10–16에서는 SFSpeechRecognizer가 Apple의 클라우드 서버를 통해서만 작동합니다(인터넷 필요). 모든 버전에서 명시적 사용자 권한이 필요합니다(NSMicrophoneUsageDescription + NSSpeechRecognitionUsageDescription). SFSpeechRecognizer.supportedLocales — 동적 목록, 지역 및 기기 모델에 따라 다릅니다.
예, isFinal 후에 새 recognitionTask를 만들어 가능합니다. 연속 인식을 위해 이전 작업이 완료된 후 작업을 다시 시작합니다. iOS 17에서 온디바이스 연속 ASR은 시간당 2–5%의 배터리를 소비합니다(A15+). iOS 16-에서 연속 ASR은 인터넷이 필요합니다(트래픽 ~1MB/분). 진정한 연속 인식(항상 듣기)의 경우 Vosk(오프라인) 또는 Whisper Core ML을 사용하세요. SFSpeechRecognizer는 iOS 16-에서 항상 켜짐 모드를 지원하지 않습니다.
result.bestTranscription.segments를 사용하세요 — 각 SFTranscriptionSegment에는 단어의 confidence(Float 0..1)가 포함됩니다. segments[i].substring — 단어 텍스트. segments[i].confidence — 해당 단어의 ASR 신뢰도. confidence < 0.5인 단어는 신뢰할 수 없습니다 — UI에서 강조 표시하세요. segments[i].timestamp — 시작 시간(TimeInterval). segments[i].duration — 지속 시간. segments[i].alternativeSubstrings — 단어의 대체 인식 가설. 긴 파일의 경우 segments를 반복하면 수동 구문 분석 없이 단어별 신뢰도를 얻을 수 있습니다.
203은 SFSpeechError.ErrorCode.opportunistic(클라우드 ASR용 인터넷 없음)입니다. iOS 16-에서 또는 request.requiresOnDeviceRecognition = false일 때 인터넷 없이 발생합니다. 해결책: 오프라인 작동을 위해 requiresOnDeviceRecognition = true(iOS 17+)로 설정합니다. iOS 16-에서는 NWPathMonitor를 사용 — 인터넷이 없을 때 “음성 인식에는 인터넷 연결이 필요합니다”라는 메시지를 표시합니다. 대안: 네트워크를 사용할 수 없을 때 폴백으로 Vosk(오프라인, iOS 12+)를 사용합니다.
SFSpeechRecognizer — Apple 내장 API, 무료, 통합 쉬움, 하지만 길이 제한(1–2분), WER 정확도 7–14%, iOS 생태계만 해당. Whisper Core ML — 오픈소스(MIT), 99개 언어 지원, WER 6–10%, 길이 제한 없음, 하지만 수동 통합, Core ML 모델(39M–769M 매개변수), RTF 0.5–6(SFSpeechRecognizer보다 느림) 필요. SFSpeechRecognizer — 표준 음성 입력용. Whisper — 고정확도 긴 오디오 전사용.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.