В большинстве случаев, когда я запускаю приложение, аудио и тест распознавания речи работают отлично. Но иногда я запускаю его, и он падает при первом запуске распознавания речи. Похоже, что он набирает обороты и совершает sh несколько запусков подряд, поэтому он немного последовательный, как только он входит в одно из своих «настроений» :)
Распознавание начинается после TTS введение и в то же время, как TTS говорит «прослушивание» - поэтому оба активны одновременно. Возможно, для переключения звука требуется несколько миллисекунд, и он дает сбой, но я не понимаю, как это работает или как его предотвратить.
Я вижу следующую ошибку:
[avae] AVAEInternal.h:70:_AVAE_Check: required condition is false:
[AVAudioIONodeImpl.mm:911:SetOutputFormat: (format.sampleRate == hwFormat.sampleRate)]
*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio',
reason: 'required condition is false: format.sampleRate == hwFormat.sampleRate'
I вставили try-catches
, чтобы посмотреть, предотвращает ли она эту ошибку и нет. Я также добавил крошечный sleep
, который также не имел никакого значения. Так что мне даже не ясно, какой код вызывает это. Если я поставлю точку останова перед кодом removeTapOnBus
, он не обработает sh, пока не выполнится эта строка. Если я поставлю точку останова на строке installTapOnBus
, она не будет обрабатывать sh до этой строки. И если я ставлю точку останова после кода, он падает. Так что, похоже, этот код.
В любом случае, что я делаю не так или как я могу это отладить?
- (void) recordAndRecognizeWithLang:(NSString *) lang
{
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:lang];
self.sfSpeechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
if (!self.sfSpeechRecognizer) {
[self sendErrorWithMessage:@"The language is not supported" andCode:7];
} else {
// Cancel the previous task if it's running.
if ( self.recognitionTask ) {
[self.recognitionTask cancel];
self.recognitionTask = nil;
}
//[self initAudioSession];
self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
self.recognitionRequest.shouldReportPartialResults = [[self.command argumentAtIndex:1] boolValue];
// https://developer.apple.com/documentation/speech/sfspeechrecognizerdelegate
// only callback is availabilityDidChange
self.sfSpeechRecognizer.delegate = self;
self.recognitionTask = [self.sfSpeechRecognizer recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {
NSLog(@"recognise");
if (error) {
NSLog(@"error %ld", error.code);
// code 1 or 203 or 216 = we called abort via self.recognitionTask cancel
// 1101 is thrown when in simulator
// 1700 is when not given permission
if (error.code==203){ //|| error.code==216
// nothing, carry on, this is bullshit, or maybe not...
[self sendErrorWithMessage:@"sfSpeechRecognizer Error" andCode:error.code];
}else{
[self stopAndRelease];
// note: we can't send error back to js as I found it crashes (when recognising, then switch apps, then come back)
[self sendErrorWithMessage:@"sfSpeechRecognizer Error" andCode:error.code];
return;
}
}
if (result) {
NSMutableArray * alternatives = [[NSMutableArray alloc] init];
int maxAlternatives = [[self.command argumentAtIndex:2] intValue];
for ( SFTranscription *transcription in result.transcriptions ) {
if (alternatives.count < maxAlternatives) {
float confMed = 0;
for ( SFTranscriptionSegment *transcriptionSegment in transcription.segments ) {
//NSLog(@"transcriptionSegment.confidence %f", transcriptionSegment.confidence);
if (transcriptionSegment.confidence){
confMed +=transcriptionSegment.confidence;
}
}
NSLog(@"transcriptionSegment.transcript %@", transcription.formattedString);
NSMutableDictionary * resultDict = [[NSMutableDictionary alloc]init];
[resultDict setValue:transcription.formattedString forKey:@"transcript"];
[resultDict setValue:[NSNumber numberWithBool:result.isFinal] forKey:@"final"];
float conf = 0;
if (confMed && transcription.segments && transcription.segments.count && transcription.segments.count>0){
conf = confMed/transcription.segments.count;
}
[resultDict setValue:[NSNumber numberWithFloat:conf]forKey:@"confidence"];
[alternatives addObject:resultDict];
}
}
[self sendResults:@[alternatives]];
if ( result.isFinal ) {
//NSLog(@"recog: isFinal");
[self stopAndRelease];
}
}
}];
//[self.audioEngine.inputNode disconnectNodeInput:0];
AVAudioFormat *recordingFormat = [self.audioEngine.inputNode outputFormatForBus:0];
//AVAudioFormat *recordingFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100 channels:1];
NSLog(@"samplerate=%f", recordingFormat.sampleRate);
NSLog(@"channelCount=%i", recordingFormat.channelCount);
// tried this but does not prevent crashing
//if (recordingFormat.sampleRate <= 0) {
// [self.audioEngine.inputNode reset];
// recordingFormat = [[self.audioEngine inputNode] outputFormatForBus:0];
//}
sleep(1); // to prevent random crashes
@try {
[self.audioEngine.inputNode removeTapOnBus:0];
} @catch (NSException *exception) {
NSLog(@"removeTapOnBus exception");
}
sleep(1); // to prevent random crashes
@try {
NSLog(@"install tap on bus");
[self.audioEngine.inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
//NSLog(@"tap");
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];
} @catch (NSException *exception) {
NSLog(@"installTapOnBus exception");
}
sleep(1); // to prevent random crashes
[self.audioEngine prepare];
NSError* error = nil;
BOOL isOK = [self.audioEngine startAndReturnError:&error];
if (!isOK){
NSLog(@"audioEngine startAndReturnError returned false");
}
if (error){
NSLog(@"audioEngine startAndReturnError error");
}
}