1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdint>
17 #include <cstdio>
18
19 #include "kws_manager.h"
20
21 using namespace OHOS::AI;
22 using namespace OHOS::Audio;
23 using namespace OHOS::Media;
24
25 namespace KWS {
26 namespace {
27 const int32_t CONFIDENCE = 2662;
28 const int32_t MAX_CACHE_SIZE = 16000;
29 const int32_t SUCCESS = 0;
30 const int32_t CHANNEL_COUNT = 1;
31
32 using Capturer = std::shared_ptr<AudioCapturer>;
33 using Cache = std::shared_ptr<AudioCache>;
34 using Plugin = std::shared_ptr<KWSSdk>;
35
36 // Can not create KwsManager twice
37 std::shared_ptr<std::thread> g_producer = nullptr;
38 std::shared_ptr<std::thread> g_consumer = nullptr;
__anon61e25a810202(uint8_t *array) 39 const auto DELETE_ARRAY = [](uint8_t *array) {
40 if (array != nullptr) {
41 delete[] array;
42 }
43 };
44 }
45
46 class MyKwsCallback : public KWSCallback {
47 public:
MyKwsCallback()48 MyKwsCallback() {}
~MyKwsCallback()49 ~MyKwsCallback() {}
50
OnError(int32_t errorCode)51 void OnError(int32_t errorCode)
52 {
53 printf("Executing error, error code: %d\n", errorCode);
54 }
55
OnResult(const Array<int32_t> & result)56 void OnResult(const Array<int32_t> &result)
57 {
58 if (result.size != WORD_CONTENT.size()) {
59 return;
60 }
61 for (size_t i = 0; i < result.size; ++i) {
62 if (result.data[i] > CONFIDENCE) {
63 printf("[%s]\n", WORD_CONTENT[i].c_str());
64 }
65 }
66 }
67 };
68
AudioProducer(KwsManager * kwsManager)69 void ThreadTask::AudioProducer(KwsManager *kwsManager)
70 {
71 kwsManager->ProduceSamples();
72 }
73
AudioConsumer(KwsManager * kwsManager)74 void ThreadTask::AudioConsumer(KwsManager *kwsManager)
75 {
76 kwsManager->ConsumeSamples();
77 }
78
KwsManager(int32_t sampleRate,int32_t bitRate)79 KwsManager::KwsManager(int32_t sampleRate, int32_t bitRate)
80 : sampleRate_(sampleRate), bitRate_(bitRate)
81 {
82 status_ = IDLE;
83 }
84
~KwsManager()85 KwsManager::~KwsManager()
86 {
87 OnStop();
88 status_ = IDLE;
89 }
90
ProduceSamples()91 void KwsManager::ProduceSamples()
92 {
93 printf("[KwsManager]ProduceSamples start\n");
94 if (capturer_ == nullptr || cache_ == nullptr || aacHandler_ == -1) {
95 printf("[KwsManager]Produce AudioSample failed for nullptr\n");
96 return;
97 }
98 int32_t readLen = 0;
99 int32_t retCode = SUCCESS;
100 size_t frameSize = capturer_->GetFrameCount() * sizeof(uint16_t);
101 if (frameSize <= 0) {
102 printf("[KwsManager]Capturer get frame count failed.\n");
103 return;
104 }
105 CoderStream aacStream = {
106 .buffer = new (std::nothrow) uint8_t[frameSize],
107 .size = frameSize
108 };
109 CoderStream pcmStream = {
110 .buffer = new (std::nothrow) uint8_t[frameSize],
111 .size = frameSize
112 };
113 if (aacStream.buffer == nullptr || pcmStream.buffer == nullptr) {
114 printf("[KwsManager]Allocate buffer for aacStream and pcmStream failed.\n");
115 DELETE_ARRAY(aacStream.buffer);
116 DELETE_ARRAY(pcmStream.buffer);
117 return;
118 }
119 while (status_ == RUNNING) {
120 {
121 std::lock_guard<std::mutex> lock(mutex_);
122 if (capturer_ == nullptr) {
123 break;
124 }
125 readLen = capturer_->Read(aacStream.buffer, frameSize, false);
126 }
127 if (readLen <= 0 || readLen > static_cast<int32_t>(frameSize)) {
128 continue;
129 }
130 aacStream.size = readLen;
131 retCode = AudioWrapper::GetInstance().Convert(aacHandler_, aacStream, pcmStream);
132 if (retCode != SUCCESS) {
133 continue;
134 }
135 {
136 std::lock_guard<std::mutex> lock(mutex_);
137 if (cache_ == nullptr) {
138 break;
139 }
140 if (!cache_->AppendBuffer(pcmStream.size, pcmStream.buffer)) {
141 printf("[KwsManager]Fail to append pcm into cache.\n");
142 }
143 }
144 }
145 DELETE_ARRAY(aacStream.buffer);
146 DELETE_ARRAY(pcmStream.buffer);
147 }
148
ConsumeSamples()149 void KwsManager::ConsumeSamples()
150 {
151 uintptr_t sampleAddr = 0;
152 size_t sampleSize = 0;
153 int32_t retCode = SUCCESS;
154 while (status_ == RUNNING) {
155 {
156 std::lock_guard<std::mutex> lock(mutex_);
157 if (cache_ == nullptr) {
158 printf("[KwsManager]cache_ is nullptr\n");
159 break;
160 }
161 sampleSize = cache_->GetCapturedBuffer(sampleAddr);
162 }
163 if (sampleSize == 0 || sampleAddr == 0) {
164 continue;
165 }
166 Array<int16_t> input = {
167 .data = (int16_t *)sampleAddr,
168 .size = sampleSize >> 1
169 };
170 {
171 std::lock_guard<std::mutex> lock(mutex_);
172 if (plugin_ == nullptr) {
173 printf("[KwsManager]cache_ is nullptr\n");
174 break;
175 }
176 if ((retCode = plugin_->SyncExecute(input)) != SUCCESS) {
177 printf("[KwsManager]SyncExecute KWS failed with retcode = [%d]\n", retCode);
178 continue;
179 }
180 }
181 }
182 }
183
Prepare()184 bool KwsManager::Prepare()
185 {
186 printf("[KwsManager]Prepare.\n");
187 if (status_ != IDLE) {
188 printf("[KwsManager]Already prepared.\n");
189 return false;
190 }
191 if (!PreparedAudioCapturer()) {
192 printf("[KwsManager]Fail to prepare AudioCapturer!\n");
193 OnStop();
194 return false;
195 }
196 if (!PreparedAudioWrapper()) {
197 printf("[KwsManager]Fail to prepare AudioWrapper!\n");
198 OnStop();
199 return false;
200 }
201 if (!PreparedInference()) {
202 printf("[KwsManager]Fail to prepare Inference!\n");
203 OnStop();
204 return false;
205 }
206 status_ = PREPARED;
207 return true;
208 }
209
Start()210 void KwsManager::Start()
211 {
212 printf("[KwsManager]Start.\n");
213 if (status_ == RUNNING) {
214 printf("[KwsManager]Already running.\n");
215 return;
216 }
217 if (status_ != PREPARED && !Prepare()) {
218 printf("[KwsManager]Fail to prepare KwsManager!\n");
219 return;
220 }
221 OnStart();
222 }
223
Stop()224 void KwsManager::Stop()
225 {
226 printf("[KwsManager]Stop.\n");
227 if (status_ == IDLE) {
228 printf("[KwsManager]Is already stopped.\n");
229 return;
230 }
231 std::lock_guard<std::mutex> lock(mutex_);
232 status_ = IDLE;
233 OnStop();
234 }
235
OnStart()236 void KwsManager::OnStart()
237 {
238 if (!capturer_->Start()) {
239 printf("[KwsManager]Fail to start audioCapturer\n");
240 OnStop();
241 return;
242 }
243 if (aacHandler_ == -1) {
244 printf("[KwsManager]Fail to start producer for the illegal aac-to-pcm handler\n");
245 OnStop();
246 return;
247 }
248 if (cache_ == nullptr) {
249 printf("[KwsManager]Fail to start producer for the nullptr cache\n");
250 OnStop();
251 return;
252 }
253 if (plugin_ == nullptr) {
254 printf("[KwsManager]Fail to start producer for the nullptr plugin\n");
255 OnStop();
256 return;
257 }
258 status_ = RUNNING;
259 g_producer = std::make_shared<std::thread>(ThreadTask::AudioProducer, this);
260 g_consumer = std::make_shared<std::thread>(ThreadTask::AudioConsumer, this);
261 }
262
StopAudioCapturer()263 void KwsManager::StopAudioCapturer()
264 {
265 printf("[KwsManager]StopAudioCapturer\n");
266 if (capturer_ != nullptr) {
267 capturer_->Stop();
268 capturer_ = nullptr;
269 }
270 }
271
StopAudioWrapper()272 void KwsManager::StopAudioWrapper()
273 {
274 printf("[KwsManager]StopAudioWrapper\n");
275 AudioWrapper::GetInstance().Deinit(aacHandler_);
276 }
277
StopInference()278 void KwsManager::StopInference()
279 {
280 printf("[KwsManager]StopInference\n");
281 if (plugin_ != nullptr) {
282 int32_t ret = plugin_->Destroy();
283 if (ret != SUCCESS) {
284 printf("[KwsManager]plugin_ destroy failed.\n");
285 }
286 plugin_ = nullptr;
287 }
288 }
289
OnStop()290 void KwsManager::OnStop()
291 {
292 if (capturer_ != nullptr) {
293 StopAudioCapturer();
294 }
295 StopAudioWrapper();
296 if (plugin_ != nullptr) {
297 StopInference();
298 }
299 if (g_producer != nullptr) {
300 g_producer->join();
301 }
302 if (g_consumer != nullptr) {
303 g_consumer->join();
304 }
305 }
306
PreparedAudioCapturer()307 bool KwsManager::PreparedAudioCapturer()
308 {
309 // Set audio wrapper mode before build audio capturer
310 AudioWrapper::GetInstance().SetCodecMode(false);
311 if (capturer_ != nullptr) {
312 printf("[KwsManager]Stop created AudioCapturer at first\n");
313 StopAudioCapturer();
314 }
315 capturer_ = std::make_shared<AudioCapturer>();
316 if (capturer_ == nullptr || !ConfiguredAudioCapturer()) {
317 printf("[KwsManager]Fail to create AudioCapturer.\n");
318 OnStop();
319 return false;
320 }
321 return true;
322 }
323
PreparedAudioWrapper()324 bool KwsManager::PreparedAudioWrapper()
325 {
326 cache_ = std::make_shared<AudioCache>();
327 if (cache_ == nullptr) {
328 printf("[KwsManager]Failed to create AudioCache\n");
329 return false;
330 }
331 if (!cache_->Init(MAX_CACHE_SIZE)) {
332 printf("[KwsManager]Failed to init AudioCache\n");
333 return false;
334 }
335 if (!ConfiguredAudioWrapper()) {
336 printf("[KwsManager]Failed to prepared AudioWrapper.\n");
337 OnStop();
338 return false;
339 }
340 return true;
341 }
342
PreparedInference()343 bool KwsManager::PreparedInference()
344 {
345 if (capturer_ == nullptr) {
346 printf("[KwsManager]Only load plugin after AudioCapturer ready.\n");
347 return false;
348 }
349 if (plugin_ != nullptr) {
350 printf("[KwsManager]Stop created Inference Plugin at first.\n");
351 StopInference();
352 }
353 plugin_ = std::make_shared<KWSSdk>();
354 if (plugin_ == nullptr) {
355 printf("[KwsManager]Failed to create InferencePlugin.\n");
356 return false;
357 }
358 if (plugin_->Create() != SUCCESS) {
359 printf("[KwsManager]Failed to create KWSSDK.\n");
360 return false;
361 }
362 std::shared_ptr<KWSCallback> callback = std::make_shared<MyKwsCallback>();
363 if (callback == nullptr) {
364 printf("[KwsManager]Create callback failed.\n");
365 return false;
366 }
367 plugin_->SetCallback(callback);
368 return true;
369 }
370
ConfiguredAudioCapturer()371 bool KwsManager::ConfiguredAudioCapturer()
372 {
373 AudioCapturerInfo audioConfig;
374 audioConfig.inputSource = AUDIO_MIC;
375 audioConfig.audioFormat = AAC_LC;
376 audioConfig.sampleRate = AUDIO_SAMPLE_RATE;
377 audioConfig.channelCount = CHANNEL_COUNT;
378 audioConfig.bitRate = AUDIO_CODEC_BITRATE;
379 audioConfig.streamType = TYPE_MEDIA;
380 audioConfig.bitWidth = BIT_WIDTH_16;
381 int32_t ret = capturer_->SetCapturerInfo(audioConfig);
382 if (ret != SUCCESS) {
383 printf("[KwsManager]ConfiguredAudioCapturer fail with ret = 0x%.8x\n", ret);
384 return false;
385 }
386 return true;
387 }
388
ConfiguredAudioWrapper()389 bool KwsManager::ConfiguredAudioWrapper()
390 {
391 ConvertType typo = CONVERT_AAC_TO_PCM;
392 CoderConfig codecConfig;
393 codecConfig.audioFormat = AAC_LC;
394 codecConfig.bitRate = bitRate_;
395 codecConfig.sampleRate = sampleRate_;
396 codecConfig.channelCount = CHANNEL_COUNT;
397 codecConfig.bitWidth = BIT_WIDTH_16;
398 if (AudioWrapper::GetInstance().Init(typo, aacHandler_) != SUCCESS) {
399 return false;
400 }
401 if (AudioWrapper::GetInstance().SetConfig(aacHandler_, codecConfig) != SUCCESS) {
402 return false;
403 }
404 if (AudioWrapper::GetInstance().StartCodec(aacHandler_) != SUCCESS) {
405 return false;
406 }
407 return true;
408 }
409 }