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