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 #ifdef TRIGGER_MANAGER_TEST
16 #include <thread>
17 #endif
18
19 #include "trigger_connector_internal_impl.h"
20 #include "intell_voice_log.h"
21 #include "v1_0/iintell_voice_trigger_manager.h"
22 #include "scope_guard.h"
23 #include "trigger_callback_impl.h"
24 #include "memory_guard.h"
25
26 #define LOG_TAG "TriggerConnector"
27
28 using namespace std;
29 using namespace OHOS::HDI::ServiceManager::V1_0;
30 using namespace OHOS::IntellVoiceUtils;
31 using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0;
32
33 namespace OHOS {
34 namespace IntellVoiceTrigger {
TriggerConnector(const IntellVoiceTriggerAdapterDsecriptor & desc)35 TriggerConnector::TriggerConnector(const IntellVoiceTriggerAdapterDsecriptor &desc)
36 {
37 desc_.adapterName = desc.adapterName;
38 auto mgr = IIntellVoiceTriggerManager::Get();
39 if (mgr != nullptr) {
40 mgr->LoadAdapter(desc_, adapter_);
41 if (adapter_ == nullptr) {
42 INTELL_VOICE_LOG_ERROR("failed to load adapter, adapterName is %{public}s", desc_.adapterName.c_str());
43 }
44 } else {
45 INTELL_VOICE_LOG_INFO("can not get intell voice trigger manager");
46 }
47 }
48
~TriggerConnector()49 TriggerConnector::~TriggerConnector()
50 {
51 auto mgr = IIntellVoiceTriggerManager::Get();
52 if (mgr != nullptr) {
53 mgr->UnloadAdapter(desc_);
54 }
55 adapter_ = nullptr;
56 }
57
GetModule(std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback)58 std::shared_ptr<IIntellVoiceTriggerConnectorModule> TriggerConnector::GetModule(
59 std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback)
60 {
61 if (adapter_ == nullptr) {
62 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
63 return nullptr;
64 }
65
66 if (callback == nullptr) {
67 INTELL_VOICE_LOG_ERROR("callback is nullptr");
68 return nullptr;
69 }
70
71 std::shared_ptr<TriggerSession> session = std::make_shared<TriggerSession>(callback, adapter_);
72 if (session == nullptr) {
73 INTELL_VOICE_LOG_ERROR("failed to malloc session");
74 return nullptr;
75 }
76 activeSessions_.insert(session);
77 return session;
78 }
79
GetProperties()80 IntellVoiceTriggerProperties TriggerConnector::GetProperties()
81 {
82 IntellVoiceTriggerProperties properties;
83 return properties;
84 }
85
OnReceive(const ServiceStatus & serviceStatus)86 void TriggerConnector::OnReceive(const ServiceStatus &serviceStatus)
87 {
88 OHOS::IntellVoiceUtils::MemoryGuard memoryGuard;
89 INTELL_VOICE_LOG_INFO("enter, service name:%{public}s, status:%{public}d", serviceStatus.serviceName.c_str(),
90 serviceStatus.status);
91 if (serviceStatus.serviceName != INTELL_VOICE_TRIGGER_SERVICE) {
92 return;
93 }
94
95 if (serviceStatus.status != SERVIE_STATUS_START) {
96 INTELL_VOICE_LOG_INFO("status: %{public}d is not start", serviceStatus.status);
97 return;
98 }
99
100 if (adapter_ != nullptr) {
101 return;
102 }
103
104 auto mgr = IIntellVoiceTriggerManager::Get();
105 if (mgr != nullptr) {
106 mgr->LoadAdapter(desc_, adapter_);
107 if (adapter_ == nullptr) {
108 INTELL_VOICE_LOG_ERROR("failed to load adapter, adapterName is %{public}s", desc_.adapterName.c_str());
109 }
110 } else {
111 INTELL_VOICE_LOG_ERROR("failed to get trigger manager");
112 }
113 }
114
TriggerSession(std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback,const sptr<IIntellVoiceTriggerAdapter> & adapter)115 TriggerConnector::TriggerSession::TriggerSession(
116 std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback, const sptr<IIntellVoiceTriggerAdapter> &adapter)
117 : callback_(callback), adapter_(adapter)
118 {
119 BaseThread::Start();
120 }
121
~TriggerSession()122 TriggerConnector::TriggerSession::~TriggerSession()
123 {
124 Message msg(MSG_TYPE_QUIT);
125 SendMsg(msg);
126 Join();
127 }
128
LoadModel(std::shared_ptr<GenericTriggerModel> model,int32_t & modelHandle)129 int32_t TriggerConnector::TriggerSession::LoadModel(
130 std::shared_ptr<GenericTriggerModel> model, int32_t &modelHandle)
131 {
132 std::lock_guard<std::mutex> lock(mutex_);
133 std::shared_ptr<Model> loadedModle = Model::Create(this);
134 if (loadedModle == nullptr) {
135 INTELL_VOICE_LOG_ERROR("failed to malloc intell voice model");
136 return -1;
137 }
138
139 int32_t result = loadedModle->Load(model, modelHandle);
140 if (result != 0) {
141 INTELL_VOICE_LOG_ERROR("failed to load generic trigger model");
142 return result;
143 }
144 loadedModels_.insert(std::make_pair(modelHandle, loadedModle));
145 return result;
146 }
147
UnloadModel(int32_t modelHandle)148 int32_t TriggerConnector::TriggerSession::UnloadModel(int32_t modelHandle)
149 {
150 std::lock_guard<std::mutex> lock(mutex_);
151 auto it = loadedModels_.find(modelHandle);
152 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
153 INTELL_VOICE_LOG_ERROR("failed to find model");
154 return -1;
155 }
156
157 int32_t ret = it->second->Unload();
158 loadedModels_.erase(it);
159 return ret;
160 }
161
Start(int32_t modelHandle)162 int32_t TriggerConnector::TriggerSession::Start(int32_t modelHandle)
163 {
164 std::lock_guard<std::mutex> lock(mutex_);
165 auto it = loadedModels_.find(modelHandle);
166 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
167 INTELL_VOICE_LOG_ERROR("failed to find model");
168 return -1;
169 }
170 return it->second->Start();
171 }
172
Stop(int32_t modelHandle)173 int32_t TriggerConnector::TriggerSession::Stop(int32_t modelHandle)
174 {
175 std::lock_guard<std::mutex> lock(mutex_);
176 auto it = loadedModels_.find(modelHandle);
177 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
178 INTELL_VOICE_LOG_ERROR("failed to find model");
179 return -1;
180 }
181 return it->second->Stop();
182 }
183
HandleRecognitionHdiEvent(std::shared_ptr<IntellVoiceRecognitionEvent> event,int32_t modelHandle)184 void TriggerConnector::TriggerSession::HandleRecognitionHdiEvent(std::shared_ptr<IntellVoiceRecognitionEvent> event,
185 int32_t modelHandle)
186 {
187 Message msg(MSG_TYPE_RECOGNITION_HDI_EVENT);
188
189 msg.obj2 = static_pointer_cast<void>(event);
190 msg.arg1 = modelHandle;
191 SendMsg(msg);
192 }
193
ProcessRecognitionHdiEvent(const Message & message)194 void TriggerConnector::TriggerSession::ProcessRecognitionHdiEvent(const Message &message)
195 {
196 int32_t modelHandle = message.arg1;
197 std::shared_ptr<IntellVoiceRecognitionEvent> event =
198 static_pointer_cast<IntellVoiceRecognitionEvent>(message.obj2);
199 if (event == nullptr) {
200 INTELL_VOICE_LOG_ERROR("event is nullptr");
201 return;
202 }
203
204 {
205 std::lock_guard<std::mutex> lock(mutex_);
206 auto it = loadedModels_.find(modelHandle);
207 if ((it != loadedModels_.end()) && (it->second != nullptr)) {
208 INTELL_VOICE_LOG_INFO("receive recognition event");
209 it->second->SetState(Model::ModelState::LOADED);
210 }
211 }
212 callback_->OnRecognition(modelHandle, *(event.get()));
213 }
214
HandleMsg(Message & message)215 bool TriggerConnector::TriggerSession::HandleMsg(Message &message)
216 {
217 bool quit = false;
218
219 switch (message.mWhat) {
220 case MSG_TYPE_RECOGNITION_HDI_EVENT:
221 ProcessRecognitionHdiEvent(message);
222 break;
223 default:
224 INTELL_VOICE_LOG_WARN("invalid msg id: %{public}d", message.mWhat);
225 break;
226 }
227
228 if (message.mWhat == MSG_TYPE_QUIT) {
229 quit = true;
230 }
231
232 return quit;
233 }
234
Create(TriggerSession * session)235 std::shared_ptr<TriggerConnector::TriggerSession::Model> TriggerConnector::TriggerSession::Model::Create(
236 TriggerSession *session)
237 {
238 return std::shared_ptr<Model>(new (std::nothrow) Model(session));
239 }
240
Load(std::shared_ptr<GenericTriggerModel> model,int32_t & modelHandle)241 int32_t TriggerConnector::TriggerSession::Model::Load(
242 std::shared_ptr<GenericTriggerModel> model, int32_t &modelHandle)
243 {
244 INTELL_VOICE_LOG_INFO("enter");
245 if (GetState() != IDLE) {
246 INTELL_VOICE_LOG_ERROR("model has already loaded");
247 return -1;
248 }
249
250 callback_ = sptr<IIntellVoiceTriggerCallback>(new (std::nothrow) TriggerCallbackImpl(shared_from_this()));
251 if (callback_ == nullptr) {
252 INTELL_VOICE_LOG_ERROR("callback_ is nullptr");
253 return -1;
254 }
255
256 IntellVoiceTriggerModel triggerModel;
257 triggerModel.data = CreateAshmemFromModelData(model->GetData());
258 if (triggerModel.data == nullptr) {
259 INTELL_VOICE_LOG_ERROR("data is nullptr");
260 return -1;
261 }
262 triggerModel.type = static_cast<IntellVoiceTriggerModelType>(model->GetType());
263 triggerModel.uid = static_cast<uint32_t>(model->GetUuid());
264
265 ON_SCOPE_EXIT {
266 INTELL_VOICE_LOG_INFO("close ashmem");
267 triggerModel.data->UnmapAshmem();
268 triggerModel.data->CloseAshmem();
269 };
270
271 int32_t handle;
272 int32_t ret = session_->GetAdapter()->LoadModel(triggerModel, callback_, 0, handle);
273 if (ret != 0) {
274 INTELL_VOICE_LOG_ERROR("failed to load model");
275 return ret;
276 }
277 (void)model;
278 handle_ = handle;
279 modelHandle = handle_;
280 SetState(LOADED);
281 return ret;
282 }
283
Start()284 int32_t TriggerConnector::TriggerSession::Model::Start()
285 {
286 INTELL_VOICE_LOG_INFO("enter");
287 if (GetState() != LOADED) {
288 INTELL_VOICE_LOG_ERROR("model has not loaded");
289 return -1;
290 }
291
292 int32_t ret = session_->GetAdapter()->Start(handle_);
293 if (ret != 0) {
294 INTELL_VOICE_LOG_ERROR("failed to load model");
295 return ret;
296 }
297
298 #ifdef TRIGGER_MANAGER_TEST
299 std::thread(&TriggerConnector::TriggerSession::Model::TriggerManagerCallbackTest, this).detach();
300 #endif
301
302 SetState(ACTIVE);
303 return ret;
304 }
305
Stop()306 int32_t TriggerConnector::TriggerSession::Model::Stop()
307 {
308 INTELL_VOICE_LOG_INFO("enter");
309 if (GetState() != ACTIVE) {
310 INTELL_VOICE_LOG_ERROR("model has not activated");
311 return -1;
312 }
313
314 int32_t ret = session_->GetAdapter()->Stop(handle_);
315 if (ret != 0) {
316 INTELL_VOICE_LOG_ERROR("failed to load model");
317 return ret;
318 }
319
320 SetState(LOADED);
321 return ret;
322 }
323
Unload()324 int32_t TriggerConnector::TriggerSession::Model::Unload()
325 {
326 INTELL_VOICE_LOG_INFO("enter");
327 if (GetState() == IDLE) {
328 INTELL_VOICE_LOG_ERROR("model has not loaded");
329 return -1;
330 }
331
332 int32_t ret = session_->GetAdapter()->UnloadModel(handle_);
333 if (ret != 0) {
334 INTELL_VOICE_LOG_ERROR("failed to load model");
335 return ret;
336 }
337
338 SetState(IDLE);
339 return ret;
340 }
341
342 #ifdef TRIGGER_MANAGER_TEST
TriggerManagerCallbackTest()343 void TriggerConnector::TriggerSession::Model::TriggerManagerCallbackTest()
344 {
345 INTELL_VOICE_LOG_ERROR("enter");
346 IntellVoiceRecognitionEvent recognitionEvent;
347 recognitionEvent.status = static_cast<RecognitionStatus>(0);
348 recognitionEvent.type = static_cast<IntellVoiceTriggerModelType>(1);
349 recognitionEvent.modelHandle = handle_;
350 TriggerConnector::TriggerSession::Model::OnRecognitionHdiEvent(recognitionEvent, 0);
351 }
352 #endif
353
OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent & event,int32_t cookie)354 void TriggerConnector::TriggerSession::Model::OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent& event,
355 int32_t cookie)
356 {
357 (void)cookie;
358 std::shared_ptr<IntellVoiceRecognitionEvent> recognitionEvent = std::make_shared<IntellVoiceRecognitionEvent>();
359 if (recognitionEvent == nullptr) {
360 INTELL_VOICE_LOG_ERROR("recognitionEvent is nullptr");
361 return;
362 }
363
364 recognitionEvent->status = event.status;
365 recognitionEvent->type = event.type;
366 recognitionEvent->modelHandle = event.modelHandle;
367
368 INTELL_VOICE_LOG_INFO("handle: %{public}d", handle_);
369 session_->HandleRecognitionHdiEvent(recognitionEvent, handle_);
370 }
371
CreateAshmemFromModelData(const std::vector<uint8_t> & modelData)372 sptr<Ashmem> TriggerConnector::TriggerSession::Model::CreateAshmemFromModelData(
373 const std::vector<uint8_t> &modelData)
374 {
375 if (modelData.size() == 0) {
376 INTELL_VOICE_LOG_ERROR("data is empty");
377 return nullptr;
378 }
379
380 sptr<Ashmem> buffer = OHOS::Ashmem::CreateAshmem("ModelData", modelData.size());
381 if (buffer == nullptr) {
382 INTELL_VOICE_LOG_ERROR("failed to create ashmem");
383 return nullptr;
384 }
385
386 if (!buffer->MapReadAndWriteAshmem()) {
387 INTELL_VOICE_LOG_ERROR("failed to map ashmem");
388 goto ERR_EXIT;
389 }
390
391 if (!buffer->WriteToAshmem(modelData.data(), modelData.size(), 0)) {
392 INTELL_VOICE_LOG_ERROR("failed to write ashmem");
393 goto ERR_EXIT;
394 }
395
396 INTELL_VOICE_LOG_INFO("model data size:%{public}zu", modelData.size());
397 return buffer;
398
399 ERR_EXIT:
400 buffer->UnmapAshmem();
401 buffer->CloseAshmem();
402 return nullptr;
403 }
404 } // namespace IntellVoiceTrigger
405 } // namespace OHOS