如何更细致调试SFSpeechRecognizer?集成识别异常求助
SFSpeechRecognizer 识别异常调试方案求助
我正在应用中集成SFSpeechRecognizer,但三个预录制的m4a音频文件返回的结果/错误无法帮我定位问题,相关资料也比较少。所有文件都是清晰大声录制的,但仍出现“未检测到语音”或无文本返回的情况:
SS-X-03.m4a : There was an error: Optional(Error Domain=kAFAssistantErrorDomain Code=1110 "No speech detected" UserInfo={NSLocalizedDescription=No speech detected})
SS-X-20221125000.m4a : There was an error: Optional(Error Domain=kAFAssistantErrorDomain Code=1110 "No speech detected" UserInfo={NSLocalizedDescription=No speech detected})
SS-X-20221125001.m4a : (仅当设置request.requiresOnDeviceRecognition = false时能识别出文本)
我的代码:
func findAudioFiles(){ let fm = FileManager.default var aFiles : URL print ("\(urlPath)") do { let items = try fm.contentsOfDirectory(atPath: documentsPath) let filteredInterestArray1 = items.filter({$0.hasSuffix(".m4a")}) let filteredInterestArray2 = filteredInterestArray1.filter({$0.contains("SS-X-")}) let sortedItems = filteredInterestArray2.sorted() for item in sortedItems { audioFiles.append(item) } NotificationCenter.default.post(name: Notification.Name("goAndRead"), object: nil, userInfo: myDic) } catch { print ("\(error)") } } @objc func goAndRead(){ audioIndex += 1 if audioIndex != audioFiles.count { let fileURL = NSURL.fileURL(withPath: documentsPath + "/" + audioFiles[audioIndex], isDirectory: false) transcribeAudio(url: fileURL, item: audioFiles[audioIndex]) } } func requestTranscribePermissions() { SFSpeechRecognizer.requestAuthorization { [unowned self] authStatus in DispatchQueue.main.async { if authStatus == .authorized { print("Good to go!") } else { print("Transcription permission was declined.") } } } } func transcribeAudio(url: URL, item: String) { guard let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US")) else {return} let request = SFSpeechURLRecognitionRequest(url: url) if !recognizer.supportsOnDeviceRecognition { print ("offline not available") ; return } if !recognizer.isAvailable { print ("not available") ; return } request.requiresOnDeviceRecognition = true request.shouldReportPartialResults = true recognizer.recognitionTask(with: request) {(result, error) in guard let result = result else { print("\(item) : There was an error: \(error.debugDescription)") return } if result.isFinal { print("\(item) : \(result.bestTranscription.formattedString)") NotificationCenter.default.post(name: Notification.Name("goAndRead"), object: nil, userInfo: self.myDic) } } }
更新信息
- 之前存在频繁调用
SFSpeechURLRecognitionRequest的问题,前一次请求未完成就发起新请求,不确定是否需要创建新的SFSpeechRecognizer实例 - 调整为前一次请求返回结果后再调用新请求,情况有所改善,但仍有一个音频文件无识别结果(无错误返回,仅无文本)
- 该文件与能识别的文件格式、音量一致,是同一录音拆分而来
- 需要更有效的调试方法定位该文件的问题
调试排查方案
一、音频文件本身验证
- 检查音频编码与参数
使用音频工具(如Audacity)打开异常文件,确认:- 采样率:SFSpeechRecognizer推荐16kHz(离线识别对采样率更敏感)
- 声道:必须是单声道(离线识别不支持立体声)
- 编码格式:m4a需使用AAC-LC编码,避免使用其他特殊编码
- 音量电平:确保语音部分的音量在-16dB到-6dB之间,无静音开头/结尾过长(超过1-2秒可能被判定为无语音)
- 手动播放验证
直接播放异常文件,确认确实包含清晰可辨的英文语音,无背景噪音、断音情况;同时检查文件是否完整,无损坏。
二、代码逻辑优化与调试
- 请求队列管理
- 不需要每次创建新的
SFSpeechRecognizer实例,可全局复用一个实例(确保locale一致) - 维护一个请求状态标记,确保同一时间只有一个识别任务在运行,避免并发请求被系统限流或干扰
- 不需要每次创建新的
- 增强错误与结果日志
在recognitionTask的回调中,补充以下日志,获取更多调试信息:// 打印部分结果,查看是否有临时识别内容 if !result.bestTranscription.formattedString.isEmpty { print("\(item) 临时识别结果: \(result.bestTranscription.formattedString)") } // 打印错误的详细信息,包括所有UserInfo字段 if let error = error { print("\(item) 错误详情: \(error),UserInfo: \(error.userInfo)") } - 离线与在线识别对比测试
对异常文件分别测试在线(requiresOnDeviceRecognition = false)和离线模式:- 若在线能识别,说明离线语言包可能未正确下载,需检查
SFSpeechRecognizer.isAvailable状态,或手动在系统设置中确认英文离线语音包已下载 - 若在线也无法识别,说明音频文件本身存在不符合识别要求的问题
- 若在线能识别,说明离线语言包可能未正确下载,需检查
三、系统环境验证
- 离线语言包状态
调用SFSpeechRecognizer.supportedLocales()确认当前设备支持的离线语言,同时检查系统设置中「Siri与搜索」-「离线语音识别」是否已开启并下载对应语言包 - 权限与系统版本
确保应用已配置NSSpeechRecognitionUsageDescription权限,且设备系统版本符合离线识别要求(iOS 13+支持离线英文识别) - 系统限流检查
SFSpeechRecognizer有请求频率限制,若短时间内发起大量请求,可能被系统静默拒绝,可在每次请求前添加1-2秒延迟,测试是否恢复正常
内容的提问来源于stack exchange,提问作者Bartender1382
相关产品推荐
相关产品推荐

