1 /*
2 * Copyright (c) 2023 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 "wakeup_engine.h"
16 #include <fstream>
17 #include "securec.h"
18 #include "intell_voice_log.h"
19
20 #include "v1_0/iintell_voice_engine_manager.h"
21 #include "v1_0/iintell_voice_engine_callback.h"
22
23 #include "time_util.h"
24 #include "scope_guard.h"
25 #include "audio_system_manager.h"
26 #include "adapter_callback_service.h"
27 #include "intell_voice_service_manager.h"
28 #include "ability_manager_client.h"
29 #include "memory_guard.h"
30
31 #define LOG_TAG "WakeupEngine"
32
33 using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0;
34 using namespace OHOS::IntellVoiceUtils;
35 using namespace OHOS::AudioStandard;
36
37 namespace OHOS {
38 namespace IntellVoiceEngine {
39 static constexpr uint32_t MIN_BUFFER_SIZE = 1280;
40 static constexpr uint32_t INTERVAL = 50;
41 static const std::string RECOGNITION_FILE = "/data/data/recognition.pcm";
42
WakeupEngine()43 WakeupEngine::WakeupEngine()
44 {
45 INTELL_VOICE_LOG_INFO("enter");
46
47 capturerOptions_.streamInfo.channels = AudioChannel::MONO;
48 capturerOptions_.streamInfo.samplingRate = AudioSamplingRate::SAMPLE_RATE_16000;
49 capturerOptions_.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
50 capturerOptions_.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE;
51 capturerOptions_.capturerInfo.sourceType = SourceType::SOURCE_TYPE_WAKEUP;
52 capturerOptions_.capturerInfo.capturerFlags = 0;
53 }
54
~WakeupEngine()55 WakeupEngine::~WakeupEngine()
56 {
57 auto mgr = IIntellVoiceEngineManager::Get();
58 if (mgr != nullptr) {
59 mgr->ReleaseAdapter(desc_);
60 }
61 adapter_ = nullptr;
62 callback_ = nullptr;
63 }
64
OnDetected()65 void WakeupEngine::OnDetected()
66 {
67 INTELL_VOICE_LOG_INFO("on detected");
68 std::thread(&WakeupEngine::StartAbility, this).detach();
69 SetParameter("VprTrdType=0;WakeupScene=0");
70 Start(true);
71 }
72
OnWakeupEvent(int32_t msgId,int32_t result)73 void WakeupEngine::OnWakeupEvent(int32_t msgId, int32_t result)
74 {
75 if (msgId == INTELL_VOICE_ENGINE_MSG_RECOGNIZE_COMPLETE) {
76 std::thread(&WakeupEngine::OnWakeupRecognition, this).detach();
77 }
78 }
79
OnWakeupRecognition()80 void WakeupEngine::OnWakeupRecognition()
81 {
82 INTELL_VOICE_LOG_INFO("on wakeup recognition");
83 Stop();
84 StopAudioSource();
85 }
86
SetCallback()87 bool WakeupEngine::SetCallback()
88 {
89 std::lock_guard<std::mutex> lock(mutex_);
90 INTELL_VOICE_LOG_INFO("enter");
91 if (adapter_ == nullptr) {
92 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
93 return false;
94 }
95
96 adapterListener_ = std::make_shared<WakeupAdapterListener>(
97 std::bind(&WakeupEngine::OnWakeupEvent, this, std::placeholders::_1, std::placeholders::_2));
98 if (adapterListener_ == nullptr) {
99 INTELL_VOICE_LOG_ERROR("adapterListener_ is nullptr");
100 return false;
101 }
102
103 callback_ = sptr<IIntellVoiceEngineCallback>(new (std::nothrow) AdapterCallbackService(adapterListener_));
104 if (callback_ == nullptr) {
105 INTELL_VOICE_LOG_ERROR("callback_ is nullptr");
106 return false;
107 }
108
109 adapter_->SetCallback(callback_);
110 return true;
111 }
112
Init()113 bool WakeupEngine::Init()
114 {
115 desc_.adapterType = WAKEUP_ADAPTER_TYPE;
116 auto mgr = IIntellVoiceEngineManager::Get();
117 if (mgr == nullptr) {
118 INTELL_VOICE_LOG_ERROR("failed to get engine manager");
119 return false;
120 }
121
122 mgr->CreateAdapter(desc_, adapter_);
123 if (adapter_ == nullptr) {
124 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
125 return false;
126 }
127
128 if (!SetCallback()) {
129 INTELL_VOICE_LOG_ERROR("failed to set callback");
130 return false;
131 }
132
133 IntellVoiceEngineInfo info = {
134 .wakeupPhrase = "\xE5\xB0\x8F\xE8\x89\xBA\xE5\xB0\x8F\xE8\x89\xBA",
135 .isPcmFromExternal = false,
136 .minBufSize = 1280,
137 .sampleChannels = 1,
138 .bitsPerSample = 16,
139 .sampleRate = 16000,
140 };
141
142 if (Attach(info) != 0) {
143 INTELL_VOICE_LOG_ERROR("failed to attach");
144 return false;
145 }
146
147 return true;
148 }
149
SetCallback(sptr<IRemoteObject> object)150 void WakeupEngine::SetCallback(sptr<IRemoteObject> object)
151 {
152 std::lock_guard<std::mutex> lock(mutex_);
153 if (adapterListener_ == nullptr) {
154 INTELL_VOICE_LOG_ERROR("adapter listener is nullptr");
155 return;
156 }
157
158 sptr<IIntelligentVoiceEngineCallback> callback = iface_cast<IIntelligentVoiceEngineCallback>(object);
159 if (callback == nullptr) {
160 INTELL_VOICE_LOG_ERROR("callback is nullptr");
161 return;
162 }
163
164 adapterListener_->SetCallback(callback);
165 }
166
Attach(const IntellVoiceEngineInfo & info)167 int32_t WakeupEngine::Attach(const IntellVoiceEngineInfo &info)
168 {
169 std::lock_guard<std::mutex> lock(mutex_);
170 INTELL_VOICE_LOG_INFO("attach");
171 if (adapter_ == nullptr) {
172 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
173 return -1;
174 }
175
176 isPcmFromExternal_ = info.isPcmFromExternal;
177
178 IntellVoiceEngineAdapterInfo adapterInfo = {
179 .wakeupPhrase = info.wakeupPhrase,
180 .minBufSize = info.minBufSize,
181 .sampleChannels = info.sampleChannels,
182 .bitsPerSample = info.bitsPerSample,
183 .sampleRate = info.sampleRate,
184 };
185 return adapter_->Attach(adapterInfo);
186 }
187
Detach(void)188 int32_t WakeupEngine::Detach(void)
189 {
190 std::lock_guard<std::mutex> lock(mutex_);
191 if (adapter_ == nullptr) {
192 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
193 return -1;
194 }
195 return adapter_->Detach();
196 }
197
Start(bool isLast)198 int32_t WakeupEngine::Start(bool isLast)
199 {
200 std::lock_guard<std::mutex> lock(mutex_);
201 INTELL_VOICE_LOG_INFO("enter");
202 if (adapter_ == nullptr) {
203 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
204 return -1;
205 }
206
207 if (IntellVoiceServiceManager::GetInstance()->ApplyArbitration(INTELL_VOICE_WAKEUP, ENGINE_EVENT_START) !=
208 ARBITRATION_OK) {
209 INTELL_VOICE_LOG_ERROR("policy manager reject to start engine");
210 return 0;
211 }
212
213 StartInfo info = {
214 .isLast = isLast,
215 };
216 if (adapter_->Start(info)) {
217 INTELL_VOICE_LOG_ERROR("start adapter failed");
218 return -1;
219 }
220
221 if (isPcmFromExternal_) {
222 INTELL_VOICE_LOG_INFO("pcm is from external");
223 return 0;
224 }
225
226 wakeUpSourceStopCallback_ = std::make_shared<WakeUpSourceStopCallback>();
227 auto audioSystemManager = AudioSystemManager::GetInstance();
228 if (audioSystemManager != nullptr) {
229 audioSystemManager->SetWakeUpSourceCloseCallback(wakeUpSourceStopCallback_);
230 } else {
231 INTELL_VOICE_LOG_ERROR("audioSystemManager is null");
232 }
233
234 if (!StartAudioSource()) {
235 INTELL_VOICE_LOG_ERROR("start file source failed");
236 adapter_->Stop();
237 return -1;
238 }
239
240 INTELL_VOICE_LOG_INFO("exit");
241 return 0;
242 }
243
StartAbility()244 void WakeupEngine::StartAbility()
245 {
246 AAFwk::Want want;
247 const std::unique_ptr<HistoryInfoMgr> &historyInfoMgr =
248 IntellVoiceServiceManager::GetInstance()->GetHistoryInfoMgr();
249 if (historyInfoMgr == nullptr) {
250 INTELL_VOICE_LOG_ERROR("historyInfoMgr is nullptr");
251 return;
252 }
253
254 std::string bundleName = historyInfoMgr->GetWakeupEngineBundleName();
255 std::string abilityName = historyInfoMgr->GetWakeupEngineAbilityName();
256 INTELL_VOICE_LOG_INFO("bundleName:%{public}s, abilityName:%{public}s", bundleName.c_str(), abilityName.c_str());
257 want.SetElementName(bundleName, abilityName);
258 want.SetParam("serviceName", std::string("intell_voice"));
259 AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want);
260 }
261
SetParameter(const std::string & keyValueList)262 int32_t WakeupEngine::SetParameter(const std::string &keyValueList)
263 {
264 if (SetParameterInner(keyValueList)) {
265 INTELL_VOICE_LOG_INFO("inner parameter");
266 return 0;
267 }
268
269 return EngineBase::SetParameter(keyValueList);
270 }
271
SetParameterInner(const std::string & keyValueList)272 bool WakeupEngine::SetParameterInner(const std::string &keyValueList)
273 {
274 std::lock_guard<std::mutex> lock(mutex_);
275
276 const auto &manager = IntellVoiceServiceManager::GetInstance();
277 if (manager == nullptr) {
278 INTELL_VOICE_LOG_ERROR();
279 return false;
280 }
281
282 std::map<std::string, std::string> kvpairs;
283 SplitStringToKVPair(keyValueList, kvpairs);
284 for (auto it : kvpairs) {
285 if (it.first == std::string("start_stream")) {
286 INTELL_VOICE_LOG_INFO("start stream:%{public}s", it.second.c_str());
287 manager->StopDetection();
288 return true;
289 }
290 if (it.first == std::string("stop_stream")) {
291 INTELL_VOICE_LOG_INFO("stop stream:%{public}s", it.second.c_str());
292 manager->StartDetection();
293 return true;
294 }
295 }
296
297 return false;
298 }
299
StartAudioSource()300 bool WakeupEngine::StartAudioSource()
301 {
302 auto listener = std::make_unique<AudioSourceListener>(
303 [&](uint8_t *buffer, uint32_t size) {
304 if (adapter_ != nullptr) {
305 std::vector<uint8_t> audioBuff(&buffer[0], &buffer[size]);
306 adapter_->WriteAudio(audioBuff);
307 }
308 },
309 [&](bool isError) {
310 INTELL_VOICE_LOG_INFO("end of pcm, isError:%{public}d", isError);
311 if ((adapter_ != nullptr) && (!isError)) {
312 adapter_->SetParameter("end_of_pcm=true");
313 }
314 std::thread(&WakeupEngine::StopAudioSource, this).detach();
315 });
316 if (listener == nullptr) {
317 INTELL_VOICE_LOG_ERROR("create listener failed");
318 return false;
319 }
320
321 audioSource_ = std::make_unique<AudioSource>(MIN_BUFFER_SIZE, INTERVAL, std::move(listener), capturerOptions_);
322 if (audioSource_ == nullptr) {
323 INTELL_VOICE_LOG_ERROR("create audio source failed");
324 return false;
325 }
326
327 if (!audioSource_->Start()) {
328 INTELL_VOICE_LOG_ERROR("start capturer failed");
329 audioSource_ = nullptr;
330 return false;
331 }
332
333 return true;
334 }
335
StopAudioSource()336 void WakeupEngine::StopAudioSource()
337 {
338 INTELL_VOICE_LOG_INFO("enter");
339 {
340 std::lock_guard<std::mutex> lock(mutex_);
341
342 if (audioSource_ == nullptr) {
343 INTELL_VOICE_LOG_INFO("already stop audio source");
344 return;
345 }
346
347 audioSource_->Stop();
348 audioSource_ = nullptr;
349 }
350 }
351 } // namespace IntellVoice
352 } // namespace OHOS
353