From: Ji-hoon Lee Date: Fri, 10 Apr 2020 12:33:02 +0000 (+0900) Subject: Merge commit 'b9b5dd3' into tizen X-Git-Tag: accepted/tizen/unified/20200414.135745~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2ec41063a0ee7d4ce72b1161884886d52ea65978;p=platform%2Fcore%2Fuifw%2Fmulti-assistant-service.git Merge commit 'b9b5dd3' into tizen Change-Id: I94abe17b257facb23833bade02a32a6024d7fa2e --- 2ec41063a0ee7d4ce72b1161884886d52ea65978 diff --cc src/service_main.cpp index 8fd818a,0000000..c494304 mode 100644,000000..100644 --- a/src/service_main.cpp +++ b/src/service_main.cpp @@@ -1,1479 -1,0 +1,1484 @@@ +/* + * Copyright 2020 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "service_common.h" +#include "service_main.h" +#include "service_plugin.h" +#include "service_ipc_dbus.h" +#include "service_config.h" + +static CServiceMain* g_service_main = nullptr; + +bool CServiceMain::check_preprocessing_assistant_exists() +{ + bool ret = false; + + boost::optional preprocessing_appid = + mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID); + if (preprocessing_appid) { + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + strncmp((*preprocessing_appid).c_str(), mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + if (mClientManager.check_client_validity_by_appid(*preprocessing_appid)) { + ret = true; + } + } + } + } + + MAS_LOGD("result : %d", ret); + + return ret; +} + +bool CServiceMain::is_current_preprocessing_assistant(const char* appid) +{ + if (NULL == appid) return false; + + bool ret = false; + + boost::optional preprocessing_appid = + mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID); + if (preprocessing_appid) { + if (strncmp((*preprocessing_appid).c_str(), appid, MAX_APPID_LEN) == 0) { + ret = true; + } + } + + return ret; +} + +int CServiceMain::mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type) +{ + MAS_LOGD("[Enter] pid(%d)", pid); + + int ret = mServicePlugin.get_recording_audio_format(rate, channel, audio_type); + if (0 != ret){ + MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret); + } + + return ret; +} + +#define MAX_LOCAL_VARIABLE_STRING_LEN 256 +int CServiceMain::mas_client_get_audio_source_type(int pid, char** type) +{ + MAS_LOGD("[Enter] pid(%d)", pid); + + if (NULL == type) return -1; + + static char cached[MAX_LOCAL_VARIABLE_STRING_LEN] = {'\0'}; + int ret = mServicePlugin.get_recording_audio_source_type(type); + if (0 != ret){ + MAS_LOGE("[ERROR] Fail to get recording audio source type, ret(%d)", ret); + *type = cached; + } else if (*type) { + strncpy(cached, *type, MAX_LOCAL_VARIABLE_STRING_LEN - 1); + cached[MAX_LOCAL_VARIABLE_STRING_LEN - 1] = '\0'; + } + + return ret; +} + +int CServiceMain::mas_client_send_preprocessing_information(int pid) +{ + int ret = -1; + MAS_LOGD("[Enter] pid(%d)", pid); + + boost::optional preprocessing_appid = + mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID); + if (preprocessing_appid) { + MAS_LOGD("preprocessing_assistant_appid : %s", (*preprocessing_appid).c_str()); + ret = mServiceIpc.send_preprocessing_information(pid, (*preprocessing_appid).c_str()); + } + + return ret; +} + +int CServiceMain::mas_client_send_voice_key_status_change(int pid, ma_voice_key_status_e status) +{ + int ret = -1; + MAS_LOGD("[Enter] pid(%d)", pid); + + ret = mServiceIpc.change_voice_key_status(pid, status); + if (0 != ret) { + MAS_LOGE("[ERROR] Fail to send voice key status changed information, ret(%d)", ret); + } + mLastVoiceKeyStatus = status; + + return ret; +} + +int CServiceMain::mas_client_send_asr_result(int pid, int event, const char* asr_result) +{ + MAS_LOGD("[Enter] pid(%d), event(%d), asr_result(%s)", pid, event, asr_result); + int ret = mServiceIpc.masc_ui_dbus_send_asr_result(pid, event, asr_result); + if (0 != ret){ + MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret); + } + + // if final event is , launch assistant app which is invoked with wakeup word. + /* TO_DO */ + return ret; +} + +int CServiceMain::mas_client_send_result(int pid, const char* display_text, + const char* utterance_text, const char* result_json) +{ + MAS_LOGD("[Enter] pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json); + int ret = mServiceIpc.masc_ui_dbus_send_result(pid, display_text, utterance_text, result_json); + if (0 != ret){ + MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret); + } + + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + mServicePlugin.update_recognition_result(pid_appid.c_str(), MA_RECOGNITION_RESULT_EVENT_SUCCESS); + + return ret; +} + +int CServiceMain::mas_client_send_recognition_result(int pid, int result) +{ + MAS_LOGD("[Enter] pid(%d), result(%d)", pid, result); + int ret = mServiceIpc.masc_ui_dbus_send_recognition_result(pid, result); + if (0 != ret){ + MAS_LOGE("[ERROR] Fail to send recognition result, ret(%d)", ret); + } + + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + mServicePlugin.update_recognition_result(pid_appid.c_str(), result); + + return ret; +} + +int CServiceMain::mas_client_start_streaming_audio_data(int pid, int type) +{ + int ret = -1; + switch(type) { + case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE: + ret = mServicePlugin.start_streaming_utterance_data(); + mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED); + break; + case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE: + ret = mServicePlugin.start_streaming_previous_utterance_data(); + /* Preprocessing is not required for previous utterance streaming */ + break; + case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH: + ret = mServicePlugin.start_streaming_follow_up_data(); + mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED); + break; + } + return ret; +} + +int CServiceMain::mas_client_stop_streaming_audio_data(int pid, int type) +{ + int ret = -1; + switch(type) { + case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE: + ret = mServicePlugin.stop_streaming_utterance_data(); + break; + case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE: + ret = mServicePlugin.stop_streaming_previous_utterance_data(); + break; + case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH: + ret = mServicePlugin.stop_streaming_follow_up_data(); + break; + } + return ret; +} + +int CServiceMain::mas_client_update_voice_feedback_state(int pid, int state) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + mServicePlugin.update_voice_feedback_state(pid_appid.c_str(), state); + return 0; +} + +int CServiceMain::mas_client_set_assistant_specific_command(int pid, const char *command) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + mServicePlugin.set_assistant_specific_command(pid_appid.c_str(), command); + return 0; +} + +int CServiceMain::mas_client_set_background_volume(int pid, double ratio) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + mServicePlugin.set_background_volume(pid_appid.c_str(), ratio); + return 0; +} + +int CServiceMain::mas_client_set_preprocessing_allow_mode(int pid, ma_preprocessing_allow_mode_e mode, const char* appid) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used) { + if (0 == pid_appid.compare(mClientInfo[loop].appid)) { + mClientInfo[loop].preprocessing_allow_mode = mode; + if (appid) { + strncpy(mClientInfo[loop].preprocessing_allow_appid, appid, MAX_APPID_LEN); + mClientInfo[loop].preprocessing_allow_appid[MAX_APPID_LEN - 1] = '\0'; + } else { + mClientInfo[loop].preprocessing_allow_appid[0] = '\0'; + } + } + } + } + + mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED); + + return 0; +} + +int CServiceMain::mas_client_send_preprocessing_result(int pid, bool result) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + if (!is_current_preprocessing_assistant(pid_appid.c_str())) return -1; + + const char *current_maclient_appid = NULL; + if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) { + current_maclient_appid = mClientInfo[mCurrentClientInfo].appid; + } + + if (result) { + MAS_LOGD("Preprocessing succeeded, bring (%s) to foreground", pid_appid.c_str()); + mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED); + } else { + MAS_LOGD("Preprocessing failed, bring (%s) to foreground", current_maclient_appid); + mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED); + } + + if (current_maclient_appid) { + int pid_by_appid = mClientManager.find_client_pid_by_appid( + std::string{current_maclient_appid}); + mServiceIpc.send_preprocessing_result(pid_by_appid, result); + } + + return 0; +} + +int CServiceMain::mas_client_set_wake_word_audio_require_flag(int pid, bool require) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + + mServicePlugin.set_wake_word_audio_require_flag(pid_appid.c_str(), require); + return 0; +} + +int CServiceMain::mas_client_set_assistant_language(int pid, const char* language) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + + mServicePlugin.set_assistant_language(pid_appid.c_str(), language); + return 0; +} + +int CServiceMain::mas_client_add_wake_word(int pid, const char* wake_word, const char* language) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + 0 == pid_appid.compare(mClientInfo[loop].appid)) { + int ret = mServiceConfig.add_custom_wake_word(wake_word, language, + mClientInfo[loop].wakeup_word, + mClientInfo[loop].wakeup_language); + if (0 == ret) { + mServiceConfig.save_custom_wake_words(pid_appid.c_str(), + mClientInfo[loop].wakeup_word, + mClientInfo[loop].wakeup_language); + } else { + LOGE("add new wake word failed!"); + return -1; + } + } + } + + mServicePlugin.add_assistant_wakeup_word(pid_appid.c_str(), wake_word, language); + return 0; +} + +int CServiceMain::mas_client_remove_wake_word(int pid, const char* wake_word, const char* language) +{ + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + } + + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + 0 == pid_appid.compare(mClientInfo[loop].appid)) { + int ret = mServiceConfig.remove_custom_wake_word(wake_word, language, + mClientInfo[loop].wakeup_word, + mClientInfo[loop].wakeup_language); + if (0 == ret) { + mServiceConfig.save_custom_wake_words(pid_appid.c_str(), + mClientInfo[loop].wakeup_word, + mClientInfo[loop].wakeup_language); + } + } + } + + mServicePlugin.remove_assistant_wakeup_word(pid_appid.c_str(), wake_word, language); + return 0; +} + +int CServiceMain::mas_ui_client_initialize(int pid) +{ + MAS_LOGD("[Enter] pid(%d)", pid); + + return 0; +} + +int CServiceMain::mas_ui_client_deinitialize(int pid) +{ + MAS_LOGD("[Enter] pid(%d)", pid); + + return 0; +} + +int CServiceMain::mas_ui_client_change_assistant(const char* appid) +{ + MAS_LOGD("[Enter]"); + + if (NULL == appid) { + MAS_LOGE("NULL parameter"); + return -1; + } + + bool use_custom_ui = mas_get_client_custom_ui_option_by_appid(appid); + mServiceIpc.masc_ui_dbus_enable_common_ui(!use_custom_ui); + + mas_set_current_client_by_appid(appid); + int pid = mas_get_client_pid_by_appid(appid); + if (pid != -1) { + mas_bring_client_to_foreground(appid); + mas_client_send_preprocessing_information(pid); + if (MA_VOICE_KEY_STATUS_PRESSED == mLastVoiceKeyStatus) { + mas_client_send_voice_key_status_change(pid, mLastVoiceKeyStatus); + } + + mServiceIpc.change_active_state(pid, MA_ACTIVE_STATE_ACTIVE); + MAS_LOGD("MA Client with appid %s exists, requesting speech data", (appid ? appid : "NULL")); + /* + int ret = mServicePlugin.start_streaming_utterance_data(); + if (0 != ret) { + MAS_LOGE("[ERROR] Fail to start streaming utterance data(%d)", ret); + } + */ + } else { + // Appropriate MA Client not available, trying to launch new one + MAS_LOGD("MA Client with appid %s does not exist, launching client", (appid ? appid : "NULL")); + + /* The appid parameter might not exist after this function call, so we use appid string in our mClientInfo */ + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid) && + 0 < strlen(mClientInfo[loop].wakeup_word[0])) { + if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + mas_launch_client_by_appid(mClientInfo[loop].appid, CLIENT_LAUNCH_MODE_ACTIVATION); + } + } + } + } + + return 0; +} + +static int mas_assistant_info_cb(ma_assistant_info_s* info, void* user_data) { + int ret = -1; + CServiceMain* service_main = static_cast(user_data); + if (service_main) { + ret = service_main->add_assistant_info(info); + } + return ret; +} + +int CServiceMain::add_assistant_info(ma_assistant_info_s* info) { + MAS_LOGD("__mas_assistant_info_cb called"); + + if (NULL == info) { + MAS_LOGE("info NULL, returning"); + return -1; + } + if (NULL == info->app_id) { + MAS_LOGE("app_id NULL, returning"); + return -1; + } + + int index = -1; + int loop = 0; + while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) { + if (false == mClientInfo[loop].used) { + index = loop; + } + loop++; + } + if (-1 != index) { + mClientInfo[index].used = true; + mClientInfo[index].preprocessing_allow_mode = MA_PREPROCESSING_ALLOW_NONE; + mClientInfo[index].preprocessing_allow_appid[0] = '\0'; + MAS_LOGD("app_id(%s)", info->app_id); + strncpy(mClientInfo[index].appid, info->app_id, MAX_APPID_LEN); + mClientInfo[index].appid[MAX_APPID_LEN - 1] = '\0'; + + if (is_current_preprocessing_assistant(mClientInfo[index].appid)) { + mCurrentPreprocessingClientInfo = index; + } + + for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) { + if (loop < info->cnt_wakeup && info->wakeup_list[loop]) { + MAS_LOGD("wakeup_list(%d)(%s)(%s)", loop, info->wakeup_list[loop], info->wakeup_language[loop]); + strncpy(mClientInfo[index].wakeup_word[loop], info->wakeup_list[loop], MAX_WAKEUP_WORD_LEN); + mClientInfo[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0'; + if (info->wakeup_language[loop]) { + strncpy(mClientInfo[index].wakeup_language[loop], info->wakeup_language[loop], MAX_SUPPORTED_LANGUAGE_LEN); + mClientInfo[index].wakeup_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0'; + } else { + strncpy(mClientInfo[index].wakeup_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN); + } + } else { + strncpy(mClientInfo[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN); + } + } + + for (loop = 0;loop < MAX_SUPPORTED_LANGUAGES_NUM;loop++) { + if (loop < info->cnt_lang && info->supported_lang[loop]) { + MAS_LOGD("supported_lang(%d)(%s)", loop, info->supported_lang[loop]); + strncpy(mClientInfo[index].supported_language[loop], info->supported_lang[loop], MAX_SUPPORTED_LANGUAGE_LEN); + mClientInfo[index].supported_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0'; + } else { + strncpy(mClientInfo[index].supported_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN); + } + } + + MAS_LOGD("wakeup_engine(%s)", info->wakeup_engine); + if (info->wakeup_engine) { + strncpy(mClientInfo[index].wakeup_engine, info->wakeup_engine, MAX_APPID_LEN); + mClientInfo[index].wakeup_engine[MAX_APPID_LEN - 1] = '\0'; + } else { + mClientInfo[index].wakeup_engine[0] = '\0'; + MAS_LOGW("Wakeup engine information not provided for : %s", info->app_id); + } + mClientInfo[index].custom_ui_option = info->custom_ui_option; + + MAS_LOGD("voice_key_support_mode(%d)", info->voice_key_support_mode); + mClientInfo[index].voice_key_support_mode = info->voice_key_support_mode; + MAS_LOGD("voice_key_tap_duration(%f)", info->voice_key_tap_duration); + mClientInfo[index].voice_key_tap_duration = info->voice_key_tap_duration; + } else { + MAS_LOGD("Couldn't find an empty slot for storing assistant info"); + } + + MAS_LOGD("__mas_assistant_info_cb end"); + + return 0; +} + +static void active_state_changed_cb(std::string key, void* user_data) +{ + IPreferenceManager* manager = static_cast(user_data); + if (nullptr == manager) return; + + boost::optional activated = + manager->get_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED); + if (activated) { + MAS_LOGD("multi-assistant active state : %d\n", *activated); + + CServicePlugin *plugin = nullptr; + if (g_service_main) { + plugin = g_service_main->get_service_plugin(); + } + if (plugin) { + if (*activated) { + plugin->activate(); + } else { + plugin->deactivate(); + } + } else { + MAS_LOGE("Could not change plugin state : %p %p", g_service_main, plugin); + } + } +} + +int CServiceMain::initialize_service_plugin(void) +{ + if (0 != mServicePlugin.initialize()) { + MAS_LOGE("Fail to ws intialize"); + return -1; + } + + if (0 != mServicePlugin.set_language(mCurrentLanguage.c_str())) { + MAS_LOGE("Fail to ws set language"); + return -1; + } + ++ memset(&mClientInfo, 0x00, sizeof(mClientInfo)); ++ mCurrentClientInfo = -1; ++ mCurrentPreprocessingClientInfo = -1; ++ mWakeupClientAppId.clear(); ++ + if (0 == mServiceConfig.get_assistant_info(mas_assistant_info_cb, this)) { + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + int inner_loop; + if (0 < strlen(mClientInfo[loop].appid)) { + mServiceConfig.load_custom_wake_words(mClientInfo[loop].appid, + mClientInfo[loop].wakeup_word, mClientInfo[loop].wakeup_language); + if (0 < strlen(mClientInfo[loop].wakeup_engine)) { + mServicePlugin.set_assistant_wakeup_engine( + mClientInfo[loop].appid, + mClientInfo[loop].wakeup_engine); + } + for (inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) { + MAS_LOGD("Registering wakeup word %s for app %s", + mClientInfo[loop].wakeup_word[inner_loop], mClientInfo[loop].appid); + if (0 != mServicePlugin.add_assistant_wakeup_word( + mClientInfo[loop].appid, + mClientInfo[loop].wakeup_word[inner_loop], + mClientInfo[loop].wakeup_language[inner_loop])) { + MAS_LOGE("Fail to add assistant's wakeup word"); + } + } + } + for (inner_loop = 0; inner_loop < MAX_SUPPORTED_LANGUAGES_NUM; inner_loop++) { + if (0 < strlen(mClientInfo[loop].supported_language[inner_loop])) { + MAS_LOGD("Adding language %s for app %s", + mClientInfo[loop].supported_language[inner_loop], mClientInfo[loop].appid); + if (0 != mServicePlugin.add_assistant_language( + mClientInfo[loop].appid, + mClientInfo[loop].supported_language[inner_loop])) { + MAS_LOGE("Fail to add assistant's language"); + } + } + } + } + } + } else { + MAS_LOGE("Fail to load assistant info"); + } + + if (0 != mServicePlugin.set_callbacks()) { + MAS_LOGE("Fail to set callbacks"); + return -1; + } + + return 0; +} + +int CServiceMain::deinitialize_service_plugin(void) +{ + MAS_LOGI("[ENTER]"); + if (0 != mServicePlugin.deactivate()) { + MAS_LOGE("Fail to deactivate"); + } + if (0 != mServicePlugin.deinitialize()) { + MAS_LOGE("Fail to deinitialize"); + } + MAS_LOGI("[END]"); + return 0; +} + +int CServiceMain::process_activated_setting() +{ + if (mPreferenceManager.register_changed_callback( + MULTI_ASSISTANT_SETTINGS_ACTIVATED, active_state_changed_cb, &mPreferenceManager)) { + /* Activate / deactivate according to the vconf key setting */ + active_state_changed_cb(std::string{}, &mPreferenceManager); + } else { +#ifdef ENABLE_MULTI_ASSISTANT_BY_DEFAULT + /* Multi-assistant needs to be enabled by default, unless disabled explicitly */ + mServicePlugin.activate(); + const char *default_assistant = NULL; + if (0 == mServicePlugin.get_default_assistant(&default_assistant)) { + if (NULL == default_assistant) { + if (mClientInfo[0].used) { + default_assistant = mClientInfo[0].appid; + MAS_LOGW("No default assistant, setting %s as default", default_assistant); + mServicePlugin.set_default_assistant(default_assistant); + } else { + MAS_LOGE("No default assistant, and no assistant installed"); + } + } + } +#endif + } + return 0; +} + +int CServiceMain::mas_get_current_client_pid() +{ + int ret = -1; + if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) { + const char *appid = mClientInfo[mCurrentClientInfo].appid; + if (appid) { + ret = mClientManager.find_client_pid_by_appid(std::string{appid}); + } + } + return ret; +} + +int CServiceMain::mas_get_current_preprocessing_client_pid() +{ + int ret = -1; + if (mCurrentPreprocessingClientInfo >= 0 && mCurrentPreprocessingClientInfo < MAX_MACLIENT_INFO_NUM) { + const char *appid = mClientInfo[mCurrentPreprocessingClientInfo].appid; + if (appid) { + ret = mClientManager.find_client_pid_by_appid(std::string{appid}); + } + } + return ret; +} + +int CServiceMain::mas_get_client_pid_by_appid(const char *appid) +{ + int ret = -1; + + if (appid) { + ret = mClientManager.find_client_pid_by_appid(std::string{appid}); + } + + if (-1 != ret && !mApplicationManager.is_application_running(ret)) { + MAS_LOGE("The PID for %s was %d, but it seems to be terminated", appid, ret); + on_deinitialize(ret); + ret = -1; + } + + return ret; +} + +bool CServiceMain::mas_get_client_custom_ui_option_by_appid(const char *appid) +{ + bool ret = false; + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid) && + 0 < strlen(mClientInfo[loop].wakeup_word[0])) { + if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + ret = mClientInfo[loop].custom_ui_option; + } + } + } + return ret; +} + +int CServiceMain::mas_get_client_pid_by_wakeup_word(const char *wakeup_word) +{ + const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word); + return mas_get_client_pid_by_appid(appid); +} + +const char* CServiceMain::mas_get_client_appid_by_wakeup_word(const char *wakeup_word) +{ + int loop; + const char *appid = NULL; + + if (NULL == wakeup_word) return NULL; + + for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid)) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) { + if (0 == strncmp(wakeup_word, mClientInfo[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) { + appid = mClientInfo[loop].appid; + } + } + } + } + } + + /* Perform extended search, by eliminating blank characters */ + if (NULL == appid) { + for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid)) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) { + char comparand[MAX_WAKEUP_WORD_LEN]; + int comparand_index = 0; + for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) { + if (' ' != mClientInfo[loop].wakeup_word[inner_loop][index]) { + comparand[comparand_index++] = mClientInfo[loop].wakeup_word[inner_loop][index]; + } + } + if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) { + appid = mClientInfo[loop].appid; + } + } + } + } + } + } + + return appid; +} + +int CServiceMain::mas_set_current_client_by_wakeup_word(const char *wakeup_word) +{ + int loop; + int ret = -1; + int prev_selection = mCurrentClientInfo; + + for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid)) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) { + if (0 == strncmp(wakeup_word, mClientInfo[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) { + mCurrentClientInfo = loop; + ret = 0; + } + } + } + } + } + /* Perform extended search, by eliminating blank characters */ + if (ret == -1) { + for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid)) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) { + char comparand[MAX_WAKEUP_WORD_LEN]; + int comparand_index = 0; + for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) { + if (' ' != mClientInfo[loop].wakeup_word[inner_loop][index]) { + comparand[comparand_index++] = mClientInfo[loop].wakeup_word[inner_loop][index]; + } + } + if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) { + mCurrentClientInfo = loop; + ret = 0; + } + } + } + } + } + } + + if (mCurrentClientInfo != prev_selection) { + if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) { + int pid = mas_get_client_pid_by_appid(mClientInfo[prev_selection].appid); + mServiceIpc.change_active_state(pid, MA_ACTIVE_STATE_INACTIVE); + } + } + + return ret; +} + +int CServiceMain::mas_set_current_client_by_appid(const char *appid) +{ + int ret = -1; + int prev_selection = mCurrentClientInfo; + + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid) && + 0 < strlen(mClientInfo[loop].wakeup_word[0])) { + if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + mCurrentClientInfo = loop; + ret = 0; + } + } + } + + if (mCurrentClientInfo != prev_selection) { + if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) { + int pid = mas_get_client_pid_by_appid(mClientInfo[prev_selection].appid); + mServiceIpc.change_active_state(pid, MA_ACTIVE_STATE_INACTIVE); + } + } + + return ret; +} + +int CServiceMain::mas_launch_client_by_appid(const char *appid, CLIENT_LAUNCH_MODE launch_mode) +{ + int result = 0; + + if (NULL == appid || 0 == strlen(appid)) { + MAS_LOGE("appid invalid, failed launching MA Client"); + return -1; + } + + if (CLIENT_LAUNCH_MODE_PRELAUNCH == launch_mode) { + if (mApplicationManager.is_application_running(appid)) { + MAS_LOGE("appid %s is already running, no need for a prelaunch", appid); + return -1; + } + + result = mApplicationManager.launch_app_async(appid, true); + } else { + result = mApplicationManager.launch_app_async(appid, false); + } + + if (CLIENT_LAUNCH_MODE_ACTIVATION == launch_mode) { + bool found = false; + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used && + 0 < strlen(mClientInfo[loop].appid)) { + if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + mWakeupClientAppId = mClientInfo[loop].appid; + found = true; + } + } + } + MAS_LOGD("mWakeupClientAppId : %s, %d", mWakeupClientAppId.c_str(), found); + } + + return result; +} + +int CServiceMain::mas_bring_client_to_foreground(const char* appid) +{ + int ret = 0; + + if (NULL == appid || 0 == strlen(appid)) { + MAS_LOGE("appid invalid, failed launching MA Client"); + return -1; + } + + if (!mApplicationManager.bring_app_to_foreground(appid)) { + ret = -1; + } + + return ret; +} + +int CServiceMain::mas_launch_client_by_wakeup_word(const char *wakeup_word) +{ + const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word); + return mas_launch_client_by_appid(appid, CLIENT_LAUNCH_MODE_ACTIVATION); +} + +int CServiceMain::mas_prelaunch_default_assistant() +{ + /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */ + boost::optional prelaunch_mode = + mPreferenceManager.get_bool(WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE); + if (prelaunch_mode && *prelaunch_mode) { + const char *default_assistant = NULL; + if (0 == mServicePlugin.get_default_assistant(&default_assistant)) { + if (!(mApplicationManager.is_application_running(default_assistant))) { + MAS_LOGD("prelaunching default_assistant_appid : %s", default_assistant); + mas_launch_client_by_appid(default_assistant, CLIENT_LAUNCH_MODE_PRELAUNCH); + } + } + } + return 0; +} + +int CServiceMain::mas_update_voice_key_support_mode() +{ + /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */ + bool successful = false; + const char *default_assistant = NULL; + if (0 == mServicePlugin.get_default_assistant(&default_assistant)) { + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (mClientInfo[loop].used) { + if (default_assistant && + strncmp(default_assistant, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + float duration = mClientInfo[loop].voice_key_tap_duration; + if (0.0f < duration) { + mServicePlugin.set_voice_key_tap_duration(duration); + } else { + mServicePlugin.unset_voice_key_tap_duration(); + } + mServicePlugin.set_voice_key_support_mode( + mClientInfo[loop].voice_key_support_mode); + successful = true; + } + } + } + } + + if (!successful) { + mServicePlugin.unset_voice_key_tap_duration(); + mServicePlugin.set_voice_key_support_mode(VOICE_KEY_SUPPORT_MODE_NONE); + } + return 0; +} + +ma_preprocessing_allow_mode_e CServiceMain::get_preprocessing_allow_mode(const char* appid) +{ + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (appid && mClientInfo[loop].used) { + if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) { + return mClientInfo[loop].preprocessing_allow_mode; + } + } + } + return MA_PREPROCESSING_ALLOW_NONE; +} + +/* This might need to be read from settings in the future, but using macro for now */ +//#define BRING_PREPROCESSING_ASSISTANT_TO_FRONT + +int CServiceMain::mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT event) +{ + const char* current_maclient_appid = NULL; + const char* preprocessing_allow_appid = NULL; + if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) { + current_maclient_appid = mClientInfo[mCurrentClientInfo].appid; + preprocessing_allow_appid = mClientInfo[mCurrentClientInfo].preprocessing_allow_appid; + } + ma_preprocessing_allow_mode_e mode = get_preprocessing_allow_mode(current_maclient_appid); + + switch (event) { + case PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED: + { +#ifndef BRING_PREPROCESSING_ASSISTANT_TO_FRONT + /* If there is no need to bring preprocessing assistant to front, + current_maclient should always be brought to front */ + mas_bring_client_to_foreground(current_maclient_appid); +#endif + mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED; + if (check_preprocessing_assistant_exists()) { + if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode || + MA_PREPROCESSING_ALLOW_ALL == mode) { + if (is_current_preprocessing_assistant(preprocessing_allow_appid)) { + mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED; + } + } + } else { +#ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT + /* If preprocessing assistant does not exist, there is no way to enable + preprocessing assistant, so bring current maclient to front right away */ + mas_bring_client_to_foreground(current_maclient_appid); +#endif + } + } + break; + case PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED: + { + mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED; + /* Enable preprocessing mode only if the preprocessing assistant exists */ + if (check_preprocessing_assistant_exists()) { + if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode || + MA_PREPROCESSING_ALLOW_ALL == mode) { + if (is_current_preprocessing_assistant(preprocessing_allow_appid)) { + mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED; + } + } + } + } + break; + case PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED: + { + if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED == mCurrentPreprocessingState) { + mCurrentPreprocessingState = PREPROCESSING_STATE_PREPROCESSING_UTTERANCE; + } else if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED == mCurrentPreprocessingState) { + /* If preprocessing assistant does not exist, the current_maclient + would have been brought to front already on wakeup event */ +#ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT + if (check_preprocessing_assistant_exists()) { + mas_bring_client_to_foreground(current_maclient_appid); + } +#endif + mCurrentPreprocessingState = PREPROCESSING_STATE_NONE; + } + } + break; + case PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED: + { + mCurrentPreprocessingState = PREPROCESSING_STATE_NONE; + if (check_preprocessing_assistant_exists()) { + if (MA_PREPROCESSING_ALLOW_FOLLOW_UP == mode || + MA_PREPROCESSING_ALLOW_ALL == mode) { + mCurrentPreprocessingState = PREPROCESSING_STATE_PREPROCESSING_FOLLOW_UP; + } + } + } + break; + case PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED: + { +#ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT + if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == mCurrentPreprocessingState || + PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == mCurrentPreprocessingState) { + boost::optional preprocessing_assistant = + mPreferenceManager.get_bool(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID); + if (preprocessing_assistant) { + MAS_LOGD("preprocessing_assistant_appid : %s", (*preprocessing_assistant).c_str()); + mas_bring_client_to_foreground((*preprocessing_assistant).c_str()); + } + } +#endif + mCurrentPreprocessingState = PREPROCESSING_STATE_NONE; + } + break; + case PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED: + { +#ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT + if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == mCurrentPreprocessingState || + PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == mCurrentPreprocessingState) { + mas_bring_client_to_foreground(current_maclient_appid); + } +#endif + mCurrentPreprocessingState = PREPROCESSING_STATE_NONE; + } + break; + } + return 0; +} + +int CServiceMain::mas_set_current_service_state(ma_service_state_e state) +{ + mCurrentServiceState = state; + + int count = mClientManager.get_client_num(); + int i; + + for (i = 0; i < count; i++) { + int pid = mClientManager.find_client_pid_by_index(i); + + if (-1 != pid) { + int ret = mServiceIpc.change_service_state(pid, state); + if (0 != ret) { + MAS_LOGE("[ERROR] Fail to set service state change to %d, ret(%d)", pid, ret); + } + } + } + return 0; +} + +ma_service_state_e CServiceMain::mas_get_current_service_state() +{ + return mCurrentServiceState; +} + +bool CServiceMain::is_valid_wakeup_engine(const char* appid) +{ + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM;loop++) { + if (mClientInfo[loop].used) { + LOGD("comparing appid : %s %s", mClientInfo[loop].wakeup_engine, appid); + if (0 == strncmp(mClientInfo[loop].wakeup_engine, appid, MAX_APPID_LEN)) { + return true; + } + } + } + return false; +} + +int pkg_app_list_cb(const pkgmgrinfo_appinfo_h handle, void *user_data) +{ + if (nullptr == g_service_main) return -1; + + char *appid = NULL; + + int ret = pkgmgrinfo_appinfo_get_appid(handle, &appid); + if (PMINFO_R_OK == ret && NULL != appid) { + int *result = (int*)user_data; + if (result) { + bool exists = g_service_main->is_valid_wakeup_engine(appid); + if (exists) { + *result = 1; + } + } + } else { + LOGE("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret); + } + + return 0; +} + +/* +INFO: Package install/update/uninstall scenario +Install and Uninstall are obviously simple. + Install: just INSTALL + Uninstall: just UNINSTALL +Update package (change the source codes and Run As again), there are four scenarios: +1. UPDATE + Source code change +2. UNINSTALL -> INSTALL + This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Check "Enable Project specific settings" + and change Application ID in tizen-manifest.xml file and Run As. +3. UPDATE -> INSTALL + This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Uncheck "Enable Project specific settings" + and change Application ID in tizen-manifest.xml file and Run As. + At UPDATE event, pkgid (package parameter) is invalid... +4. UPDATE + Exceptionally, only UPDATE can be called when Application ID in tizen-manifest.xml file is changed. + At UPDATE event, pkgid (package parameter) is valid, and only appid is changed; the previous appid is invalid. +*/ +static void _package_manager_event_cb(const char *type, const char *package, package_manager_event_type_e event_type, package_manager_event_state_e event_state, int progress, package_manager_error_e error, void *user_data) +{ + CServiceMain* service_main = static_cast(user_data); + + int ret = 0; + uid_t uid = getuid(); + pkgmgrinfo_pkginfo_h handle = NULL; + static bool in_progress = false; + bool should_exit = false; + + if (!package || !type) + return; + + if (PACKAGE_MANAGER_EVENT_TYPE_UPDATE != event_type && + PACKAGE_MANAGER_EVENT_TYPE_INSTALL != event_type && + PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL != event_type) + return; + + if (PACKAGE_MANAGER_EVENT_STATE_STARTED != event_state && + PACKAGE_MANAGER_EVENT_STATE_COMPLETED != event_state) + return; + + bool user = false; + MAS_LOGD("type=%s package=%s event_type=%d event_state=%d progress=%d error=%d", + type, package, event_type, event_state, progress, error); + ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle); + if (ret != PMINFO_R_OK || NULL == handle) { + MAS_LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid()); + /* Try to get in user packages */ + user = true; + ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(package, uid, &handle); + if (ret != PMINFO_R_OK || NULL == handle) { + MAS_LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid()); + return; + } + } + + if (user) { + /* Try to get in user packages */ + pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret, uid); + } else { + /* Try to get in global packages */ + pkgmgrinfo_appinfo_get_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret); + } + if (1 == ret) { + if (PACKAGE_MANAGER_EVENT_STATE_STARTED == event_state) { + MAS_LOGI("processing PACKAGE_MANAGER_EVENT_STATE_STARTED event : %d", event_type); + if (false == in_progress) { + in_progress = true; + if (service_main) { + service_main->deinitialize_service_plugin(); + } else { + MAS_LOGE("service_main is NULL"); + } + } + } else if (PACKAGE_MANAGER_EVENT_STATE_COMPLETED == event_state) { + MAS_LOGI("processing PACKAGE_MANAGER_EVENT_STATE_COMPLETED event : %d", event_type); + if (false == in_progress) { + if (service_main) { + service_main->deinitialize_service_plugin(); + } else { + MAS_LOGE("service_main is NULL"); + } + } + /* + if (service_main) { + service_main->initialize_service_plugin(); + service_main->process_activated_setting(); + } else { + MAS_LOGE("service_main is NULL"); + } + */ + should_exit = true; + in_progress = false; + } + } + + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + + if (should_exit) { + LOGI("Now restarting multi-assistant-service for reloading updated modules"); + service_app_exit(); + } + + return; +} + +bool CServiceMain::app_create(void *data) +{ + // Todo: add your code here. + MAS_LOGD("[Enter] Service app create"); + + g_service_main = this; + + mClientManager.set_application_manager(&mApplicationManager); + + mServiceIpc.set_client_manager(&mClientManager); + mServiceIpc.set_service_ipc_observer(this); + + mServicePlugin.set_service_ipc(&mServiceIpc); + mServicePlugin.set_service_main(this); + + int ret = mServiceIpc.open_connection(); + if (0 != ret) { + MAS_LOGE("[ERROR] Fail to open connection"); + } + + initialize_service_plugin(); + + process_activated_setting(); + + mas_prelaunch_default_assistant(); + mas_update_voice_key_support_mode(); + + /* For the case of preprocessing assistant, it always have to be launched beforehand */ + boost::optional preprocessing_assistant = + mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID); + if (preprocessing_assistant) { + MAS_LOGD("prelaunching preprocessing_assistant_appid : %s", (*preprocessing_assistant).c_str()); + mas_launch_client_by_appid((*preprocessing_assistant).c_str(), CLIENT_LAUNCH_MODE_PRELAUNCH); + } + + if (!mPackageManagerHandle) { + int ret = package_manager_create(&mPackageManagerHandle); + if (ret == PACKAGE_MANAGER_ERROR_NONE) { + ret = package_manager_set_event_cb(mPackageManagerHandle, _package_manager_event_cb, this); + if (ret == PACKAGE_MANAGER_ERROR_NONE) { + LOGD("package_manager_set_event_cb succeeded."); + } else { + LOGE("package_manager_set_event_cb failed(%d)", ret); + } + } else { + LOGE("package_manager_create failed(%d)", ret); + } + } + + return true; +} + +void CServiceMain::app_terminate(void *data) +{ + MAS_LOGI("[ENTER]"); + if (mPackageManagerHandle) { + package_manager_unset_event_cb(mPackageManagerHandle); + package_manager_destroy(mPackageManagerHandle); + mPackageManagerHandle = NULL; + } + + deinitialize_service_plugin(); + + mPreferenceManager.unregister_changed_callback( + MULTI_ASSISTANT_SETTINGS_ACTIVATED, active_state_changed_cb); + + int ret = mServiceIpc.close_connection(); + if (0 != ret) { + MAS_LOGE("[ERROR] Fail to close connection"); + } + + g_service_main = nullptr; + + MAS_LOGI("[END]"); + return; +} + +int CServiceMain::on_initialize(int pid) { + MAS_LOGD("[Enter] pid(%d)", pid); + + std::string pid_appid; + boost::optional appid_by_pid = mApplicationManager.get_appid_by_pid(pid); + if (appid_by_pid) { + pid_appid = *appid_by_pid; + MAS_LOGD("appid for pid %d is : %s", pid, pid_appid.c_str()); + + /* Remove existing client that has same appid, if there's any */ + mClientManager.destroy_client_by_appid(pid_appid.c_str()); + + /* And remove a client that has same pid also */ + mClientManager.destroy_client_by_pid(pid); + + mClientManager.create_client(pid, pid_appid.c_str()); + + const char *current_maclient_appid = NULL; + if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) { + current_maclient_appid = mClientInfo[mCurrentClientInfo].appid; + } + + mas_client_send_preprocessing_information(pid); + if (MA_VOICE_KEY_STATUS_PRESSED == mLastVoiceKeyStatus) { + mas_client_send_voice_key_status_change(pid, mLastVoiceKeyStatus); + } + if (current_maclient_appid && 0 == pid_appid.compare(current_maclient_appid)) { + MAS_LOGD("MA client with current maclient appid connected!"); + + if (0 == mWakeupClientAppId.compare(pid_appid)) { + mWakeupClientAppId.clear(); + mServiceIpc.change_active_state(pid, MA_ACTIVE_STATE_ACTIVE); + mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED); + } else { + MAS_LOGE("[ERROR] mWakeupClientAppId and appid differ : %s %s", + mWakeupClientAppId.c_str(), pid_appid.c_str()); + } + } else { + MAS_LOGD("MA client connected, but its appid does not match with current maclient"); + } + + mServiceIpc.change_service_state(pid, mas_get_current_service_state()); + } else { + MAS_LOGE("[ERROR] Fail to retrieve appid"); + } + + return 0; +} + +int CServiceMain::on_deinitialize(int pid) { + MAS_LOGD("[Enter] pid(%d)", pid); + mClientManager.destroy_client_by_pid(pid); + return 0; +} + +int CServiceMain::on_get_audio_format(int pid, int& rate, int& channel, int& audio_type) { + int main_rate, main_channel, main_audio_type; + int ret = mas_client_get_audio_format(pid, + &main_rate, &main_channel, &main_audio_type); + rate = main_rate; + channel = main_channel; + audio_type = main_audio_type; + return ret; +} + +int CServiceMain::on_get_audio_source_type(int pid, std::string& type) { + char *main_type = nullptr; + int ret = mas_client_get_audio_source_type(pid, &main_type); + if (0 == ret && main_type) { + type = std::string{main_type}; + } + return ret; +} + +int CServiceMain::on_send_asr_result(int pid, int event, std::string asr_result) { + return mas_client_send_asr_result(pid, event, asr_result.c_str()); +} + +int CServiceMain::on_send_result(int pid, std::string display_text, + std::string utterance_text, std::string result_json) { + return mas_client_send_result(pid, + display_text.c_str(), utterance_text.c_str(), result_json.c_str()); +} + +int CServiceMain::on_send_recognition_result(int pid, int result) { + return mas_client_send_recognition_result(pid, result); +} + +int CServiceMain::on_start_streaming_audio_data(int pid, int type) { + return mas_client_start_streaming_audio_data(pid, type); +} + +int CServiceMain::on_stop_streaming_audio_data(int pid, int type) { + return mas_client_stop_streaming_audio_data(pid, type); +} + +int CServiceMain::on_update_voice_feedback_state(int pid, int state) { + return mas_client_update_voice_feedback_state(pid, state); +} + +int CServiceMain::on_send_assistant_specific_command(int pid, std::string command) { + return mas_client_set_assistant_specific_command(pid, command.c_str()); +} + +int CServiceMain::on_set_background_volume(int pid, double ratio) { + return mas_client_set_background_volume(pid, ratio); +} + +int CServiceMain::on_set_preprocessing_allow_mode(int pid, int mode, std::string app_id) { + return mas_client_set_preprocessing_allow_mode(pid, + static_cast(mode), app_id.c_str()); +} + +int CServiceMain::on_send_preprocessing_result(int pid, int result) { + return mas_client_send_preprocessing_result(pid, result); +} + +int CServiceMain::on_set_wake_word_audio_require_flag(int pid, int require) { + return mas_client_set_wake_word_audio_require_flag(pid, require); +} + +int CServiceMain::on_set_assistant_language(int pid, std::string language) { + return mas_client_set_assistant_language(pid, language.c_str()); +} + +int CServiceMain::on_add_wake_word(int pid, std::string wake_word, std::string language) { + return mas_client_add_wake_word(pid, wake_word.c_str(), language.c_str()); +} + +int CServiceMain::on_remove_wake_word(int pid, std::string wake_word, std::string language) { + return mas_client_remove_wake_word(pid, wake_word.c_str(), language.c_str()); +} + +int CServiceMain::on_ui_initialize(int pid) +{ + return mas_ui_client_initialize(pid); +} + +int CServiceMain::on_ui_deinitialize(int pid) +{ + return mas_ui_client_deinitialize(pid); +} + +int CServiceMain::on_ui_change_assistant(std::string app_id) +{ + return mas_ui_client_change_assistant(app_id.c_str()); +}