From 6e0f37e7699109652a78efa4c81256b8f9312d5a Mon Sep 17 00:00:00 2001 From: Koyyani Maheswari Date: Wed, 11 Jan 2023 11:24:26 +0530 Subject: [PATCH] [M108 Migration][TTS] Text to Speech Bringup This patch brings the following changes to TTS -Change state, destruction handling -Run TTS as native platform interface. -Remove unused code -Handle EWK tts_mode set method -Handle pause/stop during initialization Reference: https://review.tizen.org/gerrit/274760/ https://review.tizen.org/gerrit/275686/ Change-Id: Id23d3cb0c766b93fa7e7c7db83bab87f5ed99724 Signed-off-by: Koyyani Maheswari --- content/browser/speech/tts_platform_impl.cc | 3 - .../modules/speech/speech_synthesis_utterance.cc | 7 + .../chromium_impl/content/browser/browser_efl.gni | 18 +- .../browser/speech/tts_message_filter_efl.cc | 97 --- .../browser/speech/tts_message_filter_efl.h | 54 -- .../browser/speech/tts_platform_impl_tizen.cc | 651 +++++++++++++++++++++ .../browser/speech/tts_platform_impl_tizen.h | 107 ++++ .../content/browser/speech/tts_tizen.cc | 354 ----------- .../content/browser/speech/tts_tizen.h | 74 --- .../content/renderer/renderer_efl.gni | 8 - .../content/renderer/tts_dispatcher_efl.cc | 205 ------- .../content/renderer/tts_dispatcher_efl.h | 81 --- .../efl_integration/content_browser_client_efl.cc | 4 - tizen_src/ewk/efl_integration/public/ewk_view.cc | 26 +- .../renderer/content_renderer_client_efl.cc | 5 - 15 files changed, 794 insertions(+), 900 deletions(-) delete mode 100644 tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.cc delete mode 100644 tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.h create mode 100644 tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.cc create mode 100644 tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.h delete mode 100644 tizen_src/chromium_impl/content/browser/speech/tts_tizen.cc delete mode 100644 tizen_src/chromium_impl/content/browser/speech/tts_tizen.h delete mode 100644 tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.cc delete mode 100644 tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.h diff --git a/content/browser/speech/tts_platform_impl.cc b/content/browser/speech/tts_platform_impl.cc index bae789c..daf7584 100644 --- a/content/browser/speech/tts_platform_impl.cc +++ b/content/browser/speech/tts_platform_impl.cc @@ -33,9 +33,6 @@ TtsPlatform* TtsPlatform::GetInstance() { // if this is hit in something like a content-only unit test. NOTREACHED(); return nullptr; -#elif BUILDFLAG(IS_TIZEN) - LOG(ERROR) << " returning nullptr "; - return nullptr; #else return TtsPlatformImpl::GetInstance(); #endif diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis_utterance.cc b/third_party/blink/renderer/modules/speech/speech_synthesis_utterance.cc index 7bc0180..6861582 100644 --- a/third_party/blink/renderer/modules/speech/speech_synthesis_utterance.cc +++ b/third_party/blink/renderer/modules/speech/speech_synthesis_utterance.cc @@ -52,9 +52,16 @@ SpeechSynthesisUtterance::SpeechSynthesisUtterance(ExecutionContext* context, // Set default values. |voice| intentionally left null. mojom_utterance_->text = text; mojom_utterance_->lang = String(""); + +#if defined(TIZEN_WEB_SPEECH_RECOGNITION) + mojom_utterance_->volume = mojom::blink::kSpeechSynthesisDefaultVolume; + mojom_utterance_->rate = mojom::blink::kSpeechSynthesisDefaultRate; + mojom_utterance_->pitch = mojom::blink::kSpeechSynthesisDefaultPitch; +#else mojom_utterance_->volume = mojom::blink::kSpeechSynthesisDoublePrefNotSet; mojom_utterance_->rate = mojom::blink::kSpeechSynthesisDoublePrefNotSet; mojom_utterance_->pitch = mojom::blink::kSpeechSynthesisDoublePrefNotSet; +#endif } SpeechSynthesisUtterance::~SpeechSynthesisUtterance() = default; diff --git a/tizen_src/chromium_impl/content/browser/browser_efl.gni b/tizen_src/chromium_impl/content/browser/browser_efl.gni index 5056150..e8e3ce9 100644 --- a/tizen_src/chromium_impl/content/browser/browser_efl.gni +++ b/tizen_src/chromium_impl/content/browser/browser_efl.gni @@ -23,8 +23,6 @@ external_content_browser_efl_configs = [ "//tizen_src/build:libefl-extension", "//tizen_src/build:security-manager", "//tizen_src/build:libsecurity-manager", - "//tizen_src/build:tts", - "//tizen_src/build:libtts", ] if (is_tizen) { @@ -56,6 +54,8 @@ if (tizen_web_speech_recognition) { external_content_browser_efl_configs += [ "//tizen_src/build:stt", "//tizen_src/build:libstt", + "//tizen_src/build:tts", + "//tizen_src/build:libtts", ] if (tizen_product_tv) { external_content_browser_efl_configs += [ @@ -121,16 +121,6 @@ if (is_tizen) { "tracing/tracing_ui.cc", "tracing/tracing_ui.h", ] - - external_content_browser_efl_sources += [ - # "//tizen_src/chromium_impl/content/browser/device_sensors/data_fetcher_impl_tizen.cc", - # "//tizen_src/chromium_impl/content/browser/device_sensors/data_fetcher_impl_tizen.h", - # "//tizen_src/chromium_impl/content/browser/device_sensors/data_fetcher_shared_memory_tizen.cc", - "//tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.cc", - "//tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.h", - "//tizen_src/chromium_impl/content/browser/speech/tts_tizen.cc", - "//tizen_src/chromium_impl/content/browser/speech/tts_tizen.h", - ] } if (tizen_multimedia_support) { external_content_browser_efl_sources += [ @@ -163,5 +153,7 @@ if (tizen_web_speech_recognition) { "//tizen_src/chromium_impl/content/browser/speech/speech_recognizer_impl_tizen.h", "//tizen_src/chromium_impl/content/browser/speech/tizen_speech_recognition_manager_delegate.cc", "//tizen_src/chromium_impl/content/browser/speech/tizen_speech_recognition_manager_delegate.h", - ] + "//tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.cc", + "//tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.h", + ] } diff --git a/tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.cc b/tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.cc deleted file mode 100644 index 332bbee..0000000 --- a/tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/speech/tts_message_filter_efl.h" - -#include "base/bind.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/render_process_host.h" - -namespace content { - -TtsMessageFilterEfl::TtsMessageFilterEfl() - : BrowserMessageFilter(TtsMsgStart) { - tts_tizen_.reset(new TtsTizen(this)); -} - -TtsMessageFilterEfl::~TtsMessageFilterEfl() { -} - -void TtsMessageFilterEfl::OverrideThreadForMessage( - const IPC::Message& message, BrowserThread::ID* thread) { - switch (message.type()) { - case TtsHostMsg_InitializeVoiceList::ID: - case TtsHostMsg_Speak::ID: - case TtsHostMsg_Pause::ID: - case TtsHostMsg_Resume::ID: - case TtsHostMsg_Cancel::ID: - *thread = BrowserThread::UI; - break; - default: - NOTREACHED(); - } -} - -bool TtsMessageFilterEfl::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(TtsMessageFilterEfl, message) - IPC_MESSAGE_HANDLER(TtsHostMsg_InitializeVoiceList, OnInitializeVoiceList) - IPC_MESSAGE_HANDLER(TtsHostMsg_Speak, OnSpeak) - IPC_MESSAGE_HANDLER(TtsHostMsg_Pause, OnPause) - IPC_MESSAGE_HANDLER(TtsHostMsg_Resume, OnResume) - IPC_MESSAGE_HANDLER(TtsHostMsg_Cancel, OnCancel) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void TtsMessageFilterEfl::OnChannelClosing() { - NOTIMPLEMENTED(); -} - -void TtsMessageFilterEfl::OnInitializeVoiceList() { - if(!tts_tizen_->IsTtsInitialized()) - tts_tizen_->Init(); - - const std::vector& voices = tts_tizen_->GetVoiceList(); - Send(new TtsMsg_SetVoiceList(voices)); -} - -void TtsMessageFilterEfl::OnSpeak(const TtsUtteranceRequest& request) { - tts_tizen_->Speak(request); -} - -void TtsMessageFilterEfl::OnPause() { - tts_tizen_->Pause(); -} - -void TtsMessageFilterEfl::OnResume() { - tts_tizen_->Resume(); -} - -void TtsMessageFilterEfl::OnCancel() { - tts_tizen_->Cancel(); -} - -void TtsMessageFilterEfl::DidFinishSpeaking(int utteranceid) { - Send(new TtsMsg_DidFinishSpeaking(utteranceid)); -} - -void TtsMessageFilterEfl::DidResumeSpeaking(int utteranceid) { - Send(new TtsMsg_DidResumeSpeaking(utteranceid)); -} - -void TtsMessageFilterEfl::DidPauseSpeaking(int utteranceid) { - Send(new TtsMsg_DidPauseSpeaking(utteranceid)); -} - -void TtsMessageFilterEfl::DidStartSpeaking(int utteranceid) { - Send(new TtsMsg_DidStartSpeaking(utteranceid)); -} - -void TtsMessageFilterEfl::SpeakingErrorOccurred(int utteranceid, const std::string& reason) { - Send(new TtsMsg_SpeakingErrorOccurred(utteranceid, reason)); -} - -} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.h b/tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.h deleted file mode 100644 index d5c5cf0..0000000 --- a/tizen_src/chromium_impl/content/browser/speech/tts_message_filter_efl.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BROWSER_SPEECH_TTS_MESSAGE_FILTER_H_ -#define BROWSER_SPEECH_TTS_MESSAGE_FILTER_H_ - -#include "base/memory/weak_ptr.h" -#include "content/browser/speech/tts_tizen.h" -#include "content/common/content_export.h" -#include "content/common/tts_messages_efl.h" -#include "content/public/browser/browser_message_filter.h" - -namespace content { -class TtsTizen; - -// Handle IPC message from browser process to renderer process. -class CONTENT_EXPORT TtsMessageFilterEfl - : public content::BrowserMessageFilter, - public base::SupportsWeakPtr { - public: - TtsMessageFilterEfl(); - - TtsMessageFilterEfl(const TtsMessageFilterEfl&) = delete; - TtsMessageFilterEfl& operator=(const TtsMessageFilterEfl&) = delete; - - // content::BrowserMessageFilter implementation. - void OverrideThreadForMessage( - const IPC::Message& message, - content::BrowserThread::ID* thread) override; - bool OnMessageReceived(const IPC::Message& message) override; - void OnChannelClosing() override; - - void DidFinishSpeaking(int utteranceid); - void DidResumeSpeaking(int utteranceid); - void DidPauseSpeaking(int utteranceid); - void DidStartSpeaking(int utteranceid); - void SpeakingErrorOccurred(int utteranceid, const std::string& reason); - - private: - ~TtsMessageFilterEfl() override; - - void OnInitializeVoiceList(); - void OnSpeak(const TtsUtteranceRequest& utterance); - void OnPause(); - void OnResume(); - void OnCancel(); - - std::unique_ptr tts_tizen_; -}; - -} // namespace content - -#endif // BROWSER_SPEECH_TTS_MESSAGE_FILTER_H_ diff --git a/tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.cc b/tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.cc new file mode 100644 index 0000000..6640b7f --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.cc @@ -0,0 +1,651 @@ +// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/speech/tts_platform_impl_tizen.h" + +#include "base/bind.h" +#include "base/debug/leak_annotations.h" +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/task/thread_pool.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" + +namespace content { + +namespace { + +const char kUriPrefix[] = "localhost:"; +const std::string kAuto = "Auto"; +const std::string kMale = "Male"; +const std::string kFemale = "Female"; +const std::string kChild = "Child"; + +std::string VoiceTypeToName(tts_voice_type_e type) { + switch (type) { + case TTS_VOICE_TYPE_AUTO: + return kAuto; + case TTS_VOICE_TYPE_MALE: + return kMale; + case TTS_VOICE_TYPE_FEMALE: + return kFemale; + case TTS_VOICE_TYPE_CHILD: + return kChild; + } + return kAuto; +} + +tts_voice_type_e VoiceNameToType(std::string name) { + if (name == kAuto) + return TTS_VOICE_TYPE_AUTO; + else if (name == kMale) + return TTS_VOICE_TYPE_MALE; + else if (name == kFemale) + return TTS_VOICE_TYPE_FEMALE; + else if (name == kChild) + return TTS_VOICE_TYPE_CHILD; + else + return TTS_VOICE_TYPE_AUTO; +} + +#define ENUM_CASE(x) \ + case x: \ + return #x + +const std::string ErrorToString(tts_error_e error) { + switch (error) { + ENUM_CASE(TTS_ERROR_NONE); + ENUM_CASE(TTS_ERROR_OUT_OF_MEMORY); + ENUM_CASE(TTS_ERROR_IO_ERROR); + ENUM_CASE(TTS_ERROR_INVALID_PARAMETER); + ENUM_CASE(TTS_ERROR_OUT_OF_NETWORK); + ENUM_CASE(TTS_ERROR_INVALID_STATE); + ENUM_CASE(TTS_ERROR_INVALID_VOICE); + ENUM_CASE(TTS_ERROR_ENGINE_NOT_FOUND); + ENUM_CASE(TTS_ERROR_TIMED_OUT); + ENUM_CASE(TTS_ERROR_OPERATION_FAILED); + ENUM_CASE(TTS_ERROR_AUDIO_POLICY_BLOCKED); + default: + LOG(WARNING) << "TTS: Unknown tts_error_e! (code=" << error << ")"; + } + return "Unknown Error"; +} + +const std::string StateToString(tts_state_e state) { + switch (state) { + ENUM_CASE(TTS_STATE_CREATED); + ENUM_CASE(TTS_STATE_READY); + ENUM_CASE(TTS_STATE_PLAYING); + ENUM_CASE(TTS_STATE_PAUSED); + default: + LOG(WARNING) << "TTS: Unknown tts_state_e! (code=" << state << ")"; + } + return "Unknown State"; +} + +// Tizen will not accept '-' in language string. Convert to '_'. +const std::string ConvertLangString(std::string lang) { + int pos = lang.find('-'); + if (pos != std::string::npos) + lang.replace(pos, 1, "_"); + return lang; +} + +} // namespace + +#if BUILDFLAG(IS_TIZEN_TV) +tts_mode_e TtsPlatformImplTizen::tts_mode_ = TTS_MODE_SCREEN_READER; +#else +tts_mode_e TtsPlatformImplTizen::tts_mode_ = TTS_MODE_DEFAULT; +#endif + +// Send a TTS event notification to the TTS controller. +void SendTtsEvent(int utterance_id, + TtsEventType event_type, + int char_index, + int length) { + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&TtsController::OnTtsEvent, + base::Unretained(TtsController::GetInstance()), + utterance_id, event_type, char_index, length, + std::string())); +} + +void TtsStateChangedCallback(tts_h tts_handle, + tts_state_e previous, + tts_state_e current, + void* user_data) { + TtsPlatformImplTizen* _this = static_cast(user_data); + LOG(INFO) << "TTS: utterance_id " << _this->GetUtteranceId() + << " State Changed from " << StateToString(previous) << " to " + << StateToString(current); + + if (TTS_STATE_CREATED == previous && TTS_STATE_READY == current) { + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce(&TtsPlatformImplTizen::TtsInitialized, + base::Unretained(TtsPlatformImplTizen::GetInstance()))); + } else if (TTS_STATE_PAUSED == previous && TTS_STATE_PLAYING == current) { + SendTtsEvent(_this->GetUtteranceId(), TTS_EVENT_RESUME, + _this->GetUtteranceText().size(), 0); + } else if (TTS_STATE_PLAYING == previous && TTS_STATE_PAUSED == current) { + SendTtsEvent(_this->GetUtteranceId(), TTS_EVENT_PAUSE, + _this->GetUtteranceText().size(), 0); + } else if ((TTS_STATE_PLAYING == previous || TTS_STATE_PAUSED == previous) && + TTS_STATE_READY == current) { + _this->OnUtteranceStoped(); + } +} + +void TtsUtteranceStartedCallback(tts_h tts_handle, + int utterance_id, + void* user_data) { + TtsPlatformImplTizen* _this = static_cast(user_data); + if (_this->GetPlatformUttId() != utterance_id) { + LOG(ERROR) << "TTS: utterance ID mismatch (" << _this->GetUtteranceId() + << ") platform ID " << _this->GetPlatformUttId(); + return; + } + + LOG(INFO) << "TTS: utterance_id " << _this->GetUtteranceId() << " started"; + SendTtsEvent(_this->GetUtteranceId(), TTS_EVENT_START, + _this->GetUtteranceText().size(), 0); +} + +void TtsUtteranceCompletedCallback(tts_h tts_handle, + int utterance_id, + void* user_data) { + TtsPlatformImplTizen* _this = static_cast(user_data); + if (_this->GetPlatformUttId() != utterance_id) { + LOG(ERROR) << "TTS: utterance ID mismatch (" << _this->GetUtteranceId() + << ") platform ID " << _this->GetPlatformUttId(); + return; + } + + LOG(INFO) << "TTS: utterance_id " << _this->GetUtteranceId() + << " completed. "; + _this->OnUtteranceCompletedCallback(); +} + +void TtsErrorCallback(tts_h tts_handle, + int utterance_id, + tts_error_e reason, + void* user_data) { + TtsPlatformImplTizen* _this = static_cast(user_data); + if (_this->GetPlatformUttId() != utterance_id) { + LOG(ERROR) << "TTS: utterance ID mismatch (" << _this->GetUtteranceId() + << ") platform ID " << _this->GetPlatformUttId(); + return; + } + + LOG(ERROR) << "TTS: utterance_id " << _this->GetUtteranceId() << " Error - " + << ErrorToString(reason); + SendTtsEvent(_this->GetUtteranceId(), TTS_EVENT_ERROR, + _this->GetUtteranceText().size(), 0); +} + +bool TtsSupportedVoiceCallback(tts_h tts_handle, + const char* language, + int voice_type, + void* user_data) { + TtsPlatformImplTizen* _this = static_cast(user_data); + _this->AddVoice(std::string(language), voice_type); + return true; +} + +void TtsDefaultVoiceChangedCallback(tts_h tts_handle, + const char* previous_language, + int previous_voice_type, + const char* current_language, + int current_voice_type, + void* user_data) { + TtsPlatformImplTizen* _this = static_cast(user_data); + _this->ChangeTtsDefaultVoice(current_language, current_voice_type); +} + +int GetTtsVoiceSpeed(tts_h tts_handle, float rate) { + // TTS engine dependent capability. + const float kRateMin = 0.6f, kRateMax = 2.0f, kRateNormal = 1.0f; + + int tts_speed_min = 0, tts_speed_normal = 0, tts_speed_max = 0; + int ret = tts_get_speed_range(tts_handle, &tts_speed_min, &tts_speed_normal, + &tts_speed_max); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: tts_get_speed_range() failed - " + << ErrorToString(static_cast(ret)); + return TTS_SPEED_AUTO; + } + + if (rate <= kRateMin) + return tts_speed_min; + + if (rate >= kRateMax) + return tts_speed_max; + + // Piecewise linear interpolation from |rate| to TTS internal speed value. + if (rate < kRateNormal) + return static_cast( + tts_speed_min + + (rate - kRateMin) * + ((tts_speed_normal - tts_speed_min) / (kRateNormal - kRateMin))); + else + return static_cast( + tts_speed_normal + + (rate - kRateNormal) * + ((tts_speed_max - tts_speed_normal) / (kRateMax - kRateNormal))); +} + +void DestroyOnUI(tts_h tts_handle) { + if (!tts_handle) + return; + + LOG(INFO) << "TTS: Calling tts_destroy"; + int ret = tts_destroy(tts_handle); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_destroy - " + << ErrorToString(static_cast(ret)); + } +} + +// static +TtsPlatformImplTizen* TtsPlatformImplTizen::GetInstance() { + return base::Singleton::get(); +} + +// static +TtsPlatformImpl* TtsPlatformImpl::GetInstance() { + return TtsPlatformImplTizen::GetInstance(); +} + +TtsPlatformImplTizen::TtsPlatformImplTizen() { + Initialize(); +} + +TtsPlatformImplTizen::~TtsPlatformImplTizen() { + LOG(INFO) << "TTS: TtsPlatformImplTizen instance [ " << (void*)this + << " ] destruct"; + if (!tts_handle_) { + LOG(INFO) << "TTS: TtsPlatformImplTizen instance [ " << (void*)this + << " ] destruct, no handle, finished"; + return; + } + + if (is_initialized_) { + tts_state_e tts_state = TTS_STATE_CREATED; + int ret = tts_get_state(tts_handle_, &tts_state); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_get_state - " + << ErrorToString(static_cast(ret)); + } + + if (TTS_STATE_PAUSED == tts_state || TTS_STATE_PLAYING == tts_state) { + ret = tts_stop(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to stop - " + << ErrorToString(static_cast(ret)); + } + } + + ret = tts_unprepare(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to unprepare - " + << ErrorToString(static_cast(ret)); + } + is_initialized_ = false; + } + + int ret = tts_unset_state_changed_cb(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_unset_state_changed_cb - " + << ErrorToString(static_cast(ret)); + } + + ret = tts_unset_utterance_completed_cb(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_unset_utterance_completed_cb - " + << ErrorToString(static_cast(ret)); + } + + ret = tts_unset_utterance_started_cb(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_unset_utterance_started_cb - " + << ErrorToString(static_cast(ret)); + } + + ret = tts_unset_error_cb(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_unset_error_cb - " + << ErrorToString(static_cast(ret)); + } + + ret = tts_unset_default_voice_changed_cb(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to tts_unset_default_voice_changed_cb - " + << ErrorToString(static_cast(ret)); + } + + // TTS destruction is not thread safe, call destory from UI. + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&DestroyOnUI, tts_handle_)); + + tts_handle_ = NULL; + LOG(INFO) << "TTS: TtsPlatformImplTizen instance [ " << (void*)this + << " ] destruct, finished"; +} + +bool TtsPlatformImplTizen::Initialize() { + int ret = tts_create(&tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to create - " + << ErrorToString(static_cast(ret)); + return false; + } + + StoreTtsDefaultVoice(); + + // Set callbacks + if (!SetTtsCallback()) + return false; + + LOG(INFO) << __func__ << " tts_mode #" << tts_mode_; + ret = tts_set_mode(tts_handle_, tts_mode_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to set mode - " + << ErrorToString(static_cast(ret)); + } + ret = tts_prepare(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to prepare - " + << ErrorToString(static_cast(ret)); + return false; + } + return true; +} + +void TtsPlatformImplTizen::StoreTtsDefaultVoice() { + char* language = NULL; + int voice_type; + int ret = tts_get_default_voice(tts_handle_, &language, &voice_type); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to get default voice - " + << ErrorToString(static_cast(ret)); + + // Even if ret != TTS_ERROR_NONE, do not return here. + // Set the default values. + const char kDefaultLanguage[] = "en_GB"; + default_language_ = kDefaultLanguage; + default_voice_ = TTS_VOICE_TYPE_AUTO; + } else { + DCHECK(language); + default_language_ = language; + free(language); + default_voice_ = voice_type; + } +} + +bool TtsPlatformImplTizen::SetTtsCallback() { + int ret = + tts_set_state_changed_cb(tts_handle_, TtsStateChangedCallback, this); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Unable to set state callback - " + << ErrorToString(static_cast(ret)); + return false; + } + + ret = tts_set_utterance_started_cb(tts_handle_, TtsUtteranceStartedCallback, + this); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to set utterance started callback - " + << ErrorToString(static_cast(ret)); + return false; + } + + ret = tts_set_utterance_completed_cb(tts_handle_, + TtsUtteranceCompletedCallback, this); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to set utterance completed callback - " + << ErrorToString(static_cast(ret)); + return false; + } + + ret = tts_set_error_cb(tts_handle_, TtsErrorCallback, this); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to set error callback - " + << ErrorToString(static_cast(ret)); + return false; + } + + ret = tts_foreach_supported_voices(tts_handle_, TtsSupportedVoiceCallback, + this); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to get supported voices - " + << ErrorToString(static_cast(ret)); + return false; + } + + ret = tts_set_default_voice_changed_cb(tts_handle_, + TtsDefaultVoiceChangedCallback, this); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to set default voice changed callback - " + << ErrorToString(static_cast(ret)); + return false; + } + return true; +} + +bool TtsPlatformImplTizen::PlatformImplSupported() { + return true; +} + +bool TtsPlatformImplTizen::PlatformImplInitialized() { + return true; +} + +void TtsPlatformImplTizen::TtsInitialized() { + is_initialized_ = true; + if (utterance_pending_) { + SpeakStoredUtterance(); + utterance_pending_ = false; + } +} + +void TtsPlatformImplTizen::Speak( + int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback on_speak_finished) { + utterance_.utterance_id = utterance_id; + utterance_.utterance = utterance; + utterance_.language = lang; + utterance_.voice_name = voice.name; + utterance_.volume = params.volume; + utterance_.rate = params.rate; + utterance_.pitch = params.pitch; + utterance_.on_speak_finished = std::move(on_speak_finished); + should_speak_ = true; + + // TTS package can be litle slow at times. Always wait for READY state. + if (!is_initialized_ || is_speaking_) { + LOG(INFO) << "TTS: Storing utterance " << utterance_id + << " state :" << StateToString(GetTtsState()); + utterance_pending_ = true; + return; + } + + SpeakStoredUtterance(); +} + +void TtsPlatformImplTizen::SpeakStoredUtterance() { + LOG(INFO) << "TTS: Speak utterance " << utterance_.utterance_id << " text #" + << utterance_.utterance; + std::string current_language = default_language_; + if (!utterance_.language.empty()) + current_language = ConvertLangString(utterance_.language); + + int voiceType = static_cast(default_voice_); + if (!utterance_.voice_name.empty()) + voiceType = static_cast(VoiceNameToType(utterance_.voice_name)); + int textSpeed = GetTtsVoiceSpeed(tts_handle_, utterance_.rate); + int ret = tts_add_text(tts_handle_, utterance_.utterance.c_str(), + current_language.c_str(), voiceType, textSpeed, + &utterance_.platform_utt_id); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to add text. Error - " + << ErrorToString(static_cast(ret)) << " in " + << GetTtsState(); + SendTtsEvent(utterance_.utterance_id, TTS_EVENT_ERROR, + utterance_.utterance.size(), 0); + std::move(utterance_.on_speak_finished).Run(false); + return; + } + + if (should_speak_) + Play(); +} + +bool TtsPlatformImplTizen::StopSpeaking() { + // TTS package can be litle slow at times. + if (!is_initialized_ && utterance_pending_) { + LOG(INFO) << "TTS: not initialized. Ignore pending utterance " + << utterance_.utterance_id + << " state :" << StateToString(GetTtsState()); + should_speak_ = false; + return true; + } + + tts_state_e current_state = GetTtsState(); + if (current_state != TTS_STATE_PLAYING && current_state != TTS_STATE_PAUSED) { + LOG(WARNING) << "TTS: Ignoring stop. ID: " << utterance_.utterance_id + << " state " << StateToString(current_state); + is_speaking_ = false; + return true; + } + + LOG(INFO) << "TTS: Stop. ID: " << utterance_.utterance_id; + int ret = tts_stop(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to stop. Error - " + << ErrorToString(static_cast(ret)) << " in " + << StateToString(current_state); + SendTtsEvent(utterance_.utterance_id, TTS_EVENT_ERROR, + utterance_.utterance.size(), 0); + return false; + } + + return true; +} + +bool TtsPlatformImplTizen::Play() { + tts_state_e current_state = GetTtsState(); + if (current_state == TTS_STATE_PLAYING) { + LOG(WARNING) << "TTS: Already in play state. ID: " + << utterance_.utterance_id; + return false; + } + + if (current_state != TTS_STATE_READY && current_state != TTS_STATE_PAUSED) { + LOG(WARNING) << "TTS: Ignoring play. ID: " << utterance_.utterance_id + << " state " << StateToString(current_state); + return false; + } + + LOG(INFO) << "TTS: Play. ID: " << utterance_.utterance_id; + int ret = tts_play(tts_handle_); + if (ret != (int)TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to play. Error - " + << ErrorToString(static_cast(ret)) << " in " + << StateToString(current_state); + SendTtsEvent(utterance_.utterance_id, TTS_EVENT_ERROR, + utterance_.utterance.size(), 0); + return false; + } + + is_speaking_ = true; + return true; +} + +void TtsPlatformImplTizen::Pause() { + // TTS package can be litle slow at times. + if (!is_initialized_ && utterance_pending_) { + LOG(INFO) << "TTS: not initialized. Ignore pending utterance " + << utterance_.utterance_id + << " state :" << StateToString(GetTtsState()); + should_speak_ = false; + SendTtsEvent(utterance_.utterance_id, TTS_EVENT_PAUSE, + GetUtteranceText().size(), 0); + return; + } + + if (GetTtsState() != TTS_STATE_PLAYING) { + LOG(WARNING) << "TTS: Ignoring pause. ID: " << utterance_.utterance_id + << " state " << StateToString(GetTtsState()); + return; + } + + LOG(INFO) << "TTS: Pause. ID: " << utterance_.utterance_id; + int ret = tts_pause(tts_handle_); + if (ret != TTS_ERROR_NONE) { + LOG(ERROR) << "TTS: Fail to pause - " + << ErrorToString(static_cast(ret)) << " in " + << StateToString(GetTtsState()); + SendTtsEvent(utterance_.utterance_id, TTS_EVENT_ERROR, + utterance_.utterance.size(), 0); + } +} + +void TtsPlatformImplTizen::Resume() { + Play(); +} + +bool TtsPlatformImplTizen::IsSpeaking() { + return is_speaking_; +} + +tts_state_e TtsPlatformImplTizen::GetTtsState() { + tts_state_e current_state; + tts_get_state(tts_handle_, ¤t_state); + return current_state; +} + +void TtsPlatformImplTizen::ChangeTtsDefaultVoice(const std::string language, + const int voice_type) { + default_language_ = language; + default_voice_ = voice_type; +} + +void TtsPlatformImplTizen::GetVoices(std::vector* out_voices) { + for (auto it = voice_list_.begin(); it != voice_list_.end(); ++it) { + out_voices->push_back(VoiceData()); + VoiceData& voice = out_voices->back(); + voice.native = it->native; + voice.name = it->name; + voice.lang = it->lang; + voice.events.insert(TTS_EVENT_START); + voice.events.insert(TTS_EVENT_END); + voice.events.insert(TTS_EVENT_INTERRUPTED); + voice.events.insert(TTS_EVENT_ERROR); + voice.events.insert(TTS_EVENT_PAUSE); + voice.events.insert(TTS_EVENT_RESUME); + } +} + +void TtsPlatformImplTizen::AddVoice(std::string language, + tts_voice_type_e type) { + voice_list_.push_back(VoiceData()); + VoiceData& data = voice_list_.back(); + data.native = true; + data.name = VoiceTypeToName(type); + data.lang = language; +} + +void TtsPlatformImplTizen::OnUtteranceCompletedCallback() { + StopSpeaking(); + std::move(utterance_.on_speak_finished).Run(true); + SendTtsEvent(utterance_.utterance_id, TTS_EVENT_END, + utterance_.utterance.size(), 0); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.h b/tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.h new file mode 100644 index 0000000..26faa8a --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/speech/tts_platform_impl_tizen.h @@ -0,0 +1,107 @@ +// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BROWSER_SPEECH_TTS_PLATFORM_IMPL_TIZEN_H_ +#define BROWSER_SPEECH_TTS_PLATFORM_IMPL_TIZEN_H_ + +#include "content/browser/speech/tts_platform_impl.h" + +#include +#include +#include "base/functional/callback.h" + +namespace content { + +typedef int tts_voice_type_e; + +class TtsPlatformImplTizen : public TtsPlatformImpl { + public: + void TtsInitialized(); + const std::string& GetUtteranceText() const { return utterance_.language; } + int GetUtteranceId() const { return utterance_.utterance_id; } + int GetPlatformUttId() const { return utterance_.platform_utt_id; } + + // Get voices one by one from tts engine, append them into a voice list + void AddVoice(std::string language, tts_voice_type_e name); + void ChangeTtsDefaultVoice(const std::string, const int); + + void OnUtteranceCompletedCallback(); + void OnUtteranceStoped() { is_speaking_ = false; } + + // Get the single instance of this class. + static TtsPlatformImplTizen* GetInstance(); + static void SetTtsMode(tts_mode_e tts_mode) { tts_mode_ = tts_mode; } + + private: + struct TtsUtterance { + int utterance_id; + int platform_utt_id = -1; + std::string utterance; + std::string language; + std::string voice_name; + double volume; + double rate; + double pitch; + base::OnceCallback on_speak_finished; + }; + + bool PlatformImplSupported() override; + bool PlatformImplInitialized() override; + void Speak(int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback on_speak_finished) override; + bool StopSpeaking() override; + void Pause() override; + void Resume() override; + bool IsSpeaking() override; + void GetVoices(std::vector* out_voices) override; + + TtsPlatformImplTizen(); + ~TtsPlatformImplTizen(); + + bool Initialize(); + bool Play(); + tts_state_e GetTtsState(); + + // Create and Set tts and tts callback. If any of these failes, tts will not + // work at all. + bool SetTtsCallback(); + void StoreTtsDefaultVoice(); + void SpeakStoredUtterance(); + + tts_h tts_handle_ = NULL; + std::string default_language_; + tts_voice_type_e default_voice_ = TTS_VOICE_TYPE_AUTO; + + static tts_mode_e tts_mode_; + + TtsUtterance utterance_; + bool utterance_pending_ = false; + + // TTS initialization is slow. Play should be ignored if pause / stop command + // is received. + bool should_speak_ = false; + + // This variable stores list of voicees that tts engine support. + std::vector voice_list_; + + // This variable check whether tts is initialized. + // It will be true when tts engine set the variable tts_. + bool is_initialized_ = false; + bool is_speaking_ = false; + + friend struct base::DefaultSingletonTraits; + + base::WeakPtrFactory weak_factory_{this}; + + TtsPlatformImplTizen(const TtsPlatformImplTizen&) = delete; + TtsPlatformImplTizen& operator=(const TtsPlatformImplTizen&) = delete; +}; + +} // namespace content + +#endif // BROWSER_SPEECH_TTS_PLATFORM_IMPL_TIZEN_H_ diff --git a/tizen_src/chromium_impl/content/browser/speech/tts_tizen.cc b/tizen_src/chromium_impl/content/browser/speech/tts_tizen.cc deleted file mode 100644 index cbd0a65..0000000 --- a/tizen_src/chromium_impl/content/browser/speech/tts_tizen.cc +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/speech/tts_tizen.h" - -#include - -#include "base/logging.h" - -namespace content { -namespace { -const char kUriPrefix[] = "localhost:"; -const std::string kAuto = "Auto"; -const std::string kMale = "Male"; -const std::string kFemale = "Female"; -const std::string kChild = "Child"; - -std::string VoiceTypeToName(tts_voice_type_e type) { - switch (type) { - case TTS_VOICE_TYPE_AUTO: - return kAuto; - case TTS_VOICE_TYPE_MALE: - return kMale; - case TTS_VOICE_TYPE_FEMALE: - return kFemale; - case TTS_VOICE_TYPE_CHILD: - return kChild; - } - return kAuto; -} - -tts_voice_type_e VoiceNameToType(std::string name) { - if (name == kAuto) - return TTS_VOICE_TYPE_AUTO; - else if (name == kMale) - return TTS_VOICE_TYPE_MALE; - else if (name == kFemale) - return TTS_VOICE_TYPE_FEMALE; - else if (name == kChild) - return TTS_VOICE_TYPE_CHILD; - else - return TTS_VOICE_TYPE_AUTO; -} - -const std::string ErrorToString(tts_error_e error) { - switch (error) { - case TTS_ERROR_NONE: - return "Successful"; - case TTS_ERROR_OUT_OF_MEMORY: - return "Out of Memory"; - case TTS_ERROR_IO_ERROR: - return "I/O error"; - case TTS_ERROR_INVALID_PARAMETER: - return "Invalid parameter"; - case TTS_ERROR_OUT_OF_NETWORK: - return "Out of network"; - case TTS_ERROR_INVALID_STATE: - return "Invalid state"; - case TTS_ERROR_INVALID_VOICE: - return "Invalid voice"; - case TTS_ERROR_ENGINE_NOT_FOUND: - return "No available engine"; - case TTS_ERROR_TIMED_OUT: - return "No answer from the daemon"; - case TTS_ERROR_OPERATION_FAILED: - return "Operation failed"; - case TTS_ERROR_AUDIO_POLICY_BLOCKED: - return "Audio policy blocked"; - default: - return "Unknown Error"; - } -} - -void TtsStateChangedCallback(tts_h tts_handle, tts_state_e previous, tts_state_e current, - void* user_data) { - TtsTizen* _this = static_cast(user_data); - - if (TTS_STATE_CREATED == previous && TTS_STATE_READY == current) - _this->TtsReady(); - else if (TTS_STATE_PAUSED == previous && - TTS_STATE_PLAYING == current && _this->GetUtterance().id) - _this->GetTtsMessageFilterEfl()->DidResumeSpeaking(_this->GetUtterance().id); - else if (TTS_STATE_PLAYING == previous && - TTS_STATE_PAUSED == current && _this->GetUtterance().id) - _this->GetTtsMessageFilterEfl()->DidPauseSpeaking(_this->GetUtterance().id); -} - -void TtsUtteranceStartedCallback(tts_h tts_handle, int utteranceId, void* user_data) { - TtsTizen* _this = static_cast(user_data); - if (_this->GetUtterance().id) - _this->GetTtsMessageFilterEfl()-> - DidStartSpeaking(_this->GetUtterance().id); -} - -void TtsUtteranceCompletedCallback(tts_h tts_handle, int utteranceId, void *user_data) { - TtsTizen* _this = static_cast(user_data); - if (_this->GetUtterance().id) - _this->GetTtsMessageFilterEfl()-> - DidFinishSpeaking(_this->GetUtterance().id); -} - -void TtsErrorCallback(tts_h tts_handle, int utteranceId, tts_error_e reason, void* user_data) { - TtsTizen* _this = static_cast(user_data); - if (_this->GetUtterance().id) - _this->GetTtsMessageFilterEfl()-> - SpeakingErrorOccurred(_this->GetUtterance().id, ErrorToString(reason)); -} - -bool TtsSupportedVoiceCallback(tts_h tts_handle, - const char* language, - int voice_type, void* user_data) { - TtsTizen* _this = static_cast(user_data); - int currentVoiceType = voice_type; - _this->AddVoice(std::string(language), currentVoiceType); - return true; -} - -bool InitializeTtsEngine(tts_h* tts_handle) { - int ret = tts_create(tts_handle); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "Fail to create TTS: " << ErrorToString(static_cast(ret)); - *tts_handle = NULL; - return false; - } - ret = tts_set_mode(*tts_handle, TTS_MODE_DEFAULT); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "Fail to set TTS mode: " << ErrorToString(static_cast(ret)); - } - ret = tts_prepare(*tts_handle); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "Fail to prepare TTS: " << ErrorToString(static_cast(ret)); - *tts_handle = NULL; - return false; - } - return true; -} - -int GetTtsVoiceSpeed(tts_h tts_handle, float rate) { - // TTS engine dependent capability. - const float kRateMin = 0.6f, kRateMax = 2.0f, kRateNormal = 1.0f; - - int tts_speed_min = 0, tts_speed_normal = 0, tts_speed_max = 0; - int ret = tts_get_speed_range(tts_handle, - &tts_speed_min, &tts_speed_normal, &tts_speed_max); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: tts_get_speed_range() failed"; - return TTS_SPEED_AUTO; - } - - if (rate <= kRateMin) - return tts_speed_min; - - if (rate >= kRateMax) - return tts_speed_max; - - // Piecewise linear interpolation from |rate| to TTS internal speed value. - if (rate < kRateNormal) - return static_cast(tts_speed_min + (rate - kRateMin) - * ((tts_speed_normal - tts_speed_min) / (kRateNormal - kRateMin))); - else - return static_cast(tts_speed_normal + (rate - kRateNormal) - * ((tts_speed_max - tts_speed_normal) / (kRateMax - kRateNormal))); -} - -} // namespace - -TtsTizen::TtsTizen(TtsMessageFilterEfl* tts_message_filter_efl) - : tts_message_filter_efl_(tts_message_filter_efl), - tts_handle_(NULL), - default_voice_(TTS_VOICE_TYPE_AUTO), - tts_initialized_(false), - tts_state_ready_(false), - utterance_waiting_(false) { -} - -TtsTizen::~TtsTizen() { - if(tts_initialized_ && tts_handle_) - { - int ret = tts_unset_state_changed_cb(tts_handle_) && - tts_unset_utterance_completed_cb(tts_handle_) && - tts_unset_error_cb(tts_handle_); - - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Fail to unset callbacks"; - - ret = tts_unprepare(tts_handle_); - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Fail to unprepare"; - - tts_destroy(tts_handle_); - tts_handle_ = NULL; - tts_initialized_ = false; - } -} - -bool TtsTizen::Init() { - tts_initialized_ = InitializeTtsEngine(&tts_handle_); - if (!tts_initialized_) { - return false; - } - - SetTtsDefaultVoice(); - - // Set callbacks - SetTtsCallback(this); - return true; -} - -void TtsTizen::SetTtsDefaultVoice() { - char* language = NULL; - int voice_type; - int ret = tts_get_default_voice(tts_handle_, &language, &voice_type); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: Fail to get default voice"; - // Even if ret != TTS_ERROR_NONE, do not return here. - // Set the default values. - const char kDefaultLanguage[] = "en_GB"; - default_language_ = kDefaultLanguage; - default_voice_ = TTS_VOICE_TYPE_AUTO; - } else { - DCHECK(language); - default_language_ = language; - free(language); - default_voice_ = voice_type; - } -} - - -void TtsTizen::SetTtsCallback(void* tts_data) { - int ret = tts_set_state_changed_cb(tts_handle_, TtsStateChangedCallback, tts_data); - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Unable to set state callback"; - - ret = tts_set_utterance_started_cb(tts_handle_, TtsUtteranceStartedCallback, tts_data); - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Fail to set utterance started callback"; - - ret = tts_set_utterance_completed_cb(tts_handle_, TtsUtteranceCompletedCallback, tts_data); - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Fail to set utterance completed callback"; - - ret = tts_set_error_cb(tts_handle_, TtsErrorCallback, this); - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Fail to set error callback"; - - ret = tts_foreach_supported_voices(tts_handle_, TtsSupportedVoiceCallback, this); - if (ret != TTS_ERROR_NONE) - LOG(ERROR) << "TTS: Fail to get supported voices"; -} - -const std::vector& TtsTizen::GetVoiceList() { - return voice_list_; -} - -void TtsTizen::TtsReady() { - tts_state_ready_ = true; - if (utterance_waiting_) - SpeakStoredUtterance(); - utterance_waiting_ = false; -} - -void TtsTizen::Speak(const TtsUtteranceRequest& utterance) { - utterance_ = utterance; - if (!tts_state_ready_) { - utterance_waiting_ = true; - return; - } - SpeakStoredUtterance(); -} - -void TtsTizen::SpeakStoredUtterance() { - if (utterance_.text.empty()) { - return; - } - std::string current_language = default_language_; - if (!utterance_.lang.empty()) - current_language = utterance_.lang; - - int voiceType = static_cast(default_voice_); - if (!utterance_.voice.empty()) - voiceType = static_cast(VoiceNameToType(utterance_.voice)); - int textSpeed = GetTtsVoiceSpeed(tts_handle_, utterance_.rate); - int utteranceId = utterance_.id; - int ret = tts_add_text(tts_handle_, utterance_.text.c_str(), current_language.c_str(), - voiceType, textSpeed, &utteranceId); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: Fail to add text"; - GetTtsMessageFilterEfl()-> - SpeakingErrorOccurred(utterance_.id, ErrorToString(static_cast(ret))); - return; - } - tts_state_e current_state; - tts_get_state(tts_handle_, ¤t_state); - if (TTS_STATE_PLAYING != current_state) - ret = tts_play(tts_handle_); - - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: Play Error occured"; - GetTtsMessageFilterEfl()-> - SpeakingErrorOccurred(utterance_.id, ErrorToString(static_cast(ret))); - return; - } -} - -void TtsTizen::Pause() { - if (!utterance_.id) - return; - - int ret = tts_pause(tts_handle_); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: Fail to pause #tts_pause"; - GetTtsMessageFilterEfl()-> - SpeakingErrorOccurred(utterance_.id, ErrorToString(static_cast(ret))); - } -} - -void TtsTizen::Resume() { - if (!utterance_.id) - return; - - int ret = tts_play(tts_handle_); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: Fail to resume"; - GetTtsMessageFilterEfl()-> - SpeakingErrorOccurred(utterance_.id, ErrorToString(static_cast(ret))); - } -} - -void TtsTizen::Cancel() { - int ret = tts_stop(tts_handle_); - if (ret != TTS_ERROR_NONE) { - LOG(ERROR) << "TTS: Fail to cancel"; - GetTtsMessageFilterEfl()-> - SpeakingErrorOccurred(utterance_.id, ErrorToString(static_cast(ret))); - } - GetTtsMessageFilterEfl()->DidFinishSpeaking(utterance_.id); -} - -void TtsTizen::AddVoice(std::string language, tts_voice_type_e type) { - TtsVoice voice; - std::string uri(kUriPrefix); - uri.append(VoiceTypeToName(type)); - uri.append("/"); - uri.append(language); - - voice.voice_uri = uri ; - voice.name = VoiceTypeToName(type); - voice.lang = language; - voice.is_default = (language == default_language_); - voice_list_.push_back(voice); -} - -} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/speech/tts_tizen.h b/tizen_src/chromium_impl/content/browser/speech/tts_tizen.h deleted file mode 100644 index 2c1cbc3..0000000 --- a/tizen_src/chromium_impl/content/browser/speech/tts_tizen.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BROWSER_SPEECH_TTS_TIZEN_H_ -#define BROWSER_SPEECH_TTS_TIZEN_H_ - -#include "build/tizen_version.h" - -typedef int tts_voice_type_e; - -#include "content/browser/speech/tts_message_filter_efl.h" -#include "content/common/tts_utterance_request_efl.h" - -#include -#include - -namespace content { -class TtsMessageFilterEfl; - -// TtsTizen is the class that actually communicate with tts engine. -// It handles tts instance, callbacks and callback returns -class TtsTizen { - public: - TtsTizen(TtsMessageFilterEfl* tts_message_filter_efl); - ~TtsTizen(); - bool Init(); - - // Return voice list - const std::vector& GetVoiceList(); - void Speak(const TtsUtteranceRequest& utterance); - void Pause(); - void Resume(); - void Cancel(); - tts_h GetTTS() { return tts_handle_; } - TtsMessageFilterEfl* GetTtsMessageFilterEfl() { - return tts_message_filter_efl_; } - const TtsUtteranceRequest& GetUtterance() const { return utterance_; } - void TtsReady(); - - // Get voices one by one from tts engine, append them into a voice list - void AddVoice(std::string language, tts_voice_type_e name); - bool IsTtsInitialized() const { return tts_initialized_; } - - private: - // Create and Set tts and tts callback. If any of these failes, tts will not work at all. - void SetTtsCallback(void* tts_data); - void SetTtsDefaultVoice(); - void SpeakStoredUtterance(); - TtsMessageFilterEfl* tts_message_filter_efl_; - TtsUtteranceRequest utterance_; - tts_h tts_handle_; - std::string default_language_; - tts_voice_type_e default_voice_; - - // This variable stores list of voicees that tts engine support. - std::vector voice_list_; - - // This variable check whether tts is initialized. - // It will be true when tts engine set the variable tts_. - bool tts_initialized_; - - // This variable check whether tts is ready, after initialized. - // Initial value is false and it will be true when tts state change to - // TTS_STATE_CREATED && TTS_STATE_READY. - bool tts_state_ready_; - - // This variable check whether any utterance is currently wating to speak. - bool utterance_waiting_; -}; - -} // namespace content - -#endif // BROWSER_SPEECH_TTS_TIZEN_H_ diff --git a/tizen_src/chromium_impl/content/renderer/renderer_efl.gni b/tizen_src/chromium_impl/content/renderer/renderer_efl.gni index 8a8408e..6e5706a 100644 --- a/tizen_src/chromium_impl/content/renderer/renderer_efl.gni +++ b/tizen_src/chromium_impl/content/renderer/renderer_efl.gni @@ -34,14 +34,6 @@ external_content_renderer_efl_sources = [ "//tizen_src/chromium_impl/content/renderer/common_renderer_client.h", ] -if (!ewk_bringup) { #FIXME:m85 bringup - if (is_tizen) { - external_content_renderer_efl_sources += [ - "//tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.cc", - "//tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.h", - ] - } -} if (tizen_multimedia_support) { #"media/audio_decoder.cc", #"media/audio_decoder.h", diff --git a/tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.cc b/tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.cc deleted file mode 100644 index ff6790a..0000000 --- a/tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.cc +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/tts_dispatcher_efl.h" - -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "content/common/tts_messages_efl.h" -#include "content/common/tts_utterance_request_efl.h" -#include "content/public/renderer/render_thread.h" -#include "third_party/blink/public/platform/web_speech_synthesis_utterance.h" -#include "third_party/blink/public/platform/web_speech_synthesis_voice.h" -#include "third_party/blink/public/platform/web_string.h" -#include "third_party/blink/public/platform/web_vector.h" - -namespace content { - -int TtsDispatcherEfl::next_utterance_id_ = 1; - -static const std::vector& getDefaultVoiceList() { - static std::vector default_voices( - 1, TtsVoice("localhost:Female/en_US", "Female", "en_US", false, false)); - - return default_voices; -} - -TtsDispatcherEfl::TtsDispatcherEfl(blink::WebSpeechSynthesizerClient* client) - : synthesizer_client_(client) { - content::RenderThread::Get()->AddObserver(this); - OnSetVoiceList(getDefaultVoiceList()); -} - -TtsDispatcherEfl::~TtsDispatcherEfl() { - content::RenderThread::Get()->RemoveObserver(this); -} - -bool TtsDispatcherEfl::OnControlMessageReceived(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(TtsDispatcherEfl, message) - IPC_MESSAGE_HANDLER(TtsMsg_SetVoiceList, OnSetVoiceList) - IPC_MESSAGE_HANDLER(TtsMsg_DidStartSpeaking, OnDidStartSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_DidFinishSpeaking, OnDidFinishSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_DidPauseSpeaking, OnDidPauseSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_DidResumeSpeaking, OnDidResumeSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_WordBoundary, OnWordBoundary) - IPC_MESSAGE_HANDLER(TtsMsg_SentenceBoundary, OnSentenceBoundary) - IPC_MESSAGE_HANDLER(TtsMsg_MarkerEvent, OnMarkerEvent) - IPC_MESSAGE_HANDLER(TtsMsg_WasInterrupted, OnWasInterrupted) - IPC_MESSAGE_HANDLER(TtsMsg_WasCancelled, OnWasCancelled) - IPC_MESSAGE_HANDLER(TtsMsg_SpeakingErrorOccurred, OnSpeakingErrorOccurred) - IPC_END_MESSAGE_MAP() - - // Always return false because there may be multiple TtsDispatchers - // and we want them all to have a chance to handle this message. - return false; -} - -void TtsDispatcherEfl::UpdateVoiceList() { - content::RenderThread::Get()->Send(new TtsHostMsg_InitializeVoiceList()); -} - -void TtsDispatcherEfl::Speak( - const blink::WebSpeechSynthesisUtterance& web_utterance) { - int id = next_utterance_id_++; - - utterance_id_map_[id] = web_utterance; - - TtsUtteranceRequest utterance; - utterance.id = id; - utterance.text = web_utterance.GetText().Utf8(); - if (!web_utterance.Lang().IsEmpty() && - web_utterance.Lang().Utf8().at(2) == '-') - utterance.lang = web_utterance.Lang().Utf8().replace(2, 1, "_"); - utterance.voice = web_utterance.Voice().Utf8(); - utterance.volume = web_utterance.Volume(); - utterance.rate = web_utterance.Rate(); - utterance.pitch = web_utterance.Pitch(); - content::RenderThread::Get()->Send(new TtsHostMsg_Speak(utterance)); -} - -void TtsDispatcherEfl::Pause() { - content::RenderThread::Get()->Send(new TtsHostMsg_Pause()); -} - -void TtsDispatcherEfl::Resume() { - content::RenderThread::Get()->Send(new TtsHostMsg_Resume()); -} - -void TtsDispatcherEfl::Cancel() { - content::RenderThread::Get()->Send(new TtsHostMsg_Cancel()); -} - -blink::WebSpeechSynthesisUtterance TtsDispatcherEfl::FindUtterance(int utterance_id) { - const auto iter = utterance_id_map_.find(utterance_id); - if (iter == utterance_id_map_.end()) - return blink::WebSpeechSynthesisUtterance(); - return iter->second; -} - -void TtsDispatcherEfl::OnSetVoiceList(const std::vector& voices) { - blink::WebVector out_voices(voices.size()); - for (size_t i = 0; i < voices.size(); ++i) { - out_voices[i].SetVoiceURI(blink::WebString::FromUTF8(voices[i].voice_uri)); - out_voices[i].SetName(blink::WebString::FromUTF8(voices[i].name)); - out_voices[i].SetLanguage(blink::WebString::FromUTF8(voices[i].lang)); - out_voices[i].SetIsLocalService(voices[i].local_service); - out_voices[i].SetIsDefault(voices[i].is_default); - } - synthesizer_client_->SetVoiceList(out_voices); -} - -void TtsDispatcherEfl::OnDidStartSpeaking(int utterance_id) { - if (utterance_id_map_.find(utterance_id) == utterance_id_map_.end()) - return; - - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - synthesizer_client_->DidStartSpeaking(utterance); -} - -void TtsDispatcherEfl::OnDidFinishSpeaking(int utterance_id) { - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - synthesizer_client_->DidFinishSpeaking(utterance); - utterance_id_map_.erase(utterance_id); -} - -void TtsDispatcherEfl::OnDidPauseSpeaking(int utterance_id) { - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - synthesizer_client_->DidPauseSpeaking(utterance); -} - -void TtsDispatcherEfl::OnDidResumeSpeaking(int utterance_id) { - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - synthesizer_client_->DidResumeSpeaking(utterance); -} - -void TtsDispatcherEfl::OnWordBoundary(int utterance_id, int char_index) { - CHECK(char_index >= 0); - - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - synthesizer_client_->WordBoundaryEventOccurred( - utterance, static_cast(char_index), 0); -} - -void TtsDispatcherEfl::OnSentenceBoundary(int utterance_id, int char_index) { - CHECK(char_index >= 0); - - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - synthesizer_client_->SentenceBoundaryEventOccurred( - utterance, static_cast(char_index), 0); -} - -void TtsDispatcherEfl::OnMarkerEvent(int utterance_id, int char_index) { - // Not supported yet. -} - -void TtsDispatcherEfl::OnWasInterrupted(int utterance_id) { - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - // The web speech API doesn't support "interrupted". - synthesizer_client_->DidFinishSpeaking(utterance); - utterance_id_map_.erase(utterance_id); -} - -void TtsDispatcherEfl::OnWasCancelled(int utterance_id) { - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - // The web speech API doesn't support "cancelled". - synthesizer_client_->DidFinishSpeaking(utterance); - utterance_id_map_.erase(utterance_id); -} - -void TtsDispatcherEfl::OnSpeakingErrorOccurred(int utterance_id, - const std::string& error_message) { - blink::WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.IsNull()) - return; - - // The web speech API doesn't support an error message. - synthesizer_client_->SpeakingErrorOccurred(utterance); - utterance_id_map_.erase(utterance_id); -} - -} // namespace content diff --git a/tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.h b/tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.h deleted file mode 100644 index e99cf79..0000000 --- a/tizen_src/chromium_impl/content/renderer/tts_dispatcher_efl.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2014 Samsung Electronics Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef RENDERER_TTS_DISPATCHER_H_ -#define RENDERER_TTS_DISPATCHER_H_ - -#include - -#include "base/compiler_specific.h" -#include "content/common/content_export.h" -#include "content/public/renderer/render_thread_observer.h" -#include "third_party/blink/public/platform/web_speech_synthesizer.h" -#include "third_party/blink/public/platform/web_speech_synthesizer_client.h" - -namespace IPC { -class Message; -} - -namespace content { - -struct TtsVoice; - -// TtsDispatcher is a delegate for methods used by Blink for speech synthesis -// APIs. It's the complement of TtsDispatcherHost (owned by RenderViewHost). -// Each TtsDispatcher is owned by the WebSpeechSynthesizerClient in Blink; -// it registers itself to listen to IPC upon construction and unregisters -// itself when deleted. There can be multiple TtsDispatchers alive at once, -// so each one routes IPC messages to its WebSpeechSynthesizerClient only if -// the utterance id (which is globally unique) matches. -class CONTENT_EXPORT TtsDispatcherEfl - : public blink::WebSpeechSynthesizer, - public content::RenderThreadObserver { - public: - explicit TtsDispatcherEfl(blink::WebSpeechSynthesizerClient* client); - - private: - ~TtsDispatcherEfl() override; - - TtsDispatcherEfl(const TtsDispatcherEfl&) = delete; - TtsDispatcherEfl& operator=(const TtsDispatcherEfl&) = delete; - - // RenderThreadObserver override. - bool OnControlMessageReceived(const IPC::Message& message) override; - - // blink::WebSpeechSynthesizer implementation. - void UpdateVoiceList() override; - void Speak(const blink::WebSpeechSynthesisUtterance& utterance) override; - void Pause() override; - void Resume() override; - void Cancel() override; - - blink::WebSpeechSynthesisUtterance FindUtterance(int utterance_id); - - void OnSetVoiceList(const std::vector& voices); - void OnDidStartSpeaking(int utterance_id); - void OnDidFinishSpeaking(int utterance_id); - void OnDidPauseSpeaking(int utterance_id); - void OnDidResumeSpeaking(int utterance_id); - void OnWordBoundary(int utterance_id, int char_index); - void OnSentenceBoundary(int utterance_id, int char_index); - void OnMarkerEvent(int utterance_id, int char_index); - void OnWasInterrupted(int utterance_id); - void OnWasCancelled(int utterance_id); - void OnSpeakingErrorOccurred(int utterance_id, - const std::string& error_message); - - // The WebKit client class that we use to send events back to the JS world. - // Weak reference, this will be valid as long as this object exists. - blink::WebSpeechSynthesizerClient* synthesizer_client_; - - // Next utterance id, used to map response IPCs to utterance objects. - static int next_utterance_id_; - - // Map from id to utterance objects. - std::map utterance_id_map_; -}; - -} // namespace content - -#endif // RENDERER_TTS_DISPATCHER_H_ diff --git a/tizen_src/ewk/efl_integration/content_browser_client_efl.cc b/tizen_src/ewk/efl_integration/content_browser_client_efl.cc index d6d40a0..5d7bd3d 100644 --- a/tizen_src/ewk/efl_integration/content_browser_client_efl.cc +++ b/tizen_src/ewk/efl_integration/content_browser_client_efl.cc @@ -46,7 +46,6 @@ #if BUILDFLAG(IS_TIZEN) #include -#include "content/browser/speech/tts_message_filter_efl.h" #endif #include "private/ewk_notification_private.h" @@ -425,9 +424,6 @@ void ContentBrowserClientEfl::RenderProcessWillLaunch( #if !defined(EWK_BRINGUP) // FIXME: m94 bringup host->AddFilter(new editing::EditorClientObserver(host->GetID())); #endif -#if BUILDFLAG(IS_TIZEN) - host->AddFilter(new TtsMessageFilterEfl()); -#endif } content::DevToolsManagerDelegate* diff --git a/tizen_src/ewk/efl_integration/public/ewk_view.cc b/tizen_src/ewk/efl_integration/public/ewk_view.cc index 3ebd7f3..9f595df 100644 --- a/tizen_src/ewk/efl_integration/public/ewk_view.cc +++ b/tizen_src/ewk/efl_integration/public/ewk_view.cc @@ -50,6 +50,10 @@ #include "usermedia_permission_popup.h" #include "web_contents_delegate_efl.h" +#if defined(TIZEN_WEB_SPEECH_RECOGNITION) +#include "content/browser/speech/tts_platform_impl_tizen.h" +#endif + static Eina_Bool _ewk_view_default_user_media_permission( Evas_Object*, Ewk_User_Media_Permission_Request*, void*); @@ -1319,8 +1323,26 @@ Eina_Bool ewk_view_send_key_event(Evas_Object* ewk_view, void* key_event, Eina_B } Eina_Bool ewk_view_tts_mode_set(Evas_Object* view, ewk_tts_mode tts_mode) { - LOG_EWK_API_MOCKUP(); - return false; +#if defined(TIZEN_WEB_SPEECH_RECOGNITION) + switch (tts_mode) { + case EWK_TTS_MODE_DEFAULT: + content::TtsPlatformImplTizen::SetTtsMode(TTS_MODE_DEFAULT); + break; + case EWK_TTS_MODE_NOTIFICATION: + content::TtsPlatformImplTizen::SetTtsMode(TTS_MODE_NOTIFICATION); + break; + case EWK_TTS_MODE_SCREEN_READER: + content::TtsPlatformImplTizen::SetTtsMode(TTS_MODE_SCREEN_READER); + break; + default: + LOG(ERROR) << "Not supported TTS mode: " << static_cast(tts_mode); + return EINA_FALSE; + } + return EINA_TRUE; +#else + LOG_EWK_API_MOCKUP("API unavailable."); + return EINA_FALSE; +#endif } Eina_Bool ewk_view_javascript_message_handler_add( diff --git a/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc b/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc index b182d0b..aebd674 100644 --- a/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc +++ b/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc @@ -43,11 +43,6 @@ #include "third_party/blink/public/web/web_view.h" #include "url/gurl.h" -#if defined(TIZEN_MULTIMEDIA_SUPPORT) -#include "content/common/tts_messages_efl.h" -#include "content/renderer/tts_dispatcher_efl.h" -#endif - #if defined(TIZEN_AUTOFILL_SUPPORT) #include "components/autofill/content/renderer/autofill_agent.h" #include "components/autofill/content/renderer/autofill_assistant_agent.h" -- 2.7.4