git.iko.soy/rowtype-yoga/purescript-yoga-react-native
on main help sign in
Fix speech recognition: add audio-input entitlement, add NSLog debugging
commit26c25e4f063e068969064e55fb1f9e7783d125d1 authorMark <mark.eibes@gmail.com> dateSun 15 Feb 2026, 16:58 (8 months ago) parent60d9324
3 files changed+21−12
example-macos/macos/YogaReactExample-macOS/RCTMacOSControlsManager.m+16−5 example-macos/src/Main.purs+4−6 src/Yoga/React/Native/MacOS/SpeechRecognition.js+1−1
example-macos/macos/YogaReactExample-macOS/RCTMacOSControlsManager.m+16−5
@@ -4069,8 +4069,14 @@ RCT_EXPORT_METHOD(start:(RCTPromiseResolveBlock)resolve
40694069 }
40704070
40714071 self.latestTranscript = @"";
4072− self.recognizer = [[SFSpeechRecognizer alloc] initWithLocale:[NSLocale currentLocale]];
4073− NSLog(@"[SpeechRecognition] Recognizer available: %d, locale: %@", self.recognizer.isAvailable, self.recognizer.locale.localeIdentifier);
4072+ // Use en-US explicitly — currentLocale can return region-specific locales that
4073+ // on-device speech recognition doesn't support
4074+ NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
4075+ self.recognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
4076+ NSLog(@"[SpeechRecognition] Recognizer available: %d, supportsOnDevice: %d, locale: %@",
4077+ self.recognizer.isAvailable,
4078+ self.recognizer.supportsOnDeviceRecognition,
4079+ self.recognizer.locale.localeIdentifier);
40744080
40754081 if (!self.recognizer.isAvailable) {
40764082 reject(@"UNAVAILABLE", @"Speech recognizer is not available for this locale", nil);
@@ -4080,19 +4086,24 @@ RCT_EXPORT_METHOD(start:(RCTPromiseResolveBlock)resolve
40804086 self.audioEngine = [[AVAudioEngine alloc] init];
40814087 self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
40824088 self.recognitionRequest.shouldReportPartialResults = YES;
4089+ // Do NOT require on-device — let it use server-based recognition
4090+ // On-device may not have the language model downloaded
4091+ self.recognitionRequest.requiresOnDeviceRecognition = NO;
40834092
40844093 AVAudioInputNode *inputNode = self.audioEngine.inputNode;
4094+ // Use nil format — let the system pick the right format for the input node
40854095 AVAudioFormat *format = [inputNode outputFormatForBus:0];
4086− NSLog(@"[SpeechRecognition] Audio format: %@", format);
4096+ NSLog(@"[SpeechRecognition] Audio format: sampleRate=%f channels=%u", format.sampleRate, format.channelCount);
40874097
4088− [inputNode installTapOnBus:0 bufferSize:1024 format:format block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
4098+ [inputNode installTapOnBus:0 bufferSize:4096 format:format block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
40894099 [self.recognitionRequest appendAudioPCMBuffer:buffer];
40904100 }];
40914101
40924102 self.recognitionTask = [self.recognizer recognitionTaskWithRequest:self.recognitionRequest
40934103 resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {
40944104 if (error) {
4095− NSLog(@"[SpeechRecognition] Error: %@", error.localizedDescription);
4105+ NSLog(@"[SpeechRecognition] Error: %@ (code: %ld, domain: %@)",
4106+ error.localizedDescription, (long)error.code, error.domain);
40964107 }
40974108 if (result) {
40984109 self.latestTranscript = result.bestTranscription.formattedString;
example-macos/src/Main.purs+4−6
@@ -1207,11 +1207,9 @@ aiTab = component "AITab" \p -> React.do
12071207 , sfSymbol: if listening then "mic.fill" else "mic"
12081208 , bezelStyle: T.push
12091209 , onPress: handler_ do
1210− if listening then pure unit
1211− else do
1212− setListening true
1213− setTranscript ""
1214− macosStartListening
1210+ setListening true
1211+ setTranscript ""
1212+ macosStartListening
12151213 , style: Style.style { height: 24.0, width: 130.0 }
12161214 }
12171215 , nativeButton
@@ -1219,9 +1217,9 @@ aiTab = component "AITab" \p -> React.do
12191217 , sfSymbol: "stop.circle"
12201218 , bezelStyle: T.push
12211219 , onPress: handler_ do
1220+ setListening false
12221221 macosStopListening \finalText -> do
12231222 setTranscript finalText
1224− setListening false
12251223 , style: Style.style { height: 24.0, width: 80.0, marginLeft: 8.0 }
12261224 }
12271225 ]
src/Yoga/React/Native/MacOS/SpeechRecognition.js+1−1
@@ -26,6 +26,6 @@ export const getTranscriptImpl = (callback) => {
2626 mod
2727 .getTranscript()
2828 .then((text) => callback(text)())
29− .catch((e) => console.error("[macosGetTranscript]", e));
29+ .catch(() => {});
3030 }
3131};