Fangjun Kuang
Committed by GitHub

Add keyword spotter C API for HarmonyOS (#1769)

@@ -16,6 +16,16 @@ SherpaOnnxOnlineModelConfig GetOnlineModelConfig(Napi::Object obj); @@ -16,6 +16,16 @@ SherpaOnnxOnlineModelConfig GetOnlineModelConfig(Napi::Object obj);
16 static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper( 16 static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper(
17 const Napi::CallbackInfo &info) { 17 const Napi::CallbackInfo &info) {
18 Napi::Env env = info.Env(); 18 Napi::Env env = info.Env();
  19 +#if __OHOS__
  20 + if (info.Length() != 2) {
  21 + std::ostringstream os;
  22 + os << "Expect only 2 arguments. Given: " << info.Length();
  23 +
  24 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  25 +
  26 + return {};
  27 + }
  28 +#else
19 if (info.Length() != 1) { 29 if (info.Length() != 1) {
20 std::ostringstream os; 30 std::ostringstream os;
21 os << "Expect only 1 argument. Given: " << info.Length(); 31 os << "Expect only 1 argument. Given: " << info.Length();
@@ -24,7 +34,7 @@ static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper( @@ -24,7 +34,7 @@ static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper(
24 34
25 return {}; 35 return {};
26 } 36 }
27 - 37 +#endif
28 if (!info[0].IsObject()) { 38 if (!info[0].IsObject()) {
29 Napi::TypeError::New(env, "Expect an object as the argument") 39 Napi::TypeError::New(env, "Expect an object as the argument")
30 .ThrowAsJavaScriptException(); 40 .ThrowAsJavaScriptException();
@@ -46,7 +56,18 @@ static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper( @@ -46,7 +56,18 @@ static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper(
46 SHERPA_ONNX_ASSIGN_ATTR_STR(keywords_buf, keywordsBuf); 56 SHERPA_ONNX_ASSIGN_ATTR_STR(keywords_buf, keywordsBuf);
47 SHERPA_ONNX_ASSIGN_ATTR_INT32(keywords_buf_size, keywordsBufSize); 57 SHERPA_ONNX_ASSIGN_ATTR_INT32(keywords_buf_size, keywordsBufSize);
48 58
  59 +#if __OHOS__
  60 + std::unique_ptr<NativeResourceManager,
  61 + decltype(&OH_ResourceManager_ReleaseNativeResourceManager)>
  62 + mgr(OH_ResourceManager_InitNativeResourceManager(env, info[1]),
  63 + &OH_ResourceManager_ReleaseNativeResourceManager);
  64 +
  65 + const SherpaOnnxKeywordSpotter *kws =
  66 + SherpaOnnxCreateKeywordSpotterOHOS(&c, mgr.get());
  67 +#else
49 const SherpaOnnxKeywordSpotter *kws = SherpaOnnxCreateKeywordSpotter(&c); 68 const SherpaOnnxKeywordSpotter *kws = SherpaOnnxCreateKeywordSpotter(&c);
  69 +#endif
  70 +
50 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.encoder); 71 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.encoder);
51 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.decoder); 72 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.decoder);
52 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.joiner); 73 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.joiner);
@@ -79,9 +100,9 @@ static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper( @@ -79,9 +100,9 @@ static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper(
79 static Napi::External<SherpaOnnxOnlineStream> CreateKeywordStreamWrapper( 100 static Napi::External<SherpaOnnxOnlineStream> CreateKeywordStreamWrapper(
80 const Napi::CallbackInfo &info) { 101 const Napi::CallbackInfo &info) {
81 Napi::Env env = info.Env(); 102 Napi::Env env = info.Env();
82 - if (info.Length() != 1) { 103 + if (info.Length() != 1 && info.Length() != 2) {
83 std::ostringstream os; 104 std::ostringstream os;
84 - os << "Expect only 1 argument. Given: " << info.Length(); 105 + os << "Expect only 1 or 2 arguments. Given: " << info.Length();
85 106
86 Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException(); 107 Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
87 108
@@ -96,10 +117,24 @@ static Napi::External<SherpaOnnxOnlineStream> CreateKeywordStreamWrapper( @@ -96,10 +117,24 @@ static Napi::External<SherpaOnnxOnlineStream> CreateKeywordStreamWrapper(
96 return {}; 117 return {};
97 } 118 }
98 119
  120 + if (info.Length() == 2 && !info[1].IsString()) {
  121 + std::ostringstream os;
  122 + os << "Argument 2 should be a string.";
  123 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  124 + return {};
  125 + }
  126 +
99 const SherpaOnnxKeywordSpotter *kws = 127 const SherpaOnnxKeywordSpotter *kws =
100 info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data(); 128 info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
101 129
102 - const SherpaOnnxOnlineStream *stream = SherpaOnnxCreateKeywordStream(kws); 130 + const SherpaOnnxOnlineStream *stream;
  131 + if (info.Length() == 1) {
  132 + stream = SherpaOnnxCreateKeywordStream(kws);
  133 + } else {
  134 + Napi::String js_keywords = info[1].As<Napi::String>();
  135 + std::string keywords = js_keywords.Utf8Value();
  136 + stream = SherpaOnnxCreateKeywordStreamWithKeywords(kws, keywords.c_str());
  137 + }
103 138
104 return Napi::External<SherpaOnnxOnlineStream>::New( 139 return Napi::External<SherpaOnnxOnlineStream>::New(
105 env, const_cast<SherpaOnnxOnlineStream *>(stream), 140 env, const_cast<SherpaOnnxOnlineStream *>(stream),
@@ -678,7 +678,7 @@ struct SherpaOnnxKeywordSpotter { @@ -678,7 +678,7 @@ struct SherpaOnnxKeywordSpotter {
678 std::unique_ptr<sherpa_onnx::KeywordSpotter> impl; 678 std::unique_ptr<sherpa_onnx::KeywordSpotter> impl;
679 }; 679 };
680 680
681 -const SherpaOnnxKeywordSpotter *SherpaOnnxCreateKeywordSpotter( 681 +static sherpa_onnx::KeywordSpotterConfig GetKeywordSpotterConfig(
682 const SherpaOnnxKeywordSpotterConfig *config) { 682 const SherpaOnnxKeywordSpotterConfig *config) {
683 sherpa_onnx::KeywordSpotterConfig spotter_config; 683 sherpa_onnx::KeywordSpotterConfig spotter_config;
684 684
@@ -739,10 +739,20 @@ const SherpaOnnxKeywordSpotter *SherpaOnnxCreateKeywordSpotter( @@ -739,10 +739,20 @@ const SherpaOnnxKeywordSpotter *SherpaOnnxCreateKeywordSpotter(
739 std::string(config->keywords_buf, config->keywords_buf_size); 739 std::string(config->keywords_buf, config->keywords_buf_size);
740 } 740 }
741 741
742 - if (config->model_config.debug) { 742 + if (spotter_config.model_config.debug) {
  743 +#if OHOS
  744 + SHERPA_ONNX_LOGE("%{public}s\n", spotter_config.ToString().c_str());
  745 +#else
743 SHERPA_ONNX_LOGE("%s\n", spotter_config.ToString().c_str()); 746 SHERPA_ONNX_LOGE("%s\n", spotter_config.ToString().c_str());
  747 +#endif
744 } 748 }
745 749
  750 + return spotter_config;
  751 +}
  752 +
  753 +const SherpaOnnxKeywordSpotter *SherpaOnnxCreateKeywordSpotter(
  754 + const SherpaOnnxKeywordSpotterConfig *config) {
  755 + auto spotter_config = GetKeywordSpotterConfig(config);
746 if (!spotter_config.Validate()) { 756 if (!spotter_config.Validate()) {
747 SHERPA_ONNX_LOGE("Errors in config!"); 757 SHERPA_ONNX_LOGE("Errors in config!");
748 return nullptr; 758 return nullptr;
@@ -2272,6 +2282,22 @@ SherpaOnnxCreateSpeakerEmbeddingExtractorOHOS( @@ -2272,6 +2282,22 @@ SherpaOnnxCreateSpeakerEmbeddingExtractorOHOS(
2272 return p; 2282 return p;
2273 } 2283 }
2274 2284
  2285 +const SherpaOnnxKeywordSpotter *SherpaOnnxCreateKeywordSpotterOHOS(
  2286 + const SherpaOnnxKeywordSpotterConfig *config, NativeResourceManager *mgr) {
  2287 + if (!mgr) {
  2288 + return SherpaOnnxCreateKeywordSpotter(config);
  2289 + }
  2290 +
  2291 + auto spotter_config = GetKeywordSpotterConfig(config);
  2292 +
  2293 + SherpaOnnxKeywordSpotter *spotter = new SherpaOnnxKeywordSpotter;
  2294 +
  2295 + spotter->impl =
  2296 + std::make_unique<sherpa_onnx::KeywordSpotter>(mgr, spotter_config);
  2297 +
  2298 + return spotter;
  2299 +}
  2300 +
2275 #if SHERPA_ONNX_ENABLE_TTS == 1 2301 #if SHERPA_ONNX_ENABLE_TTS == 1
2276 const SherpaOnnxOfflineTts *SherpaOnnxCreateOfflineTtsOHOS( 2302 const SherpaOnnxOfflineTts *SherpaOnnxCreateOfflineTtsOHOS(
2277 const SherpaOnnxOfflineTtsConfig *config, NativeResourceManager *mgr) { 2303 const SherpaOnnxOfflineTtsConfig *config, NativeResourceManager *mgr) {
@@ -1645,6 +1645,10 @@ SherpaOnnxCreateSpeakerEmbeddingExtractorOHOS( @@ -1645,6 +1645,10 @@ SherpaOnnxCreateSpeakerEmbeddingExtractorOHOS(
1645 const SherpaOnnxSpeakerEmbeddingExtractorConfig *config, 1645 const SherpaOnnxSpeakerEmbeddingExtractorConfig *config,
1646 NativeResourceManager *mgr); 1646 NativeResourceManager *mgr);
1647 1647
  1648 +SHERPA_ONNX_API const SherpaOnnxKeywordSpotter *
  1649 +SherpaOnnxCreateKeywordSpotterOHOS(const SherpaOnnxKeywordSpotterConfig *config,
  1650 + NativeResourceManager *mgr);
  1651 +
1648 SHERPA_ONNX_API const SherpaOnnxOfflineSpeakerDiarization * 1652 SHERPA_ONNX_API const SherpaOnnxOfflineSpeakerDiarization *
1649 SherpaOnnxCreateOfflineSpeakerDiarizationOHOS( 1653 SherpaOnnxCreateOfflineSpeakerDiarizationOHOS(
1650 const SherpaOnnxOfflineSpeakerDiarizationConfig *config, 1654 const SherpaOnnxOfflineSpeakerDiarizationConfig *config,
@@ -6,6 +6,15 @@ @@ -6,6 +6,15 @@
6 6
7 #include "sherpa-onnx/csrc/keyword-spotter-transducer-impl.h" 7 #include "sherpa-onnx/csrc/keyword-spotter-transducer-impl.h"
8 8
  9 +#if __ANDROID_API__ >= 9
  10 +#include "android/asset_manager.h"
  11 +#include "android/asset_manager_jni.h"
  12 +#endif
  13 +
  14 +#if __OHOS__
  15 +#include "rawfile/raw_file_manager.h"
  16 +#endif
  17 +
9 namespace sherpa_onnx { 18 namespace sherpa_onnx {
10 19
11 std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create( 20 std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create(
@@ -18,9 +27,9 @@ std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create( @@ -18,9 +27,9 @@ std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create(
18 exit(-1); 27 exit(-1);
19 } 28 }
20 29
21 -#if __ANDROID_API__ >= 9 30 +template <typename Manager>
22 std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create( 31 std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create(
23 - AAssetManager *mgr, const KeywordSpotterConfig &config) { 32 + Manager *mgr, const KeywordSpotterConfig &config) {
24 if (!config.model_config.transducer.encoder.empty()) { 33 if (!config.model_config.transducer.encoder.empty()) {
25 return std::make_unique<KeywordSpotterTransducerImpl>(mgr, config); 34 return std::make_unique<KeywordSpotterTransducerImpl>(mgr, config);
26 } 35 }
@@ -28,6 +37,15 @@ std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create( @@ -28,6 +37,15 @@ std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create(
28 SHERPA_ONNX_LOGE("Please specify a model"); 37 SHERPA_ONNX_LOGE("Please specify a model");
29 exit(-1); 38 exit(-1);
30 } 39 }
  40 +
  41 +#if __ANDROID_API__ >= 9
  42 +template std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create(
  43 + AAssetManager *mgr, const KeywordSpotterConfig &config);
  44 +#endif
  45 +
  46 +#if __OHOS__
  47 +template std::unique_ptr<KeywordSpotterImpl> KeywordSpotterImpl::Create(
  48 + NativeResourceManager *mgr, const KeywordSpotterConfig &config);
31 #endif 49 #endif
32 50
33 } // namespace sherpa_onnx 51 } // namespace sherpa_onnx
@@ -9,11 +9,6 @@ @@ -9,11 +9,6 @@
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
11 11
12 -#if __ANDROID_API__ >= 9  
13 -#include "android/asset_manager.h"  
14 -#include "android/asset_manager_jni.h"  
15 -#endif  
16 -  
17 #include "sherpa-onnx/csrc/keyword-spotter.h" 12 #include "sherpa-onnx/csrc/keyword-spotter.h"
18 #include "sherpa-onnx/csrc/online-stream.h" 13 #include "sherpa-onnx/csrc/online-stream.h"
19 14
@@ -24,10 +19,9 @@ class KeywordSpotterImpl { @@ -24,10 +19,9 @@ class KeywordSpotterImpl {
24 static std::unique_ptr<KeywordSpotterImpl> Create( 19 static std::unique_ptr<KeywordSpotterImpl> Create(
25 const KeywordSpotterConfig &config); 20 const KeywordSpotterConfig &config);
26 21
27 -#if __ANDROID_API__ >= 9 22 + template <typename Manager>
28 static std::unique_ptr<KeywordSpotterImpl> Create( 23 static std::unique_ptr<KeywordSpotterImpl> Create(
29 - AAssetManager *mgr, const KeywordSpotterConfig &config);  
30 -#endif 24 + Manager *mgr, const KeywordSpotterConfig &config);
31 25
32 virtual ~KeywordSpotterImpl() = default; 26 virtual ~KeywordSpotterImpl() = default;
33 27
@@ -9,16 +9,10 @@ @@ -9,16 +9,10 @@
9 #include <memory> 9 #include <memory>
10 #include <regex> // NOLINT 10 #include <regex> // NOLINT
11 #include <string> 11 #include <string>
  12 +#include <strstream>
12 #include <utility> 13 #include <utility>
13 #include <vector> 14 #include <vector>
14 15
15 -#if __ANDROID_API__ >= 9  
16 -#include <strstream>  
17 -  
18 -#include "android/asset_manager.h"  
19 -#include "android/asset_manager_jni.h"  
20 -#endif  
21 -  
22 #include "sherpa-onnx/csrc/file-utils.h" 16 #include "sherpa-onnx/csrc/file-utils.h"
23 #include "sherpa-onnx/csrc/keyword-spotter-impl.h" 17 #include "sherpa-onnx/csrc/keyword-spotter-impl.h"
24 #include "sherpa-onnx/csrc/keyword-spotter.h" 18 #include "sherpa-onnx/csrc/keyword-spotter.h"
@@ -91,9 +85,8 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl { @@ -91,9 +85,8 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl {
91 unk_id_); 85 unk_id_);
92 } 86 }
93 87
94 -#if __ANDROID_API__ >= 9  
95 - KeywordSpotterTransducerImpl(AAssetManager *mgr,  
96 - const KeywordSpotterConfig &config) 88 + template <typename Manager>
  89 + KeywordSpotterTransducerImpl(Manager *mgr, const KeywordSpotterConfig &config)
97 : config_(config), 90 : config_(config),
98 model_(OnlineTransducerModel::Create(mgr, config.model_config)), 91 model_(OnlineTransducerModel::Create(mgr, config.model_config)),
99 sym_(mgr, config.model_config.tokens) { 92 sym_(mgr, config.model_config.tokens) {
@@ -109,7 +102,6 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl { @@ -109,7 +102,6 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl {
109 model_.get(), config_.max_active_paths, config_.num_trailing_blanks, 102 model_.get(), config_.max_active_paths, config_.num_trailing_blanks,
110 unk_id_); 103 unk_id_);
111 } 104 }
112 -#endif  
113 105
114 std::unique_ptr<OnlineStream> CreateStream() const override { 106 std::unique_ptr<OnlineStream> CreateStream() const override {
115 auto stream = 107 auto stream =
@@ -130,7 +122,11 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl { @@ -130,7 +122,11 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl {
130 122
131 if (!EncodeKeywords(is, sym_, &current_ids, &current_kws, &current_scores, 123 if (!EncodeKeywords(is, sym_, &current_ids, &current_kws, &current_scores,
132 &current_thresholds)) { 124 &current_thresholds)) {
  125 +#if __OHOS__
  126 + SHERPA_ONNX_LOGE("Encode keywords %{public}s failed.", keywords.c_str());
  127 +#else
133 SHERPA_ONNX_LOGE("Encode keywords %s failed.", keywords.c_str()); 128 SHERPA_ONNX_LOGE("Encode keywords %s failed.", keywords.c_str());
  129 +#endif
134 return nullptr; 130 return nullptr;
135 } 131 }
136 132
@@ -306,16 +302,21 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl { @@ -306,16 +302,21 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl {
306 // each line in keywords_file contains space-separated words 302 // each line in keywords_file contains space-separated words
307 std::ifstream is(config_.keywords_file); 303 std::ifstream is(config_.keywords_file);
308 if (!is) { 304 if (!is) {
  305 +#if __OHOS__
  306 + SHERPA_ONNX_LOGE("Open keywords file failed: %{public}s",
  307 + config_.keywords_file.c_str());
  308 +#else
309 SHERPA_ONNX_LOGE("Open keywords file failed: %s", 309 SHERPA_ONNX_LOGE("Open keywords file failed: %s",
310 config_.keywords_file.c_str()); 310 config_.keywords_file.c_str());
  311 +#endif
311 exit(-1); 312 exit(-1);
312 } 313 }
313 InitKeywords(is); 314 InitKeywords(is);
314 #endif 315 #endif
315 } 316 }
316 317
317 -#if __ANDROID_API__ >= 9  
318 - void InitKeywords(AAssetManager *mgr) { 318 + template <typename Manager>
  319 + void InitKeywords(Manager *mgr) {
319 // each line in keywords_file contains space-separated words 320 // each line in keywords_file contains space-separated words
320 321
321 auto buf = ReadFile(mgr, config_.keywords_file); 322 auto buf = ReadFile(mgr, config_.keywords_file);
@@ -323,13 +324,17 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl { @@ -323,13 +324,17 @@ class KeywordSpotterTransducerImpl : public KeywordSpotterImpl {
323 std::istrstream is(buf.data(), buf.size()); 324 std::istrstream is(buf.data(), buf.size());
324 325
325 if (!is) { 326 if (!is) {
  327 +#if __OHOS__
  328 + SHERPA_ONNX_LOGE("Open keywords file failed: %{public}s",
  329 + config_.keywords_file.c_str());
  330 +#else
326 SHERPA_ONNX_LOGE("Open keywords file failed: %s", 331 SHERPA_ONNX_LOGE("Open keywords file failed: %s",
327 config_.keywords_file.c_str()); 332 config_.keywords_file.c_str());
  333 +#endif
328 exit(-1); 334 exit(-1);
329 } 335 }
330 InitKeywords(is); 336 InitKeywords(is);
331 } 337 }
332 -#endif  
333 338
334 void InitKeywordsFromBufStr() { 339 void InitKeywordsFromBufStr() {
335 // keywords_buf's content is supposed to be same as the keywords_file's 340 // keywords_buf's content is supposed to be same as the keywords_file's
@@ -13,6 +13,15 @@ @@ -13,6 +13,15 @@
13 #include <utility> 13 #include <utility>
14 #include <vector> 14 #include <vector>
15 15
  16 +#if __ANDROID_API__ >= 9
  17 +#include "android/asset_manager.h"
  18 +#include "android/asset_manager_jni.h"
  19 +#endif
  20 +
  21 +#if __OHOS__
  22 +#include "rawfile/raw_file_manager.h"
  23 +#endif
  24 +
16 #include "sherpa-onnx/csrc/keyword-spotter-impl.h" 25 #include "sherpa-onnx/csrc/keyword-spotter-impl.h"
17 26
18 namespace sherpa_onnx { 27 namespace sherpa_onnx {
@@ -136,11 +145,9 @@ std::string KeywordSpotterConfig::ToString() const { @@ -136,11 +145,9 @@ std::string KeywordSpotterConfig::ToString() const {
136 KeywordSpotter::KeywordSpotter(const KeywordSpotterConfig &config) 145 KeywordSpotter::KeywordSpotter(const KeywordSpotterConfig &config)
137 : impl_(KeywordSpotterImpl::Create(config)) {} 146 : impl_(KeywordSpotterImpl::Create(config)) {}
138 147
139 -#if __ANDROID_API__ >= 9  
140 -KeywordSpotter::KeywordSpotter(AAssetManager *mgr,  
141 - const KeywordSpotterConfig &config) 148 +template <typename Manager>
  149 +KeywordSpotter::KeywordSpotter(Manager *mgr, const KeywordSpotterConfig &config)
142 : impl_(KeywordSpotterImpl::Create(mgr, config)) {} 150 : impl_(KeywordSpotterImpl::Create(mgr, config)) {}
143 -#endif  
144 151
145 KeywordSpotter::~KeywordSpotter() = default; 152 KeywordSpotter::~KeywordSpotter() = default;
146 153
@@ -167,4 +174,14 @@ KeywordResult KeywordSpotter::GetResult(OnlineStream *s) const { @@ -167,4 +174,14 @@ KeywordResult KeywordSpotter::GetResult(OnlineStream *s) const {
167 return impl_->GetResult(s); 174 return impl_->GetResult(s);
168 } 175 }
169 176
  177 +#if __ANDROID_API__ >= 9
  178 +template KeywordSpotter::KeywordSpotter(AAssetManager *mgr,
  179 + const KeywordSpotterConfig &config);
  180 +#endif
  181 +
  182 +#if __OHOS__
  183 +template KeywordSpotter::KeywordSpotter(NativeResourceManager *mgr,
  184 + const KeywordSpotterConfig &config);
  185 +#endif
  186 +
170 } // namespace sherpa_onnx 187 } // namespace sherpa_onnx
@@ -9,11 +9,6 @@ @@ -9,11 +9,6 @@
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
11 11
12 -#if __ANDROID_API__ >= 9  
13 -#include "android/asset_manager.h"  
14 -#include "android/asset_manager_jni.h"  
15 -#endif  
16 -  
17 #include "sherpa-onnx/csrc/features.h" 12 #include "sherpa-onnx/csrc/features.h"
18 #include "sherpa-onnx/csrc/online-model-config.h" 13 #include "sherpa-onnx/csrc/online-model-config.h"
19 #include "sherpa-onnx/csrc/online-stream.h" 14 #include "sherpa-onnx/csrc/online-stream.h"
@@ -101,9 +96,8 @@ class KeywordSpotter { @@ -101,9 +96,8 @@ class KeywordSpotter {
101 public: 96 public:
102 explicit KeywordSpotter(const KeywordSpotterConfig &config); 97 explicit KeywordSpotter(const KeywordSpotterConfig &config);
103 98
104 -#if __ANDROID_API__ >= 9  
105 - KeywordSpotter(AAssetManager *mgr, const KeywordSpotterConfig &config);  
106 -#endif 99 + template <typename Manager>
  100 + KeywordSpotter(Manager *mgr, const KeywordSpotterConfig &config);
107 101
108 ~KeywordSpotter(); 102 ~KeywordSpotter();
109 103