1 /*
2 * Copyright (c) 2025 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 "only_first_wakeup_engine_impl.h"
16
17 #include "audio_system_manager.h"
18 #include "intell_voice_info.h"
19 #include "intell_voice_log.h"
20 #include "intell_voice_util.h"
21 #include "string_util.h"
22 #include "engine_callback_message.h"
23
24 #define LOG_TAG "OnlyFirstWakeupEngineImpl"
25
26 using namespace OHOS::IntellVoice;
27 using namespace OHOS::AudioStandard;
28 using namespace OHOS::IntellVoiceUtils;
29
30 namespace OHOS {
31 namespace IntellVoiceEngine {
32 static constexpr uint32_t MIN_BUFFER_SIZE = 640;
33 static constexpr uint32_t INTERVAL = 96;
34 static const std::string WAKEUP_SOURCE_CHANNEL = "wakeup_source_channel";
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
OnlyFirstWakeupEngineImpl()38 OnlyFirstWakeupEngineImpl::OnlyFirstWakeupEngineImpl()
39 : ModuleStates(State(IDLE), "OnlyFirstWakeupEngineImpl", "WakeupThread")
40 {
41 InitStates();
42 capturerOptions_.streamInfo.samplingRate = AudioSamplingRate::SAMPLE_RATE_16000;
43 capturerOptions_.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
44 capturerOptions_.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE;
45 capturerOptions_.streamInfo.channels = AudioChannel::MONO;
46 capturerOptions_.capturerInfo.sourceType = SourceType::SOURCE_TYPE_WAKEUP;
47 capturerOptions_.capturerInfo.capturerFlags = 0;
48 }
49
~OnlyFirstWakeupEngineImpl()50 OnlyFirstWakeupEngineImpl::~OnlyFirstWakeupEngineImpl()
51 {
52 }
53
InitStates()54 bool OnlyFirstWakeupEngineImpl::InitStates()
55 {
56 FromState(IDLE, READ_CAPTURER)
57 .ACT(GET_PARAM, HandleGetParam);
58
59 ForState(IDLE)
60 .ACT(INIT, HandleInit);
61
62 ForState(INITIALIZED)
63 .ACT(START_RECOGNIZE, HandleStart);
64
65 ForState(RECOGNIZED)
66 .WaitUntil(RECOGNIZE_COMPLETE_TIMEOUT, std::bind(&OnlyFirstWakeupEngineImpl::HandleStopCapturer, this,
67 std::placeholders::_1, std::placeholders::_2), RECOGNIZE_COMPLETE_TIMEOUT_US)
68 .ACT(START_CAPTURER, HandleStartCapturer)
69 .ACT(STOP_CAPTURER, HandleStopCapturer)
70 .ACT(RECORD_START, HandleRecordStart);
71
72 ForState(READ_CAPTURER)
73 .WaitUntil(READ_CAPTURER_TIMEOUT, std::bind(&OnlyFirstWakeupEngineImpl::HandleStopCapturer, this,
74 std::placeholders::_1, std::placeholders::_2), READ_CAPTURER_TIMEOUT_US)
75 .ACT(READ, HandleRead)
76 .ACT(STOP_CAPTURER, HandleStopCapturer);
77
78 FromState(INITIALIZED, READ_CAPTURER)
79 .ACT(RELEASE, HandleRelease);
80
81 return IsStatesInitSucc();
82 }
83
Handle(const StateMsg & msg)84 int32_t OnlyFirstWakeupEngineImpl::Handle(const StateMsg &msg)
85 {
86 if (!IsStatesInitSucc()) {
87 INTELL_VOICE_LOG_ERROR("failed to init state");
88 return -1;
89 }
90
91 return ModuleStates::HandleMsg(msg);
92 }
93
CreateWakeupSourceStopCallback()94 bool OnlyFirstWakeupEngineImpl::CreateWakeupSourceStopCallback()
95 {
96 if (wakeupSourceStopCallback_ != nullptr) {
97 INTELL_VOICE_LOG_INFO("wakeup close cb is already created");
98 return true;
99 }
100
101 auto audioSystemManager = AudioSystemManager::GetInstance();
102 if (audioSystemManager == nullptr) {
103 INTELL_VOICE_LOG_ERROR("audioSystemManager is nullptr");
104 return false;
105 }
106
107 wakeupSourceStopCallback_ = std::make_shared<WakeupSourceStopCallback>();
108 if (wakeupSourceStopCallback_ == nullptr) {
109 INTELL_VOICE_LOG_ERROR("wakeup source stop callback is nullptr");
110 return false;
111 }
112
113 audioSystemManager->SetWakeUpSourceCloseCallback(wakeupSourceStopCallback_);
114 return true;
115 }
116
DestroyWakeupSourceStopCallback()117 void OnlyFirstWakeupEngineImpl::DestroyWakeupSourceStopCallback()
118 {
119 if (wakeupSourceStopCallback_ == nullptr) {
120 INTELL_VOICE_LOG_INFO("wakeup close cb is already destroyed");
121 return;
122 }
123
124 auto audioSystemManager = AudioSystemManager::GetInstance();
125 if (audioSystemManager == nullptr) {
126 INTELL_VOICE_LOG_ERROR("audioSystemManager is nullptr");
127 return;
128 }
129
130 audioSystemManager->SetWakeUpSourceCloseCallback(nullptr);
131 wakeupSourceStopCallback_ = nullptr;
132 }
133
StartAudioSource()134 bool OnlyFirstWakeupEngineImpl::StartAudioSource()
135 {
136 auto listener = std::make_unique<AudioSourceListener>(
137 [&](uint8_t *buffer, uint32_t size, bool isEnd) {
138 ReadBufferCallback(buffer, size, isEnd);
139 },
140 [&]() {
141 IntellVoiceUtil::StartAbility("single_level_event");
142 INTELL_VOICE_LOG_INFO("single_level_event");
143 });
144 if (listener == nullptr) {
145 INTELL_VOICE_LOG_ERROR("create listener failed");
146 return false;
147 }
148
149 WakeupSourceProcess::Init(capturerOptions_.streamInfo.channels);
150
151 audioSource_ = std::make_unique<AudioSource>(MIN_BUFFER_SIZE * static_cast<uint32_t>(
152 capturerOptions_.streamInfo.channels), INTERVAL, std::move(listener), capturerOptions_);
153 if (audioSource_ == nullptr) {
154 INTELL_VOICE_LOG_ERROR("create audio source failed");
155 WakeupSourceProcess::Release();
156 return false;
157 }
158
159 if (!audioSource_->Start()) {
160 INTELL_VOICE_LOG_ERROR("start capturer failed");
161 audioSource_ = nullptr;
162 WakeupSourceProcess::Release();
163 return false;
164 }
165
166 return true;
167 }
168
StopAudioSource()169 void OnlyFirstWakeupEngineImpl::StopAudioSource()
170 {
171 INTELL_VOICE_LOG_INFO("enter");
172 if (audioSource_ == nullptr) {
173 INTELL_VOICE_LOG_INFO("audio source is nullptr, no need to stop");
174 return;
175 }
176 audioSource_->Stop();
177 audioSource_ = nullptr;
178 WakeupSourceProcess::Release();
179 }
180
OnInitDone(int32_t result)181 void OnlyFirstWakeupEngineImpl::OnInitDone(int32_t result)
182 {
183 INTELL_VOICE_LOG_INFO("on Init Done, result:%{public}d", result);
184 StateMsg msg(INIT_DONE, &result, sizeof(int32_t));
185 Handle(msg);
186 }
187
HandleGetParam(const StateMsg & msg,State &)188 int32_t OnlyFirstWakeupEngineImpl::HandleGetParam(const StateMsg &msg, State & /* nextState */)
189 {
190 StringParam *key = reinterpret_cast<StringParam *>(msg.inMsg);
191 StringParam *value = reinterpret_cast<StringParam *>(msg.outMsg);
192 if ((key == nullptr) || (value == nullptr)) {
193 INTELL_VOICE_LOG_INFO("key or value is nullptr");
194 return -1;
195 }
196
197 if (key->strParam == WAKEUP_SOURCE_CHANNEL) {
198 value->strParam = std::to_string(static_cast<uint32_t>(capturerOptions_.streamInfo.channels));
199 } else {
200 value->strParam = "";
201 }
202
203 INTELL_VOICE_LOG_INFO("key:%{public}s, value:%{public}s", key->strParam.c_str(), value->strParam.c_str());
204 return 0;
205 }
206
HandleInit(const StateMsg &,State & nextState)207 int32_t OnlyFirstWakeupEngineImpl::HandleInit(const StateMsg & /* msg */, State &nextState)
208 {
209 INTELL_VOICE_LOG_INFO("enter");
210
211 nextState = State(INITIALIZED);
212 return 0;
213 }
214
HandleStart(const StateMsg & msg,State & nextState)215 int32_t OnlyFirstWakeupEngineImpl::HandleStart(const StateMsg &msg, State &nextState)
216 {
217 int32_t *msgBody = reinterpret_cast<int32_t *>(msg.inMsg);
218 if (msgBody == nullptr) {
219 INTELL_VOICE_LOG_ERROR("msgBody is nullptr");
220 return -1;
221 }
222
223 channelId_ = CHANNEL_ID_0;
224 INTELL_VOICE_LOG_INFO("enter, channel id is %{public}d", channelId_);
225
226 if (!CreateWakeupSourceStopCallback()) {
227 INTELL_VOICE_LOG_ERROR("create wakeup source stop callback failed");
228 return -1;
229 }
230
231 if (!StartAudioSource()) {
232 INTELL_VOICE_LOG_ERROR("start audio source failed");
233 return -1;
234 }
235
236 INTELL_VOICE_LOG_INFO("exit");
237 nextState = State(RECOGNIZED);
238 return 0;
239 }
240
HandleStartCapturer(const StateMsg & msg,State & nextState)241 int32_t OnlyFirstWakeupEngineImpl::HandleStartCapturer(const StateMsg &msg, State &nextState)
242 {
243 INTELL_VOICE_LOG_INFO("enter");
244 auto ret = IntellVoiceUtil::VerifySystemPermission(OHOS_MICROPHONE_PERMISSION);
245 if (ret != INTELLIGENT_VOICE_SUCCESS) {
246 return ret;
247 }
248
249 int32_t *msgBody = reinterpret_cast<int32_t *>(msg.inMsg);
250 if (msgBody == nullptr) {
251 INTELL_VOICE_LOG_ERROR("msgBody is nullptr");
252 return INTELLIGENT_VOICE_START_CAPTURER_FAILED;
253 }
254 channels_ = *msgBody;
255
256 nextState = State(READ_CAPTURER);
257 return 0;
258 }
259
HandleRead(const StateMsg & msg,State &)260 int32_t OnlyFirstWakeupEngineImpl::HandleRead(const StateMsg &msg, State & /* nextState */)
261 {
262 CapturerData *capturerData = reinterpret_cast<CapturerData *>(msg.outMsg);
263 if (capturerData == nullptr) {
264 INTELL_VOICE_LOG_ERROR("capturer data is nullptr");
265 return -1;
266 }
267
268 auto ret = WakeupSourceProcess::Read(capturerData->data, channels_);
269 if (ret != 0) {
270 INTELL_VOICE_LOG_ERROR("read capturer data failed");
271 return ret;
272 }
273
274 ResetTimerDelay();
275 return 0;
276 }
277
HandleStopCapturer(const StateMsg &,State & nextState)278 int32_t OnlyFirstWakeupEngineImpl::HandleStopCapturer(const StateMsg & /* msg */, State &nextState)
279 {
280 INTELL_VOICE_LOG_INFO("enter");
281 StopAudioSource();
282 nextState = State(INITIALIZED);
283 return 0;
284 }
285
HandleRelease(const StateMsg &,State & nextState)286 int32_t OnlyFirstWakeupEngineImpl::HandleRelease(const StateMsg & /* msg */, State &nextState)
287 {
288 INTELL_VOICE_LOG_INFO("enter");
289 DestroyWakeupSourceStopCallback();
290 StopAudioSource();
291 nextState = State(IDLE);
292 return 0;
293 }
294
ReadBufferCallback(uint8_t * buffer,uint32_t size,bool isEnd)295 void OnlyFirstWakeupEngineImpl::ReadBufferCallback(uint8_t *buffer, uint32_t size, bool isEnd)
296 {
297 std::vector<std::vector<uint8_t>> audioData;
298 auto ret = IntellVoiceUtil::DeinterleaveAudioData(reinterpret_cast<int16_t *>(buffer),
299 size / sizeof(int16_t), static_cast<int32_t>(capturerOptions_.streamInfo.channels), audioData);
300 if ((!ret) || ((audioData.size() != static_cast<uint32_t>(capturerOptions_.streamInfo.channels))) ||
301 (channelId_ >= audioData.size())) {
302 INTELL_VOICE_LOG_ERROR("failed to deinterleave, ret:%{public}d, id:%{public}d", ret, channelId_);
303 return;
304 }
305
306 WakeupSourceProcess::Write(audioData);
307 }
308
HandleRecordStart(const StateMsg & msg,State & nextState)309 int32_t OnlyFirstWakeupEngineImpl::HandleRecordStart(const StateMsg &msg, State &nextState)
310 {
311 INTELL_VOICE_LOG_INFO("enter");
312 int32_t *value = reinterpret_cast<int32_t *>(msg.inMsg);
313 if (value == nullptr) {
314 INTELL_VOICE_LOG_ERROR("invaid value");
315 return -1;
316 }
317
318 if ((*value != 0) && (*value != 1)) {
319 INTELL_VOICE_LOG_ERROR("invaid value %d", *value);
320 return 0;
321 }
322
323 recordStart_ = *value;
324 if (recordStart_ == 0) {
325 StopAudioSource();
326 }
327
328 nextState = State(INITIALIZED);
329 return 0;
330 }
331 }
332 }
333