1 #include <multi_assistant_service.h>
3 #include "wakeup_engine_manager.h"
4 #include "wakeup_manager_main.h"
8 #include <pkgmgr-info.h>
11 namespace multiassistant
16 /* Sound buf save for test */
22 static char g_temp_file_name[128] = {'\0', };
24 static FILE* g_pFile = NULL;
26 static int g_count = 1;
29 /* Need to check whether this value needs to be configurable */
30 static int g_speech_pcm_wait_count = 800;
32 /* Utility function for checking if an element exists in a container */
33 template<class C, class T>
34 static auto contains(const C& v, const T& x) -> decltype(end(v), true)
36 return end(v) != find(begin(v), end(v), x);
39 CWakeupEngineManager::CWakeupEngineManager()
43 CWakeupEngineManager::~CWakeupEngineManager()
45 MWR_LOGI("Wakeup Engine Manager is now being destroyed");
48 CWakeupEngineManager::CWakeupEngineManager(IEngineEventObserver *observer) : CWakeupEngineManager()
53 void CWakeupEngineManager::initialize()
55 DIR* dp = opendir(MA_WAKEUP_ENGINE_PATH);
57 MWR_LOGD("Failed opening directory : %s", (const char*)MA_WAKEUP_ENGINE_PATH);
59 struct dirent *dirp = nullptr;
60 char dirpath[_POSIX_PATH_MAX];
64 if (nullptr != dirp) {
65 const string current_directory{"."};
66 const string parent_directory{".."};
67 if (0 == current_directory.compare(dirp->d_name) ||
68 0 == parent_directory.compare(dirp->d_name))
71 if (DT_DIR != dirp->d_type) /* If not a directory */
74 int dirpath_len = strlen(MA_WAKEUP_ENGINE_PATH) + strlen(dirp->d_name) + 1;
75 if (dirpath_len >= _POSIX_PATH_MAX) {
76 MWR_LOGD("File path is too long : %s", dirp->d_name);
81 memset(dirpath, '\0', _POSIX_PATH_MAX);
82 snprintf(dirpath, _POSIX_PATH_MAX, "%s/%s",
83 (const char*)(MA_WAKEUP_ENGINE_PATH), dirp->d_name);
85 add_engine_directory(string{dirp->d_name}, dirpath);
87 } while (nullptr != dirp);
93 void CWakeupEngineManager::deinitialize()
96 if (mStreamingThread.joinable()) {
97 MWR_LOGD("mStreamingThread is joinable, trying join()");
98 mStopStreamingThread.store(true);
99 mStreamingThread.join();
101 mStopStreamingThread.store(false);
103 for (auto& info : mEngineInfo) {
105 if (info.interface.set_wakeup_event_callback) {
106 info.interface.set_wakeup_event_callback(nullptr, nullptr);
108 if (info.interface.set_speech_status_callback) {
109 info.interface.set_speech_status_callback(nullptr, nullptr);
111 if (info.interface.set_error_callback) {
112 info.interface.set_error_callback(nullptr, nullptr);
114 if (info.interface.set_audio_data_require_status_callback) {
115 info.interface.set_audio_data_require_status_callback(nullptr, nullptr);
117 if (info.interface.set_wakeup_engine_command_callback) {
118 info.interface.set_wakeup_engine_command_callback(nullptr, nullptr);
120 MWR_LOGI("Trying to deinitialize engine : %s", info.engine_name.c_str());
121 if (info.interface.deinitialize) {
122 int ret = info.interface.deinitialize();
123 MWR_LOGI("Deinitialization [%s] returned %d", info.engine_name.c_str(), ret);
125 } catch (const std::exception& e) {
126 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
127 info.engine_name.c_str(), e.what());
129 if (info.engine_handle) {
130 int ret = dlclose(info.engine_handle);
131 MWR_LOGI("Closing [%s] returned %d, [%s]", info.engine_name.c_str(), ret,
132 ((0 == ret) ? "" : dlerror()));
133 info.engine_handle = nullptr;
136 mSelectedEngine = nullptr;
141 void CWakeupEngineManager::subscribe(IEngineEventObserver *observer)
143 mObservers.push_back(observer);
144 MWR_LOGD("Added Observer : %p %zu", observer, mObservers.size());
147 void CWakeupEngineManager::unsubscribe(IEngineEventObserver *observer)
149 auto iter = find(mObservers.begin(), mObservers.end(), observer);
150 if (iter != mObservers.end()) {
151 mObservers.erase(iter);
155 bool CWakeupEngineManager::get_audio_data_required()
157 return mAudioDataRequired;
160 void CWakeupEngineManager::set_selected_wakeup_info(mas_wakeup_event_info wakeup_info)
162 mSelectedEngine = nullptr;
164 const auto& iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
165 [wakeup_info](const EngineInfo& info) {
166 if (nullptr == wakeup_info.wakeup_engine)
169 return (0 == info.engine_name.compare(wakeup_info.wakeup_engine));
172 if (iter != mEngineInfo.end()) {
173 mSelectedEngine = &(*iter);
174 MWR_LOGD("Selected : %s", iter->engine_name.c_str());
178 bool CWakeupEngineManager::set_language(string language)
180 for (const auto& info : mEngineInfo) {
181 if (info.interface.set_language) {
183 info.interface.set_language(language.c_str());
184 } catch (const std::exception& e) {
185 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
186 info.engine_name.c_str(), e.what());
193 bool CWakeupEngineManager::set_assistant_language(string appid, string language)
195 for (auto& info : mEngineInfo) {
196 const auto& iter = find_if(info.assistant_list.begin(), info.assistant_list.end(),
197 [appid](const string& assistant) {
198 return (0 == assistant.compare(appid));
201 /* If the appid is in the assistant list */
202 if (info.assistant_list.end() != iter) {
204 int ret = info.interface.set_language(language.c_str());
205 MWR_LOGI("set_language returned %d : %s %s %s",
206 ret, appid.c_str(), info.engine_name.c_str(), language.c_str());
207 } catch (const std::exception& e) {
208 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
209 info.engine_name.c_str(), e.what());
216 void CWakeupEngineManager::set_assistant_activated(string appid, bool activated)
218 MWR_LOGI("[ENTER] : %s %d", appid.c_str(), activated);
219 for (auto& info : mEngineInfo) {
220 const auto& iter = find_if(info.assistant_list.begin(), info.assistant_list.end(),
221 [appid](const string& assistant) {
222 return (0 == assistant.compare(appid));
225 /* If the appid is in the assistant list */
226 if (info.assistant_list.end() != iter) {
227 MWR_LOGI("%s has %s", info.engine_name.c_str(), appid.c_str());
228 bool previously_activated = info.activated;
230 info.activated_assistants.insert(appid);
232 info.activated_assistants.erase(appid);
234 info.activated = (info.activated_assistants.size() > 0);
235 if (previously_activated != info.activated) {
236 if (info.activated) {
238 info.interface.activate();
239 } catch (const std::exception& e) {
240 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
241 info.engine_name.c_str(), e.what());
245 info.interface.deactivate();
246 } catch (const std::exception& e) {
247 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
248 info.engine_name.c_str(), e.what());
251 /* Activated status changed, need to update audio_data_require_status too */
252 on_audio_data_require_status(info.engine_name, info.audio_data_require_status);
255 MWR_LOGI("%s does not have %s", info.engine_name.c_str(), appid.c_str());
260 void CWakeupEngineManager::set_wake_word_audio_require_flag(bool require)
263 mWakeWordAudioRequired = require;
264 for (const auto& info : mEngineInfo) {
265 if (info.interface.set_wake_word_audio_require_flag) {
267 info.interface.set_wake_word_audio_require_flag(require);
268 } catch (const std::exception& e) {
269 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
270 info.engine_name.c_str(), e.what());
276 void CWakeupEngineManager::streaming_speech_data_thread_func()
280 if (nullptr == mSelectedEngine) {
281 MWR_LOGE("No Engine Selected");
285 const wakeup_engine_interface *interface = &(mSelectedEngine->interface);
287 if (NULL == interface ||
288 NULL == interface->get_utterance_data ||
289 NULL == interface->get_utterance_data_count)
292 MWR_LOGD("data_count : %d", interface->get_utterance_data_count());
299 MWR_LOGD("[Recorder Info] File not found!");
303 snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/ma_wue_%d_%d", getpid(), g_count);
304 int ret = access(g_temp_file_name, 0);
307 MWR_LOGD("[Recorder ERROR] File is already exist");
308 if (0 == remove(g_temp_file_name)) {
309 MWR_LOGD("[Recorder] Remove file");
319 MWR_LOGD("[Recorder] Temp file name=[%s]", g_temp_file_name);
322 g_pFile = fopen(g_temp_file_name, "wb+x");
324 MWR_LOGD("[Recorder ERROR] File not found!");
330 mas_speech_data speech_data;
332 bool finish_event_sent = false;
334 if (mWakeWordAudioRequired &&
335 NULL != interface->get_wake_word_data &&
336 NULL != interface->get_wake_word_data_count) {
337 for (const auto& observer : mObservers) {
339 if (!observer->on_audio_streaming_data_section(MA_AUDIO_STREAMING_DATA_SECTION_WAKE_WORD)) {
340 LOGE("[Recorder WARNING] One of the observer returned false");
344 int count = interface->get_wake_word_data_count();
345 while (!(mStopStreamingThread.load()) && index < count) {
346 int ret = interface->get_wake_word_data(index, &speech_data);
350 fwrite(speech_data.buffer, 1, speech_data.len, g_pFile);
352 for (const auto& observer : mObservers) {
354 if (!observer->on_streaming_audio_data(
355 speech_data.event, speech_data.buffer, speech_data.len)) {
356 LOGE("[Recorder WARNING] One of the observer returned false");
366 for (const auto& observer : mObservers) {
368 if (!observer->on_audio_streaming_data_section(MA_AUDIO_STREAMING_DATA_SECTION_UTTERANCE)) {
369 LOGE("[Recorder WARNING] One of the observer returned false");
376 while (!(mStopStreamingThread.load())) {
380 /* get feedback data */
381 if (interface && interface->get_utterance_data) {
382 ret = interface->get_utterance_data(index, &speech_data);
385 MWR_LOGD("[DEBUG] No feedback data. Waiting mode : %d", ret);
388 while (!(mStopStreamingThread.load())) {
390 this_thread::sleep_for(chrono::milliseconds(10));
391 if (index < interface->get_utterance_data_count()) {
392 MWR_LOGD("[INFO] Resume thread");
395 if (g_speech_pcm_wait_count < cnt) {
396 unsigned char final_buffer[2] = {'\0', };
397 MWR_LOGE("[ERROR] Wrong request, there's no pcm data");
400 fwrite(final_buffer, 1, sizeof(final_buffer), g_pFile);
401 MWR_LOGE("[Recorder SUCCESS] File Close");
406 for (const auto& observer : mObservers) {
408 if (!observer->on_streaming_audio_data(
409 MAS_SPEECH_STREAMING_EVENT_FAIL, NULL, 0)) {
410 LOGE("[Recorder WARNING] One of the observer returned false");
412 if (!observer->on_streaming_audio_data(
413 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
414 LOGE("[Recorder WARNING] One of the observer returned false");
422 MWR_LOGD("[INFO] Finish to wait for new feedback data come");
424 /* resume feedback thread */
430 fwrite(speech_data.buffer, 1, speech_data.len, g_pFile);
432 if (MAS_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
434 MWR_LOGE("[Recorder SUCCESS] File Close");
438 MWR_LOGE("[Recorder ERROR] File not found!");
442 const int sleep_duration_in_millis = 10;
443 const int max_burst_count = 3;
444 if (++burst_count >= max_burst_count) {
446 this_thread::sleep_for(chrono::milliseconds(sleep_duration_in_millis));
447 MWR_LOGI("[INFO] Streaming data burst transmission detected, forcing sleep");
449 for (const auto& observer : mObservers) {
451 if (!observer->on_streaming_audio_data(
452 speech_data.event, speech_data.buffer, speech_data.len)) {
453 LOGE("[Recorder WARNING] One of the observer returned false");
458 if (MAS_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
459 MWR_LOGI("[INFO] Finish to get and send speech data");
460 finish_event_sent = true;
468 if (true != finish_event_sent) {
469 unsigned char final_buffer[2] = {'\0', };
470 for (const auto& observer : mObservers) {
472 if (!observer->on_streaming_audio_data(
473 MAS_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
474 LOGE("[Recorder WARNING] One of the observer returned false");
480 fwrite(final_buffer, 1, sizeof(final_buffer), g_pFile);
481 MWR_LOGE("[Recorder SUCCESS] File Close");
491 void CWakeupEngineManager::start_streaming_current_utterance_data()
493 if (mStreamingThread.joinable()) {
494 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
497 mStreamingThread = thread(&CWakeupEngineManager::streaming_speech_data_thread_func, this);
500 void CWakeupEngineManager::stop_streaming_current_utterance_data()
502 if (mStreamingThread.joinable()) {
503 MWR_LOGD("mStreamingThread is joinable, trying join()");
504 mStopStreamingThread.store(true);
505 mStreamingThread.join();
507 mStopStreamingThread.store(false);
510 void CWakeupEngineManager::update_manager_state(wakeup_manager_state_e state)
512 for (const auto& info : mEngineInfo) {
513 if (info.interface.update_manager_state) {
515 info.interface.update_manager_state(state);
516 } catch (const std::exception& e) {
517 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
518 info.engine_name.c_str(), e.what());
522 mWakeupManagerState = state;
525 void CWakeupEngineManager::update_recognition_result(string appid, int result)
527 if (mSelectedEngine) {
528 if (mSelectedEngine->interface.update_recognition_result) {
529 mSelectedEngine->interface.update_recognition_result(appid.c_str(), result);
534 void CWakeupEngineManager::engine_add_target_assistant(string engine_name, string appid)
536 const auto& iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
537 [engine_name](const EngineInfo& info) {
538 return (0 == info.engine_name.compare(engine_name));
541 if (mEngineInfo.end() == iter) {
542 /* Not found, add new library */
543 pkgmgrinfo_appinfo_h handle;
544 int ret = pkgmgrinfo_appinfo_get_appinfo(engine_name.c_str(), &handle);
545 if (PMINFO_R_OK == ret) {
546 char *root_path = nullptr;
547 ret = pkgmgrinfo_appinfo_get_root_path(handle, &root_path);
548 if (PMINFO_R_OK == ret && nullptr != root_path) {
549 string path = root_path;
551 path += MA_WAKEUP_DEDICATED_ENGINE_PATH;
552 add_engine(engine_name, path);
554 pkgmgrinfo_appinfo_destroy_appinfo(handle);
556 /* Find again to add appid to the newly created engine's assistant list */
557 const auto &new_iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
558 [engine_name](const EngineInfo& info) {
559 return (0 == info.engine_name.compare(engine_name));
561 if (mEngineInfo.end() != new_iter) {
562 new_iter->assistant_list.push_back(appid);
563 for (const auto assistant : new_iter->assistant_list) {
564 MWR_LOGI("Assistant List : %s %s", assistant.c_str(), new_iter->engine_name.c_str());
568 /* If the engine already exists, simply add the appid to the assistant list */
569 iter->assistant_list.push_back(appid);
570 for (const auto assistant : iter->assistant_list) {
571 MWR_LOGI("Assistant List : %s %s", assistant.c_str(), iter->engine_name.c_str());
576 void CWakeupEngineManager::engine_add_wakeup_word(string appid, string wakeup_word, string language)
578 for (const auto& info : mEngineInfo) {
579 bool found = contains(info.assistant_list, appid);
581 if (info.interface.add_wakeup_word) {
583 info.interface.add_wakeup_word(appid.c_str(), wakeup_word.c_str(), language.c_str());
584 } catch (const std::exception& e) {
585 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
586 info.engine_name.c_str(), e.what());
589 MWR_LOGE("Wakeup Engine does not provide add_wakeup_word");
595 void CWakeupEngineManager::engine_remove_wakeup_word(string appid, string wakeup_word, string language)
597 for (const auto& info : mEngineInfo) {
598 bool found = contains(info.assistant_list, appid);
600 if (info.interface.remove_wakeup_word) {
602 info.interface.remove_wakeup_word(appid.c_str(), wakeup_word.c_str(), language.c_str());
603 } catch (const std::exception& e) {
604 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
605 info.engine_name.c_str(), e.what());
608 MWR_LOGE("Wakeup Engine does not provide remove_wakeup_word");
614 void CWakeupEngineManager::engine_set_assistant_specific_command(string appid, string command)
616 for (const auto& info : mEngineInfo) {
617 bool found = contains(info.assistant_list, appid);
619 if (info.interface.set_assistant_specific_command) {
621 info.interface.set_assistant_specific_command(appid.c_str(), command.c_str());
622 } catch (const std::exception& e) {
623 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
624 info.engine_name.c_str(), e.what());
631 void CWakeupEngineManager::engine_feed_audio_data(long time, void* data, int len)
633 for (const auto& info : mEngineInfo) {
634 if (info.activated &&
635 info.audio_data_require_status &&
636 info.interface.feed_audio_data) {
638 bool filtered_out = false;
639 /* After a wakeup event, wakeup engines other than the selected one
640 does not need to receive audio data. */
641 if (WAKEUP_MANAGER_STATE_UTTERANCE == mWakeupManagerState) {
642 if (mSelectedEngine && &info != mSelectedEngine) {
647 int ret = info.interface.feed_audio_data(time, data, len);
649 LOGE("[ERROR] Fail to feed speech data, ret(%d) : %s", ret, info.engine_name.c_str());
652 } catch (const std::exception& e) {
653 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
654 info.engine_name.c_str(), e.what());
660 void CWakeupEngineManager::engine_set_dependency_module_command(string engine_name, string command)
662 const auto& iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
663 [engine_name](const EngineInfo& info) {
664 return (0 == info.engine_name.compare(engine_name));
667 if (mEngineInfo.end() != iter) {
668 if (iter->activated &&
669 iter->interface.set_dependency_module_command) {
671 int ret = iter->interface.set_dependency_module_command(command.c_str());
673 LOGE("[ERROR] Fail to set dependency module command, ret(%d) : %s",
674 ret, iter->engine_name.c_str());
676 } catch (const std::exception& e) {
677 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
678 iter->engine_name.c_str(), e.what());
684 bool CWakeupEngineManager::on_wakeup_event(string engine_name, mas_wakeup_event_info info)
688 for (const auto& observer : mObservers) {
690 if (!observer->on_wakeup_event(engine_name, info)) {
691 LOGE("[Recorder WARNING] One of the observer returned false");
699 bool CWakeupEngineManager::on_speech_status(string engine_name, mas_speech_status_e status)
703 for (const auto& observer : mObservers) {
705 if (!observer->on_speech_status(engine_name, status)) {
706 LOGE("[Recorder WARNING] One of the observer returned false");
714 bool CWakeupEngineManager::on_error(string engine_name, int error_code, string error_message)
718 for (const auto& observer : mObservers) {
720 if (!observer->on_error(engine_name, error_code, error_message)) {
721 LOGE("[Recorder WARNING] One of the observer returned false");
729 bool CWakeupEngineManager::on_audio_data_require_status(string engine_name, bool require)
731 MWR_LOGI("[ENTER] %s, %d", engine_name.c_str(), require);
736 for (auto& info : mEngineInfo) {
737 if (info.engine_name.compare(engine_name) == 0) {
739 info.audio_data_require_status = require;
741 if (info.activated && info.audio_data_require_status) {
745 MWR_LOGD("count : %d", count);
747 mAudioDataRequired = true;
749 mAudioDataRequired = false;
753 for (const auto& observer : mObservers) {
755 if (!observer->on_audio_data_require_status(engine_name, require)) {
756 LOGE("[Recorder WARNING] One of the observer returned false");
765 bool CWakeupEngineManager::on_wakeup_engine_command(string engine_name, mas_wakeup_engine_command_target_e target, string assistant_name, string command)
767 MWR_LOGI("[ENTER] : %s %d %s %s",
768 engine_name.c_str(), target, assistant_name.c_str(), command.c_str());
770 for (const auto& observer : mObservers) {
772 if (MAS_WAKEUP_ENGINE_COMMAND_TARGET_DEPENDENCY_MODULE == target) {
773 if (!observer->on_wakeup_engine_command(target, engine_name, assistant_name, command)) {
774 LOGE("[Recorder WARNING] One of the observer returned false");
777 const auto& iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
778 [engine_name](const EngineInfo& info) {
779 return (0 == info.engine_name.compare(engine_name));
781 if (mEngineInfo.end() != iter) {
782 for (const auto& assistant : iter->assistant_list) {
783 if (0 == assistant_name.compare(assistant) ||
784 MAS_WAKEUP_ENGINE_COMMAND_TARGET_ALL_ASSISTANTS == target) {
785 MWR_LOGI("Calling on_wakeup_engine_command for %s", assistant.c_str());
786 if (!observer->on_wakeup_engine_command(target, engine_name, assistant, command)) {
787 LOGE("[Recorder WARNING] One of the observer returned false");
799 void CWakeupEngineManager::add_engine(string name, string path)
801 MWR_LOGD("Name (%s), Filepath(%s)", name.c_str(), path.c_str());
805 info.engine_handle = dlopen(path.c_str(), RTLD_LAZY);
806 if (nullptr != (error = dlerror()) || nullptr == info.engine_handle) {
807 MWR_LOGD("[ERROR] Fail to dlopen(%s), error(%s)", path.c_str(), error);
808 if (info.engine_handle) dlclose(info.engine_handle);
812 /* Interfaces without version information */
813 info.interface.initialize =
814 (wakeup_engine_initialize)dlsym(info.engine_handle,
815 MA_WAKEUP_ENGINE_FUNC_INITIALIZE);
816 info.interface.deinitialize =
817 (wakeup_engine_deinitialize)dlsym(info.engine_handle,
818 MA_WAKEUP_ENGINE_FUNC_DEINITIALIZE);
819 info.interface.activate =
820 (wakeup_engine_activate)dlsym(info.engine_handle,
821 MA_WAKEUP_ENGINE_FUNC_ACTIVATE);
822 info.interface.deactivate =
823 (wakeup_engine_deactivate)dlsym(info.engine_handle,
824 MA_WAKEUP_ENGINE_FUNC_DEACTIVATE);
825 info.interface.add_wakeup_word =
826 (wakeup_engine_add_wakeup_word)dlsym(info.engine_handle,
827 MA_WAKEUP_ENGINE_FUNC_ADD_WAKEUP_WORD);
828 info.interface.remove_wakeup_word =
829 (wakeup_engine_remove_wakeup_word)dlsym(info.engine_handle,
830 MA_WAKEUP_ENGINE_FUNC_REMOVE_WAKEUP_WORD);
831 info.interface.add_language =
832 (wakeup_engine_add_language)dlsym(info.engine_handle,
833 MA_WAKEUP_ENGINE_FUNC_ADD_LANGUAGE);
834 info.interface.set_language =
835 (wakeup_engine_set_language)dlsym(info.engine_handle,
836 MA_WAKEUP_ENGINE_FUNC_SET_LANGUAGE);
837 info.interface.update_manager_state =
838 (wakeup_engine_update_manager_state)dlsym(info.engine_handle,
839 MA_WAKEUP_ENGINE_FUNC_UPDATE_MANAGER_STATE);
840 info.interface.update_recognition_result =
841 (wakeup_engine_update_recognition_result)dlsym(info.engine_handle,
842 MA_WAKEUP_ENGINE_FUNC_UPDATE_RECOGNITION_RESULT);
843 info.interface.set_audio_format =
844 (wakeup_engine_set_audio_format)dlsym(info.engine_handle,
845 MA_WAKEUP_ENGINE_FUNC_SET_AUDIO_FORMAT);
846 info.interface.get_audio_format =
847 (wakeup_engine_get_audio_format)dlsym(info.engine_handle,
848 MA_WAKEUP_ENGINE_FUNC_GET_AUDIO_FORMAT);
849 info.interface.feed_audio_data =
850 (wakeup_engine_feed_audio_data)dlsym(info.engine_handle,
851 MA_WAKEUP_ENGINE_FUNC_FEED_AUDIO_DATA);
852 info.interface.get_utterance_data_count =
853 (wakeup_engine_get_utterance_data_count)dlsym(info.engine_handle,
854 MA_WAKEUP_ENGINE_FUNC_GET_UTTERANCE_DATA_COUNT);
855 info.interface.get_utterance_data =
856 (wakeup_engine_get_utterance_data)dlsym(info.engine_handle,
857 MA_WAKEUP_ENGINE_FUNC_GET_UTTERANCE_DATA);
858 info.interface.get_wake_word_data_count =
859 (wakeup_engine_get_wake_word_data_count)dlsym(info.engine_handle,
860 MA_WAKEUP_ENGINE_FUNC_GET_WAKE_WORD_DATA_COUNT);
861 info.interface.get_wake_word_data =
862 (wakeup_engine_get_wake_word_data)dlsym(info.engine_handle,
863 MA_WAKEUP_ENGINE_FUNC_GET_WAKE_WORD_DATA);
864 info.interface.set_assistant_specific_command =
865 (wakeup_engine_set_assistant_specific_command)dlsym(info.engine_handle,
866 MA_WAKEUP_ENGINE_FUNC_SET_ASSISTANT_SPECIFIC_COMMAND);
867 info.interface.set_wake_word_audio_require_flag =
868 (wakeup_engine_set_wake_word_audio_require_flag)dlsym(info.engine_handle,
869 MA_WAKEUP_ENGINE_FUNC_SET_WAKE_WORD_AUDIO_REQUIRE_FLAG);
870 info.interface.set_wakeup_event_callback =
871 (wakeup_engine_set_wakeup_event_callback)dlsym(info.engine_handle,
872 MA_WAKEUP_ENGINE_FUNC_SET_WAKEUP_EVENT_CALLBACK);
873 info.interface.set_speech_status_callback =
874 (wakeup_engine_set_speech_status_callback)dlsym(info.engine_handle,
875 MA_WAKEUP_ENGINE_FUNC_SET_SPEECH_STATUS_CALLBACK);
876 info.interface.set_error_callback =
877 (wakeup_engine_set_error_callback)dlsym(info.engine_handle,
878 MA_WAKEUP_ENGINE_FUNC_SET_ERROR_CALLBACK);
879 info.interface.set_audio_data_require_status_callback =
880 (wakeup_engine_set_audio_data_require_status_callback)dlsym(info.engine_handle,
881 MA_WAKEUP_ENGINE_FUNC_SET_AUDIO_DATA_REQUIRE_STATUS_CALLBACK);
882 info.interface.set_wakeup_engine_command_callback =
883 (wakeup_engine_set_wakeup_engine_command_callback)dlsym(info.engine_handle,
884 MA_WAKEUP_ENGINE_FUNC_SET_WAKEUP_ENGINE_COMMAND_CALLBACK);
886 /* Interfaces after version 1 */
887 info.interface.get_version =
888 (wakeup_engine_get_version)dlsym(info.engine_handle,
889 MA_WAKEUP_ENGINE_FUNC_GET_VERSION);
890 info.interface.set_dependency_module_command =
891 (wakeup_engine_set_dependency_module_command)dlsym(info.engine_handle,
892 MA_WAKEUP_ENGINE_FUNC_SET_DEPENDENCY_MODULE_COMMAND);
895 info.engine_path = path;
896 info.engine_name = name;
898 info.activated = false;
899 info.audio_data_require_status = false;
901 /* All the necessary information has already been set properly */
902 mEngineInfo.push_back(info);
904 /* Workaround for registering C-style callbacks */
906 CWakeupEngineManager *manager;
910 static deque<CallbackUserData> callback_user_data;
912 CallbackUserData user_data;
913 user_data.manager = this;
914 user_data.engine_name = info.engine_name;
915 callback_user_data.push_back(user_data);
917 MWR_LOGI("Initializing wakeup engine : %s %p %p",
918 info.engine_path.c_str(),
919 info.interface.initialize,
920 &callback_user_data.back());
923 if (info.interface.set_wakeup_event_callback) {
924 info.interface.set_wakeup_event_callback(
925 [](mas_wakeup_event_info info, void* user_data) {
926 MWR_LOGI("user_data : %p", user_data);
927 CallbackUserData *data = static_cast<CallbackUserData*>(user_data);
928 if (nullptr == data) return;
929 if (nullptr == data->manager) return;
930 info.wakeup_engine = data->engine_name.c_str();
931 data->manager->on_wakeup_event(data->engine_name, info);
932 }, &(callback_user_data.back()));
935 if (info.interface.set_audio_data_require_status_callback) {
936 info.interface.set_audio_data_require_status_callback(
937 [](bool require, void* user_data) {
938 MWR_LOGI("user_data : %p", user_data);
939 CallbackUserData *data = static_cast<CallbackUserData*>(user_data);
940 if (nullptr == data) return;
941 if (nullptr == data->manager) return;
942 data->manager->on_audio_data_require_status(data->engine_name, require);
943 }, &(callback_user_data.back()));
946 if (info.interface.set_wakeup_engine_command_callback) {
947 info.interface.set_wakeup_engine_command_callback(
948 [](mas_wakeup_engine_command_target_e target,
949 const char* assistant_name, const char* command, void* user_data) {
950 MWR_LOGI("user_data : %p", user_data);
951 CallbackUserData* data = static_cast<CallbackUserData*>(user_data);
952 if (nullptr == data) return;
953 if (nullptr == data->manager) return;
954 if (nullptr == command) return;
955 data->manager->on_wakeup_engine_command(
956 data->engine_name, target, (assistant_name ? assistant_name : ""), command);
957 }, &(callback_user_data.back()));
960 if (info.interface.initialize) {
961 info.interface.initialize();
963 if (info.interface.get_version) {
965 if (0 == info.interface.get_version(&version)) {
966 info.version = version;
969 } catch (const std::exception& e) {
970 MWR_LOGE("[ERROR] wakeup engine %s threw exception : %s",
971 info.engine_name.c_str(), e.what());
975 void CWakeupEngineManager::add_engine_directory(string name, string path)
977 if (0 == path.size()) return;
979 DIR* dp = opendir(path.c_str());
981 MWR_LOGD("Failed opening directory : %s", path.c_str());
983 struct dirent *dirp = NULL;
989 if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
992 if (DT_REG != dirp->d_type) /* If not a regular file */
997 filepath += dirp->d_name;
999 if (filepath.length() >= _POSIX_PATH_MAX) {
1000 MWR_LOGD("File path is too long : %s", filepath.c_str());
1004 add_engine(name, filepath);
1006 } while (NULL != dirp);