1 /*
2 * Copyright (c) 2024 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 #include "headset_wakeup_engine_impl.h"
16 #include "audio_system_manager.h"
17 #include "adapter_callback_service.h"
18 #include "intell_voice_log.h"
19 #include "history_info_mgr.h"
20 #include "intell_voice_util.h"
21 #include "intell_voice_engine_manager.h"
22 #include "headset_host_manager.h"
23 #include "headset_wakeup_wrapper.h"
24
25 #define LOG_TAG "HeadsetWakeupEngineImpl"
26
27 using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0;
28 using namespace OHOS::IntellVoiceUtils;
29 using namespace OHOS::AudioStandard;
30 using namespace std;
31
32 namespace OHOS {
33 namespace IntellVoiceEngine {
34 static constexpr int64_t RECOGNIZING_TIMEOUT_US = 10 * 1000 * 1000; //10s
35 static constexpr int64_t RECOGNIZE_COMPLETE_TIMEOUT_US = 2 * 1000 * 1000; //2s
36 static constexpr int64_t READ_CAPTURER_TIMEOUT_US = 10 * 1000 * 1000; //10s
37 static constexpr uint32_t MAX_HEADSET_TASK_NUM = 200;
38 static const std::string HEADSET_THREAD_NAME = "HeadsetThread";
39
HeadsetWakeupEngineImpl()40 HeadsetWakeupEngineImpl::HeadsetWakeupEngineImpl()
41 : ModuleStates(State(IDLE), "HeadsetWakeupEngineImpl"), TaskExecutor(HEADSET_THREAD_NAME, MAX_HEADSET_TASK_NUM)
42 {
43 }
44
~HeadsetWakeupEngineImpl()45 HeadsetWakeupEngineImpl::~HeadsetWakeupEngineImpl()
46 {
47 }
48
Init()49 bool HeadsetWakeupEngineImpl::Init()
50 {
51 if (!InitStates()) {
52 INTELL_VOICE_LOG_ERROR("init state failed");
53 return false;
54 }
55
56 adapterListener_ = std::make_shared<WakeupAdapterListener>(
57 std::bind(&HeadsetWakeupEngineImpl::OnWakeupEvent, this, std::placeholders::_1));
58 if (adapterListener_ == nullptr) {
59 INTELL_VOICE_LOG_ERROR("adapterListener_ is nullptr");
60 return false;
61 }
62
63 TaskExecutor::StartThread();
64 return true;
65 }
66
InitStates()67 bool HeadsetWakeupEngineImpl::InitStates()
68 {
69 for (int i = IDLE; i <= READ_CAPTURER; i++) {
70 ForState(State(i))
71 .ACT(SET_LISTENER, HandleSetListener)
72 .ACT(SET_PARAM, HandleSetParam);
73 }
74
75 ForState(IDLE)
76 .ACT(INIT, HandleInit)
77 .ACT(RESET_ADAPTER, HandleResetAdapter);
78
79 ForState(INITIALIZING)
80 .ACT(INIT_DONE, HandleInitDone);
81
82 ForState(INITIALIZED)
83 .ACT(START_RECOGNIZE, HandleStart);
84
85 ForState(RECOGNIZING)
86 .WaitUntil(RECOGNIZING_TIMEOUT, std::bind(&HeadsetWakeupEngineImpl::HandleRecognizingTimeout,
87 this, std::placeholders::_1, std::placeholders::_2), RECOGNIZING_TIMEOUT_US)
88 .ACT(STOP_RECOGNIZE, HandleStop)
89 .ACT(RECOGNIZE_COMPLETE, HandleRecognizeComplete);
90
91 ForState(RECOGNIZED)
92 .WaitUntil(RECOGNIZE_COMPLETE_TIMEOUT, std::bind(&HeadsetWakeupEngineImpl::HandleStopCapturer,
93 this, std::placeholders::_1, std::placeholders::_2), RECOGNIZE_COMPLETE_TIMEOUT_US)
94 .ACT(START_CAPTURER, HandleStartCapturer);
95
96 ForState(READ_CAPTURER)
97 .WaitUntil(READ_CAPTURER_TIMEOUT, std::bind(&HeadsetWakeupEngineImpl::HandleStopCapturer,
98 this, std::placeholders::_1, std::placeholders::_2), READ_CAPTURER_TIMEOUT_US)
99 .ACT(READ, HandleRead)
100 .ACT(STOP_CAPTURER, HandleStopCapturer);
101
102 FromState(INITIALIZING, READ_CAPTURER)
103 .ACT(RELEASE_ADAPTER, HandleRelease)
104 .ACT(RELEASE, HandleRelease);
105
106 return IsStatesInitSucc();
107 }
108
Handle(const StateMsg & msg)109 int32_t HeadsetWakeupEngineImpl::Handle(const StateMsg &msg)
110 {
111 if (!IsStatesInitSucc()) {
112 INTELL_VOICE_LOG_ERROR("failed to init state");
113 return -1;
114 }
115
116 return ModuleStates::HandleMsg(msg);
117 }
118
SetCallbackInner()119 bool HeadsetWakeupEngineImpl::SetCallbackInner()
120 {
121 INTELL_VOICE_LOG_INFO("enter");
122 if (adapter_ == nullptr) {
123 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
124 return false;
125 }
126
127 if (adapterListener_ == nullptr) {
128 INTELL_VOICE_LOG_ERROR("adapterListener_ is nullptr");
129 return false;
130 }
131
132 callback_ = sptr<IIntellVoiceEngineCallback>(new (std::nothrow) AdapterCallbackService(adapterListener_));
133 if (callback_ == nullptr) {
134 INTELL_VOICE_LOG_ERROR("callback_ is nullptr");
135 return false;
136 }
137
138 adapter_->SetCallback(callback_);
139 return true;
140 }
141
AttachInner(const IntellVoiceEngineInfo & info)142 int32_t HeadsetWakeupEngineImpl::AttachInner(const IntellVoiceEngineInfo &info)
143 {
144 INTELL_VOICE_LOG_INFO("enter");
145 if (adapter_ == nullptr) {
146 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
147 return -1;
148 }
149
150 IntellVoiceEngineAdapterInfo adapterInfo = {
151 };
152
153 return adapter_->Attach(adapterInfo);
154 }
155
OnWakeupEvent(const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent & event)156 void HeadsetWakeupEngineImpl::OnWakeupEvent(
157 const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent &event)
158 {
159 INTELL_VOICE_LOG_INFO("enter, msgId:%{public}d, result:%{public}d", event.msgId, event.result);
160 if (event.msgId == INTELL_VOICE_ENGINE_MSG_INIT_DONE) {
161 TaskExecutor::AddAsyncTask([this, result = event.result]() { OnInitDone(result); },
162 "HeadsetWakeupEngineImpl::InitDone", false);
163 } else if (
164 event.msgId == static_cast<OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineMessageType>(
165 OHOS::HDI::IntelligentVoice::Engine::V1_2::INTELL_VOICE_ENGINE_MSG_HEADSET_RECOGNIZE_COMPLETE)) {
166 TaskExecutor::AddAsyncTask([this, result = event.result, info = event.info]() {
167 OnWakeupRecognition(result, info);
168 }, "HeadsetWakeupEngineImpl::RecgonizeComplete", false);
169 } else {
170 }
171 }
172
OnInitDone(int32_t result)173 void HeadsetWakeupEngineImpl::OnInitDone(int32_t result)
174 {
175 INTELL_VOICE_LOG_INFO("enter, result:%{public}d", result);
176 StateMsg msg(INIT_DONE, &result, sizeof(int32_t));
177 Handle(msg);
178 }
179
OnWakeupRecognition(int32_t result,const std::string & info)180 void HeadsetWakeupEngineImpl::OnWakeupRecognition(int32_t result, const std::string &info)
181 {
182 INTELL_VOICE_LOG_INFO("enter, result:%{public}d", result);
183 OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent event;
184 event.msgId = static_cast<OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineMessageType>(
185 HDI::IntelligentVoice::Engine::V1_2::INTELL_VOICE_ENGINE_MSG_HEADSET_RECOGNIZE_COMPLETE);
186 event.result = static_cast<OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineErrors>(result);
187 event.info = info;
188 StateMsg msg(RECOGNIZE_COMPLETE, reinterpret_cast<void *>(&event),
189 sizeof(OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent));
190 Handle(msg);
191 }
192
HandleInit(const StateMsg &,State & nextState)193 int32_t HeadsetWakeupEngineImpl::HandleInit(const StateMsg & /* msg */, State &nextState)
194 {
195 INTELL_VOICE_LOG_INFO("enter");
196 if (!EngineUtil::CreateAdapterInner(HeadsetHostManager::GetInstance(), WAKEUP_ADAPTER_TYPE)) {
197 INTELL_VOICE_LOG_ERROR("failed to create adapter");
198 return -1;
199 }
200
201 if (!SetCallbackInner()) {
202 INTELL_VOICE_LOG_ERROR("failed to set callback");
203 return -1;
204 }
205
206 EngineUtil::SetLanguage();
207 EngineUtil::SetArea();
208 adapter_->SetParameter("model_path=/vendor/etc/audio/encoder.om");
209 IntellVoiceEngineInfo info = {};
210
211 if (AttachInner(info) != 0) {
212 INTELL_VOICE_LOG_ERROR("failed to attach");
213 return -1;
214 }
215
216 nextState = State(INITIALIZING);
217 return 0;
218 }
219
HandleInitDone(const StateMsg & msg,State & nextState)220 int32_t HeadsetWakeupEngineImpl::HandleInitDone(const StateMsg &msg, State &nextState)
221 {
222 INTELL_VOICE_LOG_INFO("enter");
223 int32_t *result = reinterpret_cast<int32_t *>(msg.inMsg);
224 if ((result == nullptr) || (*result != 0)) {
225 INTELL_VOICE_LOG_ERROR("init done failed");
226 return -1;
227 }
228
229 nextState = State(INITIALIZED);
230 return 0;
231 }
232
HandleSetListener(const StateMsg & msg,State &)233 int32_t HeadsetWakeupEngineImpl::HandleSetListener(const StateMsg &msg, State & /* nextState */)
234 {
235 SetListenerMsg *listenerMsg = reinterpret_cast<SetListenerMsg *>(msg.inMsg);
236 if (listenerMsg == nullptr || adapterListener_ == nullptr) {
237 INTELL_VOICE_LOG_ERROR("listenerMsg or adapter listener is nullptr");
238 return -1;
239 }
240
241 adapterListener_->SetCallback(listenerMsg->callback);
242 return 0;
243 }
244
HandleStart(const StateMsg &,State & nextState)245 int32_t HeadsetWakeupEngineImpl::HandleStart(const StateMsg & /* msg */, State &nextState)
246 {
247 INTELL_VOICE_LOG_INFO("enter");
248 if (adapter_ == nullptr) {
249 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
250 return -1;
251 }
252
253 StartInfo info = {
254 .isLast = true,
255 };
256 if (adapter_->Start(info)) {
257 INTELL_VOICE_LOG_ERROR("start adapter failed");
258 return -1;
259 }
260
261 if (!StartAudioSource()) {
262 INTELL_VOICE_LOG_ERROR("start audio source failed");
263 adapter_->Stop();
264 return -1;
265 }
266
267 INTELL_VOICE_LOG_INFO("exit");
268 nextState = State(RECOGNIZING);
269 return 0;
270 }
271
ReadThread()272 void HeadsetWakeupEngineImpl::ReadThread()
273 {
274 bool isEnd = false;
275 while (isReading_.load()) {
276 std::vector<uint8_t> audioStream;
277 bool hasAwakeWord = true;
278 int ret = HeadsetWakeupWrapper::GetInstance().ReadHeadsetStream(audioStream, hasAwakeWord);
279 if (ret != 1) {
280 INTELL_VOICE_LOG_INFO("finish reading, ret:%{public}d, isEnd:%{public}d, hasAwakeWord:%{public}d",
281 ret, isEnd, hasAwakeWord);
282 if (!isEnd) {
283 adapter_->SetParameter("end_of_pcm=true");
284 }
285 break;
286 }
287 if (hasAwakeWord && !isEnd) {
288 adapter_->WriteAudio(audioStream);
289 }
290 if (!hasAwakeWord && !isEnd) {
291 isEnd = true;
292 adapter_->SetParameter("end_of_pcm=true");
293 }
294 WakeupSourceProcess::Write({ audioStream });
295 }
296 }
297
StartAudioSource()298 bool HeadsetWakeupEngineImpl::StartAudioSource()
299 {
300 INTELL_VOICE_LOG_INFO("enter");
301 isReading_.store(true);
302
303 WakeupSourceProcess::Init(1);
304
305 std::thread t1(std::bind(&HeadsetWakeupEngineImpl::ReadThread, this));
306 readThread_ = std::move(t1);
307 return true;
308 }
309
StopAudioSource()310 void HeadsetWakeupEngineImpl::StopAudioSource()
311 {
312 if (!isReading_.load()) {
313 INTELL_VOICE_LOG_INFO("already stop");
314 return;
315 }
316 isReading_.store(false);
317 readThread_.join();
318 HeadsetWakeupWrapper::GetInstance().StopReadingStream();
319 WakeupSourceProcess::Release();
320 }
321
HandleStop(const StateMsg &,State & nextState)322 int32_t HeadsetWakeupEngineImpl::HandleStop(const StateMsg & /* msg */, State &nextState)
323 {
324 StopAudioSource();
325 EngineUtil::Stop();
326 nextState = State(INITIALIZED);
327 return 0;
328 }
329
HandleRecognizeComplete(const StateMsg & msg,State & nextState)330 int32_t HeadsetWakeupEngineImpl::HandleRecognizeComplete(const StateMsg &msg, State &nextState)
331 {
332 EngineUtil::Stop();
333 OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent *event =
334 reinterpret_cast<OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent *>(msg.inMsg);
335 if (event == nullptr) {
336 INTELL_VOICE_LOG_ERROR("event is nullptr");
337 return -1;
338 }
339
340 adapterListener_->Notify(*event);
341
342 if (event->result != 0) {
343 INTELL_VOICE_LOG_INFO("wakeup failed");
344 HeadsetWakeupWrapper::GetInstance().NotifyVerifyResult(false);
345 StopAudioSource();
346 nextState = State(INITIALIZED);
347 } else {
348 HeadsetWakeupWrapper::GetInstance().NotifyVerifyResult(true);
349 nextState = State(RECOGNIZED);
350 }
351 return 0;
352 }
353
HandleStartCapturer(const StateMsg & msg,State & nextState)354 int32_t HeadsetWakeupEngineImpl::HandleStartCapturer(const StateMsg &msg, State &nextState)
355 {
356 INTELL_VOICE_LOG_INFO("enter");
357 int32_t *msgBody = reinterpret_cast<int32_t *>(msg.inMsg);
358 if (msgBody == nullptr) {
359 INTELL_VOICE_LOG_ERROR("msgBody is nullptr");
360 return -1;
361 }
362 channels_ = *msgBody;
363 nextState = State(READ_CAPTURER);
364 return 0;
365 }
366
HandleRead(const StateMsg & msg,State &)367 int32_t HeadsetWakeupEngineImpl::HandleRead(const StateMsg &msg, State & /* nextState */)
368 {
369 CapturerData *capturerData = reinterpret_cast<CapturerData *>(msg.outMsg);
370 auto ret = WakeupSourceProcess::Read(capturerData->data, channels_);
371 if (ret != 0) {
372 INTELL_VOICE_LOG_ERROR("read capturer data failed");
373 return ret;
374 }
375
376 ResetTimerDelay();
377 return 0;
378 }
379
HandleStopCapturer(const StateMsg &,State & nextState)380 int32_t HeadsetWakeupEngineImpl::HandleStopCapturer(const StateMsg & /* msg */, State &nextState)
381 {
382 INTELL_VOICE_LOG_INFO("enter");
383 StopAudioSource();
384 nextState = State(INITIALIZED);
385 return 0;
386 }
387
HandleRecognizingTimeout(const StateMsg &,State & nextState)388 int32_t HeadsetWakeupEngineImpl::HandleRecognizingTimeout(const StateMsg & /* msg */, State &nextState)
389 {
390 INTELL_VOICE_LOG_INFO("enter");
391 HeadsetWakeupWrapper::GetInstance().NotifyVerifyResult(false);
392 StopAudioSource();
393 EngineUtil::Stop();
394 nextState = State(INITIALIZED);
395 return 0;
396 }
397
HandleResetAdapter(const StateMsg &,State & nextState)398 int32_t HeadsetWakeupEngineImpl::HandleResetAdapter(const StateMsg & /* msg */, State &nextState)
399 {
400 INTELL_VOICE_LOG_INFO("enter");
401 if (!EngineUtil::CreateAdapterInner(HeadsetHostManager::GetInstance(), WAKEUP_ADAPTER_TYPE)) {
402 INTELL_VOICE_LOG_ERROR("failed to create adapter");
403 return -1;
404 }
405
406 adapter_->SetCallback(callback_);
407 EngineUtil::SetLanguage();
408 EngineUtil::SetArea();
409
410 IntellVoiceEngineAdapterInfo adapterInfo = {
411 };
412
413 if (adapter_->Attach(adapterInfo) != 0) {
414 INTELL_VOICE_LOG_ERROR("failed to attach");
415 EngineUtil::ReleaseAdapterInner(HeadsetHostManager::GetInstance());
416 return -1;
417 }
418
419 nextState = State(INITIALIZING);
420 return 0;
421 }
422
HandleRelease(const StateMsg &,State & nextState)423 int32_t HeadsetWakeupEngineImpl::HandleRelease(const StateMsg & /* msg */, State &nextState)
424 {
425 StopAudioSource();
426 if (adapter_ != nullptr) {
427 adapter_->Detach();
428 ReleaseAdapterInner(HeadsetHostManager::GetInstance());
429 }
430 nextState = State(IDLE);
431 return 0;
432 }
433
HandleSetParam(const StateMsg & msg,State &)434 int32_t HeadsetWakeupEngineImpl::HandleSetParam(const StateMsg &msg, State & /* nextState */)
435 {
436 StringParam *param = reinterpret_cast<StringParam *>(msg.inMsg);
437 if (param == nullptr) {
438 INTELL_VOICE_LOG_INFO("param is nullptr");
439 return -1;
440 }
441
442 return EngineUtil::SetParameter(param->strParam);
443 }
444 }
445 }