在通过 AVSpeechUtterance 向用户发表欢迎信息后,我尝试使用 SFSpeechRecognizer 进行语音转文本。但是随机地,语音识别没有启动(在说出欢迎信息之后),它会抛出下面的错误信息。
[avas] 错误:AVAudioSession.mm:1049:-[AVAudioSession setActive:withOptions:error:]:停用具有运行 I/O 的音频会话。在停用音频会话之前,应停止或暂停所有 I/O。
它工作了几次。我不清楚为什么它不能始终如一地工作。
我尝试了其他 SO 帖子中提到的解决方案,其中提到检查是否有音频播放器正在运行。我将语音检查添加到代码的文本部分。它返回 false(即没有其他音频播放器正在运行)但文本语音仍然没有开始收听用户语音。你能指导我出什么问题吗?
正在运行 iOS 10.3 的 iPhone 6 上进行测试
以下是使用的代码片段:
文字转语音:
- (void) speak:(NSString *) textToSpeak {
[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionDuckOthers error:nil];
[synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
AVSpeechUtterance* utterance = [[AVSpeechUtterance new] initWithString:textToSpeak];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:locale];
utterance.rate = (AVSpeechUtteranceMinimumSpeechRate * 1.5 + AVSpeechUtteranceDefaultSpeechRate) / 2.5 * rate * rate;
utterance.pitchMultiplier = 1.2;
[synthesizer speakUtterance:utterance];
}
- (void)speechSynthesizer:(AVSpeechSynthesizer*)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance*)utterance {
//Return success message back to caller
[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient
withOptions: 0 error: nil];
[[AVAudioSession sharedInstance] setActive:YES withOptions: 0 error:nil];
}
语音转文本:
- (void) recordUserSpeech:(NSString *) lang {
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:lang];
self.sfSpeechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
[self.sfSpeechRecognizer setDelegate:self];
NSLog(@"Step1: ");
// Cancel the previous task if it's running.
if ( self.recognitionTask ) {
NSLog(@"Step2: ");
[self.recognitionTask cancel];
self.recognitionTask = nil;
}
NSLog(@"Step3: ");
[self initAudioSession];
self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
NSLog(@"Step4: ");
if (!self.audioEngine.inputNode) {
NSLog(@"Audio engine has no input node");
}
if (!self.recognitionRequest) {
NSLog(@"Unable to created a SFSpeechAudioBufferRecognitionRequest object");
}
self.recognitionTask = [self.sfSpeechRecognizer recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {
bool isFinal= false;
if (error) {
[self stopAndRelease];
NSLog(@"In recognitionTaskWithRequest.. Error code ::: %ld, %@", (long)error.code, error.description);
[self sendErrorWithMessage:error.localizedFailureReason andCode:error.code];
}
if (result) {
[self sendResults:result.bestTranscription.formattedString];
isFinal = result.isFinal;
}
if (isFinal) {
NSLog(@"result.isFinal: ");
[self stopAndRelease];
//return control to caller
}
}];
NSLog(@"Step5: ");
AVAudioFormat *recordingFormat = [self.audioEngine.inputNode outputFormatForBus:0];
[self.audioEngine.inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
//NSLog(@"Installing Audio engine: ");
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];
NSLog(@"Step6: ");
[self.audioEngine prepare];
NSLog(@"Step7: ");
NSError *err;
[self.audioEngine startAndReturnError:&err];
}
- (void) initAudioSession
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
[audioSession setMode:AVAudioSessionModeMeasurement error:nil];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}
-(void) stopAndRelease
{
NSLog(@"Invoking SFSpeechRecognizer stopAndRelease: ");
[self.audioEngine stop];
[self.recognitionRequest endAudio];
[self.audioEngine.inputNode removeTapOnBus:0];
self.recognitionRequest = nil;
[self.recognitionTask cancel];
self.recognitionTask = nil;
}
关于添加的日志,我能够看到所有日志,直到打印“Step7”。
在调试设备中的代码时,它始终在以下行触发中断(我设置了异常断点),但继续继续执行。然而,在少数成功的执行过程中也会以同样的方式发生。
AVAudioFormat *recordingFormat = [self.audioEngine.inputNode outputFormatForBus:0];
[self.audioEngine 准备];