• 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 #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