• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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