Deactivate wakeup engines with no activated assistant
[platform/core/uifw/multi-assistant-service.git] / plugins / wakeup-manager / src / wakeup_engine_manager.cpp
1 #include "wakeup_engine_manager.h"
2 #include "wakeup_manager_main.h"
3
4 #include <dlfcn.h>
5 #include <algorithm>
6 #include <pkgmgr-info.h>
7 #include <deque>
8
9 namespace multiassistant
10 {
11 namespace wakeup
12 {
13
14 /* Need to check whether this value needs to be configurable */
15 static int g_speech_pcm_wait_count = 400;
16
17 /* Utility function for checking if an element exists in a container */
18 template<class C, class T>
19 static auto contains(const C& v, const T& x) -> decltype(end(v), true)
20 {
21         return end(v) != find(begin(v), end(v), x);
22 }
23
24 CWakeupEngineManager::CWakeupEngineManager()
25 {
26 }
27
28 CWakeupEngineManager::~CWakeupEngineManager()
29 {
30 }
31
32 CWakeupEngineManager::CWakeupEngineManager(IEngineEventObserver *observer) : CWakeupEngineManager()
33 {
34         subscribe(observer);
35 }
36
37 void CWakeupEngineManager::initialize()
38 {
39         DIR* dp = opendir(MA_WAKEUP_ENGINE_PATH);
40         if (nullptr == dp) {
41                 MWR_LOGD("Failed opening directory : %s", (const char*)MA_WAKEUP_ENGINE_PATH);
42         } else {
43                 struct dirent *dirp = nullptr;
44                 char dirpath[_POSIX_PATH_MAX];
45                 do {
46                         dirp = readdir(dp);
47
48                         if (nullptr != dirp) {
49                                 const string current_directory{"."};
50                                 const string parent_directory{".."};
51                                 if (0 == current_directory.compare(dirp->d_name) ||
52                                         0 == parent_directory.compare(dirp->d_name))
53                                         continue;
54
55                                 if (DT_DIR != dirp->d_type) /* If not a directory */
56                                         continue;
57
58                                 int dirpath_len = strlen(MA_WAKEUP_ENGINE_PATH) + strlen(dirp->d_name) + 1;
59                                 if (dirpath_len >= _POSIX_PATH_MAX) {
60                                         MWR_LOGD("File path is too long : %s", dirp->d_name);
61                                         closedir(dp);
62                                         return;
63                                 }
64
65                                 memset(dirpath, '\0', _POSIX_PATH_MAX);
66                                 snprintf(dirpath, _POSIX_PATH_MAX, "%s/%s",
67                                         (const char*)(MA_WAKEUP_ENGINE_PATH), dirp->d_name);
68
69                                 add_engine_directory(string{dirp->d_name}, dirpath);
70                         }
71                 } while (nullptr != dirp);
72
73                 closedir(dp);
74         }
75 }
76
77 void CWakeupEngineManager::deinitialize()
78 {
79         for (auto& info : mEngineInfo) {
80                 if (info.interface.set_wakeup_event_callback) {
81                         info.interface.set_wakeup_event_callback(nullptr, nullptr);
82                 }
83                 if (info.interface.set_speech_status_callback) {
84                         info.interface.set_speech_status_callback(nullptr, nullptr);
85                 }
86                 if (info.interface.set_error_callback) {
87                         info.interface.set_error_callback(nullptr, nullptr);
88                 }
89                 if (info.interface.set_audio_data_require_status_callback) {
90                         info.interface.set_audio_data_require_status_callback(nullptr, nullptr);
91                 }
92                 if (info.interface.deinitialize) {
93                         info.interface.deinitialize();
94                 }
95                 if (info.engine_handle) {
96                         dlclose(info.engine_handle);
97                         info.engine_handle = nullptr;
98                 }
99         }
100         mSelectedEngine = nullptr;
101         mEngineInfo.clear();
102 }
103
104 void CWakeupEngineManager::subscribe(IEngineEventObserver *observer)
105 {
106         mObservers.push_back(observer);
107         MWR_LOGD("Added Observer : %p %zu", observer, mObservers.size());
108 }
109
110 void CWakeupEngineManager::unsubscribe(IEngineEventObserver *observer)
111 {
112         auto iter = find(mObservers.begin(), mObservers.end(), observer);
113         if (iter != mObservers.end()) {
114                 mObservers.erase(iter);
115         }
116 }
117
118 bool CWakeupEngineManager::get_audio_data_required()
119 {
120         return mAudioDataRequired;
121 }
122
123 void CWakeupEngineManager::set_selected_wakeup_info(wakeup_event_info wakeup_info)
124 {
125         mSelectedEngine = nullptr;
126         for (const auto& info : mEngineInfo) {
127                 string appid = string{wakeup_info.wakeup_appid};
128                 bool found = contains(info.assistant_list, appid);
129
130                 if (found) {
131                         mSelectedEngine = &info;
132                         MWR_LOGD("Selected : %s", info.engine_name.c_str());
133                 }
134         }
135 }
136
137 bool CWakeupEngineManager::set_language(string language)
138 {
139         for (const auto& info : mEngineInfo) {
140                 if (info.interface.set_language) {
141                         info.interface.set_language(language.c_str());
142                 }
143         }
144         return true;
145 }
146
147 void CWakeupEngineManager::set_assistant_activated(string appid, bool activated)
148 {
149         MWR_LOGD("[ENTER] : %s %d", appid.c_str(), activated);
150         for (auto& info : mEngineInfo) {
151                 const auto& iter = find_if(info.assistant_list.begin(), info.assistant_list.end(),
152                         [appid](const string& assistant) {
153                                 return (0 == assistant.compare(appid));
154                         });
155
156                 /* If the appid is in the assistant list */
157                 if (info.assistant_list.end() != iter) {
158                         bool previously_activated = info.activated;
159                         if (activated) {
160                                 info.activated_assistants.insert(appid);
161                         } else {
162                                 info.activated_assistants.erase(appid);
163                         }
164                         info.activated = (info.activated_assistants.size() > 0);
165                         if (previously_activated != info.activated) {
166                                 if (info.activated) {
167                                         info.interface.activate();
168                                 } else {
169                                         info.interface.deactivate();
170                                 }
171                                 /* Activated status changed, need to update audio_data_require_status too */
172                                 on_audio_data_require_status(info.engine_name, info.audio_data_require_status);
173                         }
174                 }
175         }
176 }
177
178 void CWakeupEngineManager::set_wake_word_audio_require_flag(bool require)
179 {
180         MWR_LOGD("[ENTER]");
181         mWakeWordAudioRequired = require;
182         for (const auto& info : mEngineInfo) {
183                 if (info.interface.set_wake_word_audio_require_flag) {
184                         info.interface.set_wake_word_audio_require_flag(require);
185                 }
186         }
187 }
188
189 void CWakeupEngineManager::streaming_speech_data_thread_func()
190 {
191         MWR_LOGD("[ENTER]");
192
193         if (nullptr == mSelectedEngine)
194                 return;
195
196         const wakeup_engine_interface *interface = &(mSelectedEngine->interface);
197
198         if (NULL == interface ||
199                 NULL == interface->get_utterance_data ||
200                 NULL == interface->get_utterance_data_count)
201                 return;
202
203         MWR_LOGD("data_count : %d", interface->get_utterance_data_count());
204
205         wakeup_speech_data speech_data;
206         int index = 0;
207         bool finish_event_sent = false;
208
209         if (mWakeWordAudioRequired &&
210                 NULL != interface->get_wake_word_data &&
211                 NULL != interface->get_wake_word_data_count) {
212                 for (const auto& observer : mObservers) {
213                         if (observer) {
214                                 if (!observer->on_audio_streaming_data_section(MA_AUDIO_STREAMING_DATA_SECTION_WAKE_WORD)) {
215                                         LOGE("[Recorder WARNING] One of the observer returned false");
216                                 }
217                         }
218                 }
219                 int count = interface->get_wake_word_data_count();
220                 while (!(mStopStreamingThread.load()) && index < count) {
221                         int ret = interface->get_wake_word_data(index, &speech_data);
222                         if (0 == ret) {
223                                 for (const auto& observer : mObservers) {
224                                         if (observer) {
225                                                 if (!observer->on_streaming_audio_data(
226                                                         speech_data.event, speech_data.buffer, speech_data.len)) {
227                                                         LOGE("[Recorder WARNING] One of the observer returned false");
228                                                 }
229                                         }
230                                 }
231                         } else {
232                                 break;
233                         }
234                         index++;
235                 }
236                 index = 0;
237                 for (const auto& observer : mObservers) {
238                         if (observer) {
239                                 if (!observer->on_audio_streaming_data_section(MA_AUDIO_STREAMING_DATA_SECTION_UTTERANCE)) {
240                                         LOGE("[Recorder WARNING] One of the observer returned false");
241                                 }
242                         }
243                 }
244         }
245
246         while (!(mStopStreamingThread.load())) {
247                 int ret = -1;
248                 int cnt = 0;
249
250                 /* get feedback data */
251                 if (interface && interface->get_utterance_data) {
252                         ret = interface->get_utterance_data(index, &speech_data);
253                         if (0 != ret) {
254                                 /* empty queue */
255                                 MWR_LOGD("[DEBUG] No feedback data. Waiting mode : %d", ret);
256
257                                 /* waiting */
258                                 while (!(mStopStreamingThread.load())) {
259                                         this_thread::sleep_for(chrono::milliseconds(10));
260                                         if (index < interface->get_utterance_data_count()) {
261                                                 MWR_LOGI("[INFO] Resume thread");
262                                                 break;
263                                         }
264                                         if (g_speech_pcm_wait_count < cnt) {
265                                                 MWR_LOGE("[ERROR] Wrong request, there's no pcm data");
266                                                 for (const auto& observer : mObservers) {
267                                                         if (observer) {
268                                                                 if (!observer->on_streaming_audio_data(
269                                                                         WAKEUP_SPEECH_STREAMING_EVENT_FAIL, NULL, 0)) {
270                                                                         LOGE("[Recorder WARNING] One of the observer returned false");
271                                                                 }
272                                                         }
273                                                 }
274                                                 return;
275                                         }
276                                         cnt++;
277                                 }
278                                 MWR_LOGI("[INFO] Finish to wait for new feedback data come");
279
280                                 /* resume feedback thread */
281                                 continue;
282                         }
283
284                         for (const auto& observer : mObservers) {
285                                 if (observer) {
286                                         if (!observer->on_streaming_audio_data(
287                                                 speech_data.event, speech_data.buffer, speech_data.len)) {
288                                                 LOGE("[Recorder WARNING] One of the observer returned false");
289                                         }
290                                 }
291                         }
292
293                         if (WAKEUP_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
294                                 MWR_LOGI("[INFO] Finish to get and send speech data");
295                                 finish_event_sent = true;
296                                 break;
297                         }
298
299                         index++;
300                 }
301         }
302
303         if (true != finish_event_sent) {
304                 unsigned char final_buffer[2] = {'\0', };
305                 for (const auto& observer : mObservers) {
306                         if (observer) {
307                                 if (!observer->on_streaming_audio_data(
308                                         WAKEUP_SPEECH_STREAMING_EVENT_FINISH, final_buffer, sizeof(final_buffer))) {
309                                         LOGE("[Recorder WARNING] One of the observer returned false");
310                                 }
311                         }
312                 }
313         }
314 }
315
316 void CWakeupEngineManager::start_streaming_current_utterance_data()
317 {
318         if (mStreamingThread.joinable()) {
319                 MWR_LOGE("ERROR : mStreamingThread is joinable, will not start a new thread");
320                 return;
321         }
322         mStreamingThread = thread(&CWakeupEngineManager::streaming_speech_data_thread_func, this);
323 }
324
325 void CWakeupEngineManager::stop_streaming_current_utterance_data()
326 {
327         if (mStreamingThread.joinable()) {
328                 MWR_LOGD("mStreamingThread is joinable, trying join()");
329                 mStopStreamingThread.store(true);
330                 mStreamingThread.join();
331         }
332         mStopStreamingThread.store(false);
333 }
334
335 void CWakeupEngineManager::update_manager_state(wakeup_manager_state_e state)
336 {
337         for (const auto& info : mEngineInfo) {
338                 if (info.interface.update_manager_state) {
339                         info.interface.update_manager_state(state);
340                 }
341         }
342 }
343
344 void CWakeupEngineManager::update_recognition_result(string appid, int result)
345 {
346         if (mSelectedEngine) {
347                 if (mSelectedEngine->interface.update_recognition_result) {
348                         mSelectedEngine->interface.update_recognition_result(appid.c_str(), result);
349                 }
350         }
351 }
352
353 void CWakeupEngineManager::engine_add_target_assistant(string engine_name, string appid)
354 {
355         const auto& iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
356                 [engine_name](const EngineInfo& info) {
357                         return (0 == info.engine_name.compare(engine_name));
358                 });
359
360         if (mEngineInfo.end() == iter) {
361                 /* Not found, add new library */
362                 pkgmgrinfo_appinfo_h handle;
363                 int ret = pkgmgrinfo_appinfo_get_appinfo(engine_name.c_str(), &handle);
364                 if (PMINFO_R_OK == ret) {
365                         char *root_path = nullptr;
366                         ret = pkgmgrinfo_appinfo_get_root_path(handle, &root_path);
367                         if (PMINFO_R_OK == ret && nullptr != root_path) {
368                                 string path = root_path;
369                                 path += "/";
370                                 path += MA_WAKEUP_DEDICATED_ENGINE_PATH;
371                                 add_engine(engine_name, path);
372                         }
373                         pkgmgrinfo_appinfo_destroy_appinfo(handle);
374                 }
375                 /* Find again to add appid to the newly created engine's assistant list */
376                 const auto &new_iter = find_if(mEngineInfo.begin(), mEngineInfo.end(),
377                         [engine_name](const EngineInfo& info) {
378                                 return (0 == info.engine_name.compare(engine_name));
379                         });
380                 if (mEngineInfo.end() != new_iter) {
381                         new_iter->assistant_list.push_back(appid);
382                 }
383         } else {
384                 /* If the engine already exists, simply add the appid to the assistant list */
385                 iter->assistant_list.push_back(appid);
386         }
387 }
388
389 void CWakeupEngineManager::engine_add_wakeup_word(string appid, string wakeup_word, string language)
390 {
391         for (const auto& info : mEngineInfo) {
392                 bool found = contains(info.assistant_list, appid);
393                 if (found) {
394                         if (info.interface.add_wakeup_word) {
395                                 info.interface.add_wakeup_word(appid.c_str(), wakeup_word.c_str(), language.c_str());
396                         }
397                 }
398         }
399 }
400
401 void CWakeupEngineManager::engine_set_assistant_specific_command(string appid, string command)
402 {
403         for (const auto& info : mEngineInfo) {
404                 bool found = contains(info.assistant_list, appid);
405                 if (found) {
406                         if (info.interface.set_assistant_specific_command) {
407                                 info.interface.set_assistant_specific_command(appid.c_str(), command.c_str());
408                         }
409                 }
410         }
411 }
412
413 void CWakeupEngineManager::engine_feed_audio_data(long time, void* data, int len)
414 {
415         for (const auto& info : mEngineInfo) {
416                 if (info.activated &&
417                         info.audio_data_require_status &&
418                         info.interface.feed_audio_data) {
419                         int ret = info.interface.feed_audio_data(time, data, len);
420                         if (0 != ret) {
421                                 LOGE("[ERROR] Fail to feed speech data, ret(%d) : %s", ret, info.engine_name.c_str());
422                         }
423                 }
424         }
425 }
426
427 bool CWakeupEngineManager::on_wakeup_event(string engine_name, wakeup_event_info info)
428 {
429         MWR_LOGD("[ENTER]");
430
431         for (const auto& observer : mObservers) {
432                 if (observer) {
433                         if (!observer->on_wakeup_event(engine_name, info)) {
434                                 LOGE("[Recorder WARNING] One of the observer returned false");
435                         }
436                 }
437         }
438
439         return true;
440 }
441
442 bool CWakeupEngineManager::on_speech_status(string engine_name, wakeup_service_speech_status_e status)
443 {
444         MWR_LOGD("[ENTER]");
445
446         for (const auto& observer : mObservers) {
447                 if (observer) {
448                         if (!observer->on_speech_status(engine_name, status)) {
449                                 LOGE("[Recorder WARNING] One of the observer returned false");
450                         }
451                 }
452         }
453
454         return true;
455 }
456
457 bool CWakeupEngineManager::on_error(string engine_name, int error_code, string error_message)
458 {
459         MWR_LOGD("[ENTER]");
460
461         for (const auto& observer : mObservers) {
462                 if (observer) {
463                         if (!observer->on_error(engine_name, error_code, error_message)) {
464                                 LOGE("[Recorder WARNING] One of the observer returned false");
465                         }
466                 }
467         }
468
469         return true;
470 }
471
472 bool CWakeupEngineManager::on_audio_data_require_status(string engine_name, bool require)
473 {
474         MWR_LOGD("[ENTER] %s, %d", engine_name.c_str(), require);
475
476         bool found = false;
477         // LOCK REQUIRED
478         int count = 0;
479         for (auto& info : mEngineInfo) {
480                 if (info.engine_name.compare(engine_name) == 0) {
481                         found = true;
482                         info.audio_data_require_status = require;
483                 }
484                 if (info.activated && info.audio_data_require_status) {
485                         count++;
486                 }
487         }
488         MWR_LOGD("count : %d", count);
489         if (count > 0) {
490                 mAudioDataRequired = true;
491         } else {
492                 mAudioDataRequired = false;
493         }
494
495         if (found) {
496                 for (const auto& observer : mObservers) {
497                         if (observer) {
498                                 if (!observer->on_audio_data_require_status(engine_name, require)) {
499                                         LOGE("[Recorder WARNING] One of the observer returned false");
500                                 }
501                         }
502                 }
503         }
504         // UNLOCK REQUIRED
505         return true;
506 }
507
508 void CWakeupEngineManager::add_engine(string name, string path)
509 {
510         MWR_LOGD("Name (%s), Filepath(%s)", name.c_str(), path.c_str());
511
512         char* error = NULL;
513         EngineInfo info;
514         info.engine_handle = dlopen(path.c_str(), RTLD_LAZY);
515         if (nullptr != (error = dlerror()) || nullptr == info.engine_handle) {
516                 MWR_LOGD("[ERROR] Fail to dlopen(%s), error(%s)", path.c_str(), error);
517                 if (info.engine_handle) dlclose(info.engine_handle);
518                 return;
519         }
520
521         /* Interfaces without version information */
522         info.interface.initialize =
523                 (wakeup_engine_initialize)dlsym(info.engine_handle,
524                 MA_WAKEUP_ENGINE_FUNC_INITIALIZE);
525         info.interface.deinitialize =
526                 (wakeup_engine_deinitialize)dlsym(info.engine_handle,
527                 MA_WAKEUP_ENGINE_FUNC_DEINITIALIZE);
528         info.interface.activate =
529                 (wakeup_engine_activate)dlsym(info.engine_handle,
530                 MA_WAKEUP_ENGINE_FUNC_ACTIVATE);
531         info.interface.deactivate =
532                 (wakeup_engine_deactivate)dlsym(info.engine_handle,
533                 MA_WAKEUP_ENGINE_FUNC_DEACTIVATE);
534         info.interface.add_wakeup_word =
535                 (wakeup_engine_add_wakeup_word)dlsym(info.engine_handle,
536                 MA_WAKEUP_ENGINE_FUNC_ADD_WAKEUP_WORD);
537         info.interface.add_language =
538                 (wakeup_engine_add_language)dlsym(info.engine_handle,
539                 MA_WAKEUP_ENGINE_FUNC_ADD_LANGUAGE);
540         info.interface.set_language =
541                 (wakeup_engine_set_language)dlsym(info.engine_handle,
542                 MA_WAKEUP_ENGINE_FUNC_SET_LANGUAGE);
543         info.interface.update_manager_state =
544                 (wakeup_engine_update_manager_state)dlsym(info.engine_handle,
545                 MA_WAKEUP_ENGINE_FUNC_UPDATE_MANAGER_STATE);
546         info.interface.update_recognition_result =
547                 (wakeup_engine_update_recognition_result)dlsym(info.engine_handle,
548                 MA_WAKEUP_ENGINE_FUNC_UPDATE_RECOGNITION_RESULT);
549         info.interface.set_audio_format =
550                 (wakeup_engine_set_audio_format)dlsym(info.engine_handle,
551                 MA_WAKEUP_ENGINE_FUNC_SET_AUDIO_FORMAT);
552         info.interface.get_audio_format =
553                 (wakeup_engine_get_audio_format)dlsym(info.engine_handle,
554                 MA_WAKEUP_ENGINE_FUNC_GET_AUDIO_FORMAT);
555         info.interface.feed_audio_data =
556                 (wakeup_engine_feed_audio_data)dlsym(info.engine_handle,
557                 MA_WAKEUP_ENGINE_FUNC_FEED_AUDIO_DATA);
558         info.interface.get_utterance_data_count =
559                 (wakeup_engine_get_utterance_data_count)dlsym(info.engine_handle,
560                 MA_WAKEUP_ENGINE_FUNC_GET_UTTERANCE_DATA_COUNT);
561         info.interface.get_utterance_data =
562                 (wakeup_engine_get_utterance_data)dlsym(info.engine_handle,
563                 MA_WAKEUP_ENGINE_FUNC_GET_UTTERANCE_DATA);
564         info.interface.get_wake_word_data_count =
565                 (wakeup_engine_get_wake_word_data_count)dlsym(info.engine_handle,
566                 MA_WAKEUP_ENGINE_FUNC_GET_WAKE_WORD_DATA_COUNT);
567         info.interface.get_wake_word_data =
568                 (wakeup_engine_get_wake_word_data)dlsym(info.engine_handle,
569                 MA_WAKEUP_ENGINE_FUNC_GET_WAKE_WORD_DATA);
570         info.interface.set_assistant_specific_command =
571                 (wakeup_engine_set_assistant_specific_command)dlsym(info.engine_handle,
572                 MA_WAKEUP_ENGINE_FUNC_SET_ASSISTANT_SPECIFIC_COMMAND);
573         info.interface.set_wake_word_audio_require_flag =
574                 (wakeup_engine_set_wake_word_audio_require_flag)dlsym(info.engine_handle,
575                 MA_WAKEUP_ENGINE_FUNC_SET_WAKE_WORD_AUDIO_REQUIRE_FLAG);
576         info.interface.set_wakeup_event_callback =
577                 (wakeup_engine_set_wakeup_event_callback)dlsym(info.engine_handle,
578                 MA_WAKEUP_ENGINE_FUNC_SET_WAKEUP_EVENT_CALLBACK);
579         info.interface.set_speech_status_callback =
580                 (wakeup_engine_set_speech_status_callback)dlsym(info.engine_handle,
581                 MA_WAKEUP_ENGINE_FUNC_SET_SPEECH_STATUS_CALLBACK);
582         info.interface.set_error_callback =
583                 (wakeup_engine_set_error_callback)dlsym(info.engine_handle,
584                 MA_WAKEUP_ENGINE_FUNC_SET_ERROR_CALLBACK);
585         info.interface.set_audio_data_require_status_callback =
586                 (wakeup_engine_set_audio_data_require_status_callback)dlsym(info.engine_handle,
587                 MA_WAKEUP_ENGINE_FUNC_SET_AUDIO_DATA_REQUIRE_STATUS_CALLBACK);
588
589         /* Interfaces after version 1 */
590         info.interface.get_version =
591                 (wakeup_engine_get_version)dlsym(info.engine_handle,
592                 MA_WAKEUP_ENGINE_FUNC_GET_VERSION);
593
594         info.version = 0;
595         info.engine_path = path;
596         info.engine_name = name;
597
598         info.activated = false;
599         info.audio_data_require_status = false;
600
601         /* All the necessary information has already been set properly */
602         mEngineInfo.push_back(info);
603
604         MWR_LOGD("Initializing wakeup engine : %s %p",
605                 info.engine_path.c_str(),
606                 info.interface.initialize);
607
608         /* Workaround for registering C-style callbacks */
609         typedef struct {
610                 CWakeupEngineManager *manager;
611                 string engine_name;
612         } CallbackUserData;
613
614         static deque<CallbackUserData> callback_user_data;
615
616         CallbackUserData user_data;
617         user_data.manager = this;
618         user_data.engine_name = info.engine_name;
619         callback_user_data.push_back(user_data);
620
621         if (info.interface.set_wakeup_event_callback) {
622                 info.interface.set_wakeup_event_callback(
623                         [](wakeup_event_info info, void* user_data) {
624                                 CallbackUserData *data = static_cast<CallbackUserData*>(user_data);
625                                 if (nullptr == data) return;
626                                 if (nullptr == data->manager) return;
627                                 info.wakeup_engine = data->engine_name.c_str();
628                                 data->manager->on_wakeup_event(data->engine_name, info);
629                         }, &(callback_user_data.back()));
630         }
631
632         if (info.interface.set_audio_data_require_status_callback) {
633                 info.interface.set_audio_data_require_status_callback(
634                         [](bool require, void* user_data) {
635                                 CallbackUserData *data = static_cast<CallbackUserData*>(user_data);
636                                 if (nullptr == data) return;
637                                 if (nullptr == data->manager) return;
638                                 data->manager->on_audio_data_require_status(data->engine_name, require);
639                         }, &(callback_user_data.back()));
640         }
641
642         if (info.interface.initialize) {
643                 info.interface.initialize();
644         }
645         if (info.interface.get_version) {
646                 int version;
647                 if (0 == info.interface.get_version(&version)) {
648                         info.version = version;
649                 }
650         }
651 }
652
653 void CWakeupEngineManager::add_engine_directory(string name, string path)
654 {
655         if (0 == path.size()) return;
656
657         DIR* dp = opendir(path.c_str());
658         if (NULL == dp) {
659                 MWR_LOGD("Failed opening directory : %s", path.c_str());
660         } else {
661                 struct dirent *dirp = NULL;
662                 string filepath;
663                 do {
664                         dirp = readdir(dp);
665
666                         if (NULL != dirp) {
667                                 if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
668                                         continue;
669
670                                 if (DT_REG != dirp->d_type) /* If not a regular file */
671                                         continue;
672
673                                 filepath = path;
674                                 filepath += "/";
675                                 filepath += dirp->d_name;
676
677                                 if (filepath.length() >= _POSIX_PATH_MAX) {
678                                         MWR_LOGD("File path is too long : %s", filepath.c_str());
679                                         closedir(dp);
680                                         return;
681                                 }
682                                 add_engine(name, filepath);
683                         }
684                 } while (NULL != dirp);
685
686                 closedir(dp);
687         }
688 }
689
690 } // wakeup
691 } // multiassistant