| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/speech/tts_crosapi_util.h" |
| |
| #include "base/feature_list.h" |
| #include "base/values.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "content/public/browser/tts_controller.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "ash/constants/ash_features.h" |
| #include "chrome/browser/ash/crosapi/browser_util.h" |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| #include "chromeos/startup/browser_params_proxy.h" |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| namespace tts_crosapi_util { |
| |
| content::TtsEventType FromMojo(crosapi::mojom::TtsEventType mojo_event) { |
| switch (mojo_event) { |
| case crosapi::mojom::TtsEventType::kStart: |
| return content::TtsEventType::TTS_EVENT_START; |
| case crosapi::mojom::TtsEventType::kEnd: |
| return content::TtsEventType::TTS_EVENT_END; |
| case crosapi::mojom::TtsEventType::kWord: |
| return content::TtsEventType::TTS_EVENT_WORD; |
| case crosapi::mojom::TtsEventType::kSentence: |
| return content::TtsEventType::TTS_EVENT_SENTENCE; |
| case crosapi::mojom::TtsEventType::kMarker: |
| return content::TtsEventType::TTS_EVENT_MARKER; |
| case crosapi::mojom::TtsEventType::kInterrupted: |
| return content::TtsEventType::TTS_EVENT_INTERRUPTED; |
| case crosapi::mojom::TtsEventType::kCanceled: |
| return content::TtsEventType::TTS_EVENT_CANCELLED; |
| case crosapi::mojom::TtsEventType::kError: |
| return content::TtsEventType::TTS_EVENT_ERROR; |
| case crosapi::mojom::TtsEventType::kPause: |
| return content::TtsEventType::TTS_EVENT_PAUSE; |
| case crosapi::mojom::TtsEventType::kResume: |
| return content::TtsEventType::TTS_EVENT_RESUME; |
| } |
| } |
| |
| crosapi::mojom::TtsEventType ToMojo(content::TtsEventType event_type) { |
| switch (event_type) { |
| case content::TtsEventType::TTS_EVENT_START: |
| return crosapi::mojom::TtsEventType::kStart; |
| case content::TtsEventType::TTS_EVENT_END: |
| return crosapi::mojom::TtsEventType::kEnd; |
| case content::TtsEventType::TTS_EVENT_WORD: |
| return crosapi::mojom::TtsEventType::kWord; |
| case content::TtsEventType::TTS_EVENT_SENTENCE: |
| return crosapi::mojom::TtsEventType::kSentence; |
| case content::TtsEventType::TTS_EVENT_MARKER: |
| return crosapi::mojom::TtsEventType::kMarker; |
| case content::TtsEventType::TTS_EVENT_INTERRUPTED: |
| return crosapi::mojom::TtsEventType::kInterrupted; |
| case content::TtsEventType::TTS_EVENT_CANCELLED: |
| return crosapi::mojom::TtsEventType::kCanceled; |
| case content::TtsEventType::TTS_EVENT_ERROR: |
| return crosapi::mojom::TtsEventType::kError; |
| case content::TtsEventType::TTS_EVENT_PAUSE: |
| return crosapi::mojom::TtsEventType::kPause; |
| case content::TtsEventType::TTS_EVENT_RESUME: |
| return crosapi::mojom::TtsEventType::kResume; |
| } |
| } |
| |
| content::VoiceData FromMojo(const crosapi::mojom::TtsVoicePtr& mojo_voice) { |
| content::VoiceData voice_data; |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // The mojo_voice is from the remote TTS engine in Lacros. |
| voice_data.from_remote_tts_engine = true; |
| #endif |
| voice_data.name = mojo_voice->voice_name; |
| voice_data.lang = mojo_voice->lang; |
| voice_data.engine_id = mojo_voice->engine_id; |
| voice_data.remote = mojo_voice->remote; |
| voice_data.native = mojo_voice->native; |
| voice_data.native_voice_identifier = mojo_voice->native_voice_identifier; |
| |
| for (const auto& mojo_event : mojo_voice->events) |
| voice_data.events.insert(tts_crosapi_util::FromMojo(mojo_event)); |
| |
| return voice_data; |
| } |
| |
| crosapi::mojom::TtsVoicePtr ToMojo(const content::VoiceData& voice) { |
| auto mojo_voice = crosapi::mojom::TtsVoice::New(); |
| mojo_voice->voice_name = voice.name; |
| mojo_voice->lang = voice.lang; |
| mojo_voice->remote = voice.remote; |
| mojo_voice->engine_id = voice.engine_id; |
| mojo_voice->native = voice.native; |
| mojo_voice->native_voice_identifier = voice.native_voice_identifier; |
| std::vector<crosapi::mojom::TtsEventType> mojo_events; |
| for (const auto& event : voice.events) { |
| mojo_events.push_back(tts_crosapi_util::ToMojo(event)); |
| } |
| mojo_voice->events = std::move(mojo_events); |
| |
| return mojo_voice; |
| } |
| |
| crosapi::mojom::TtsUtterancePtr ToMojo(content::TtsUtterance* utterance) { |
| auto mojo_utterance = crosapi::mojom::TtsUtterance::New(); |
| mojo_utterance->utterance_id = utterance->GetId(); |
| mojo_utterance->text = utterance->GetText(); |
| mojo_utterance->lang = utterance->GetLang(); |
| mojo_utterance->voice_name = utterance->GetVoiceName(); |
| mojo_utterance->volume = utterance->GetContinuousParameters().volume; |
| mojo_utterance->rate = utterance->GetContinuousParameters().rate; |
| mojo_utterance->pitch = utterance->GetContinuousParameters().pitch; |
| mojo_utterance->engine_id = utterance->GetEngineId(); |
| mojo_utterance->should_clear_queue = utterance->GetShouldClearQueue(); |
| mojo_utterance->src_id = utterance->GetSrcId(); |
| mojo_utterance->src_url = utterance->GetSrcUrl(); |
| |
| for (const auto& event : utterance->GetDesiredEventTypes()) |
| mojo_utterance->desired_event_types.push_back( |
| tts_crosapi_util::ToMojo(event)); |
| |
| for (const auto& event : utterance->GetRequiredEventTypes()) |
| mojo_utterance->required_event_types.push_back( |
| tts_crosapi_util::ToMojo(event)); |
| |
| content::WebContents* web_contents = utterance->GetWebContents(); |
| mojo_utterance->was_created_with_web_contents = web_contents != nullptr; |
| |
| base::Value::Dict options = utterance->GetOptions()->Clone(); |
| mojo_utterance->options = std::move(options); |
| |
| return mojo_utterance; |
| } |
| |
| std::unique_ptr<content::TtsUtterance> CreateUtteranceFromMojo( |
| crosapi::mojom::TtsUtterancePtr& mojo_utterance, |
| bool should_always_be_spoken) { |
| // Construct TtsUtterance object. |
| content::BrowserContext* browser_context = |
| ProfileManager::GetPrimaryUserProfile(); |
| std::unique_ptr<content::TtsUtterance> utterance = |
| content::TtsUtterance::Create(browser_context, should_always_be_spoken); |
| |
| utterance->SetText(mojo_utterance->text); |
| utterance->SetLang(mojo_utterance->lang); |
| utterance->SetVoiceName(mojo_utterance->voice_name); |
| utterance->SetContinuousParameters( |
| mojo_utterance->rate, mojo_utterance->pitch, mojo_utterance->volume); |
| utterance->SetEngineId(mojo_utterance->engine_id); |
| utterance->SetShouldClearQueue(mojo_utterance->should_clear_queue); |
| utterance->SetSrcUrl(mojo_utterance->src_url); |
| utterance->SetSrcId(mojo_utterance->src_id); |
| |
| std::set<content::TtsEventType> desired_events; |
| for (const auto& mojo_event : mojo_utterance->desired_event_types) |
| desired_events.insert(tts_crosapi_util::FromMojo(mojo_event)); |
| utterance->SetDesiredEventTypes(std::move(desired_events)); |
| |
| std::set<content::TtsEventType> required_events; |
| for (const auto& mojo_event : mojo_utterance->required_event_types) |
| required_events.insert(tts_crosapi_util::FromMojo(mojo_event)); |
| utterance->SetRequiredEventTypes(std::move(required_events)); |
| |
| base::Value::Dict options = mojo_utterance->options.Clone(); |
| utterance->SetOptions(std::move(options)); |
| return utterance; |
| } |
| |
| bool ShouldEnableLacrosTtsSupport() { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| bool lacros_tts_support_enabled = |
| crosapi::browser_util::IsLacrosPrimaryBrowser() && |
| !base::FeatureList::IsEnabled(ash::features::kDisableLacrosTtsSupport); |
| return lacros_tts_support_enabled; |
| #else // IS_CHROMEOS_LACROS |
| return chromeos::BrowserParamsProxy::Get()->EnableLacrosTtsSupport(); |
| #endif |
| } |
| |
| void GetAllVoicesForTesting(content::BrowserContext* browser_context, |
| const GURL& source_url, |
| std::vector<content::VoiceData>* out_voices) { |
| content::TtsController::GetInstance()->GetVoices( |
| ProfileManager::GetActiveUserProfile(), GURL(), out_voices); |
| } |
| |
| void SpeakForTesting(std::unique_ptr<content::TtsUtterance> utterance) { |
| content::TtsController::GetInstance()->SpeakOrEnqueue(std::move(utterance)); |
| } |
| |
| int GetTtsUtteranceQueueSizeForTesting() { |
| return content::TtsController::GetInstance()->QueueSize(); |
| } |
| |
| } // namespace tts_crosapi_util |