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 "enroll_engine.h"
16 #include <fstream>
17 #include "securec.h"
18 #include "intell_voice_log.h"
19 #include "intell_voice_util.h"
20 #include "enroll_adapter_listener.h"
21 #include "time_util.h"
22 #include "scope_guard.h"
23 #include "adapter_callback_service.h"
24 #include "intell_voice_service_manager.h"
25 #include "update_engine_utils.h"
26 #include "engine_host_manager.h"
27
28 #define LOG_TAG "EnrollEngine"
29
30 using namespace OHOS::IntellVoiceTrigger;
31 using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0;
32 using namespace OHOS::IntellVoiceUtils;
33 using namespace OHOS::AudioStandard;
34
35 namespace OHOS {
36 namespace IntellVoiceEngine {
37 static constexpr uint32_t MIN_BUFFER_SIZE = 1280; // 16 * 2 * 40ms
38 static constexpr uint32_t INTERVAL = 125; // 125 * 40ms = 5s
EnrollEngine()39 EnrollEngine::EnrollEngine()
40 {
41 INTELL_VOICE_LOG_INFO("enter");
42
43 capturerOptions_.streamInfo.samplingRate = AudioSamplingRate::SAMPLE_RATE_16000;
44 capturerOptions_.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
45 capturerOptions_.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE;
46 capturerOptions_.streamInfo.channels = AudioChannel::MONO;
47 capturerOptions_.capturerInfo.sourceType = SourceType::SOURCE_TYPE_VOICE_RECOGNITION;
48 capturerOptions_.capturerInfo.capturerFlags = 0;
49 }
50
~EnrollEngine()51 EnrollEngine::~EnrollEngine()
52 {
53 INTELL_VOICE_LOG_INFO("enter");
54 callback_ = nullptr;
55 }
56
OnEnrollEvent(int32_t msgId,int32_t result)57 void EnrollEngine::OnEnrollEvent(int32_t msgId, int32_t result)
58 {
59 if (msgId == INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE) {
60 std::thread(&EnrollEngine::OnEnrollComplete, this).detach();
61 } else if (msgId == INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE) {
62 std::lock_guard<std::mutex> lock(mutex_);
63 enrollResult_ = result;
64 IntellVoiceServiceManager::SetEnrollResult(INTELL_VOICE_ENROLL, result == 0 ? true : false);
65 }
66 }
67
OnEnrollComplete()68 void EnrollEngine::OnEnrollComplete()
69 {
70 std::lock_guard<std::mutex> lock(mutex_);
71 StopAudioSource();
72 }
73
Init(const std::string & param)74 bool EnrollEngine::Init(const std::string ¶m)
75 {
76 if (!EngineUtil::CreateAdapterInner(EngineHostManager::GetInstance(), ENROLL_ADAPTER_TYPE)) {
77 INTELL_VOICE_LOG_ERROR("failed to create adapter");
78 return false;
79 }
80 return true;
81 }
82
SetCallback(sptr<IRemoteObject> object)83 void EnrollEngine::SetCallback(sptr<IRemoteObject> object)
84 {
85 std::lock_guard<std::mutex> lock(mutex_);
86 INTELL_VOICE_LOG_INFO("enter");
87 if (adapter_ == nullptr) {
88 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
89 return;
90 }
91
92 sptr<IIntelligentVoiceEngineCallback> callback = iface_cast<IIntelligentVoiceEngineCallback>(object);
93 if (callback == nullptr) {
94 INTELL_VOICE_LOG_ERROR("callback is nullptr");
95 return;
96 }
97
98 std::shared_ptr<IntellVoiceAdapterListener> listener = std::make_shared<EnrollAdapterListener>(callback,
99 std::bind(&EnrollEngine::OnEnrollEvent, this, std::placeholders::_1, std::placeholders::_2));
100 if (listener == nullptr) {
101 INTELL_VOICE_LOG_ERROR("listener is nullptr");
102 return;
103 }
104
105 callback_ = sptr<IIntellVoiceEngineCallback>(new (std::nothrow) AdapterCallbackService(listener));
106 if (callback_ == nullptr) {
107 INTELL_VOICE_LOG_ERROR("callback_ is nullptr");
108 return;
109 }
110
111 adapter_->SetCallback(callback_);
112 }
113
Attach(const IntellVoiceEngineInfo & info)114 int32_t EnrollEngine::Attach(const IntellVoiceEngineInfo &info)
115 {
116 std::lock_guard<std::mutex> lock(mutex_);
117 INTELL_VOICE_LOG_INFO("attach");
118 if (adapter_ == nullptr) {
119 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
120 return -1;
121 }
122
123 SetDspFeatures();
124 isPcmFromExternal_ = info.isPcmFromExternal;
125 HistoryInfoMgr::GetInstance().SetWakeupPhrase(info.wakeupPhrase);
126
127 IntellVoiceEngineAdapterInfo adapterInfo = {
128 .wakeupPhrase = info.wakeupPhrase,
129 .minBufSize = info.minBufSize,
130 .sampleChannels = info.sampleChannels,
131 .bitsPerSample = info.bitsPerSample,
132 .sampleRate = info.sampleRate,
133 };
134 return adapter_->Attach(adapterInfo);
135 }
136
Detach(void)137 int32_t EnrollEngine::Detach(void)
138 {
139 INTELL_VOICE_LOG_INFO("enter");
140 std::lock_guard<std::mutex> lock(mutex_);
141 StopAudioSource();
142 if (adapter_ == nullptr) {
143 INTELL_VOICE_LOG_WARN("already detach");
144 return 0;
145 }
146
147 if (enrollResult_ == 0) {
148 ProcDspModel(OHOS::HDI::IntelligentVoice::Engine::V1_0::DSP_MODLE);
149 /* save new version number */
150 UpdateEngineUtils::SaveWakeupVesion();
151 INTELL_VOICE_LOG_INFO("enroll save version");
152 }
153
154 int32_t ret = adapter_->Detach();
155 ReleaseAdapterInner(EngineHostManager::GetInstance());
156 return ret;
157 }
158
Start(bool isLast)159 int32_t EnrollEngine::Start(bool isLast)
160 {
161 std::lock_guard<std::mutex> lock(mutex_);
162 INTELL_VOICE_LOG_INFO("enter");
163 if (audioSource_ != nullptr) {
164 INTELL_VOICE_LOG_ERROR("audioSource_ existed, wait for last start to finish");
165 return -1;
166 }
167
168 if (adapter_ == nullptr) {
169 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
170 return -1;
171 }
172
173 StartInfo info = {
174 .isLast = isLast,
175 };
176 if (adapter_->Start(info)) {
177 INTELL_VOICE_LOG_ERROR("start adapter failed");
178 return -1;
179 }
180
181 if (isPcmFromExternal_) {
182 INTELL_VOICE_LOG_INFO("pcm is from external");
183 return 0;
184 }
185
186 if (!StartAudioSource()) {
187 INTELL_VOICE_LOG_ERROR("start audio source failed");
188 adapter_->Stop();
189 return -1;
190 }
191
192 INTELL_VOICE_LOG_INFO("exit");
193 return 0;
194 }
195
Stop()196 int32_t EnrollEngine::Stop()
197 {
198 std::lock_guard<std::mutex> lock(mutex_);
199 StopAudioSource();
200
201 return EngineUtil::Stop();
202 }
203
SetParameter(const std::string & keyValueList)204 int32_t EnrollEngine::SetParameter(const std::string &keyValueList)
205 {
206 std::lock_guard<std::mutex> lock(mutex_);
207 if (SetParameterInner(keyValueList)) {
208 INTELL_VOICE_LOG_INFO("inner parameter");
209 return 0;
210 }
211
212 INTELL_VOICE_LOG_INFO("EnrollEngine SetParameter:%{public}s", keyValueList.c_str());
213
214 return EngineUtil::SetParameter(keyValueList);
215 }
216
SetParameterInner(const std::string & keyValueList)217 bool EnrollEngine::SetParameterInner(const std::string &keyValueList)
218 {
219 HistoryInfoMgr &historyInfoMgr = HistoryInfoMgr::GetInstance();
220
221 std::map<std::string, std::string> kvpairs;
222 IntellVoiceUtil::SplitStringToKVPair(keyValueList, kvpairs);
223 for (auto it : kvpairs) {
224 if (it.first == std::string("wakeup_bundle_name")) {
225 INTELL_VOICE_LOG_INFO("set wakeup bundle name:%{public}s", it.second.c_str());
226 historyInfoMgr.SetWakeupEngineBundleName(it.second);
227 return true;
228 }
229 if (it.first == std::string("wakeup_ability_name")) {
230 INTELL_VOICE_LOG_INFO("set wakeup ability name:%{public}s", it.second.c_str());
231 historyInfoMgr.SetWakeupEngineAbilityName(it.second);
232 return true;
233 }
234 if (it.first == std::string("language")) {
235 INTELL_VOICE_LOG_INFO("set language:%{public}s", it.second.c_str());
236 historyInfoMgr.SetLanguage(it.second);
237 continue;
238 }
239 if (it.first == std::string("area")) {
240 INTELL_VOICE_LOG_INFO("set area:%{public}s", it.second.c_str());
241 historyInfoMgr.SetArea(it.second);
242 continue;
243 }
244 if (it.first == std::string("Sensibility")) {
245 INTELL_VOICE_LOG_INFO("set Sensibility:%{public}s", it.second.c_str());
246 historyInfoMgr.SetSensibility(it.second);
247 continue;
248 }
249 }
250
251 return false;
252 }
253
GetParameter(const std::string & key)254 std::string EnrollEngine::GetParameter(const std::string &key)
255 {
256 std::lock_guard<std::mutex> lock(mutex_);
257 return EngineUtil::GetParameter(key);
258 }
259
WriteAudio(const uint8_t * buffer,uint32_t size)260 int32_t EnrollEngine::WriteAudio(const uint8_t *buffer, uint32_t size)
261 {
262 std::lock_guard<std::mutex> lock(mutex_);
263 return EngineUtil::WriteAudio(buffer, size);
264 }
265
Evaluate(const std::string & word,EvaluationResultInfo & info)266 int32_t EnrollEngine::Evaluate(const std::string &word, EvaluationResultInfo &info)
267 {
268 std::lock_guard<std::mutex> lock(mutex_);
269 return EngineUtil::Evaluate(word, info);
270 }
271
StartAudioSource()272 bool EnrollEngine::StartAudioSource()
273 {
274 auto listener = std::make_unique<AudioSourceListener>([&] (uint8_t *buffer, uint32_t size, bool isEnd) {
275 if ((adapter_ != nullptr) && (!isEnd)) {
276 std::vector<uint8_t> audioBuff(&buffer[0], &buffer[size]);
277 adapter_->WriteAudio(audioBuff);
278 }}, [&] () {
279 INTELL_VOICE_LOG_INFO("end of pcm");
280 if (adapter_ != nullptr) {
281 adapter_->SetParameter("end_of_pcm=true");
282 }
283 });
284 if (listener == nullptr) {
285 INTELL_VOICE_LOG_ERROR("create listener failed");
286 return false;
287 }
288
289 audioSource_ = std::make_unique<AudioSource>(MIN_BUFFER_SIZE, INTERVAL, std::move(listener),
290 capturerOptions_);
291 if (audioSource_ == nullptr) {
292 INTELL_VOICE_LOG_ERROR("create audio source failed");
293 return false;
294 }
295
296 if (!audioSource_->Start()) {
297 INTELL_VOICE_LOG_ERROR("start capturer failed");
298 audioSource_ = nullptr;
299 return false;
300 }
301
302 return true;
303 }
304
StopAudioSource()305 void EnrollEngine::StopAudioSource()
306 {
307 INTELL_VOICE_LOG_INFO("enter");
308 if (audioSource_ != nullptr) {
309 INTELL_VOICE_LOG_INFO("stop audio sopurce");
310 audioSource_->Stop();
311 audioSource_ = nullptr;
312 }
313 }
314 }
315 }
316