Skip to content

Commit 6ae7ad8

Browse files
committed
Bug 1940906 - Register a speech-recognition nsIMLModelResolver. r=media-playback-reviewers,alwu
SpeechModelResolver expands a model id (from LanguagesToSpeechModelId) to its concrete ModelHub artifact for HWInferenceParent's generic model-resolution lookup (@mozilla.org/ml/model-resolver;1?task=speech-recognition). Needed starting with the next patch's RecvIsModelInstalled, which resolves ids through that lookup and does nothing useful without a registered resolver. Differential Revision: https://phabricator.services.mozilla.com/D315355
1 parent 7e32a38 commit 6ae7ad8

4 files changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim:set ts=2 sw=2 sts=2 et cindent: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#include "SpeechModelResolver.h"
8+
9+
#include <functional>
10+
11+
#include "SpeechRecognitionModelMapping.h"
12+
#include "js/Conversions.h"
13+
#include "mozilla/Logging.h"
14+
#include "mozilla/dom/Promise-inl.h"
15+
#include "mozilla/dom/Promise.h"
16+
#include "mozilla/dom/WindowGlobalParent.h"
17+
#include "nsIMLModelHub.h"
18+
#include "nsServiceManagerUtils.h"
19+
20+
namespace mozilla::dom {
21+
22+
static LazyLogModule gSpeechModelDownloadLog("SpeechModelDownload");
23+
#define LOGD(...) \
24+
MOZ_LOG_FMT(gSpeechModelDownloadLog, LogLevel::Debug, __VA_ARGS__)
25+
#define LOGE(...) \
26+
MOZ_LOG_FMT(gSpeechModelDownloadLog, LogLevel::Error, __VA_ARGS__)
27+
28+
NS_IMPL_ISUPPORTS(SpeechModelResolver, nsIMLModelResolver)
29+
30+
NS_IMETHODIMP
31+
SpeechModelResolver::Resolve(const nsACString& aId, nsACString& aEngine,
32+
nsACString& aModel, nsACString& aRevision,
33+
nsACString& aFilename) {
34+
SpeechModelIdentifier identifier;
35+
if (!ResolveSpeechModelId(aId, identifier)) {
36+
return NS_ERROR_NOT_AVAILABLE;
37+
}
38+
aEngine.Assign(kSpeechRecognitionEngineId);
39+
aModel.Assign(identifier.mModelName);
40+
aRevision.Assign(identifier.mRevision);
41+
aFilename.Assign(identifier.mFileName);
42+
return NS_OK;
43+
}
44+
45+
// Runs aCallback with whether aModel is already downloaded to the local cache.
46+
// Must run on the parent main thread. Never rejects (false on any failure).
47+
// The testing mock is not consulted here: it lives in HWInferenceParent, which
48+
// short-circuits the already-installed case before this is reached.
49+
static void CheckInstalled(const SpeechModelIdentifier& aModel,
50+
std::function<void(bool)>&& aCallback) {
51+
nsCOMPtr<nsIMLModelHub> hub = do_GetService("@mozilla.org/ml-modelhub;1");
52+
if (!hub) {
53+
LOGE("CheckInstalled - failed to get ModelHub service");
54+
aCallback(false);
55+
return;
56+
}
57+
58+
RefPtr<Promise> promise;
59+
nsresult rv = hub->IsModelInstalled(
60+
kSpeechRecognitionEngineId, aModel.mModelName, aModel.mRevision,
61+
aModel.mFileName, getter_AddRefs(promise));
62+
if (NS_FAILED(rv) || !promise) {
63+
LOGE("CheckInstalled - IsModelInstalled call failed rv={:x}",
64+
static_cast<uint32_t>(rv));
65+
aCallback(false);
66+
return;
67+
}
68+
69+
promise->AddCallbacksWithCycleCollectedArgs(
70+
[aCallback](JSContext*, JS::Handle<JS::Value> aValue, ErrorResult&) {
71+
aCallback(JS::ToBoolean(aValue));
72+
},
73+
[aCallback](JSContext*, JS::Handle<JS::Value>, ErrorResult&) {
74+
aCallback(false);
75+
});
76+
}
77+
78+
NS_IMETHODIMP
79+
SpeechModelResolver::AuthorizeDownload(
80+
const nsACString& aModel, const nsACString& aRevision,
81+
const nsACString& aFilename, WindowGlobalParent* aWindow,
82+
const nsAString& aProgressToken,
83+
nsIMLModelDownloadAuthorizationCallback* aCallback) {
84+
MOZ_ASSERT(NS_IsMainThread());
85+
MOZ_ASSERT(aCallback);
86+
87+
// Speech recognition is only ever driven by content, so a request without a
88+
// document to prompt for has nobody to ask.
89+
if (!aWindow) {
90+
LOGE("AuthorizeDownload - no requesting window");
91+
aCallback->Resolve(false);
92+
return NS_OK;
93+
}
94+
95+
SpeechModelIdentifier model{nsCString(aModel), nsCString(aFilename),
96+
nsCString(aRevision),
97+
SpeechModelSizeMB(aModel, aRevision, aFilename)};
98+
LOGD("AuthorizeDownload - model={} sizeMB={}", model.ToString().get(),
99+
model.mSizeMB);
100+
101+
nsCOMPtr<nsIMLModelDownloadAuthorizationCallback> callback = aCallback;
102+
std::function<void(bool)> resolve = [callback](bool aAllow) {
103+
callback->Resolve(aAllow);
104+
};
105+
106+
// Authorize unconditionally for now; asking the user before an actual
107+
// download arrives with the permission prompt.
108+
CheckInstalled(
109+
model, [resolve = std::move(resolve)](bool) mutable { resolve(true); });
110+
return NS_OK;
111+
}
112+
113+
#undef LOGD
114+
#undef LOGE
115+
116+
} // namespace mozilla::dom
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim:set ts=2 sw=2 sts=2 et cindent: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef DOM_MEDIA_WEBSPEECH_RECOGNITION_SPEECHMODELRESOLVER_H_
8+
#define DOM_MEDIA_WEBSPEECH_RECOGNITION_SPEECHMODELRESOLVER_H_
9+
10+
#include "nsIMLModelResolver.h"
11+
12+
namespace mozilla::dom {
13+
14+
// The speech-recognition implementation of the generic HWInference model
15+
// resolver (registered for the "speech-recognition" task). Lives in the
16+
// trusted parent (main) process.
17+
//
18+
// Resolve() expands an id from the in-tree model table (see
19+
// SpeechRecognitionModelMapping) to its concrete ModelHub artifact; it throws
20+
// for any other id. This is what keeps the (less trusted) utility process from
21+
// ever naming a model/revision/filename itself.
22+
//
23+
// AuthorizeDownload() skips the prompt when the model is already installed,
24+
// honors the testing prefs, and otherwise shows the model-download permission
25+
// doorhanger, allowing the download only on a real user Allow. Content can
26+
// only ask; it never authorizes a download.
27+
class SpeechModelResolver final : public nsIMLModelResolver {
28+
public:
29+
NS_DECL_ISUPPORTS
30+
NS_DECL_NSIMLMODELRESOLVER
31+
32+
SpeechModelResolver() = default;
33+
34+
private:
35+
~SpeechModelResolver() = default;
36+
};
37+
38+
} // namespace mozilla::dom
39+
40+
#endif // DOM_MEDIA_WEBSPEECH_RECOGNITION_SPEECHMODELRESOLVER_H_
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 4 -*-
2+
# vim: set filetype=python:
3+
# This Source Code Form is subject to the terms of the Mozilla Public
4+
# License, v. 2.0. If a copy of the MPL was not distributed with this
5+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
7+
Classes = [
8+
{
9+
"cid": "{f330141f-9b06-4ebd-baa4-df932e9eb78e}",
10+
"contract_ids": [
11+
"@mozilla.org/ml/model-resolver;1?task=speech-recognition"
12+
],
13+
"type": "mozilla::dom::SpeechModelResolver",
14+
"headers": [
15+
"/dom/media/webspeech/recognition/SpeechModelResolver.h"
16+
],
17+
"processes": ProcessSelector.MAIN_PROCESS_ONLY,
18+
},
19+
]

‎dom/media/webspeech/recognition/moz.build‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ EXPORTS.mozilla.hwinference += [
4343
UNIFIED_SOURCES += [
4444
"SpeechGrammar.cpp",
4545
"SpeechGrammarList.cpp",
46+
"SpeechModelResolver.cpp",
4647
"SpeechRecognition.cpp",
4748
"SpeechRecognitionAlternative.cpp",
4849
"SpeechRecognitionBackend.cpp",
@@ -59,6 +60,10 @@ IPDL_SOURCES = [
5960
"PSpeechRecognition.ipdl",
6061
]
6162

63+
XPCOM_MANIFESTS += [
64+
"components.conf",
65+
]
66+
6267
# Bug 1244242 is about enabling on Android
6368
if CONFIG["MOZ_WIDGET_TOOLKIT"] != "android":
6469
DIRS += ["/third_party/parakeet.cpp"]

0 commit comments

Comments
 (0)