2 * Copyright 2018 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.1 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
28 #include <sound_manager.h>
31 #include "wakeup_manager_main.h"
32 #include "wakeup_manager.h"
33 #include "wakeup_manager_audio.h"
34 #include "wakeup_policy_default.h"
36 static wakeup_service_wakeup_event_cb g_wakeup_event_cb;
37 static void* g_wakeup_event_user_data;
39 static wakeup_service_speech_streaming_cb g_utterance_streaming_cb;
40 static void* g_utterance_streaming_user_data;
42 static wakeup_service_speech_streaming_cb g_previous_utterance_streaming_cb;
43 static void* g_previous_utterance_streaming_user_data;
45 static wakeup_service_speech_streaming_cb g_follow_up_streaming_cb;
46 static void* g_follow_up_streaming_user_data;
48 static wakeup_service_speech_status_cb g_speech_status_cb;
49 static void* g_speech_status_user_data;
51 static wakeup_service_error_cb g_error_cb;
52 static void* g_error_user_data;
54 #define MAX_WAKEUP_ENGINE_NUM 10
55 static int g_engine_count = 0;
59 #include <bluetooth_product.h>
65 bool audio_data_require_status{false};
66 char engine_name[_POSIX_PATH_MAX];
67 char engine_path[_POSIX_PATH_MAX];
68 wakeup_engine_interface interface{nullptr, };
69 std::vector<std::string> assistant_list;
72 //static int g_wakeup_engine_selected = -1;
73 static int g_wakeup_engine_selected = 0;
74 static wakeup_engine_info g_wakeup_engine_info[MAX_WAKEUP_ENGINE_NUM];
76 static char* g_current_language = NULL;
77 static wakeup_manager_state_e g_wakeup_manager_state;
79 static bool g_audio_data_required = false;
80 static audio_in_h g_audio_h = NULL;
81 static sound_stream_info_h g_stream_info_h = NULL;
83 static std::thread g_recorder_thread;
84 static std::atomic_bool g_recorder_thread_should_stop;
86 static std::thread g_speech_data_thread;
87 static std::atomic_bool g_speech_data_thread_should_stop;
89 static bool g_voice_key_pressed = false;
90 static std::vector<wakeup_engine_speech_data> g_speech_data;
92 #define DEFAULT_ASSISTANT_APPID "com.samsung.bixby-voice"
94 #define WAKEUP_SETTINGS_KEY_DEFAULT_ASSISTANT_APPID "db/multi-assistant/default_assistant_appid"
95 #define WAKEUP_SETTINGS_KEY_UI_PANEL_ENABLED "db/multi-assistant/ui_panel_enabled"
96 #define WAKEUP_SETTINGS_KEY_CONVERSATION_TIMEOUT "db/multi-assistant/conversation_timeout"
97 #define WAKEUP_SETTINGS_KEY_MULTIPLE_MODE "db/multi-assistant/multiple_mode"
98 #define WAKEUP_SETTINGS_KEY_ENABLED_ASSISTANTS "db/multi-assistant/enabled_assistants"
99 #define WAKEUP_SETTINGS_KEY_WAKEUP_POLICY_DELAY "db/multi-assistant/wakeup_policy_delay"
100 #define WAKEUP_SETTINGS_KEY_WAKEUP_POLICY_PRIORITY "db/multi-assistant/wakeup_policy_priority"
103 std::string default_assistant_appid{DEFAULT_ASSISTANT_APPID};
104 bool ui_panel_enabled{true};
105 float conversation_timeout{5.0};
106 bool multiple_mode{true};
107 std::vector<std::string> enabled_assistants{DEFAULT_ASSISTANT_APPID};
108 float wakeup_policy_delay{0.1};
109 std::vector<std::string> wakeup_policy_priority; // No priority by default
112 static wakeup_settings g_wakeup_settings;
114 class CWakeupEventObserver : public IWakeupEventObserver
117 void on_wakeup(wakeup_event_info info) override;
119 static std::unique_ptr<CWakeupPolicy> g_wakeup_policy;
120 static CWakeupEventObserver g_wakeup_event_observer;
124 #define EFL_BETA_API_SUPPORT
126 #include <Ecore_Wl2.h>
127 #include <Key_Mode.h>
128 #include <Ecore_Input.h>
130 static int g_bt_extend_count;
132 #define SMART_CONTROL_EXTEND_CMD 0x03
133 #define SMART_CONTROL_START_CMD 0x04
135 Ecore_Event_Handler* _key_down_handler = NULL;
136 Ecore_Event_Handler* _key_up_handler = NULL;
138 Eina_Bool _key_down_cb(void* data, int type, void* event)
140 Ecore_Event_Key *ev = (Ecore_Event_Key *) event;
142 MWR_LOGD("KEY[%s], typep[%d]", ev->keyname, type);
144 if (ev->keyname && strncmp(ev->keyname, KEY_BT_VOICE, strlen(KEY_BT_VOICE)) == 0 ) {
145 wakeup_manager_send_assistant_specific_command(0, "voice_key_pressed");
149 return ECORE_CALLBACK_DONE;
152 Eina_Bool _key_up_cb(void* data, int type, void* event)
154 Ecore_Event_Key *ev = (Ecore_Event_Key *) event;
156 MWR_LOGD("KEY[%s], typep[%d]", ev->keyname, type);
158 if (ev->keyname && strncmp(ev->keyname, KEY_BT_VOICE, strlen(KEY_BT_VOICE)) == 0) {
159 bt_hid_rc_stop_sending_voice(NULL);
160 wakeup_manager_send_assistant_specific_command(0, "voice_key_released");
163 return ECORE_CALLBACK_DONE;
166 bool _grab_voice_key(void)
168 Eina_Bool bRet = true;
169 bRet = ecore_wl2_window_keygrab_set(NULL, KEY_BT_VOICE, 0, 0, 0, ECORE_WL2_WINDOW_KEYGRAB_SHARED);
170 MWR_LOGD("ecore_wl2_window_keygrab_set ret[%d] [%s]", bRet, KEY_BT_VOICE);
174 bool _ungrab_voice_key(void)
176 Eina_Bool bRet = true;
177 bRet = ecore_wl2_window_keygrab_unset(NULL, KEY_BT_VOICE, 0, 0);
178 MWR_LOGD("ecore_wl2_window_keygrab_unset ret[%d] [%s]", bRet, KEY_BT_VOICE);
184 if (_key_down_handler == NULL)
186 MWR_LOGE("_key_down_handler");
187 _key_down_handler = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _key_down_cb, NULL);
188 if(_key_down_handler == NULL)
190 MWR_LOGE("_key_down_handler == NULL ");
194 if (_key_up_handler == NULL)
196 MWR_LOGE("_key_down_handler");
197 _key_up_handler = ecore_event_handler_add(ECORE_EVENT_KEY_UP, _key_up_cb, NULL);
198 if(_key_up_handler == NULL)
200 MWR_LOGE("_key_up_handler == NULL ");
206 bool _delete_key_cb(void)
209 if (_key_down_handler != NULL)
211 ecore_event_handler_del(_key_down_handler);
212 _key_down_handler = NULL;
215 if (_key_up_handler != NULL)
217 ecore_event_handler_del(_key_up_handler);
218 _key_up_handler = NULL;
224 static void _bt_cb_hid_state_changed(int result, bool connected, const char *remote_address, void *user_data)
226 MWR_LOGD("[Recorder] Bluetooth Event [%d] Received address [%s]", result, remote_address);
230 static void _bt_hid_audio_data_receive_cb(bt_hid_voice_data_s *voice_data, void *user_data)
232 static int g_buffer_count = 0;
233 if (nullptr == voice_data) return;
235 if (g_voice_key_pressed) {
236 wakeup_engine_speech_data data;
237 data.event = WAKEUP_SPEECH_STREAMING_EVENT_CONTINUE;
238 data.len = voice_data->length;
239 data.buffer = malloc(voice_data->length);
241 memcpy(data.buffer, voice_data->audio_buf, voice_data->length);
242 g_speech_data.push_back(data);
245 MWR_LOGE("[Recorder ERROR] voice key seems to be already released");
249 if (0 == g_buffer_count || 0 == g_buffer_count % 50) {
250 MWR_LOGD("[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, voice_data->length);
252 if (0 == g_bt_extend_count % 5 && 0 != g_buffer_count) {
253 const unsigned char input_data[2] = {SMART_CONTROL_EXTEND_CMD, 0x10 };
254 if (BT_ERROR_NONE != bt_hid_send_rc_command(NULL, input_data, sizeof(input_data))) {
255 MWR_LOGE("[Recorder ERROR] Fail bt_hid_send_rc_command");
257 MWR_LOGD("[Recorder] Extend bt audio recorder");
262 if (100000 == g_buffer_count) {
273 static int recorder_initialize(void)
275 const int rate = 16000;
276 const audio_channel_e channel = AUDIO_CHANNEL_MONO;
277 const audio_sample_type_e type = AUDIO_SAMPLE_TYPE_S16_LE;
279 int ret = audio_in_create(rate, channel, type, &g_audio_h);
280 if (AUDIO_IO_ERROR_NONE != ret) {
281 MWR_LOGD("[Recorder ERROR] Rate(%d) Channel(%d) Type(%d)", rate, channel, type);
282 MWR_LOGD("[Recorder ERROR] Fail to create audio handle : %d", ret);
286 if (0 != sound_manager_create_stream_information(
287 SOUND_STREAM_TYPE_VOICE_RECOGNITION, NULL, NULL, &g_stream_info_h)) {
288 MWR_LOGD("[Recorder ERROR] Fail to create stream info");
289 audio_in_destroy(g_audio_h);
293 ret = audio_in_set_sound_stream_info(g_audio_h, g_stream_info_h);
294 if (AUDIO_IO_ERROR_NONE != ret) {
295 MWR_LOGD("[Recorder ERROR] Fail to set stream info : %d", ret);
296 sound_manager_destroy_stream_information(g_stream_info_h);
297 audio_in_destroy(g_audio_h);
301 ret = audio_in_prepare(g_audio_h);
302 if (AUDIO_IO_ERROR_NONE != ret) {
303 if (AUDIO_IO_ERROR_SOUND_POLICY == ret)
305 MWR_LOGD("[Recorder ERROR] Audio is busy.");
307 MWR_LOGD("[Recorder ERROR] Fail to start audio : %d", ret);
309 sound_manager_destroy_stream_information(g_stream_info_h);
310 audio_in_destroy(g_audio_h);
315 bool is_bt_failed = false;
317 if (false == is_bt_failed && BT_ERROR_NONE != bt_product_init()) {
318 MWR_LOGE("[Recorder ERROR] Fail to init bt");
322 if (false == is_bt_failed && BT_ERROR_NONE != bt_hid_host_initialize(_bt_cb_hid_state_changed, NULL)) {
323 MWR_LOGE("[Recorder ERROR] Fail bt_hid_host_initialize()");
327 if (false == is_bt_failed && BT_ERROR_NONE != bt_hid_set_audio_data_receive_cb(_bt_hid_audio_data_receive_cb, NULL)) {
328 MWR_LOGE("[Recorder ERROR] Fail bt_hid_set_audio_data_receive_cb()");
332 if (false == is_bt_failed) {
333 MWR_LOGD("[Recorder] Bluetooth is available");
341 static int recorder_deinitialize(void)
349 bt_hid_unset_audio_data_receive_cb();
350 bt_hid_host_deinitialize();
355 ret = audio_in_unprepare(g_audio_h);
356 if (AUDIO_IO_ERROR_NONE != ret) {
357 MWR_LOGD("[Recorder ERROR] Fail to stop audio : %d", ret);
360 if (0 != sound_manager_destroy_stream_information(g_stream_info_h)) {
361 MWR_LOGD("[Recorder ERROR] Fail to destroy stream info");
364 ret = audio_in_destroy(g_audio_h);
365 if (AUDIO_IO_ERROR_NONE != ret) {
366 MWR_LOGD("[Recorder ERROR] Fail to destroy audio : %d", ret);
373 #define FRAME_LENGTH 160
374 #define BUFFER_LENGTH FRAME_LENGTH * 2
376 static void recorder_thread_func()
378 static int buffer_count = 0;
380 while (!(g_recorder_thread_should_stop.load())) {
381 unsigned char buffer[BUFFER_LENGTH];
383 memset(buffer, '\0', BUFFER_LENGTH);
385 auto now = std::chrono::system_clock::now();
386 auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
387 /* number of milliseconds since the epoch of system_clock */
388 auto value = now_ms.time_since_epoch();
390 static long time = 0;
391 if (time == value.count()) {
392 LOGE("[Recorder WARNING] Time value duplicated : %lu", time);
394 time = value.count();
396 int read_bytes = audio_in_read(g_audio_h, buffer, BUFFER_LENGTH);
397 if (0 > read_bytes) {
398 LOGE("[Recorder WARNING] Fail to read audio : %d", read_bytes);
402 if (!g_audio_data_required) return;
403 for (int loop = 0;loop < g_engine_count;loop++) {
404 if (g_wakeup_engine_info[loop].audio_data_require_status &&
405 g_wakeup_engine_info[loop].interface.feed_audio_data) {
406 ret = g_wakeup_engine_info[loop].interface.feed_audio_data(time, buffer, read_bytes);
408 LOGE("[ERROR] Fail to feed speech data, ret(%d)", ret);
414 if (0 == buffer_count % 100) {
415 LOGD("[Recorder][%d] Recording... : read_size(%d)", buffer_count, read_bytes);
421 /* write pcm buffer */
423 fwrite(buffer, 1, BUFFER_LENGTH, g_pFile);
428 static void wakeup_engine_wakeup_event_cb(wakeup_event_info info, void* user_data)
431 if (NULL == user_data) return;
433 for (int loop = 0;loop < g_engine_count;loop++) {
434 if (NULL != g_wakeup_engine_info[loop].engine_name &&
435 strncmp(g_wakeup_engine_info[loop].engine_name,
436 (const char*)user_data, _POSIX_PATH_MAX) == 0) {
437 if (g_wakeup_policy) {
438 g_wakeup_policy->wakeup_candidate(info);
440 //g_wakeup_event_cb(event, g_wakeup_event_user_data);
445 static void wakeup_engine_speech_status_cb(wakeup_service_speech_status_e status, void* user_data)
448 if (NULL == user_data) return;
450 for (int loop = 0;loop < g_engine_count;loop++) {
451 if (NULL != g_wakeup_engine_info[loop].engine_name &&
452 strncmp(g_wakeup_engine_info[loop].engine_name,
453 (const char*)user_data, _POSIX_PATH_MAX) == 0) {
458 static void wakeup_engine_error_cb(int error, const char* err_msg, void* user_data)
461 if (NULL == user_data) return;
463 for (int loop = 0;loop < g_engine_count;loop++) {
464 if (NULL != g_wakeup_engine_info[loop].engine_name &&
465 strncmp(g_wakeup_engine_info[loop].engine_name,
466 (const char*)user_data, _POSIX_PATH_MAX) == 0) {
471 static void join_recorder_thread()
473 if (g_recorder_thread.joinable()) {
474 MWR_LOGD("g_recorder_thread is joinable, trying join()");
475 g_recorder_thread_should_stop.store(true);
476 g_recorder_thread.join();
480 static void start_recorder_thread()
482 join_recorder_thread();
485 /* Do not start normal recorder thread if TV_BT_MODE and g_voice_key_pressed,
486 just send bt_hid start message */
487 if (g_voice_key_pressed)
489 const unsigned char input_data[2] = {SMART_CONTROL_START_CMD, 0x00};
491 const int max_retry = 5;
492 while (max_retry > bt_retry) {
493 int ret = bt_hid_send_rc_command(NULL, input_data, sizeof(input_data));
494 if (BT_ERROR_NONE == ret) {
495 MWR_LOGD("[Recorder] Start bt audio recorder");
497 } else if (BT_ERROR_NOW_IN_PROGRESS == ret) {
498 MWR_LOGE("[Recorder ERROR] Fail bt_hid_send_rc_command : %d", ret);
505 if (max_retry == bt_retry) {
506 MWR_LOGE("[Recorder ERROR] Fail to start bt audio");
510 g_bt_extend_count = 0;
515 g_recorder_thread_should_stop.store(false);
516 g_recorder_thread = std::thread(recorder_thread_func);
520 static void wakeup_engine_audio_data_require_status_cb(bool require, void* user_data)
523 if (NULL == user_data) return;
525 bool prev_audio_data_required = g_audio_data_required;
527 int audio_data_require_count = 0;
528 for (int loop = 0;loop < g_engine_count;loop++) {
529 if (NULL != g_wakeup_engine_info[loop].engine_name &&
530 strncmp(g_wakeup_engine_info[loop].engine_name,
531 (const char*)user_data, _POSIX_PATH_MAX) == 0) {
532 g_wakeup_engine_info[loop].audio_data_require_status = require;
534 if (g_wakeup_engine_info[loop].enabled &&
535 g_wakeup_engine_info[loop].audio_data_require_status) {
536 audio_data_require_count++;
539 if (audio_data_require_count > 0) {
540 g_audio_data_required = true;
541 if (g_audio_data_required != prev_audio_data_required &&
542 g_voice_key_pressed != true) {
543 start_recorder_thread();
546 g_audio_data_required = false;
547 if (g_audio_data_required != prev_audio_data_required &&
548 g_voice_key_pressed != true) {
549 join_recorder_thread();
555 static void wakeup_engine_add_directory(const char* name, const char* path)
557 if (NULL == path) return;
559 DIR* dp = opendir(path);
561 MWR_LOGD("Failed opening directory : %s", path);
563 struct dirent *dirp = NULL;
564 char filepath[_POSIX_PATH_MAX];
569 if (g_engine_count >= MAX_WAKEUP_ENGINE_NUM) break;
571 if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
574 if (DT_REG != dirp->d_type) /* If not a regular file */
577 int filepath_len = strlen(MA_WAKEUP_ENGINE_PATH) + strlen(dirp->d_name) + 2;
578 if (filepath_len >= _POSIX_PATH_MAX) {
579 MWR_LOGD("File path is too long : %s", dirp->d_name);
584 memset(filepath, '\0', _POSIX_PATH_MAX);
585 snprintf(filepath, _POSIX_PATH_MAX, "%s/%s", path, dirp->d_name);
587 MWR_LOGD("Name (%s), Filepath(%s)", name, filepath);
588 strncpy(g_wakeup_engine_info[g_engine_count].engine_path, filepath, _POSIX_PATH_MAX);
589 strncpy(g_wakeup_engine_info[g_engine_count].engine_name, name, _POSIX_PATH_MAX);
592 void* handle = dlopen(filepath, RTLD_LAZY);
593 if (NULL != (error = dlerror()) || NULL == handle) {
594 MWR_LOGD("[ERROR] Fail to dlopen(%s), error(%s)", filepath, error);
596 g_wakeup_engine_info[g_engine_count].interface.initialize =
597 (wakeup_engine_initialize)dlsym(handle,
598 MA_WAKEUP_ENGINE_FUNC_INITIALIZE);
599 g_wakeup_engine_info[g_engine_count].interface.deinitialize =
600 (wakeup_engine_deinitialize)dlsym(handle,
601 MA_WAKEUP_ENGINE_FUNC_DEINITIALIZE);
602 g_wakeup_engine_info[g_engine_count].interface.activate =
603 (wakeup_engine_activate)dlsym(handle,
604 MA_WAKEUP_ENGINE_FUNC_ACTIVATE);
605 g_wakeup_engine_info[g_engine_count].interface.deactivate =
606 (wakeup_engine_deactivate)dlsym(handle,
607 MA_WAKEUP_ENGINE_FUNC_DEACTIVATE);
608 g_wakeup_engine_info[g_engine_count].interface.add_wakeup_word =
609 (wakeup_engine_add_wakeup_word)dlsym(handle,
610 MA_WAKEUP_ENGINE_FUNC_ADD_WAKEUP_WORD);
611 g_wakeup_engine_info[g_engine_count].interface.add_language =
612 (wakeup_engine_add_language)dlsym(handle,
613 MA_WAKEUP_ENGINE_FUNC_ADD_LANGUAGE);
614 g_wakeup_engine_info[g_engine_count].interface.set_language =
615 (wakeup_engine_set_language)dlsym(handle,
616 MA_WAKEUP_ENGINE_FUNC_SET_LANGUAGE);
617 g_wakeup_engine_info[g_engine_count].interface.update_manager_state =
618 (wakeup_engine_update_manager_state)dlsym(handle,
619 MA_WAKEUP_ENGINE_FUNC_UPDATE_MANAGER_STATE);
620 g_wakeup_engine_info[g_engine_count].interface.set_audio_format =
621 (wakeup_engine_set_audio_format)dlsym(handle,
622 MA_WAKEUP_ENGINE_FUNC_SET_AUDIO_FORMAT);
623 g_wakeup_engine_info[g_engine_count].interface.get_audio_format =
624 (wakeup_engine_get_audio_format)dlsym(handle,
625 MA_WAKEUP_ENGINE_FUNC_GET_AUDIO_FORMAT);
626 g_wakeup_engine_info[g_engine_count].interface.feed_audio_data =
627 (wakeup_engine_feed_audio_data)dlsym(handle,
628 MA_WAKEUP_ENGINE_FUNC_FEED_AUDIO_DATA);
629 g_wakeup_engine_info[g_engine_count].interface.get_utterance_data_count =
630 (wakeup_engine_get_utterance_data_count)dlsym(handle,
631 MA_WAKEUP_ENGINE_FUNC_GET_UTTERANCE_DATA_COUNT);
632 g_wakeup_engine_info[g_engine_count].interface.get_utterance_data =
633 (wakeup_engine_get_utterance_data)dlsym(handle,
634 MA_WAKEUP_ENGINE_FUNC_GET_UTTERANCE_DATA);
635 g_wakeup_engine_info[g_engine_count].interface.set_assistant_specific_command =
636 (wakeup_engine_set_assistant_specific_command)dlsym(handle,
637 MA_WAKEUP_ENGINE_FUNC_SET_ASSISTANT_SPECIFIC_COMMAND);
638 g_wakeup_engine_info[g_engine_count].interface.set_wakeup_event_callback =
639 (wakeup_engine_set_wakeup_event_callback)dlsym(handle,
640 MA_WAKEUP_ENGINE_FUNC_SET_WAKEUP_EVENT_CALLBACK);
641 g_wakeup_engine_info[g_engine_count].interface.set_speech_status_callback =
642 (wakeup_engine_set_speech_status_callback)dlsym(handle,
643 MA_WAKEUP_ENGINE_FUNC_SET_SPEECH_STATUS_CALLBACK);
644 g_wakeup_engine_info[g_engine_count].interface.set_error_callback =
645 (wakeup_engine_set_error_callback)dlsym(handle,
646 MA_WAKEUP_ENGINE_FUNC_SET_ERROR_CALLBACK);
647 g_wakeup_engine_info[g_engine_count].interface.set_audio_data_require_status_callback =
648 (wakeup_engine_set_audio_data_require_status_callback)dlsym(handle,
649 MA_WAKEUP_ENGINE_FUNC_SET_AUDIO_DATA_REQUIRE_STATUS_CALLBACK);
653 } while (NULL != dirp && g_engine_count < MAX_WAKEUP_ENGINE_NUM);
659 static int wakeup_engine_info_initialize()
661 DIR* dp = opendir(MA_WAKEUP_ENGINE_PATH);
663 MWR_LOGD("Failed opening directory : %s", (const char*)MA_WAKEUP_ENGINE_PATH);
665 struct dirent *dirp = NULL;
666 char dirpath[_POSIX_PATH_MAX];
671 if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
674 if (DT_DIR != dirp->d_type) /* If not a directory */
677 int dirpath_len = strlen(MA_WAKEUP_ENGINE_PATH) + strlen(dirp->d_name) + 1;
678 if (dirpath_len >= _POSIX_PATH_MAX) {
679 MWR_LOGD("File path is too long : %s", dirp->d_name);
684 memset(dirpath, '\0', _POSIX_PATH_MAX);
685 snprintf(dirpath, _POSIX_PATH_MAX, "%s/%s",
686 (const char*)(MA_WAKEUP_ENGINE_PATH), dirp->d_name);
688 wakeup_engine_add_directory(dirp->d_name, dirpath);
690 } while (NULL != dirp && g_engine_count < MAX_WAKEUP_ENGINE_NUM);
695 for (int loop = 0;loop < g_engine_count;loop++) {
696 g_wakeup_engine_info[loop].active = false;
697 /* We'll need to check vconf for enabled wakeup engines */
698 g_wakeup_engine_info[loop].enabled = true;
699 g_wakeup_engine_info[loop].audio_data_require_status = false;
700 MWR_LOGD("Initializing wakeup engine : %s %p", g_wakeup_engine_info[loop].engine_path, g_wakeup_engine_info[loop].interface.initialize);
701 if (g_wakeup_engine_info[loop].interface.initialize) {
702 g_wakeup_engine_info[loop].interface.initialize();
704 if (g_wakeup_engine_info[loop].interface.set_wakeup_event_callback) {
705 g_wakeup_engine_info[loop].interface.set_wakeup_event_callback(
706 wakeup_engine_wakeup_event_cb, g_wakeup_engine_info[loop].engine_name);
708 if (g_wakeup_engine_info[loop].interface.set_speech_status_callback) {
709 g_wakeup_engine_info[loop].interface.set_speech_status_callback(
710 wakeup_engine_speech_status_cb, g_wakeup_engine_info[loop].engine_name);
712 if (g_wakeup_engine_info[loop].interface.set_error_callback) {
713 g_wakeup_engine_info[loop].interface.set_error_callback(
714 wakeup_engine_error_cb, g_wakeup_engine_info[loop].engine_name);
716 if (g_wakeup_engine_info[loop].interface.set_audio_data_require_status_callback) {
717 g_wakeup_engine_info[loop].interface.set_audio_data_require_status_callback(
718 wakeup_engine_audio_data_require_status_cb, g_wakeup_engine_info[loop].engine_name);
724 void CWakeupEventObserver::on_wakeup(wakeup_event_info info)
726 g_wakeup_event_cb(info, g_wakeup_event_user_data);
729 void wakeup_policy_initialize(void)
731 g_wakeup_policy.reset(new CWakeupPolicyDefault);
732 if (g_wakeup_policy) {
733 g_wakeup_policy->subscribe(&g_wakeup_event_observer);
736 /* Default Policy specific initialization */
737 CWakeupPolicyDefault *default_policy = dynamic_cast<CWakeupPolicyDefault*>(g_wakeup_policy.get());
738 if (default_policy) {
741 default_policy->set_delay(g_wakeup_settings.wakeup_policy_delay);
742 MWR_LOGD("Setting Delay : %f", g_wakeup_settings.wakeup_policy_delay);
743 for (const auto& assistant : g_wakeup_settings.wakeup_policy_priority) {
744 default_policy->set_assistant_priority(assistant, ++priority);
745 MWR_LOGD("Setting Priority : %d %s", priority, assistant.c_str());
750 int wakeup_manager_initialize(void)
754 g_wakeup_event_cb = NULL;
755 g_wakeup_event_user_data = NULL;
757 g_utterance_streaming_cb = NULL;
758 g_utterance_streaming_user_data = NULL;
760 g_follow_up_streaming_cb = NULL;
761 g_follow_up_streaming_user_data = NULL;
763 g_speech_status_cb = NULL;
764 g_speech_status_user_data = NULL;
767 g_error_user_data = NULL;
776 vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_DEFAULT_ASSISTANT_APPID);
778 g_wakeup_settings.default_assistant_appid = vconf_str;
779 MWR_LOGD("default_assistant_appid : %s", g_wakeup_settings.default_assistant_appid.c_str());
783 vconf_ret = vconf_get_bool(WAKEUP_SETTINGS_KEY_UI_PANEL_ENABLED, &vconf_bool);
784 if (0 == vconf_ret) {
785 g_wakeup_settings.ui_panel_enabled = vconf_bool;
786 MWR_LOGD("ui_panel_enabled : %s", (g_wakeup_settings.ui_panel_enabled ? "true" : "false"));
788 vconf_ret = vconf_get_dbl(WAKEUP_SETTINGS_KEY_CONVERSATION_TIMEOUT, &vconf_double);
789 if (0 == vconf_ret) {
790 g_wakeup_settings.conversation_timeout = vconf_double;
791 MWR_LOGD("conversation_timeout : %f", g_wakeup_settings.conversation_timeout);
793 vconf_ret = vconf_get_bool(WAKEUP_SETTINGS_KEY_MULTIPLE_MODE, &vconf_bool);
794 if (0 == vconf_ret) {
795 g_wakeup_settings.multiple_mode = vconf_bool;
796 MWR_LOGD("multiple_mode : %s", (g_wakeup_settings.multiple_mode ? "true" : "false"));
798 vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_ENABLED_ASSISTANTS);
801 std::istringstream iss(vconf_str);
802 g_wakeup_settings.enabled_assistants.clear();
803 while (std::getline(iss, token, ';')) {
804 g_wakeup_settings.enabled_assistants.push_back(token);
805 MWR_LOGD("enabled_assistants : %s", token.c_str());
810 vconf_ret = vconf_get_dbl(WAKEUP_SETTINGS_KEY_WAKEUP_POLICY_DELAY, &vconf_double);
811 if (0 == vconf_ret) {
812 g_wakeup_settings.wakeup_policy_delay = vconf_double;
813 MWR_LOGD("conversation_timeout : %f", g_wakeup_settings.wakeup_policy_delay);
815 vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_WAKEUP_POLICY_PRIORITY);
818 std::istringstream iss(vconf_str);
819 g_wakeup_settings.wakeup_policy_priority.clear();
820 while (std::getline(iss, token, ';')) {
821 g_wakeup_settings.wakeup_policy_priority.push_back(token);
822 MWR_LOGD("wakeup_policy_priority : %s", token.c_str());
828 wakeup_policy_initialize();
830 recorder_initialize();
831 wakeup_engine_info_initialize();
837 int wakeup_manager_deinitialize(void)
841 recorder_deinitialize();
843 for (const auto &data : g_speech_data) {
846 g_speech_data.clear();
848 if (g_current_language) {
849 free(g_current_language);
850 g_current_language = NULL;
853 for (int loop = 0;loop < g_engine_count;loop++) {
854 if (g_wakeup_engine_info[loop].interface.deinitialize) {
855 g_wakeup_engine_info[loop].interface.deinitialize();
863 static int _is_valid_language(const char* language, bool* is_valid)
865 if (language && is_valid) {
871 int wakeup_manager_add_assistant_wakeup_word(const char* appid, const char* wakeup_word, const char* language)
875 if (NULL == appid || NULL == wakeup_word) {
876 MWR_LOGD("[ERROR] Parameter is invalid, appid(%s), wakeup_word(%s), language(%s)", appid, wakeup_word, language);
880 MWR_LOGD("[DEBUG] appid(%s), wakeup word(%s),language(%s)", appid, wakeup_word, language);
881 for (int loop = 0;loop < g_engine_count;loop++) {
882 auto iter = std::find(
883 g_wakeup_engine_info[loop].assistant_list.begin(),
884 g_wakeup_engine_info[loop].assistant_list.end(),
886 if (iter != g_wakeup_engine_info[loop].assistant_list.end()) {
887 if (g_wakeup_engine_info[loop].interface.add_wakeup_word) {
888 g_wakeup_engine_info[loop].interface.add_wakeup_word(
889 appid, wakeup_word, language);
898 int wakeup_manager_add_assistant_language(const char* appid, const char* language)
902 if (NULL == appid || NULL == language) {
903 MWR_LOGD("[ERROR] Parameter is invalid, appid(%s), language(%s)", appid, language);
907 bool is_valid = false;
908 int ret = _is_valid_language(language, &is_valid);
910 MWR_LOGE("[ERROR] Fail to do wakeup_service_is_valid_language function (%d)", ret);
913 if (is_valid == false) {
914 MWR_LOGE("[ERROR] Not supported language (%s)", language);
918 MWR_LOGD("[DEBUG] language(%s)", language);
924 int wakeup_manager_set_assistant_wakeup_engine(const char* appid, const char* engine)
928 if (NULL == appid || NULL == engine) {
929 MWR_LOGD("[ERROR] Parameter is invalid, appid(%s), wakeup engine(%s)", appid, engine);
933 MWR_LOGD("[DEBUG] appid(%s), wakeup engine(%s)", appid, engine);
934 for (int loop = 0;loop < g_engine_count;loop++) {
935 if (0 == strncmp(g_wakeup_engine_info[loop].engine_name, engine, _POSIX_PATH_MAX)) {
936 g_wakeup_engine_info[loop].assistant_list.push_back(std::string{appid});
944 int wakeup_manager_set_assistant_enabled(const char* appid, int enabbled)
953 int wakeup_manager_set_language(const char* language)
958 bool is_valid = false;
959 ret = _is_valid_language(language, &is_valid);
961 MWR_LOGE("[ERROR] wakeup_service_is_valid_language fail (%d)", ret);
964 if (is_valid == false) {
965 MWR_LOGE("[ERROR] Not supported language (%s)", language);
969 g_current_language = strdup(language);
975 int wakeup_manager_change_state(wakeup_manager_state_e state)
977 for (int loop = 0;loop < g_engine_count;loop++) {
978 if (g_wakeup_engine_info[loop].interface.update_manager_state) {
979 g_wakeup_engine_info[loop].interface.update_manager_state(state);
984 int wakeup_manager_activate(void)
988 wakeup_manager_change_state(WAKEUP_MANAGER_STATE_LISTENING);
990 for (int loop = 0;loop < g_engine_count;loop++) {
991 if (g_wakeup_engine_info[loop].interface.activate) {
992 g_wakeup_engine_info[loop].interface.activate();
1000 int wakeup_manager_deactivate(void)
1002 MWR_LOGD("[ENTER]");
1004 for (int loop = 0;loop < g_engine_count;loop++) {
1005 if (g_wakeup_engine_info[loop].interface.deactivate) {
1006 g_wakeup_engine_info[loop].interface.deactivate();
1009 wakeup_manager_change_state(WAKEUP_MANAGER_STATE_INACTIVE);
1015 int wakeup_manager_update_voice_feedback_state(const char* appid, int state)
1017 MWR_LOGD("[ENTER]");
1019 if (NULL == appid) {
1020 MWR_LOGD("[ERROR] Parameter is invalid, appid(%s)",
1021 (appid ? appid : "NULL"));
1026 if (g_wakeup_manager_state == WAKEUP_MANAGER_STATE_LISTENING ||
1027 g_wakeup_manager_state == WAKEUP_MANAGER_STATE_PROCESSING) {
1028 wakeup_manager_change_state(WAKEUP_MANAGER_STATE_VOICE_FEEDBACK);
1031 if (g_wakeup_manager_state == WAKEUP_MANAGER_STATE_VOICE_FEEDBACK) {
1032 wakeup_manager_change_state(WAKEUP_MANAGER_STATE_LISTENING);
1040 int wakeup_manager_send_assistant_specific_command(const char* appid, const char* command)
1042 MWR_LOGD("[ENTER]");
1044 if (NULL == appid || NULL == command) {
1045 MWR_LOGD("[ERROR] Parameter is invalid, appid(%s), command(%s)",
1046 (appid ? appid : "NULL"), (command ? command : "NULL"));
1050 const char* voice_key_pressed = "voice_key_pressed";
1051 const char* voice_key_released = "voice_key_released";
1054 if (0 == strncmp(command, voice_key_pressed, strlen(voice_key_pressed))) {
1055 wakeup_manager_process_event(MA_PLUGIN_EVENT_VOICE_KEY_PRESSED, NULL, 0);
1056 } else if (0 == strncmp(command, voice_key_released, strlen(voice_key_released))) {
1057 wakeup_manager_process_event(MA_PLUGIN_EVENT_VOICE_KEY_RELEASED, NULL, 0);
1061 for (int loop = 0;loop < g_engine_count;loop++) {
1062 /* Need to find the appropriate engine for this assistant,
1063 for now assuming 0 is the one */
1065 if (g_wakeup_engine_info[loop].interface.set_assistant_specific_command) {
1066 g_wakeup_engine_info[loop].interface.set_assistant_specific_command(appid, command);
1075 int wakeup_manager_update_result_state(const char* appid, int state)
1077 MWR_LOGD("[ENTER]");
1078 if (NULL == appid) {
1079 MWR_LOGD("[ERROR] Parameter is invalid, appid(%s)",
1080 (appid ? appid : "NULL"));
1083 if (g_wakeup_manager_state == WAKEUP_MANAGER_STATE_PROCESSING) {
1084 wakeup_manager_change_state(WAKEUP_MANAGER_STATE_LISTENING);
1090 int wakeup_manager_process_event(int event, void* data, int len)
1092 MWR_LOGD("[ENTER]");
1095 if (event == MA_PLUGIN_EVENT_VOICE_KEY_PRESSED) {
1096 if (g_voice_key_pressed != true) {
1097 /* Clear all existing data */
1098 for (const auto &speech_data : g_speech_data) {
1099 if (speech_data.buffer) free(speech_data.buffer);
1101 g_speech_data.clear();
1103 g_voice_key_pressed = true;
1104 /* (Re)Start recorder thread using bt hid */
1105 start_recorder_thread();
1106 for (int loop = 0;loop < g_engine_count;loop++) {
1107 /* Need to find the default assistant, for now assuming 0 is the one */
1109 wakeup_event_info event;
1110 event.wakeup_word = "hi bixby";
1111 event.wakeup_appid = g_wakeup_engine_info[loop].assistant_list.at(0).c_str();
1112 g_wakeup_event_cb(event, g_wakeup_event_user_data);
1116 } else if (event == MA_PLUGIN_EVENT_VOICE_KEY_RELEASED) {
1117 if (g_voice_key_pressed != false) {
1118 unsigned char final_buffer[2] = {'\0', };
1120 g_voice_key_pressed = false;
1121 if (g_audio_data_required == true) {
1122 /* Restart recorder thread using standard mic */
1123 start_recorder_thread();
1125 join_recorder_thread();
1127 wakeup_engine_speech_data speech_data;
1128 speech_data.event = WAKEUP_SPEECH_STREAMING_EVENT_FINISH;
1129 speech_data.len = sizeof(final_buffer);
1130 speech_data.buffer = malloc(speech_data.len);
1131 if (speech_data.buffer) {
1132 memcpy(speech_data.buffer, final_buffer, speech_data.len);
1133 g_speech_data.push_back(speech_data);
1143 void __wakeup_service_streaming_cb(wakeup_service_speech_streaming_event_e event, void* buffer, unsigned int len)
1145 if (WAKEUP_SPEECH_STREAMING_EVENT_START == event) {
1146 MWR_LOGD("streaming_cb START");
1148 if (WAKEUP_SPEECH_STREAMING_EVENT_FINISH == event) {
1149 MWR_LOGD("streaming_cb FINISH");
1151 if (NULL != g_utterance_streaming_cb) {
1152 g_utterance_streaming_cb(event, buffer, len, g_utterance_streaming_user_data);
1154 MWR_LOGI("[INFO] No service streaming callback");
1158 static void manager_data_thread_func(void)
1160 MWR_LOGD("[ENTER]");
1162 MWR_LOGD("data_count : %zu", g_speech_data.size());
1170 /* get feedback data */
1171 if (index >= g_speech_data.size()) {
1173 MWR_LOGD("[DEBUG] No feedback data. Waiting mode : %d", ret);
1178 if (index < g_speech_data.size()) {
1179 MWR_LOGI("[INFO] Resume thread");
1183 MWR_LOGE("[ERROR] Wrong request, there's no pcm data");
1184 __wakeup_service_streaming_cb(
1185 WAKEUP_SPEECH_STREAMING_EVENT_FAIL, NULL, 0);
1190 MWR_LOGI("[INFO] Finish to wait for new feedback data come");
1192 /* resume feedback thread */
1196 wakeup_engine_speech_data &speech_data = g_speech_data.at(index);
1197 __wakeup_service_streaming_cb(
1198 speech_data.event, speech_data.buffer, speech_data.len);
1200 if (WAKEUP_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
1201 MWR_LOGI("[INFO] Finish to get and send speech data");
1209 static void engine_data_thread_func(void)
1211 MWR_LOGD("[ENTER]");
1213 if (g_wakeup_engine_selected < 0 ||
1214 g_wakeup_engine_selected >= MAX_WAKEUP_ENGINE_NUM)
1217 wakeup_engine_interface *interface =
1218 &(g_wakeup_engine_info[g_wakeup_engine_selected].interface);
1220 if (NULL == interface ||
1221 NULL == interface->get_utterance_data ||
1222 NULL == interface->get_utterance_data_count)
1225 MWR_LOGD("data_count : %d", interface->get_utterance_data_count());
1227 wakeup_engine_speech_data speech_data;
1234 /* get feedback data */
1235 if (interface && interface->get_utterance_data) {
1236 ret = interface->get_utterance_data(index, &speech_data);
1239 MWR_LOGD("[DEBUG] No feedback data. Waiting mode : %d", ret);
1244 if (index < interface->get_utterance_data_count()) {
1245 MWR_LOGI("[INFO] Resume thread");
1249 MWR_LOGE("[ERROR] Wrong request, there's no pcm data");
1250 __wakeup_service_streaming_cb(
1251 WAKEUP_SPEECH_STREAMING_EVENT_FAIL, NULL, 0);
1256 MWR_LOGI("[INFO] Finish to wait for new feedback data come");
1258 /* resume feedback thread */
1262 __wakeup_service_streaming_cb(
1263 speech_data.event, speech_data.buffer, speech_data.len);
1265 if (WAKEUP_SPEECH_STREAMING_EVENT_FINISH == speech_data.event) {
1266 MWR_LOGI("[INFO] Finish to get and send speech data");
1275 int wakeup_manager_start_streaming_utterance_data(void)
1277 MWR_LOGD("[ENTER]");
1279 if (g_speech_data_thread.joinable()) {
1280 MWR_LOGD("g_speech_data_thread is joinable, trying join()");
1281 g_speech_data_thread_should_stop.store(true);
1282 g_speech_data_thread.join();
1284 g_speech_data_thread_should_stop.store(false);
1285 if (g_voice_key_pressed) {
1286 g_speech_data_thread = std::thread(manager_data_thread_func);
1288 g_speech_data_thread = std::thread(engine_data_thread_func);
1295 int wakeup_manager_stop_streaming_utterance_data(void)
1297 MWR_LOGD("[ENTER]");
1298 if (g_wakeup_manager_state == WAKEUP_MANAGER_STATE_UTTERANCE) {
1299 wakeup_manager_change_state(WAKEUP_MANAGER_STATE_PROCESSING);
1300 if (g_speech_data_thread.joinable()) {
1301 MWR_LOGD("g_speech_data_thread is joinable, trying join()");
1302 g_speech_data_thread_should_stop.store(true);
1303 g_speech_data_thread.join();
1310 int wakeup_manager_start_streaming_follow_up_data(void)
1312 MWR_LOGD("[ENTER]");
1318 int wakeup_manager_stop_streaming_follow_up_data(void)
1320 MWR_LOGD("[ENTER]");
1326 int wakeup_manager_start_streaming_previous_utterance_data(void)
1328 MWR_LOGD("[ENTER]");
1334 int wakeup_manager_stop_streaming_previous_utterance_data(void)
1336 MWR_LOGD("[ENTER]");
1342 int wakeup_manager_get_audio_format(int* rate, int* channel, int* audio_type)
1344 MWR_LOGD("[ENTER]");
1346 if (!audio_type || !rate || !channel) {
1347 MWR_LOGE("[ERROR] Invalid parameter");
1355 MWR_LOGD("[END] rate(%d), channel(%d), audio_type(%d)", *rate, *channel, *audio_type);
1359 int wakeup_manager_set_wakeup_event_callback(wakeup_service_wakeup_event_cb callback, void* user_data)
1361 MWR_LOGD("[ENTER]");
1363 if (NULL == callback) {
1364 MWR_LOGE("[ERROR] Input parameter is NULL");
1368 g_wakeup_event_cb = callback;
1369 g_wakeup_event_user_data = user_data;
1375 int wakeup_manager_set_utterance_streaming_callback(wakeup_service_speech_streaming_cb callback, void* user_data)
1377 MWR_LOGD("[ENTER]");
1379 if (NULL == callback) {
1380 MWR_LOGE("[ERROR] Input parameter is NULL");
1384 g_utterance_streaming_cb = callback;
1385 g_utterance_streaming_user_data = user_data;
1391 int wakeup_manager_set_previous_utterance_streaming_callback(wakeup_service_speech_streaming_cb callback, void* user_data)
1393 MWR_LOGD("[ENTER]");
1395 if (NULL == callback) {
1396 MWR_LOGE("[ERROR] Input parameter is NULL");
1400 g_previous_utterance_streaming_cb = callback;
1401 g_previous_utterance_streaming_user_data = user_data;
1407 int wakeup_manager_set_follow_up_streaming_callback(wakeup_service_speech_streaming_cb callback, void* user_data)
1409 MWR_LOGD("[ENTER]");
1411 if (NULL == callback) {
1412 MWR_LOGE("[ERROR] Input parameter is NULL");
1416 g_follow_up_streaming_cb = callback;
1417 g_follow_up_streaming_user_data = user_data;
1423 int wakeup_manager_set_speech_status_callback(wakeup_service_speech_status_cb callback, void* user_data)
1425 MWR_LOGD("[ENTER]");
1427 if (NULL == callback) {
1428 MWR_LOGE("[ERROR] Input parameter is NULL");
1432 g_speech_status_cb = callback;
1433 g_speech_status_user_data = user_data;
1439 int wakeup_manager_set_error_callback(wakeup_service_error_cb callback, void* user_data)
1441 MWR_LOGD("[ENTER]");
1443 if (NULL == callback) {
1444 MWR_LOGE("[ERROR] Input parameter is NULL");
1448 g_error_cb = callback;
1449 g_error_user_data = user_data;