【问题标题】:SFSpeechRecognizer on MacOS not available despite successful authorization尽管授权成功,但 MacOS 上的 SFSpeechRecognizer 不可用
【发布时间】:2026-01-19 11:25:01
【问题描述】:

我正在尝试获取一个笨拙的 Objective-C 概念验证示例,以便在 Catalina 上使用 SFSpeechRecognizer 运行并转录本地音频文件。

经过一番谷歌搜索后,我设法通过添加一个带有 NSSpeechRecognitionUsageDescription 的 Info.plist 来获得授权,并且我得到了授权对话框和正确的 SFSpeechRecognizerAuthorizationStatus (SFSpeechRecognizerAuthorizationStatusAuthorized)。

但是,我的 SFSpeechRecognizer 实例仍然不可用。我怀疑,由于缺乏基本的 Objective-C 知识,我一定犯了一个愚蠢的错误。

非常感谢任何提示。

这是我的代码:

//
//  main.m
//  SpeechTestCatalina
//

#import <Foundation/Foundation.h>
#import <Speech/Speech.h>

void transcribeTestFile(){
    NSLocale *locale =[[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
    SFSpeechRecognizer *speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];

    NSLog(@"Locale %@, %@", speechRecognizer.locale.languageCode, speechRecognizer.locale.countryCode);
    NSLog(@"Available %hhd", speechRecognizer.available);
    NSLog(@"Auth status %ld", [SFSpeechRecognizer authorizationStatus]);
    NSLog(@"Supports on device %hhd", speechRecognizer.supportsOnDeviceRecognition);
    if(speechRecognizer.isAvailable && speechRecognizer.supportsOnDeviceRecognition){
        NSString *audioFilePath = @"/Users/doe/speech-detection/speech_sample.wav";
        NSURL *url = [[NSURL alloc] initFileURLWithPath:audioFilePath];
        NSLog(@"Analyzing %@ in language %@", url, locale.languageCode);
        SFSpeechURLRecognitionRequest *urlRequest = [[SFSpeechURLRecognitionRequest alloc] initWithURL:url];
        urlRequest.requiresOnDeviceRecognition = true;
        urlRequest.shouldReportPartialResults = YES; // YES if animate writting
        [speechRecognizer recognitionTaskWithRequest: urlRequest resultHandler:  ^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error){
            NSString *transcriptText = result.bestTranscription.formattedString;
            if(!error){
                NSLog(@"Transcript: %@", transcriptText);
            } else {
                NSLog(@"Error: %@", error);
            }
        }];
    } else {
        NSLog(@"speechRecognizer is not available on this device");
    }
}


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus authStatus) {
            NSLog(@"Status: %ld", (long)authStatus);
            switch (authStatus) {
                case SFSpeechRecognizerAuthorizationStatusAuthorized:
                    //User gave access to speech recognition
                    NSLog(@"Authorized");

                    transcribeTestFile();

                    break;

                case SFSpeechRecognizerAuthorizationStatusDenied:
                    //User denied access to speech recognition
                    NSLog(@"SFSpeechRecognizerAuthorizationStatusDenied");
                    break;

                case SFSpeechRecognizerAuthorizationStatusRestricted:
                    //Speech recognition restricted on this device
                    NSLog(@"SFSpeechRecognizerAuthorizationStatusRestricted");
                    break;

                case SFSpeechRecognizerAuthorizationStatusNotDetermined:
                    //Speech recognition not yet authorized

                    break;

                default:
                    NSLog(@"Default");
                    break;
            }
        }];

        NSLog(@"Sleeping");
        [NSThread sleepForTimeInterval:20.0f];

    }
    return 0;
}

我运行它时的输出是:

2020-01-26 17:48:39.454809+0100 SpeechTestCatalina[3623:82404] Sleeping
2020-01-26 17:48:41.182459+0100 SpeechTestCatalina[3623:82811] Status: 3
2020-01-26 17:48:41.182562+0100 SpeechTestCatalina[3623:82811] Authorized
2020-01-26 17:48:41.186933+0100 SpeechTestCatalina[3623:82811] Locale en, US
2020-01-26 17:48:41.190973+0100 SpeechTestCatalina[3623:82811] Available 0
2020-01-26 17:48:41.191269+0100 SpeechTestCatalina[3623:82811] Auth status 3
2020-01-26 17:48:41.197965+0100 SpeechTestCatalina[3623:82811] Supports on device 0
2020-01-26 17:48:41.198065+0100 SpeechTestCatalina[3623:82811] speechRecognizer is not available on this device
Program ended with exit code: 0

【问题讨论】:

  • 我不这么认为。在发布我的问题之前,我已经阅读了这篇文章,但用户报告了一个不同的问题,即没有出现授权对话框,这在我的情况下工作正常。此外,我不明白在我的简单主程序示例中我可以使用什么作为委托,以及什么机制可以让它工作。后一个问题你有答案吗?
  • 我在我的机器上尝试了你的代码并且它有效(语音识别可用)。我在“系统偏好设置”>“Siri”中禁用了“启用询问 Siri”,然后再试一次,现在语音识别不可用。您可以尝试切换该设置并查看是否有变化吗?
  • 你是对的。这会有所不同。除此之外,我意识到我没有在项目中启用协同设计,而启用 Siri 让我更进一步。但是,现在我得到的 speechRecognizer.supportsOnDeviceRecognition 为 0,我不希望语​​言环境“en-US”出现这种情况,如果我删除对它的检查并删除将 requiresOnDeviceRecognition 设置为 1 的行,我现在会收到这些错误 AddInstanceForFactory: No factory registered for id &lt;CFUUID 0x1007c3870&gt; F8BB1C28-BAE8-11D6-9C31-00039315CD46 HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
  • iOS 13 中存在一个错误:The supportsOnDeviceRecognition property always returns false the first time it’s accessed. After a few seconds, accessing it again returns the correct value.。也许是同一件事?

标签: macos speech-recognition sfspeechrecognizer


【解决方案1】:

您没有收到回调,因为您的二进制文件没有运行循环。我会从这个不同的问题中得到答复,但same answer

大多数 Apple 框架中的回调是通过应用程序的主运行循环传递的。如果您的命令行工具没有运行循环,则它无法接收以这种方式发送的回调。

如果没有 runloop,框架调用回调的唯一方法是在另一个线程上运行它,这可能会导致应用程序出现意想不到的奇怪行为。

您可以通过在main 结尾之前插入此代码来手动抽取运行循环:

NSRunLoop* runloop = [NSRunLoop currentRunLoop];
[runloop runUntilDate:[NSDate distantFuture]];

这将阻止您的应用程序退出;您需要更新您的逻辑以了解语音识别何时完成并使用while 循环或其他东西对其进行重组 - 但我假设您的“真实”应用程序中的逻辑与这个玩具示例不同。


消息:

AddInstanceForFactory:没有为 id F8BB1C28-BAE8-11D6-9C31-00039315CD46 HALC_ShellDriverPlugIn::Open 注册工厂:无法获得指向 Open 例程的指针

那在你的控制台中出现一个没有意义的;这是系统框架中泄露的一些日志语句,你可以忽略它。


最后,澄清一下其他几点:

  • 需要在“系统偏好设置”>“Siri”中启用“启用询问 Siri”才能使用语音识别
  • 存在一个潜在问题,即设备可能会在您第一次检查时报告“设备识别”不可用,尽管所选语言环境受支持

【讨论】:

  • 非常感谢!这是正确的。尽管您告诉我忽略的消息仍然存在,但在我添加运行循环后,识别现在按预期工作。您为澄清而添加的两点也是正确的。对于后一点,我不能 100% 确定重启是否解决了这个问题(我当然在第一次成功运行之前做了一个),或者它只是在某个时候开始工作。是的,现在我有一个工作的概念证明,真正的代码看起来会大不相同。
  • 在我的例子中,“Ask Siri”被禁用了。
最近更新 更多