From 6fd0cd53b9b0bbc3297af752069c9d2503d11d79 Mon Sep 17 00:00:00 2001 From: "sungwook79.park" Date: Wed, 7 Sep 2016 16:49:19 +0900 Subject: [PATCH] Add feedback effect in voice layout Change-Id: Ifcac157014d6cfc75136a1e08c74f1e8958b8593 Signed-off-by: sungwook79.park --- CMakeLists.txt | 5 +- po/en_US.po | 65 +++- res/edje/w-input-stt.edc | 4 +- src/MicEffector.cpp | 478 +++++++++++++++++++++++++++ src/SttFeedback.cpp | 185 +++++++++++ src/SttManager.cpp | 505 +++++++++++++++++++++++++++++ src/WInputSttMicEffect.cpp | 155 +++++++++ src/include/MicEffector.h | 183 +++++++++++ src/include/SttFeedback.h | 57 ++++ src/include/SttManager.h | 229 +++++++++++++ src/include/WInputSttMicEffect.h | 64 ++++ src/include/ise-stt-engine.h | 56 ---- src/include/ise-stt-mode.h | 79 +++++ src/include/ise-stt-option.h | 5 +- src/ise-stt-mode.cpp | 684 ++++++++++++++++++++++++++++++++++++++- src/ise-stt-option.cpp | 43 ++- src/ise.cpp | 5 +- 17 files changed, 2704 insertions(+), 98 deletions(-) create mode 100644 src/MicEffector.cpp create mode 100644 src/SttFeedback.cpp create mode 100644 src/SttManager.cpp create mode 100644 src/WInputSttMicEffect.cpp create mode 100644 src/include/MicEffector.h create mode 100644 src/include/SttFeedback.h create mode 100644 src/include/SttManager.h create mode 100644 src/include/WInputSttMicEffect.h delete mode 100644 src/include/ise-stt-engine.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f19f159..fb9dee0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,9 +7,12 @@ SET(ISE_SRCS src/config.cpp src/option.cpp src/imdata.cpp - src/ise-stt-engine.cpp src/ise-stt-mode.cpp src/ise-stt-option.cpp + src/MicEffector.cpp + src/SttFeedback.cpp + src/SttManager.cpp + src/WInputSttMicEffect.cpp src/sdk/ise_lang_table.cpp src/sdk/cji.cpp src/sdk/sdk.cpp diff --git a/po/en_US.po b/po/en_US.po index 30363d0..5a235e5 100755 --- a/po/en_US.po +++ b/po/en_US.po @@ -104,4 +104,67 @@ msgid "IDS_VOICE_OPT_LANGUAGE_ABB" msgstr "Language" msgid "IDS_VC_BODY_AUTOMATIC" -msgstr "Automatic" \ No newline at end of file +msgstr "Automatic" + + + + +msgid "IDS_ACCS_BODY_DISABLED_TTS" +msgstr "Turned off." + +msgid "IDS_MSG_BODY_SELECTED_TTS" +msgstr "Selected." + +msgid "IDS_MSGS_BODY_NOT_SELECTED_T_TTS" +msgstr "Not selected" + +msgid "IDS_WNOTI_TPOP_CHECK_YOUR_PHONE_ABB" +msgstr "Check your phone." + +msgid "IDS_ST_TPOP_CONNECT_VIA_BLUETOOTH_TO_REVIEW_AND_ACCEPT_THE_LEGAL_NOTICE_ABB" +msgstr "Connect via Bluetooth to review and accept the legal notice." + +msgid "IDS_IME_HEADER_INPUT_LANGUAGES_ABB" +msgstr "Input languages" + +msgid "IDS_TTS_TBBODY_DOUBLE_TAP_TO_SEND" +msgstr "Double tap to send." + +msgid "IDS_VTR_BODY_SPEAK_IN_PS_NOW" +msgstr "Speak in %s now." + +msgid "IDS_IME_BODY_FAILED_TO_RECOGNISE_VOICE" +msgstr "Failed to recognize voice." + +msgid "IDS_VC_HEADER_VOICE_INPUT_LANGUAGE" +msgstr "Voice input language" + +msgid "IDS_ST_ACBUTTON_AGREE_ABB" +msgstr "AGREE" + +msgid "IDS_IME_POP_NETWORK_CONNECTION_ERROR" +msgstr "Network connection error." + +msgid "IDS_ST_POP_NETWORK_ERROR" +msgstr "Network error." + +msgid "IDS_VOICE_NPBODY_SPEAK_NOW_ABB" +msgstr "Speak now" + +msgid "IDS_VOICE_TPOP_RECOGNITION_FAILED_ABB" +msgstr "Recognition failed." + +msgid "IDS_VOICE_MBODY_NETWORK_ERROR_ABB" +msgstr "Network error" + +msgid "IDS_AMEMO_BUTTON_SEND" +msgstr "Send" + +msgid "IDS_TTS_TBBODY_DOUBLE_TAP_TO_SPEAK" +msgstr "Double tap to speak." + +msgid "IDS_VTR_BODY_RECOGNITION_SERVICE_BUSY" +msgstr "Recognition service busy." + +msgid "IDS_VOICE_NPBODY_TAP_TO_PAUSE_ABB" +msgstr "Tap to pause" \ No newline at end of file diff --git a/res/edje/w-input-stt.edc b/res/edje/w-input-stt.edc index b56e430..b627c6f 100644 --- a/res/edje/w-input-stt.edc +++ b/res/edje/w-input-stt.edc @@ -801,7 +801,7 @@ collections fit: 1 1; style, "textblock_style"; } - color, 120 120 120 120; + color, 255 255 255 255; } description { @@ -812,7 +812,7 @@ collections fit: 1 1; style, "textblock_style_bottom"; } - color, 120 120 120 120; + color, 255 255 255 255; } } } diff --git a/src/MicEffector.cpp b/src/MicEffector.cpp new file mode 100644 index 0000000..f2602d1 --- /dev/null +++ b/src/MicEffector.cpp @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "MicEffector.h" + +using namespace is::ui; + +/** + * animation configuration values + * + */ +static size_t start_stop_anim_count = 28; +static size_t spectrum_count = SAMPLE_COUNT; +static float spectrum_posx = 40.0f; + +static float timeout_s = 1.0f / 60.0f; + +#define MATH_PI (3.141592) + +double cubic_easy_in_out(double index, double start, double end, double duration) +{ + index /= duration/2; + if (index < 1) + return end/2*index*index*index + start; + + index -= 2; + return end/2*(index*index*index + 2) + start; +} + +double cubic_easy_in(double index, double start, double end, double duration) +{ + index /= duration; + return end*index*index*index*index*index + start; +} + +double cubic_easy_out(double index, double start, double end, double duration) +{ + index /= duration; + index--; + return end*(index*index*index + 1) + start; +} + + +/** + * Constructor + * + * #1. Create ea_vector handle for drawing effect. + * ( 1 canvas, 1 paint and 45 paths ) + * #2. Drawing empty frame to avoid broken screen. + * + */ + +MicEffector::MicEffector(Evas_Object *canvas, Evas_Object *layout, IMicEffector& effect) + : drawcount(0) + , forcestop(false) + , started(false) + , fake(false) + , timer(NULL) + , layout(layout) + , ieffect(effect) +{ +// path = ea_vector_path_create(); +// paint = ea_vector_paint_create(); +// ea_vector_paint_set_style(paint, EA_VECTOR_PAINT_STYLE_STROKE); +// ea_vector_paint_set_line_cap(paint, EA_VECTOR_PAINT_LINE_CAP_ROUND); +// ea_vector_paint_set_line_join(paint, EA_VECTOR_PAINT_LINE_JOIN_ROUND); +// ea_vector_paint_set_line_width(paint, 3.0); +// ea_vector_paint_set_color(paint, 1.0f, 1.0f, 1.0f, 1.0f); + +// this->canvas = ea_vector_canvas_create(canvas); + + DrawDummyFrame(); +}; + + + +/** + * Destructor + * + * #1. Destroy ea_vector handle + * + */ +MicEffector::~MicEffector() +{ + if(timer) + { + ecore_timer_del(timer); + timer = NULL; + } + +// ea_vector_path_destroy(path); +// ea_vector_paint_destroy(paint); +// ea_vector_canvas_destroy(canvas); +} + + + +/** + * Draw empty frame to remove or initiate screen + * + */ +void MicEffector::DrawDummyFrame() +{ +// ea_vector_path_reset(path); +// ea_vector_path_move_to(path, 0, 0); +// ea_vector_path_line_to(path, 0, 0); +// ea_vector_canvas_draw(canvas, path, paint); +} + + + +/** + * Draw Que animation + * + * In case of start, it shows 2 more dots per one time. + * In case of stop, it remove 2 dots per one time. + * + * it works during 22 times. + * + */ +void MicEffector::DrawQue(int idx, bool is_start) +{ +// float margin = spectrum_posx; +// float posx = 0.0; + + double speed = cubic_easy_out(idx + 1.0, 0.0, 23.0, 23); + + unsigned int start = start_stop_anim_count - (int) speed; + unsigned int end = start_stop_anim_count + (int) speed; + +// double opacity; + + if (is_start) { +// opacity = cubic_easy_out(idx, 0.0, 1.0, 26.0); + } else { +// opacity = cubic_easy_out(idx, 0, 1.0, 26.0); + } + +// ea_vector_path_reset(path); + + for(unsigned int i = start; i < end; i++) + { +// posx = margin + (i * 5); + +// ea_vector_path_move_to(path, posx, 37.0f); +// ea_vector_path_line_to(path, posx, 38.0f); + +// ea_vector_paint_set_color(paint, 1.0f, 1.0f, 1.0f, opacity); + } + +// ea_vector_canvas_draw(canvas, path, paint); +} + + + +float MicEffector::GetAmplifyValue(unsigned int idx) +{ + float amplify = 0.0; + + int max[SAMPLE_COUNT] = { + /** + * dot "A" (9) + * + */ + 1, 1, 1, 1, + + + 1, 1, 1, 1, 1, 1, 1, 1, 1, + + /** + * dot "B" (9) + * + */ + 10, 8, 2, 3, 10, 11, 6, 12, 4, + + /** + * dot "C" (15) + * + */ + 3, 5, 9, 12, 11, 8, 14, 15, 13, 11, 12, 6, 8, 3, 2, + + /** + * reverse dot "B" (9) + * + */ + 4, 12, 6, 11, 10, 3, 2, 8, 10, + + /** + * dot "A" (9) + * + */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1 + }; + + amplify = (float) max[idx] / 10.0f * 1.9f; + + return amplify; +} + +/** + * Draw effect animation + * + * It draws volume effect. during 5 times. + * Center of effect area, it applies amplified value. + * + */ +void MicEffector::DrawWave(unsigned int idx, int amount, int prev_amount, double opacity, bool is_lastcmd) +{ +// float ratio = GetAmplifyValue(idx); + +// float am = ((float) amount) * ratio; +// float pam = ((float) prev_amount) * ratio; +// float cnt = (float) drawcount; + + float posx = spectrum_posx; + +// float height = pam > am? +// pam - cubic_easy_in_out(cnt + 1.0, am, pam, 7): +// cubic_easy_in_out(cnt + 1.0, pam, am, 7); + + posx += idx * 5; + +// ea_vector_path_move_to(path, posx, (37.0f - (height / 2.0))); +// ea_vector_path_line_to(path, posx, (38.0f + (height / 2.0))); + + if (is_lastcmd) { +// ea_vector_paint_set_color(paint, 0.1451f, 0.204f, 0.255f, opacity);//RGB = 37:52:65 + } else { +// ea_vector_paint_set_color(paint, 1.0f, 1.0f, 1.0f, opacity);//RGB: 255 255 255 + } +} + + + +/** + * Effect Start + * + */ +void MicEffector::Start() +{ + if(timer) { + ecore_timer_del(timer); + timer = NULL; + } + + drawcount = 0; + + prev.clear(); + current.clear(); + + for(size_t i = 0; i < spectrum_count; i++) + { + prev.push_back(0); + current.push_back(0); + } + + Listening(); + + /** + * Que animation + * + */ + timer = ecore_timer_add(timeout_s, + [](void *data)->Eina_Bool + { + MicEffector *effector = static_cast(data); + + effector->DrawQue(effector->drawcount); + + if(effector->drawcount < (int) start_stop_anim_count) { + effector->drawcount += 2; + return ECORE_CALLBACK_RENEW; + } else { + for(unsigned int i = 0; i < spectrum_count; i++) + effector->DrawWave(i, 0, 0); + +// ea_vector_canvas_draw(effector->canvas, effector->path, effector->paint); + + effector->drawcount = 0; + effector->timer = NULL; + effector->VolumeCheck(); + effector->Effect(); + return ECORE_CALLBACK_CANCEL; + } + }, + this); +} + +/** + * Volume effect + * + */ +void MicEffector::Effect(bool fake) +{ + /** + * Volume effect animation + * + */ + if ( timer ) { + ecore_timer_del(timer); + timer = NULL; + } + + timer = ecore_timer_add(timeout_s, + [](void *data)->Eina_Bool + { + MicEffector *effector = static_cast(data); + + bool is_empty_prev = effector->prev.empty(); + + +// ea_vector_path_reset(effector->path); + + for(unsigned int i = 0; i < effector->current.size(); i++) + { + if (is_empty_prev) + effector->DrawWave(i, effector->current.at(i), 0); + else + effector->DrawWave(i, effector->current.at(i), effector->prev.at(i)); + } +// ea_vector_canvas_draw(effector->canvas, effector->path, effector->paint); + + if (effector->drawcount < 7) { + effector->drawcount++; + } else { + effector->drawcount = 0; + effector->VolumeCheck(effector->fake); + } + + return ECORE_CALLBACK_RENEW; + }, this); +} + + + +/** + * Stop volume animation effect + * + */ +void MicEffector::Stop(bool forced) +{ + if(timer) + { + ecore_timer_del(timer); + timer = NULL; + } + + if(!started) + { + Idle(); + return; + } + + forcestop = forced; + + timer = ecore_timer_add(timeout_s, + [](void *data)->Eina_Bool + { + MicEffector *effector = static_cast(data); + + effector->DrawQue(start_stop_anim_count - effector->drawcount, false); + + if(effector->drawcount < (int) start_stop_anim_count) { + effector->drawcount += 2; + return ECORE_CALLBACK_RENEW; + } else { + if(!effector->forcestop) { + effector->Processing(); + } else { + effector->Idle(); + } + + effector->forcestop = false; + effector->drawcount = 0; + effector->timer = NULL; + return ECORE_CALLBACK_CANCEL; + } + }, this); +} + +/** + * Signal. Refresh volume effect + * + */ +void MicEffector::VolumeCheck(bool fake) +{ + std::vector volumes; + + this->fake = fake; + + if(!fake) { + volumes = ieffect.GetVolume(); + } else { + for(unsigned int i = 0; i < spectrum_count; i++) { + volumes.push_back(rand_r((unsigned int*)time(NULL)) % 2); + } + } + + prev.clear(); + prev.assign(current.begin(), current.end()); + + current.clear(); + current.assign(volumes.begin(), volumes.end()); +} + + + +/** + * Signal. Listening effect + * + */ +void MicEffector::Listening() +{ + started = true; + + elm_object_signal_emit(layout, "elm,state,eq,show", "eq"); + elm_object_signal_emit(layout, "elm,state,listening", "elm"); +} + + + +/** + * Signal. Processing effect + * + */ +void MicEffector::Processing() +{ + started = false; + + elm_object_signal_emit(layout, "elm,state,eq,hide", "eq"); + elm_object_signal_emit(layout, "elm,state,processing", "elm"); + + ieffect.ProcessingAnimationStart(); +} + + + +/** + * Signal. Idle effect + * + */ +void MicEffector::Idle() +{ + const char *text; + const char *state; + double val; + + started = false; + + elm_object_signal_emit(layout, "elm,state,eq,hide", "eq"); + + text = elm_object_part_text_get(layout, "elm.text"); + state = edje_object_part_state_get(elm_layout_edje_get(layout), "guide_text_block", &val); + + if ((text && strlen(text) > 0) && (state && !strcmp(state, "bottom"))) + elm_object_signal_emit(layout, "elm,state,init_message", "elm"); + else + elm_object_signal_emit(layout, "elm,state,init", "elm"); + + ieffect.ProcessingAnimationStop(); +} + diff --git a/src/SttFeedback.cpp b/src/SttFeedback.cpp new file mode 100644 index 0000000..ec73e87 --- /dev/null +++ b/src/SttFeedback.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "SttFeedback.h" +#include "ise-stt-mode.h" + + +using namespace is::stt; + +SttFeedback::SttFeedback() +{ + owner = NULL; +} + +SttFeedback::~SttFeedback() +{ +} + +void SttFeedback::OnResult( + std::string asrtype, + stt_result_event_e event, + std::vector results, + std::string msg) { + if (!owner) return; + + VoiceData& vd = *((VoiceData *) owner); + + if (vd.state == STT_STATE_VAL_TERMINATING) { + LOGD("STT_STATE_VAL_TERMINATING"); + return; + } + + // asrtype + // Partial result case : STT_RECOGNITION_TYPE_FREE_PARTIAL + // Normal result case : STT_RECOGNITION_TYPE_FREE + + if(results.size() < 1) { + LOGD("Result size : %d", results.size()); + vd.state = STT_STATE_VAL_NOT_RECOGNISED; + set_animation_state(&vd); + } else { + for(std::vector::iterator result = results.begin(); result != results.end(); std::advance(result, 1)) { + if(!result->empty() && result->length() > 0) { + LOGD("%s\n", result->c_str()); + switch(event){ + case STT_RESULT_EVENT_FINAL_RESULT: + LOGD("STT_RESULT_EVENT_FINAL_RESULT"); + vd.state = STT_STATE_VAL_INIT; + set_animation_state(&vd); + vd.result_type = STT_RESULT_EVENT_FINAL_RESULT; + voice_get_string(result->c_str(), &vd); + break; + case STT_RESULT_EVENT_PARTIAL_RESULT: + LOGD("STT_RESULT_EVENT_PARTIAL_RESULT"); + vd.result_type = STT_RESULT_EVENT_PARTIAL_RESULT; + voice_get_string(result->c_str(), &vd); + break; + default: + break; + } + return; + } + } + + /** + * Note. + * + * if recognized result doesn't have any data, + * it will process as recognition fail. + * + */ + //vd.state = STT_STATE_VAL_NOT_RECOGNISED; + vd.state = STT_STATE_VAL_INIT; + set_animation_state(&vd); + } +} + +void SttFeedback::AutoStart(void) { + LOGD("SttFeedback : AutoStart"); + start_by_press((VoiceData *) owner); +} + +void SttFeedback::SttIdle(void) +{ + if (!owner) { + LOGD("no owner"); + return; + } + + VoiceData& vd = *((VoiceData *) owner); + + /** + * Note. + * + * When recognition is failed, do nothing. + * Because after result, it's called continuous. So it looks not natural. + * + * So in this case, we will not change as INIT state. + * using 2 sec timer, it will change as idle state. + * + */ + if (vd.state == STT_STATE_VAL_NOT_RECOGNISED) { + LOGD("Ignore when state was STT_STATE_VAL_NOT_RECOGNISED"); + return; + } + + LOGD("UI will go to idle state"); + + vd.state = STT_STATE_VAL_INIT; + set_animation_state(&vd); +} + +void SttFeedback::SttRecording(void) +{ + if(!owner) { + LOGD("no owner"); + return; + } + + VoiceData& vd = *((VoiceData *) owner); + + if(vd.partial_result){ + free(vd.partial_result); + vd.partial_result = NULL; + } + + LOGD("UI will go to listening state"); + + vd.state = STT_STATE_VAL_LISTENING; + set_animation_state(&vd); +} + +void SttFeedback::SttProcessing(void) +{ + if(!owner) { + LOGD("no owner"); + return; + } + + VoiceData& vd = *((VoiceData *) owner); + + LOGD("UI will go to processing state"); + + vd.state = STT_STATE_VAL_PROCESSING; + set_animation_state(&vd); +} + + + +void SttFeedback::OnError(stt_error_e reason) +{ + if(!owner) { + LOGD("no owner"); + return; + } + + VoiceData& vd = *((VoiceData *) owner); + + LOGD("error = %d\n", reason); + vd.state = STT_STATE_VAL_INIT; + set_animation_state(&vd); + show_error_message(&vd, reason); +} + + +void SttFeedback::SetVoiceData(void *data) { + if(!data) { + LOGD("no data"); + return; + } + owner = data; +} diff --git a/src/SttManager.cpp b/src/SttManager.cpp new file mode 100644 index 0000000..cc19d8a --- /dev/null +++ b/src/SttManager.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "SttManager.h" + +using namespace is::stt; + +enum { + READY = 0x0001, + RECORDING = 0x0010, + PROCESSING = 0x0100, + CREATE = 0x1000 +}; + +static inline const char *stt_state_str(stt_state_e cur) +{ + if (cur == STT_STATE_CREATED) + return (const char *) "STT_STATE_CREATED"; + + else if (cur == STT_STATE_READY) + return (const char *) "STT_STATE_READY"; + + else if (cur == STT_STATE_RECORDING) + return (const char *) "STT_STATE_RECORDING"; + + else if (cur == STT_STATE_PROCESSING) + return (const char *) "STT_STATE_PROCESSING"; + + else + return (const char *) "ABNORMAL CASE"; +} + +SttManager::SttManager(ISttFeedback& feedback) +: ifeedback(feedback), + iscancelled(false) +{ + try { + /** + * Create stt handle. + * + */ + int ret = stt_create(&handle); + + if(ret != STT_ERROR_NONE) + throw SttException(ret, ErrorString((stt_error_e)ret)); + + /** + * Set default properties + * + */ + EnableFeedback(); + } + catch(SttException &e) { + LOGD("reason : %s", e.what()); + assert(0); + } +} + +SttManager::~SttManager() { + try { + EnableFeedback(false); + + Cancel(); + UnPrepare(); + } + catch(SttException &e) { + LOGD("reason : %s", e.what()); + stt_destroy(handle); + } +} + +void SttManager::Prepare() { + /** + * Prepare stt service. + * + */ + int ret = stt_prepare(handle); + + if(ret != STT_ERROR_NONE) + throw SttException(ret, ErrorString((stt_error_e)ret)); +} + +void SttManager::UnPrepare() { + /** + * UnPrepare stt service. + * + */ + int ret = stt_unprepare(handle); + + if (ret != STT_ERROR_NONE) + throw SttException(ret, ErrorString((stt_error_e)ret)); +} + +void SttManager::Start() { + if(!Validate((int) READY)) { + throw SttException((int) STT_ERROR_INVALID_STATE, "INVALID STATE - !STT_STATE_READY"); + } + + LOGD("HERE"); + + iscancelled = false; + + /** + * Start stt service. + * + */ + asrtype = STT_RECOGNITION_TYPE_FREE; + int ret; + ret = stt_start(handle, language.c_str(), asrtype.c_str()); + + if(ret != STT_ERROR_NONE) + throw SttException(ret, ErrorString((stt_error_e)ret)); +} + +void SttManager::Stop() { + if(!Validate((int) RECORDING)) { + throw SttException((int) STT_ERROR_INVALID_STATE, "INVALID STATE - !STT_STATE_RECORDING"); + } + + /** + * Stop stt service. + * + */ + int ret = stt_stop(handle); + + if(ret != STT_ERROR_NONE) + throw SttException(ret, ErrorString((stt_error_e)ret)); +} + +void SttManager::Cancel() { + if(iscancelled) { + LOGD("iscancelled (%d)", iscancelled); + return; + } + + if(!Validate((int) (RECORDING|PROCESSING))) { + throw SttException((int) STT_ERROR_INVALID_STATE, "INVALID STATE - !(STT_STATE_RECORDING or STT_STATE_PROCESSING)"); + } + + /** + * Cancel stt service (recording, processing) + * + */ + int ret = stt_cancel(handle); + + if(ret != STT_ERROR_NONE) + throw SttException(ret, ErrorString((stt_error_e)ret)); + + iscancelled = true; + LOGD("iscancelled (%d)", iscancelled); + + ifeedback.SttIdle(); +} + + +bool SttManager::Validate(int state) { + stt_state_e cur; + + int ret = stt_get_state(handle, &cur); + if (ret != STT_ERROR_NONE) { + return false; + } + + LOGD("validate state - %d", state); + LOGD("stt deamon state - %s", + cur == STT_STATE_CREATED ? "STT_STATE_CREATED" : + cur == STT_STATE_READY ? "STT_STATE_READY" : + cur == STT_STATE_RECORDING ? "STT_STATE_RECORDING" : + cur == STT_STATE_PROCESSING ? "STT_STATE_PROCESSING" : "ABNORMAL"); + + switch(cur) { + case STT_STATE_CREATED : + if (state & CREATE) return true; + break; + case STT_STATE_READY : + if (state & READY) return true; + break; + case STT_STATE_RECORDING : + if (state & RECORDING) return true; + break; + case STT_STATE_PROCESSING : + if (state & PROCESSING) return true; + break; + default : + break; + } + + return false; +} + +void SttManager::Initialize() { + /** Todo. add routine to intialize */ +} + +void SttManager::PrintResultState(stt_result_event_e result_type) +{ + std::string result; + + switch (result_type) { + case STT_RESULT_EVENT_FINAL_RESULT : + result = "STT_RESULT_EVENT_FINAL_RESULT"; + break; + case STT_RESULT_EVENT_PARTIAL_RESULT : + result = "STT_RESULT_EVENT_PARTIAL_RESULT"; + break; + case STT_RESULT_EVENT_ERROR : + result = "STT_RESULT_EVENT_ERROR"; + break; + default : + result = "UNKNOWN"; + break; + } + LOGD("result type : %s", result.c_str()); +} + +void SttManager::on_result( + stt_h handle, + stt_result_event_e event, + const char** data, + int size, + const char* msg, + void *user_data) { + PrintResultState(event); + + if (!user_data) { + LOGD("user_data null"); + throw SttException((int)STT_ERROR_INVALID_PARAMETER, "invalid self reference"); + } + + SttManager& manager = *((SttManager *) user_data); + + std::vector results; + + LOGD("result size : %d, msg : %s", size, msg); + + for (size_t i = 0; i < (size_t) size; i++) { + if (data[i]) { + results.push_back(std::string(data[i])); + } + + if (msg) + manager.ifeedback.OnResult(manager.asrtype, event, results, std::string(msg)); + else + manager.ifeedback.OnResult(manager.asrtype, event, results, std::string("")); + } +} + +void SttManager::PrintState(stt_state_e previous, stt_state_e current) +{ + std::string prev; + std::string curr; + + switch (previous) { + case STT_STATE_READY : + prev = "STT_STATE_READY"; + break; + case STT_STATE_CREATED : + prev = "STT_STATE_CREATED"; + break; + case STT_STATE_RECORDING : + prev = "STT_STATE_RECORDING"; + break; + case STT_STATE_PROCESSING : + prev = "STT_STATE_PROCESSING"; + break; + default : + prev = "UNKNOWN"; + break; + } + + switch (current) { + case STT_STATE_READY : + curr = "STT_STATE_READY"; + break; + case STT_STATE_CREATED : + curr = "STT_STATE_CREATED"; + break; + case STT_STATE_RECORDING : + curr = "STT_STATE_RECORDING"; + break; + case STT_STATE_PROCESSING : + curr = "STT_STATE_PROCESSING"; + break; + default : + curr = "UNKNOWN"; + break; + } + LOGD("previous: %s(%d), current: %s(%d)", prev.c_str(), previous, curr.c_str(), current); +} + +void SttManager::on_state_changed( + stt_h handle, + stt_state_e previous, + stt_state_e current, + void *user_data) { + PrintState(previous, current); + LOGD("SttManager::on_state_changed"); + + if (!user_data) + throw SttException((int)STT_ERROR_INVALID_PARAMETER, "invalid self reference"); + + SttManager& manager = *((SttManager *) user_data); + + if (current== STT_STATE_READY) { + if (previous == STT_STATE_CREATED) { + manager.EnableSilenceDetection(); + manager.ifeedback.AutoStart(); + } else if (previous == STT_STATE_RECORDING) { + std::string msg; + std::vector results; + manager.ifeedback.OnResult(manager.asrtype, STT_RESULT_EVENT_ERROR, results, msg); + } else { + manager.ifeedback.SttIdle(); + } + } else if (current == STT_STATE_RECORDING) { + manager.ifeedback.SttRecording(); + } else if (current == STT_STATE_PROCESSING) { + if (!manager.iscancelled) { + LOGD("iscancelled (%d)", manager.iscancelled); + manager.ifeedback.SttProcessing(); + } else { + manager.iscancelled = false; + LOGD("iscancelled (%d)", manager.iscancelled); + } + } +} + +void SttManager::PrintErrorState(stt_error_e reason) +{ + std::string res; + + switch (reason) { + case STT_ERROR_OUT_OF_MEMORY : + res = "STT_ERROR_OUT_OF_MEMORY"; + break; + case STT_ERROR_IO_ERROR : + res = "STT_ERROR_IO_ERROR"; + break; + case STT_ERROR_INVALID_PARAMETER : + res = "STT_ERROR_INVALID_PARAMETER"; + break; + case STT_ERROR_TIMED_OUT : + res = "STT_ERROR_TIMED_OUT"; + break; + case STT_ERROR_RECORDER_BUSY : + res = "STT_ERROR_RECORDER_BUSY"; + break; + case STT_ERROR_OUT_OF_NETWORK : + res = "STT_ERROR_OUT_OF_NETWORK"; + break; + case STT_ERROR_PERMISSION_DENIED : + res = "STT_ERROR_PERMISSION_DENIED"; + break; + case STT_ERROR_NOT_SUPPORTED : + res = "STT_ERROR_NOT_SUPPORTED"; + break; + case STT_ERROR_INVALID_STATE : + res = "STT_ERROR_INVALID_STATE"; + break; + case STT_ERROR_INVALID_LANGUAGE : + res = "STT_ERROR_INVALID_LANGUAGE"; + break; + case STT_ERROR_ENGINE_NOT_FOUND : + res = "STT_ERROR_ENGINE_NOT_FOUND"; + break; + case STT_ERROR_OPERATION_FAILED : + res = "STT_ERROR_OPERATION_FAILED"; + break; + case STT_ERROR_NOT_SUPPORTED_FEATURE : + res = "STT_ERROR_NOT_SUPPORTED_FEATURE"; + break; + default : + res = "UNKNOWN ERROR REASON"; + break; + } + LOGD("Error reason %s(%d)", res.c_str(), reason); +} + +void SttManager::on_error( + stt_h handle, + stt_error_e reason, + void *user_data) { + LOGD("stt-daemon error (%d)", reason); + + if (!user_data) + throw SttException((int)STT_ERROR_INVALID_PARAMETER, "invalid self reference"); + + SttManager& manager = *((SttManager *) user_data); + manager.ifeedback.OnError(reason); +} + +void SttManager::SetLanguage(std::string language) { + this->language = language; +} + +void SttManager::EnableFeedback(bool enabled) { + LOGD("SttManager::EnableFeedback"); + int ret = STT_ERROR_NONE; + + void *udata = static_cast(this); + + if (enabled) { + ret = stt_set_recognition_result_cb(handle, on_result, udata); + if (STT_ERROR_NONE != ret) + throw SttException(ret, ErrorString((stt_error_e)ret)); + + ret = stt_set_error_cb(handle, on_error, udata); + if (STT_ERROR_NONE != ret) + throw SttException(ret, ErrorString((stt_error_e)ret)); + + ret = stt_set_state_changed_cb(handle, on_state_changed, udata); + if (STT_ERROR_NONE != ret) + throw SttException(ret, ErrorString((stt_error_e)ret)); + } else { + ret = stt_unset_error_cb(handle); + if (STT_ERROR_NONE != ret) + throw SttException(ret, ErrorString((stt_error_e)ret)); + + ret = stt_unset_state_changed_cb(handle); + if (STT_ERROR_NONE != ret) + throw SttException(ret, ErrorString((stt_error_e)ret)); + + ret = stt_unset_recognition_result_cb(handle); + if (STT_ERROR_NONE != ret) + throw SttException(ret, ErrorString((stt_error_e)ret)); + } +} + +const char* SttManager::ErrorString(int ecode) { + const char *str = NULL; + + switch (ecode) { + case STT_ERROR_OUT_OF_MEMORY: + str = (const char *) "STT_ERROR_OUT_OF_MEMORY"; + break; + case STT_ERROR_IO_ERROR: + str = (const char *) "STT_ERROR_IO_ERROR"; + break; + case STT_ERROR_INVALID_PARAMETER: + str = (const char *) "STT_ERROR_INVALID_PARAMETER"; + break; + case STT_ERROR_TIMED_OUT: + str = (const char *) "STT_ERROR_TIMED_OUT"; + break; + case STT_ERROR_RECORDER_BUSY: + str = (const char *) "STT_ERROR_RECORDER_BUSY"; + break; + case STT_ERROR_OUT_OF_NETWORK: + str = (const char *) "STT_ERROR_OUT_OF_NETWORK"; + break; + case STT_ERROR_INVALID_STATE: + str = (const char *) " STT_ERROR_INVALID_STATE"; + break; + case STT_ERROR_INVALID_LANGUAGE: + str = (const char *) "STT_ERROR_INVALID_LANGUAGE"; + break; + case STT_ERROR_ENGINE_NOT_FOUND: + str = (const char *) "STT_ERROR_ENGINE_NOT_FOUND"; + break; + case STT_ERROR_OPERATION_FAILED: + str = (const char *) "STT_ERROR_OPERATION_FAILED"; + break; + case STT_ERROR_NOT_SUPPORTED_FEATURE: + str = (const char *) "STT_ERROR_NOT_SUPPORTED_FEATURE"; + break; + } + return str; +} + +void SttManager::SoundFeedback() { +} + +void SttManager::EnableSilenceDetection(bool enabled) { + stt_option_silence_detection_e s_option; + + if (enabled) + s_option = STT_OPTION_SILENCE_DETECTION_TRUE; + else + s_option = STT_OPTION_SILENCE_DETECTION_FALSE; + + int ret = stt_set_silence_detection(handle, s_option); + if (STT_ERROR_NONE != ret) { + LOGD("error(%d) = %s", ret, ErrorString((stt_error_e) ret)); + } else { + LOGD("stt_set_silence_detection Successful"); + } +} + diff --git a/src/WInputSttMicEffect.cpp b/src/WInputSttMicEffect.cpp new file mode 100644 index 0000000..44a41d9 --- /dev/null +++ b/src/WInputSttMicEffect.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "WInputSttMicEffect.h" + +namespace { +template +static unsigned long long SumSquare(unsigned long long const& a, T const& b) { + return a + b*b; +} + +const double MAX_AMPLITUDE_MEAN_16 = 23170.115738161934; +const double MAX_AMPLITUDE_MEAN_08 = 89.803909382810; + +unsigned int sample_count = SAMPLE_COUNT; + +} + +using namespace is::ui; + + +WInputSttMicEffect::WInputSttMicEffect() + : square_sum(0) + , count(5) + , handle(NULL) + , processing_effect_timer(NULL) + , progressbar(NULL) { +} + +WInputSttMicEffect::~WInputSttMicEffect() { + ProcessingAnimationStop(); +} + +std::vector WInputSttMicEffect::GetVolume() { + std::vector result; + + short pcm[512] = {0}; + int size = 0; + int ret = 0; + +// ret = stt_get_spectrum(handle, (void *) pcm, &size); + count = 5; + + if (STT_ERROR_NONE != ret) { + + } else { + unsigned int level = 0; + unsigned int step = (unsigned int) (size/2/sample_count); + + for (unsigned int k = 0; k < sample_count; k++ ){ + square_sum = std::accumulate(pcm + k*step, pcm + k*step + 5, 0ull, SumSquare); + level = ConvertLevel(); + result.push_back(level); + } + } + return result; +} + +float WInputSttMicEffect::GetDecibel() const +{ + float rms = std::sqrt(square_sum/count); + return 20.0*log10(rms); +} + +int WInputSttMicEffect::ConvertLevel() +{ + float db = GetDecibel(); + + if ( db <= 30.0 ){ + return 0; + } else if ( db <= 33.3 ){ + return 1; + } else if ( db <= 36.6 ){ + return 2; + } else if ( db <= 40 ){ + return 3; + } else if ( db <= 43.3 ){ + return 4; + } else if ( db <= 46.6 ){ + return 5; + } else if ( db <= 50 ){ + return 6; + } else if ( db <= 53.3 ){ + return 7; + } else if ( db <= 56.6 ){ + return 8; + } else if ( db <= 60 ){ + return 9; + } else { + return 10; + } +} + +void WInputSttMicEffect::ProcessingAnimationStart() { + elm_progressbar_pulse(progressbar, EINA_TRUE); + + processing_effect_timer = ecore_timer_add(0.1, + [](void *data)->Eina_Bool + { + if(!data) return ECORE_CALLBACK_CANCEL; +/* + WInputSttMicEffect *effect = (WInputSttMicEffect *) data; + Evas_Object *progressbar = effect->progressbar; + + double progress = eext_circle_value_get(progressbar); + + if (progress < 100) + progress += 5.0; + else + progress = 0.0; + + eext_circle_value_set(progressbar, progress); +*/ + return ECORE_CALLBACK_RENEW; + }, this); +} + +void WInputSttMicEffect::ProcessingAnimationStop() { + if(processing_effect_timer) + { + ecore_timer_del(processing_effect_timer); + processing_effect_timer = NULL; + } + elm_progressbar_pulse(progressbar, EINA_FALSE); +} + + + +void WInputSttMicEffect::SetSttHandle(stt_h handle) { + this->handle = handle; +} + + + +void WInputSttMicEffect::SetProgressBar(Evas_Object *progress) { + this->progressbar = progress; +} diff --git a/src/include/MicEffector.h b/src/include/MicEffector.h new file mode 100644 index 0000000..ca888eb --- /dev/null +++ b/src/include/MicEffector.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#pragma once + +#include +#include + +#define SAMPLE_COUNT 59 + +namespace is { /** name space input selector */ +namespace ui { /** name space ui */ + +/** + * Interface for external controller + * + */ +class IMicEffector +{ + public : + virtual ~IMicEffector() = 0; + virtual std::vector GetVolume() = 0; + virtual void ProcessingAnimationStart() = 0; + virtual void ProcessingAnimationStop() = 0; +}; +inline IMicEffector::~IMicEffector() { }; + +/** + * Effect & Effect Controller + * + */ +class MicEffector +{ + public : + MicEffector(Evas_Object *canvas, Evas_Object *layout, IMicEffector& effect); + ~MicEffector(); + + /** + * Start Effect. + * + * It support signaling to edje and start animation. + * + */ + void Start(); + + /** + * Equalizer Effect animation. + * + * @param volumes sampled volume values. + * @param fake default false. if it set as true, it works using fixed volume values. + * + */ + void Effect(bool fake = false); + + /** + * Stop Effect. + * + * It support signaling to edje and stop animation. + * + * @param forced default false. if it set as true, it should go idle state without processing. + * + */ + void Stop(bool forced = false); + + /** + * Get volumes via ieffect and refresh equalizer effect. + * + * @param fake default false. if it set as true, it works using fixed volume values. + * + */ + void VolumeCheck(bool fake = false); + + /** + * Draw image to show que animation. + * + * @param idx frame index value + * + */ + void DrawQue(int idx, bool is_start = true); + + /** + * Draw image to show que animation. + * + * @param idx frame index value + * @param amount current volume amount + * @param prev_amount previous volume amount + * @param opacity opacity value for effect + * @param is_lastcmd + * + */ + void DrawWave(unsigned int idx, int amount, int prev_amount, double opacity = 1.0f, bool is_lastcmd = false); + + /** + * Get ratio for tuned volume value. + * + * @param idx volume stick index + * @return ratio for each volume stick + * + */ + float GetAmplifyValue(unsigned int idx); + + private : + /** + * Support idle state actions. + * + */ + void Idle(); + + /** + * Support listening state actions. + * + */ + void Listening(); + + /** + * Support processing state actions. + * + */ + void Processing(); + + /** + * Draw dummy frame to avoid broken frame showing. + * It have to be call one time internally. + * + */ + void DrawDummyFrame(); + + /** + * Efl vector canvas handle + * + */ +// ea_vector_canvas_h *canvas; +// ea_vector_path_h *path; +// ea_vector_paint_h *paint; + + /** + * Volume values. + * + */ + std::vector prev; + std::vector current; + + public : + int startcount; + int drawcount; + bool forcestop; + bool started; + bool fake; + + /** + * timer handle + * + */ + Ecore_Timer *timer; + + /** + * mic widget layout + * + */ + Evas_Object *layout; + + /** + * interface with app + * + */ + IMicEffector& ieffect; +}; + +}} /** end of is::ui */ + diff --git a/src/include/SttFeedback.h b/src/include/SttFeedback.h new file mode 100644 index 0000000..f0c54b0 --- /dev/null +++ b/src/include/SttFeedback.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + + +#pragma once + + +#include "SttManager.h" +#include +#undef LOG_TAG +#define LOG_TAG "ISE_DEFAULT" + + +namespace is { +namespace stt { + +class SttFeedback : public ISttFeedback +{ + public : + SttFeedback(); + virtual ~SttFeedback(); + + virtual void OnResult( + std::string asrtype, + stt_result_event_e event, + std::vector results, + std::string msg); + + virtual void AutoStart(void); + + virtual void SttIdle(void); + + virtual void SttRecording(void); + + virtual void SttProcessing(void); + + virtual void OnError(stt_error_e reason); + + void SetVoiceData(void *data); + + void *owner; +}; + +}} /** end of is::stt*/ diff --git a/src/include/SttManager.h b/src/include/SttManager.h new file mode 100644 index 0000000..1c31d41 --- /dev/null +++ b/src/include/SttManager.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + + +#pragma once + +#include +#include +#include +#include +#undef LOG_TAG +#define LOG_TAG "ISE_DEFAULT" + + +extern "C" { + #include +} + +namespace is { +namespace stt { + +class SttException : public std::runtime_error { + public : + SttException(int code, const char *reason) + : std::runtime_error(reason) + , ecode(code) { }; + + int GetEcode() { + return ecode; + }; + + int ecode; +}; + +class ISttFeedback +{ + public : + virtual ~ISttFeedback() = 0; + /** + * Result event which can be overloaded + * + * @param event + * @param results + * @param msg + */ + virtual void OnResult( + std::string asrtype, + stt_result_event_e event, + std::vector results, + std::string msg) = 0; + + virtual void AutoStart(void) = 0; + + virtual void SttIdle(void) = 0; + + virtual void SttRecording(void) = 0; + + virtual void SttProcessing(void) = 0; + + /** + * Error event which can be overloaded + * + * @param reason + */ + virtual void OnError(stt_error_e reason) = 0; +}; +inline ISttFeedback::~ISttFeedback() { }; + +class SttManager +{ + private : + stt_h handle; + std::string language; + + public : + ISttFeedback& ifeedback; + bool iscancelled; + std::string asrtype; + + public : + + SttManager(ISttFeedback& feedback); + + ~SttManager(); + + /** + * Prepare stt service. + * + */ + void Prepare(); + + /** + * Unprepare stt service + * + */ + void UnPrepare(); + + /** + * Start stt service + * + */ + void Start(); + + /** + * Stop stt service + * + */ + void Stop(); + + /** + * Cancle stt service + * + */ + void Cancel(); + + /** + * Initialize + * + */ + void Initialize(); + + bool Validate(int state); + + + /** + * result cb for tizen stt api. + * + * @param handle + * @param event + * @param data + * @param data_count + * @param msg + * @param user_data + */ + static void on_result( + stt_h handle, + stt_result_event_e event, + const char **data, + int data_count, + const char *msg, + void *user_data); + + /** + * state changed cb for tizen stt api. + * + * @param handle + * @param previous + * @param current + * @param user_data + */ + static void on_state_changed( + stt_h handle, + stt_state_e previous, + stt_state_e current, + void *user_data); + + /** + * error cb for tizen stt api. + * + * @param handle + * @param reason + * @param user_data + */ + static void on_error(stt_h handle, stt_error_e reason, void *user_data); + + /** + * Setter language property + * + * @param language + */ + void SetLanguage(std::string language); + + /** + * Enable cb event or not + * + * @param enabled + */ + void EnableFeedback(bool enabled = true); + + /** + * Enable silence detect + * + * @param enabled + */ + void EnableSilenceDetection(bool enabled = false); + + /** + * Sound feedback + * + */ + void SoundFeedback(); + + /** + * Convert erroro code as string + * + * @param errocode + * @return human readable string about error code. + */ + const char *ErrorString(int ecode); + + stt_state_e GetCurrent(void) { + stt_state_e cur; + stt_get_state(handle, &cur); + + return cur; + }; + + stt_h GetSttHandle() { return handle; } + + private : + static void PrintErrorState(stt_error_e reason); + static void PrintState(stt_state_e previous, stt_state_e current); + static void PrintResultState(stt_result_event_e result_type); +}; + +}} /** end of is::stt */ diff --git a/src/include/WInputSttMicEffect.h b/src/include/WInputSttMicEffect.h new file mode 100644 index 0000000..41331d0 --- /dev/null +++ b/src/include/WInputSttMicEffect.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +#pragma once + +#include + +extern "C" { + #include +} + +#include +#include + +#include "MicEffector.h" + +namespace is { +namespace ui { + +class WInputSttMicEffect : public IMicEffector +{ + private : + unsigned long long square_sum; + unsigned int count; + + + public : + WInputSttMicEffect(); + + virtual ~WInputSttMicEffect(); + + std::vector GetVolume(); + + void ProcessingAnimationStart(); + + void ProcessingAnimationStop(); + + float GetDecibel() const; + + int ConvertLevel(); + + void SetSttHandle(stt_h handle); + + void SetProgressBar(Evas_Object *progress); + + stt_h handle; + + Ecore_Timer *processing_effect_timer; + Evas_Object *progressbar; +}; + +}} /** end of is::ui */ diff --git a/src/include/ise-stt-engine.h b/src/include/ise-stt-engine.h deleted file mode 100644 index 0fbd7a8..0000000 --- a/src/include/ise-stt-engine.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ - - -#ifndef ISE_STT_ENGINE_H_ -#define ISE_STT_ENGINE_H_ - -/* - * This file will be included from ISE - */ - - -#include - -#ifdef EAPI -# undef EAPI -#endif - - -#ifdef __GNUC__ -# if __GNUC__ >= 4 -# define EAPI __attribute__ ((visibility("default"))) -# else -# define EAPI -# endif -#else -# define EAPI -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -void ise_stt_start(); -void ise_stt_finish(); - - -#ifdef __cplusplus -} -#endif - -#endif /* ISE_STT_ENGINE_H_ */ diff --git a/src/include/ise-stt-mode.h b/src/include/ise-stt-mode.h index f2c2e71..13eae21 100644 --- a/src/include/ise-stt-mode.h +++ b/src/include/ise-stt-mode.h @@ -25,6 +25,12 @@ #include +#include +#include "SttFeedback.h" +#include "SttManager.h" +#include "MicEffector.h" +#include "WInputSttMicEffect.h" + #ifdef EAPI # undef EAPI #endif @@ -48,9 +54,82 @@ extern "C" #define STT_EDJ_FILE "edje/w-input-stt.edj" +#define SK_INIT "IDS_VOICE_BODY_TAP_MIC" +#define SK_SPEAK_NOW "IDS_VOICE_NPBODY_SPEAK_NOW_ABB" +#define SK_RECOGNITION_FAILED "IDS_VOICE_TPOP_RECOGNITION_FAILED_ABB" + +#define SK_DOUBLE_TAP_TO_SPEAK "IDS_TTS_TBBODY_DOUBLE_TAP_TO_SPEAK" +#define SK_TAP_TO_PAUSE "IDS_VOICE_NPBODY_TAP_TO_PAUSE_ABB" + +#define TTS_NOT_SELECTED "IDS_MSGS_BODY_NOT_SELECTED_T_TTS" +#define TTS_SELECTED "IDS_MSG_BODY_SELECTED_TTS" + +#define TTS_SEND "IDS_AMEMO_BUTTON_SEND" +#define TTS_DISABLED "IDS_ACCS_BODY_DISABLED_TTS" + +#define SK_NETWORK_ERROR "IDS_VOICE_MBODY_NETWORK_ERROR_ABB" +#define SK_STT_BUSY "IDS_VTR_BODY_RECOGNITION_SERVICE_BUSY" + +#define POPUP_OK_AGREE "IDS_ST_ACBUTTON_AGREE_ABB" +#define POPUP_OK_BTN "IDS_ST_SK_OK" + + +typedef enum _SttStateVal { + STT_STATE_VAL_INIT = 0, + STT_STATE_VAL_PREPARE_LISTENING, + STT_STATE_VAL_LISTENING, + STT_STATE_VAL_PREPARE_PROCESSING, + STT_STATE_VAL_PROCESSING, + STT_STATE_VAL_PREPARE_CANCEL, + STT_STATE_VAL_NOT_RECOGNISED, + STT_STATE_VAL_TERMINATING, + STT_STATE_VAL_MAX +} SttStateVal; + +typedef struct _VoiceData VoiceData; + +struct _VoiceData +{ + int voicefw_state; //0 means init failed else success + stt_h voicefw_handle; //Wonyoung Lee added + Evas_Object *naviframe; //main window + Evas_Object *layout_main; //layout + Evas_Object *progressbar; //progressbar + Evas_Object *scroller; //scroller + Evas_Object *main_entry; //entry + Evas_Object *mic_button; //MIC button + SttStateVal state; + char *kbd_lang; + Ecore_Timer *start_timer; + Ecore_Timer *refresh_timer; + Ecore_Timer *progressbar_timer; + Ecore_Timer *textblock_timer; + Ecore_Timer *guide_text_timer; + Ecore_Timer *btn_disabling_timer; + Ecore_Timer *power_unlock_timer; + + std::vector stt_results; + char *partial_result; + int result_type; + + int disclaimer; + + is::stt::SttFeedback *sttfeedback; + is::stt::SttManager *sttmanager; + + is::ui::WInputSttMicEffect *ieffect; + is::ui::MicEffector *effector; +}; + void ise_show_stt_mode(Evas_Object *win); void ise_hide_stt_mode(); +void start_by_press(VoiceData *voicedata); +void set_animation_state(VoiceData *voicedata); +void show_popup_toast(const char *text, bool check_img); +void show_error_message(VoiceData *voicedata, stt_error_e reason); +void voice_get_string(const char *keyValue, VoiceData *voicedata); + #ifdef __cplusplus diff --git a/src/include/ise-stt-option.h b/src/include/ise-stt-option.h index 1602f2a..e9e4f9d 100644 --- a/src/include/ise-stt-option.h +++ b/src/include/ise-stt-option.h @@ -24,6 +24,7 @@ #include +#include "ise-stt-mode.h" #ifdef EAPI # undef EAPI @@ -50,7 +51,9 @@ extern "C" void create_setting_window(); -char *get_stt_default_language(); +void get_stt_default_language(VoiceData *my_voicedata); +void _stt_lang_changed_cb(keynode_t *key, void* data); +int is_lang_supported_by_stt(char lang[]); #ifdef __cplusplus diff --git a/src/ise-stt-mode.cpp b/src/ise-stt-mode.cpp index 204dcf1..2c5066e 100644 --- a/src/ise-stt-mode.cpp +++ b/src/ise-stt-mode.cpp @@ -25,28 +25,178 @@ #include "ise.h" #include "ise-stt-mode.h" +#include "ise-stt-option.h" #define _EDJ(x) elm_layout_edje_get(x) #define STT_EDJ_FILE "edje/w-input-stt.edj" -static Evas_Object *layout_main = NULL; -static Evas_Object *progress_bar = NULL; +VoiceData *my_voicedata; +static Evas_Object *win_main = NULL; +static void set_guide_text(VoiceData *vd, const char* text, bool translatable = false); +static void _popup_close_cb(void *data, Evas_Object *obj, void *event_info); +static void _popup_back_cb(void *data, Evas_Object *obj, void *event_info); -void start_by_press() +void send_result_text(void *data) { - edje_object_signal_emit(_EDJ(layout_main), "mouse,clicked,1", "background"); + if(!data) + return; + + VoiceData* voicedata = (VoiceData*)data; + LOGD("result_text = %s", voicedata->partial_result); + ise_send_string(voicedata->partial_result); + ise_send_string(" "); +} + +void voice_get_string(const char *keyValue, VoiceData *voicedata) +{ + if(!voicedata) + return; + + char* strbuf = NULL; + + strbuf = elm_entry_utf8_to_markup(keyValue); + + LOGD("text : %s, voicedata->partial_result=%s", strbuf, voicedata->partial_result); + + if(strbuf){ + if(voicedata->partial_result){ // partial_result is not Null so replace + if(strcmp(voicedata->partial_result, strbuf)){ + // different replace + LOGD("different replace"); + + voicedata->stt_results.pop_back(); + voicedata->stt_results.push_back(strbuf); + + free(voicedata->partial_result); + voicedata->partial_result = strdup(strbuf); + } + } else { // partial_result is Null so first case + LOGD("first push"); + voicedata->stt_results.push_back(strbuf); + voicedata->partial_result = strdup(strbuf); + } + } + + send_result_text(voicedata); + + if(strbuf) + free(strbuf); + + LOGD("ends"); +} + + +static Eina_Bool _recognition_failure_cb(void *data) +{ + if(data) { + VoiceData *voicedata = (VoiceData *) data; + + voicedata->state = STT_STATE_VAL_INIT; + set_animation_state(voicedata); + voicedata->refresh_timer = NULL; + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool hide_guide_text(void *data) +{ + if(data) { + VoiceData *voicedata = (VoiceData *) data; + voicedata->guide_text_timer = NULL; + elm_object_part_text_set(voicedata->layout_main, "elm.text", ""); + set_guide_text(voicedata, SK_TAP_TO_PAUSE, true); + } + + return ECORE_CALLBACK_CANCEL; +} + +static void set_guide_text(VoiceData *vd, const char* text, bool translatable) +{ + elm_object_signal_emit(vd->layout_main, "idle,state,guide_text,bottom", "elm"); + + if(translatable) + elm_object_domain_translatable_part_text_set(vd->layout_main, "elm.text", PACKAGE, text); + else + elm_object_part_text_set(vd->layout_main, "elm.text", text); + + if(!strcmp(text, SK_SPEAK_NOW)){ + if(vd->guide_text_timer == NULL) + vd->guide_text_timer = ecore_timer_add(2.0, hide_guide_text, vd); + } +} + +void show_popup_toast(const char *text, bool check_img) +{ + Evas_Object *popup; + + popup = elm_popup_add(win_main); + elm_object_style_set(popup, "toast/circle"); + elm_popup_orient_set(popup, ELM_POPUP_ORIENT_BOTTOM); + evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + if (check_img) { + std::string path = app_get_resource_path(); + std::string path_ic = path + "/images/toast_check_icon.png"; + Evas_Object * img = elm_image_add(popup); + elm_image_file_set(img, path_ic.c_str(), NULL); + elm_object_part_content_set(popup, "toast,icon", img); + } + if(text) { + elm_object_part_text_set(popup, "elm.text", text); + } + + eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, _popup_back_cb, NULL); + evas_object_smart_callback_add(popup, "dismissed", _popup_close_cb, NULL); + evas_object_smart_callback_add(popup, "block,clicked", _popup_back_cb, NULL); + + elm_popup_timeout_set(popup, 2.0); + evas_object_show(popup); +} + +static void _popup_close_cb(void *data, Evas_Object *obj, void *event_info) +{ + if(obj){ + evas_object_hide(obj); + evas_object_del(obj); + } +} + +static void _popup_back_cb(void *data, Evas_Object *obj, void *event_info) +{ + if(obj) + elm_popup_dismiss(obj); +} + + +void start_by_press(VoiceData *voicedata) +{ + LOGD("start_by_press "); + edje_object_signal_emit(_EDJ(voicedata->layout_main), "mouse,clicked,1", "background"); return; } static void on_mic_button_press_cb(void *data, Evas_Object *obj, void *event_info) { LOGD("on_mic_button_press_cb"); - elm_object_signal_emit(layout_main, "idle,state,text,visible", "elm"); - //edje_object_signal_emit(layout_main, "mouse,clicked,1", "background"); - elm_object_domain_translatable_part_text_set(layout_main, "elm.text", PACKAGE, "Speak Now"); + VoiceData *voicedata = (VoiceData *)data; + edje_object_signal_emit(_EDJ(voicedata->layout_main), "mouse,clicked,1", "background"); +} + +static Eina_Bool _mic_button_enable_cb(void *data) +{ + if(!data) + return ECORE_CALLBACK_CANCEL; + + VoiceData* voicedata = (VoiceData*)data; + voicedata->btn_disabling_timer = NULL; + Evas_Object *button = (Evas_Object *)voicedata->mic_button; + elm_object_disabled_set(button, EINA_FALSE); + + return ECORE_CALLBACK_CANCEL; } + void init_customizing_theme(void) { std::string stt_edj_path = app_get_resource_path(); @@ -54,6 +204,250 @@ void init_customizing_theme(void) elm_theme_extension_add(NULL, stt_edj_path.c_str()); } +bool _app_stt_initialize(VoiceData *voice_data) +{ + LOGD("_app_stt_initialize "); + VoiceData *vd = (VoiceData *)voice_data; + + try { + if(vd != NULL && vd->sttmanager) { + vd->sttmanager->Cancel(); + delete vd->sttmanager; + vd->sttmanager = NULL; + } + + if(vd != NULL && vd->sttfeedback) { + delete vd->sttfeedback; + vd->sttfeedback = NULL; + } + + vd->sttfeedback = new is::stt::SttFeedback(); + vd->sttfeedback->SetVoiceData(vd); + + vd->sttmanager = new is::stt::SttManager(*(vd->sttfeedback)); + vd->sttmanager->Prepare(); + } catch(std::exception &e) { + LOGD("%s", e.what()); + return false; + } + + return true; +} + +static Eina_Bool _idler_cb(void *data) +{ + LOGD("_idler_cb"); + if(!data) return ECORE_CALLBACK_CANCEL; + + if(my_voicedata == NULL) { + LOGD("_idler_cb : my_voicedata is null"); + return ECORE_CALLBACK_CANCEL; + } + + VoiceData *voicedata = (VoiceData *)data; + + if (true == _app_stt_initialize(voicedata)) { + LOGD("_app_stt_initialize None Error"); + voicedata->voicefw_state = 1; + voicedata->state = STT_STATE_VAL_INIT; + } else { + voicedata->voicefw_state = 0; + LOGD("Initialization Fail!
Check STT-daemon is running"); + } + + Evas_Object *canvas = elm_object_part_content_get(voicedata->layout_main, "EFFECT_BG"); + + is::ui::WInputSttMicEffect *ieffect = new is::ui::WInputSttMicEffect(); + ieffect->SetSttHandle(voicedata->sttmanager->GetSttHandle()); + + is::ui::MicEffector *effector = new is::ui::MicEffector(canvas, voicedata->layout_main, *ieffect); + voicedata->ieffect = ieffect; + voicedata->effector = effector; + + ieffect->SetProgressBar(voicedata->progressbar); + ieffect->SetSttHandle(voicedata->sttmanager->GetSttHandle()); + + elm_access_highlight_set(voicedata->mic_button); + + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief - function to send the signal to edc + * to change the animation as per stt state + * @param - Ug data + */ +void set_animation_state(VoiceData *voicedata) +{ + if (voicedata->state == STT_STATE_VAL_INIT) { +#if 0 + if (voicedata->sttmanager->GetCurrent() == STT_STATE_READY) { + set_guide_text(voicedata, "", false); + //_elm_access_say(voicedata->layout_main, _(SK_INIT)); + } else { + PRINTFUNC(DLOG_DEBUG, "SK_NETWORK_ERROR [%d]", voicedata->sttmanager->GetCurrent()); + set_guide_text(voicedata, _(SK_NETWORK_ERROR)); + //_elm_access_say(voicedata->layout_main, _(SK_NETWORK_CONNECTION_ERROR)); + } +#endif + + if(voicedata->effector) + voicedata->effector->Stop(true); + + set_guide_text(voicedata, ""); + + } else if (voicedata->state == STT_STATE_VAL_LISTENING) { + set_guide_text(voicedata, SK_SPEAK_NOW, true); + + if(voicedata->effector) + voicedata->effector->Start(); + + } else if (voicedata->state == STT_STATE_VAL_PROCESSING) { + set_guide_text(voicedata, ""); + if(voicedata->effector) + voicedata->effector->Stop(); + + } else { + set_guide_text(voicedata, _(SK_RECOGNITION_FAILED)); + //_elm_access_say(voicedata->layout_main, _(SK_RECOGNITION_FAILED)); + + voicedata->state = STT_STATE_VAL_NOT_RECOGNISED; + + if(voicedata->refresh_timer) { + ecore_timer_del(voicedata->refresh_timer); + } + + if(voicedata->effector) + voicedata->effector->Stop(true); + + voicedata->refresh_timer = ecore_timer_add(2.0, _recognition_failure_cb, voicedata); + } +} + +void show_error_message(VoiceData *vd, stt_error_e reason) +{ + if(reason == STT_ERROR_OUT_OF_NETWORK) { + show_popup_toast(_(SK_NETWORK_ERROR), false); + vd->state = STT_STATE_VAL_INIT; + } else if (reason == STT_ERROR_RECORDER_BUSY) { + show_popup_toast(_(SK_STT_BUSY), false); + vd->state = STT_STATE_VAL_INIT; + } else { + show_popup_toast(_(SK_STT_BUSY), false); + vd->state = STT_STATE_VAL_INIT; + } +} + +static Eina_Bool _start_timer_cb(void* data) +{ + LOGD("_start_timer_cb"); + if(data) { + VoiceData *voicedata = (VoiceData *) data; + + try { + voicedata->state = STT_STATE_VAL_PREPARE_LISTENING; + voicedata->sttmanager->Start(); + } + catch (is::stt::SttException &e) { + if (e.GetEcode() == STT_ERROR_OUT_OF_NETWORK) + { + set_guide_text(voicedata, _(SK_NETWORK_ERROR)); + voicedata->state = STT_STATE_VAL_INIT; + } else if (e.GetEcode() == STT_ERROR_RECORDER_BUSY) { + show_popup_toast(_(SK_STT_BUSY), false); + voicedata->state = STT_STATE_VAL_INIT; + } else { + show_popup_toast(_(SK_STT_BUSY), false); + voicedata->state = STT_STATE_VAL_INIT; + } + } + voicedata->start_timer = NULL; + } + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief - cancel button press callback for cross button + * @param - + */ + +void on_initial_anim_press_cb(void *data, Evas_Object *obj, const char *emission, const char *source) +{ + LOGD("on_initial_anim_press_cb"); + VoiceData *vd = (VoiceData *)data; + + int tempVal = vd->sttmanager->GetCurrent(); + if(tempVal == STT_STATE_CREATED) { + LOGD("IGNORE TOUCH event before STT READY. STT is preparing", vd->state); + return; + } + + LOGD("SttManager State : %d", vd->sttmanager->GetCurrent()); + LOGD("Ui Voice State : %d", vd->state); + + switch(vd->state) { + case STT_STATE_VAL_INIT: + LOGD("%s", "STT_STATE_VAL_INIT"); + get_stt_default_language(vd); + vd->sttmanager->SetLanguage(std::string(vd->kbd_lang)); + + if(vd->start_timer) { + ecore_timer_del(vd->start_timer); + vd->start_timer = NULL; + } + + vd->start_timer = ecore_timer_add(0.0, _start_timer_cb, vd); + break; + + case STT_STATE_VAL_LISTENING : + LOGD("%s", "STT_STATE_VAL_LISTENING"); + try { + vd->state = STT_STATE_VAL_PREPARE_PROCESSING; + vd->sttmanager->Stop(); + + /** + * Cuased touch reponse time, it can be called to stop animator. + * + */ + set_guide_text(vd, ""); + + if(vd->effector) + vd->effector->Stop(); + } + catch (is::stt::SttException &e) { + LOGD("%s", e.what()); + if(e.GetEcode() != STT_ERROR_INVALID_STATE) { + set_guide_text(vd, _(SK_RECOGNITION_FAILED)); + vd->state = STT_STATE_VAL_INIT; + + if(vd->effector) + vd->effector->Stop(true); + } + } + break; + + case STT_STATE_VAL_PROCESSING: + LOGD("%s", "STT_STATE_VAL_PROCESSING"); + try { + //vd->state = STT_STATE_VAL_PREPARE_CANCEL; + vd->sttmanager->Cancel(); + } + catch (is::stt::SttException &e) { + + } + + break; + + case STT_STATE_VAL_NOT_RECOGNISED: + LOGD("%s", "STT_STATE_VAL_NOT_RECOGNISED"); + vd->state = STT_STATE_VAL_INIT ; + break; + default: + LOGD("default [%d]", vd->state); + break; + } +} + static Evas_Object *create_progressbar(Evas_Object *parent) { Evas_Object *progressbar = NULL; @@ -65,22 +459,78 @@ static Evas_Object *create_progressbar(Evas_Object *parent) evas_object_size_hint_align_set(progressbar, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(progressbar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + //ea_theme_object_color_replace(progressbar, "B065L6", "AO012"); + evas_object_show(progressbar); return progressbar; } -void ise_show_stt_mode(Evas_Object *win) +int init_voice(Evas_Object *parent, const char *lang, VoiceData *r_voicedata) { + LOGD("init_voice"); + + VoiceData *voicedata = (VoiceData *)r_voicedata; + if (!voicedata) { + return FALSE; + } + + if (!parent) { + LOGD("Parent is NULL\n"); + return FALSE; + } else { + LOGD("Parent is there"); + } + + voicedata->voicefw_state = 0; + + /* Set Voice Language */ + if(voicedata->kbd_lang){ + free(voicedata->kbd_lang); + voicedata->kbd_lang = NULL; + } + + //stt_get_default_language(my_voicedata->voicefw_handle, &my_voicedata->kbd_lang); + get_stt_default_language(voicedata); + if(NULL == voicedata->kbd_lang || FALSE == is_lang_supported_by_stt(voicedata->kbd_lang)) { + voicedata->kbd_lang = strdup("en_US"); + } + + LOGD("Voice input active language is : %s", voicedata->kbd_lang); + + voicedata->naviframe= parent; + + if (NULL == voicedata->naviframe) { + return FALSE; + } + + if (NULL != voicedata->textblock_timer) { + ecore_timer_del(voicedata->textblock_timer); + voicedata->textblock_timer = NULL; + } + LOGD("init_voice end"); + + return TRUE; +} + +Evas_Object *create_fullview(Evas_Object *win, VoiceData *r_voicedata) +{ + LOGD("create_fullview"); + + //win_main = win; + VoiceData *voicedata = r_voicedata; + int ret; Evas_Coord win_w, win_h; init_customizing_theme(); - layout_main = elm_layout_add(win); + Evas_Object *layout_main = elm_layout_add(win); evas_object_size_hint_weight_set(layout_main, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(layout_main, EVAS_HINT_FILL, EVAS_HINT_FILL); + voicedata->layout_main = layout_main; + std::string edj_path = app_get_resource_path(); edj_path = edj_path + STT_EDJ_FILE; LOGD("edj_path = %s", edj_path.c_str()); @@ -88,28 +538,230 @@ void ise_show_stt_mode(Evas_Object *win) ret = elm_layout_file_set(layout_main, edj_path.c_str(), "mic_control"); LOGD("elm_layout_file_set result = %d", ret); + elm_object_content_set(win, layout_main); + // MIC Button Evas_Object *m_mic_button = elm_button_add(layout_main); elm_object_style_set(m_mic_button, "vic/micbutton"); elm_object_part_content_set(layout_main, "MIC", m_mic_button); - evas_object_smart_callback_add(m_mic_button, "clicked", on_mic_button_press_cb, NULL); + elm_object_disabled_set(m_mic_button, EINA_TRUE); + evas_object_smart_callback_add(m_mic_button, "clicked", on_mic_button_press_cb, (void *) voicedata); + + voicedata->mic_button = m_mic_button; + + if(voicedata->btn_disabling_timer == NULL){ + voicedata->btn_disabling_timer = ecore_timer_add(2.0, _mic_button_enable_cb, voicedata); + } + + ecore_timer_add(0.6, _idler_cb, voicedata); // Progress Bar - progress_bar = create_progressbar(layout_main); + Evas_Object *progress_bar = create_progressbar(layout_main); elm_object_part_content_set(layout_main, "PROGRESS_BAR", progress_bar); + voicedata->progressbar = progress_bar; + + // add callback + elm_object_signal_callback_add(layout_main, "idle,state,pulse,visible", "", on_initial_anim_press_cb, voicedata); evas_object_geometry_get(win, NULL, NULL, &win_w, &win_h); evas_object_resize(layout_main, win_w, win_h); evas_object_layer_set(layout_main, 32000); - evas_object_show(layout_main); + + return layout_main; } -void ise_hide_stt_mode() +Eina_Bool init_view(void *data) +{ + LOGD("init_view"); + + VoiceData *voicedata = (VoiceData *)data; + + if(voicedata == NULL) { + LOGD("init_view : voicedata == NULL"); + return ECORE_CALLBACK_CANCEL; + } + + voicedata->layout_main = create_fullview(voicedata->naviframe, voicedata); + + if (voicedata->layout_main) { + evas_object_show(voicedata->layout_main); + } + + return ECORE_CALLBACK_CANCEL; +} + + +Evas_Object *show_voice_window(Evas_Object *parent, VoiceData *r_voicedata) { - if (layout_main) { - evas_object_del(layout_main); - layout_main = NULL; + LOGD("show_voice_window"); + + VoiceData *voicedata = (VoiceData *)r_voicedata; + if (!voicedata) { + return NULL; + } + + if (!parent) { + LOGD("Parent is NULL\n"); + return NULL; + } else { + LOGD("Parent is there"); + } + + if (NULL != voicedata->layout_main) { + evas_object_del((voicedata)->layout_main); + (voicedata)->layout_main = NULL; } + + if (NULL != voicedata->effector) { + delete (voicedata->effector); + (voicedata)->effector = NULL; + } + + if (NULL != voicedata->ieffect) { + delete (voicedata->ieffect); + voicedata->ieffect = NULL; + } + + init_view((void *)voicedata); + return voicedata->layout_main; +} + +void on_destroy(VoiceData *r_voicedata) +{ + LOGD("on_destroy"); + + VoiceData *voicedata = (VoiceData *)r_voicedata; + + if (NULL != voicedata) { + if (NULL != voicedata->layout_main) { + evas_object_del(voicedata->layout_main); + voicedata->layout_main = NULL; + } + + if (NULL != voicedata->naviframe) { + voicedata->naviframe = NULL; + } + + if (NULL != voicedata->start_timer) { + ecore_timer_del(voicedata->start_timer); + voicedata->start_timer = NULL; + } + + if (NULL != voicedata->refresh_timer) { + ecore_timer_del(voicedata->refresh_timer); + voicedata->refresh_timer = NULL; + } + + if (NULL != voicedata->progressbar_timer) { + ecore_timer_del(voicedata->progressbar_timer); + voicedata->progressbar_timer = NULL; + elm_progressbar_pulse(voicedata->progressbar, EINA_FALSE); + } + + if (NULL != voicedata->textblock_timer) { + ecore_timer_del(voicedata->textblock_timer); + voicedata->textblock_timer = NULL; + } + + if (NULL != voicedata->guide_text_timer) { + ecore_timer_del(voicedata->guide_text_timer); + voicedata->guide_text_timer = NULL; + } + + if (NULL != voicedata->btn_disabling_timer) { + ecore_timer_del(voicedata->btn_disabling_timer); + voicedata->btn_disabling_timer = NULL; + } + + if (NULL != voicedata->power_unlock_timer) { + ecore_timer_del(voicedata->power_unlock_timer); + voicedata->power_unlock_timer = NULL; + } + + if(voicedata->kbd_lang) { + free(voicedata->kbd_lang); + voicedata->kbd_lang = NULL; + } + + if(voicedata->ieffect) { + delete voicedata->ieffect; + voicedata->ieffect = NULL; + } + + if(voicedata->effector) { + delete voicedata->effector; + voicedata->effector = NULL; + } + + if(voicedata->sttmanager) { + delete voicedata->sttmanager; + voicedata->sttmanager = NULL; + } + + if(voicedata->sttfeedback) { + delete voicedata->sttfeedback; + voicedata->sttfeedback = NULL; + } + + free(voicedata); + } +} + +void destroy_voice() +{ + LOGD("destroy_voice"); + vconf_ignore_key_changed(VCONFKEY_ISE_STT_LANGUAGE, _stt_lang_changed_cb); + + if (my_voicedata) { + on_destroy(my_voicedata); + my_voicedata = NULL; + } +} + +void show_voice_input(Evas_Object *parent, const char *lang, void (*get_string)(char *, int)) +{ + LOGD("show_voice_input"); + int init = 0; + + destroy_voice(); + + if (!my_voicedata) { + my_voicedata = (VoiceData*)malloc(sizeof(VoiceData)); + if (my_voicedata == NULL) { + LOGD("%d::::Heap Overflow, Voice Input cannot be shown!", __LINE__); + return; + } + memset(my_voicedata, 0, sizeof(VoiceData)); + } + + if (my_voicedata) { + init = init_voice(parent, lang, my_voicedata); + if (init) { + if (my_voicedata->naviframe) { + //ise_stt_start(my_voicedata); + show_voice_window(my_voicedata->naviframe, my_voicedata); + } + } else { + destroy_voice(); + LOGD("%d::::Fail to create Voice window!", __LINE__); + return; + } + } + + vconf_notify_key_changed(VCONFKEY_ISE_STT_LANGUAGE, _stt_lang_changed_cb, my_voicedata); +} + +void ise_show_stt_mode(Evas_Object *win) +{ + if(!win) + return; + + show_voice_input(win, NULL, NULL); +} + +void ise_hide_stt_mode() +{ + destroy_voice(); } diff --git a/src/ise-stt-option.cpp b/src/ise-stt-option.cpp index e4e748c..5907e6d 100644 --- a/src/ise-stt-option.cpp +++ b/src/ise-stt-option.cpp @@ -27,7 +27,7 @@ #include "ise.h" #include "ise-stt-option.h" -#include "ise-stt-engine.h" +#include "ise-stt-mode.h" #define item_append(obj, style, index, cb, udata) \ elm_genlist_item_append(obj, &(style), (void *)index, NULL, ELM_GENLIST_ITEM_NONE, cb, udata) @@ -46,8 +46,7 @@ static Elm_Genlist_Item_Class itc_2text; const char* get_lang_label(char lang[]); static int get_language_value(); static void set_language_value(int type); -void _stt_lang_changed_cb(keynode_t *key, void* data); -int is_lang_supported_by_stt(char lang[]); + #ifdef _WEARABLE static char *__get_genlist_title_label(void *data, Evas_Object *obj, const char *part); #endif @@ -146,7 +145,12 @@ static void set_language_value(int type) void _stt_lang_changed_cb(keynode_t *key, void* data) { - get_stt_default_language(); + if(!data) return; + + VoiceData *vd = (VoiceData *) data; + get_stt_default_language(vd); + vd->sttmanager->SetLanguage(std::string(vd->kbd_lang)); + return; } @@ -167,25 +171,33 @@ int is_lang_supported_by_stt(char lang[]) return FALSE; } -char * get_stt_default_language() +void get_stt_default_language(VoiceData *my_voicedata) { + if(!my_voicedata) { + return; + } + + if(my_voicedata->kbd_lang) { + free(my_voicedata->kbd_lang); + my_voicedata->kbd_lang = NULL; + } + STT_VOICE_LANGUAGE_N66_I stt_lang; stt_lang = (STT_VOICE_LANGUAGE_N66_I)get_language_value(); - char *kbd_lang; LOGD("language type (%d)", stt_lang); switch (stt_lang) { case STT_VOICE_N66_AUTO : { - stt_get_default_language(g_stt, &kbd_lang); + stt_get_default_language(my_voicedata->voicefw_handle, &my_voicedata->kbd_lang); // get system display language char* value = NULL; value = vconf_get_str(VCONFKEY_LANGSET); if (NULL == value) { LOGD("Fail to get display language"); - return NULL; + return; } LOGD("system language (%s)", value); @@ -197,10 +209,10 @@ char * get_stt_default_language() // if supported, set the language // otherwise, set language to en_US if (is_lang_supported_by_stt(system_lang) == TRUE) { - kbd_lang = strdup(system_lang); + my_voicedata->kbd_lang = strdup(system_lang); LOGD("Set auto language (%s)", system_lang); } else { - kbd_lang = strdup("en_US"); + my_voicedata->kbd_lang = strdup("en_US"); LOGD("System language is not supported by STT (%s), en_US will be set", system_lang); } } @@ -212,17 +224,15 @@ char * get_stt_default_language() case STT_VOICE_N66_KO_KR : case STT_VOICE_N66_ZH_CN : { - kbd_lang = strdup(supported_language[stt_lang]); + my_voicedata->kbd_lang = strdup(supported_language[stt_lang]); } break; default : - kbd_lang = strdup("en_US"); + my_voicedata->kbd_lang = strdup("en_US"); break; } - LOGD("stt language (%s)", kbd_lang); - - return strdup(kbd_lang); + LOGD("stt language (%s)", my_voicedata->kbd_lang); } #ifdef _WEARABLE @@ -337,7 +347,6 @@ static void close_setting_window() g_setting_naviframe = NULL; evas_object_del(g_setting_window); g_setting_window = NULL; - vconf_ignore_key_changed(VCONFKEY_ISE_STT_LANGUAGE, _stt_lang_changed_cb); } static Eina_Bool close_setting_window_idler_cb(void *data) @@ -478,7 +487,7 @@ static Evas_Object *create_language_list(Evas_Object *parent) void create_setting_window() { - ise_stt_finish(); + ise_hide_stt_mode(); Evas_Object *window = NULL; Evas_Object *genlist = NULL; diff --git a/src/ise.cpp b/src/ise.cpp index ca9a5d1..bb5476b 100644 --- a/src/ise.cpp +++ b/src/ise.cpp @@ -34,7 +34,6 @@ #include "candidate-factory.h" #include "ise-emoticon-mode.h" #include "cbhm.h" -#include "ise-stt-engine.h" #include "ise-stt-mode.h" #include "ise-stt-option.h" #include "modeindicator.h" @@ -1323,10 +1322,8 @@ ise_show(int ic) g_keyboard_state.visible_state = TRUE; #ifdef _WEARABLE if (g_keyboard_state.layout == ISE_LAYOUT_STYLE_VOICE) { - ise_stt_start(); ise_show_stt_mode(NATIVE_WINDOW_CAST(g_core.get_main_window())); } else { - ise_stt_finish(); ise_hide_stt_mode(); } @@ -1437,7 +1434,7 @@ ise_hide() _reset_multitap_state(true); if (g_keyboard_state.layout == ISE_LAYOUT_STYLE_VOICE) { - ise_stt_finish(); + ise_hide_stt_mode(); } #ifdef _WEARABLE -- 2.7.4