Search code examples
windowsspeech-recognitionspeechsapimicrosoft-speech-api

Microsoft SAPI Sub-language issue


My problem is this: My SAPI inproc recognizer refuses to load my grammar file when the windows 10 Display language is set to English(UK).

System Display language set to UK. Speech Recognition language is UK. System Locale is UK. SAPI xml-format Grammar even specifies LANGID=809 - as far as I can tell, EVERYTHING is set to EN-GB, and yet the grammar still won't load.

But it loads and works just fine when display language and is set to English(US).

Does anyone know what's up with this? It's extremely frustrating... Hopefully I'm just missing something simple.

SAPI Initialization code:

    //////////////INITIALIZE SAPI ENGINE AND GRAMMAR//////////////////////////////
HRESULT SpeechObject::Initialize(){
    //INITIALIZE SR ENGINE
    if (FAILED(test=::CoInitialize(NULL)))
        SRError(L"COM Initialization Fail");

    //Create recognizer instance
    if (FAILED(test=cpEngine.CoCreateInstance(CLSID_SpInprocRecognizer))){
        SRError(L"Can't Load Reco Engine");
            return test;
    }

    //Load the audio Input (in seperate function to facilitate reload)
    LoadAudio(); //should I check this?

    //load Default recognizer settings
    cpEngine->SetRecognizer(NULL);

    //get and load default reco profile
    if (FAILED(SpGetDefaultTokenFromCategoryId(SPCAT_RECOPROFILES, &cpObjectToken)))
        SRError(L"Can't Find Recognition Profile");
    if (FAILED(cpEngine->SetRecoProfile(cpObjectToken)))
        SRError(L"Can't Load Recognition Profile");

    //create reco context
    if (FAILED(test=cpEngine->CreateRecoContext(&cpContext))){
        SRError(L"Can't Create Reco Context");
        return test;
    }

    //send pSpeechObject to global callback function
    cpContext->SetNotifyCallbackFunction(
        (SPNOTIFYCALLBACK*)SpeechCallBack,
        NULL, (LPARAM)this);

    if(FAILED(cpContext->CreateGrammar(NULL, &cpGrammar)))
        SRError(L"Can't Create context");

    char str[80]; ////TEST
    sprintf(str, "LANGID: %X", GetUserDefaultUILanguage());
    MessageBoxA(GetActiveWindow(), str,0,0);

    //load grammar from compiled grammar resource
    if (FAILED(test = cpGrammar->LoadCmdFromResource(
        hModule, MAKEINTRESOURCE(GRAMMARCFG),
        L"FILE", GetUserDefaultUILanguage(), SPLO_STATIC))){
        SRError(L"Can't Load Grammar. Please check language settings");
        return test;
    }

    //(comment above and uncomment following to load from raw xml file for testing)
    //cpGrammar->LoadCmdFromFile(L"Grammar.xml", SPLO_STATIC);

    //Enable Engine and Reco Context
    cpEngine->SetRecoState(SPRST_ACTIVE);
    cpContext->SetContextState(SPCS_ENABLED);

    //enable ALWAYS ACTIVE and GROUND ENGINES ON commands
    return(cpGrammar->SetRuleState(NULL, NULL, SPRS_ACTIVE));

}

////////////LOAD (AND RELOAD) AUDIO INPUT//////////////////////
HRESULT SpeechObject::LoadAudio(bool dlgFlag){
    if (FAILED(test = SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN, &cpAudioIn))){
        SRError(L"Can't Find Default Audio Input");
        return test;
    }

    if (FAILED(test = cpEngine->SetInput(cpAudioIn, TRUE))){
        if (!dlgFlag)
            SRError(L"Can't Set Audio Input");
        return test;
    }

    if (pSRDisplay)
        pSRDisplay->DisplayText("Audio Reloaded");
    if (pDLog)
        pDLog->LogEvent("Audio Reloaded");
    //RecoState must be reenabled after audio reset
    cpEngine->SetRecoState(SPRST_ACTIVE);
    if (pDLog)
        pDLog->LogEvent("SR ENABLED");
    return test;
}

I get the "Can't Load Grammar. Please check language settings" error any time the display language is not English(US), even if I confirm that ALL SETTINGS match...

Would really appreciate any sort of insight from persons more knowledgeable than I.

Farley


Solution

  • The issue was that I had misinterpreted the meaning of the "language" parameter in LoadCmdFromResource(). I'll blame it on the ambiguous SAPI documentation, though if I had experience loading some other types of resources before I might have been tipped off to this. ;) I had thought it was somehow used by SAPI and should match the language of the system and recognizer (that's what it sounded like in the documentation). Turns out, it actually just specifies the language used to compile the .RC file the grammar is included in (presumably to allow multiple translations to be included in separate .rc's).

    The code works perfectly as originally posted, so long as I replace "GetUserDefaultUI()" with an explicit "0x409" (the language specified in the resource compiler) in the call to LoadCmdFromResource(). Now it works with US English, UK English and presumably all English recognizers, and loads the recognizer selected in the speech control panel regardless of the Display language setting (which can even be non-English).

    Many, many thanks to Eric Brown for tipping me off to this, I was starting to lose my mind.

    Farley