Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
I’ve seen a couple of questions come by the listen alias about using an in-process speech recognizer. When you use an in-process recognizer, you have to specify a lot more than you need to specify with the shared recognizer.
In particular, you need to specify an audio source and a recognition engine. The shared recognizer uses the defaults for both of these.
Most people figure out that they need to specify an audio source; more commonly (and I’ve tripped over this myself) they forget to specify a recognition engine.
And while there’s a nifty helper for the audio input in sphelper.h (namely, SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOIN, &cpToken)), there isn’t a helper for the recognition engine.
So, here’s a helper function that returns the object token for the default shared recognizer:
- // Get the object token for the default shared recognizer engine.
 - HRESULT SpGetDefaultSharedRecognizerToken(ISpObjectToken **ppSharedRecognizerToken)
 - {
 - HRESULT hr = S_OK;
 - const WCHAR pszWindowsCompatAtt[] = L"windowsV6compatible";
 - LANGID UIlangID = GetUserDefaultUILanguage();
 - // Find recognizers that match windowsV6compatible and the primary language id of the UI.
 - // Use primary language because there may be several recognizers available for different sub-languages,
 - // and there is generally only one UI language per primary language.
 - // e.g. US and UK English recognizers on a US English system.
 - // If so, to distinguish these the locale is used below.
 - CComPtr<IEnumSpObjectTokens> cpEnum;
 - hr = SpEnumTokensMatchingPrimaryLangID(SPCAT_RECOGNIZERS, PRIMARYLANGID(UIlangID), pszWindowsCompatAtt, &cpEnum);
 - ULONG ulRecognizers(0);
 - if (SUCCEEDED(hr))
 - {
 - hr = cpEnum->GetCount(&ulRecognizers);
 - }
 - if (SUCCEEDED(hr))
 - {
 - if (ulRecognizers == 0)
 - {
 - // If zero - error.
 - hr = SPERR_RECOGNIZER_NOT_FOUND;
 - }
 - else if (ulRecognizers == 1)
 - {
 - // If one - we are done.
 - hr = cpEnum->Item(0, ppSharedRecognizerToken);
 - }
 - else
 - {
 - // More than one recognizer matches - we must pick the best default:
 - BOOL fFoundDefault = FALSE;
 - // If there's no language-specific default then use the locale.
 - LANGID localeID = GetUserDefaultLangID();
 - if (!fFoundDefault && SUCCEEDED(hr) &&
 - PRIMARYLANGID(UIlangID) == PRIMARYLANGID(localeID))
 - {
 - // First see if there's an engine whose language exactly matches the locale.
 - // For example if the langid is U.S English, but the locale is U.K. English
 - // and there's a U.K. recognizer then use that.
 - hr = S_OK;
 - WCHAR pszLocaleString[] = L"Language=XXXXXXXX";
 - SpHexFromUlong(pszLocaleString + wcslen(pszLocaleString) - 8, localeID);
 - for (ULONG ul = 0; SUCCEEDED(hr) && ul < ulRecognizers; ul++)
 - {
 - CComPtr<ISpObjectToken> cpToken;
 - hr = cpEnum->Item(ul, &cpToken);
 - if (SUCCEEDED(hr))
 - {
 - hr = cpToken->MatchesAttributes(pszLocaleString, &fFoundDefault);
 - }
 - if (SUCCEEDED(hr) && fFoundDefault)
 - {
 - *ppSharedRecognizerToken = cpToken.Detach();
 - break;
 - }
 - }
 - }
 - // If there's no engine that directly matches the locale see if the backup list of SupportedLocales is matched.
 - if (!fFoundDefault && (SUCCEEDED(hr) || hr == SPERR_NOT_FOUND) &&
 - PRIMARYLANGID(UIlangID) == PRIMARYLANGID(localeID))
 - {
 - // See if there's an engine which has a supported Locale matches the current locale.
 - // For example if the langid is U.S English, but the locale is Australian English
 - // there may be no recognizer that directly supports Australian English,
 - // but a U.K. recognizer might specify it can be used in the Australian English locale with this attribute.
 - hr = S_OK;
 - WCHAR pszSupportedLocalesString[] = L"SupportedLocales=XXXXXXXX";
 - SpHexFromUlong(pszSupportedLocalesString + wcslen(pszSupportedLocalesString) - 8, localeID);
 - for (ULONG ul = 0; SUCCEEDED(hr) && ul < ulRecognizers; ul++)
 - {
 - CComPtr<ISpObjectToken> cpToken;
 - hr = cpEnum->Item(ul, &cpToken);
 - if (SUCCEEDED(hr))
 - {
 - hr = cpToken->MatchesAttributes(pszSupportedLocalesString, &fFoundDefault);
 - }
 - if (SUCCEEDED(hr) && fFoundDefault)
 - {
 - *ppSharedRecognizerToken = cpToken.Detach();
 - break;
 - }
 - }
 - }
 - // We still haven't found a match - just pick the first recognizer.
 - if (!fFoundDefault && (SUCCEEDED(hr) || hr == SPERR_NOT_FOUND))
 - {
 - CComPtr<ISpObjectToken> cpToken;
 - hr = cpEnum->Item(0, ppSharedRecognizerToken);
 - }
 - }
 - }
 - return hr;
 - }
 - // Return a token enumerator containing all tokens that match the primary language
 - // of a particular language id. pszRequiredAttributes can be used to specify additional attributes all tokens must have.
 - HRESULT SpEnumTokensMatchingPrimaryLangID(const LPCWSTR pszCategoryId, LANGID priLangID, LPCWSTR pszRequiredAtts,
 - IEnumSpObjectTokens **ppEnum)
 - {
 - HRESULT hr = S_OK;
 - // First enumerate the tokens using pszRequiredAtts.
 - CComPtr<ISpObjectTokenCategory> cpCategory;
 - hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
 - CComPtr<IEnumSpObjectTokens> cpEnum;
 - if (SUCCEEDED(hr))
 - {
 - hr = cpCategory->EnumTokens(pszRequiredAtts, NULL, &cpEnum);
 - }
 - ULONG ulTokens(0);
 - if (SUCCEEDED(hr))
 - {
 - hr = cpEnum->GetCount(&ulTokens);
 - }
 - // Create enumerator to store new tokens.
 - CComPtr<ISpObjectTokenEnumBuilder> cpBuilder;
 - if (SUCCEEDED(hr))
 - {
 - hr = cpBuilder.CoCreateInstance(CLSID_SpObjectTokenEnum);
 - }
 - if (SUCCEEDED(hr))
 - {
 - hr = cpBuilder->SetAttribs(NULL, NULL);
 - }
 - // Now, for each token, check language string to see if it matches.
 - for (ULONG ul = 0; SUCCEEDED(hr) && ul < ulTokens; ul++)
 - {
 - LANGID tokenLangID(0);
 - CComPtr<ISpObjectToken> cpToken;
 - hr = cpEnum->Item(ul, &cpToken);
 - if (SUCCEEDED(hr))
 - {
 - // Just look at the first language id
 - hr = SpGetLanguageFromToken(cpToken, &tokenLangID);
 - }
 - if (SUCCEEDED(hr) && PRIMARYLANGID(tokenLangID) == PRIMARYLANGID(priLangID))
 - {
 - // Add to builder
 - hr = cpBuilder->AddTokens(1, &(cpToken.p));
 - }
 - }
 - if (SUCCEEDED(hr))
 - {
 - hr = cpBuilder->Reset();
 - }
 - if (SUCCEEDED(hr))
 - {
 - *ppEnum = cpBuilder.Detach();
 - }
 - return hr;
 - }