#include "content/browser/speech/tts_controller_impl.h"
#include <stddef.h>
#include <algorithm>
#include <string>
#include <vector>
#include "base/containers/queue.h"
#include "base/functional/bind.h"
#include "base/json/json_reader.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/observer_list.h"
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/speech/tts_utterance_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/tts_utterance.h"
#include "content/public/browser/visibility.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "services/data_decoder/public/cpp/safe_xml_parser.h"
#include "services/data_decoder/public/mojom/xml_parser.mojom.h"
#include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
#include "ui/base/l10n/l10n_util.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "content/public/browser/tts_controller_delegate.h"
#endif
namespace content {
namespace {
const int kInvalidCharIndex = …;
const int kInvalidLength = …;
#if BUILDFLAG(IS_CHROMEOS_ASH)
bool VoiceIdMatches(
const std::optional<TtsControllerDelegate::PreferredVoiceId>& id,
const content::VoiceData& voice) {
if (!id.has_value() || voice.name.empty() ||
(voice.engine_id.empty() && !voice.native))
return false;
if (voice.native)
return id->name == voice.name && id->id.empty();
return id->name == voice.name && id->id == voice.engine_id;
}
#endif
TtsUtteranceImpl* AsUtteranceImpl(TtsUtterance* utterance) { … }
bool IsUtteranceSpokenByRemoteEngine(TtsUtterance* utterance) { … }
}
VoiceData::VoiceData() : … { … }
VoiceData::VoiceData(const VoiceData& other) = default;
VoiceData::~VoiceData() { … }
TtsController* TtsController::GetInstance() { … }
void TtsController::SkipAddNetworkChangeObserverForTests(bool enabled) { … }
enum class UMATextToSpeechEvent { … };
bool TtsControllerImpl::skip_add_network_change_observer_for_tests_ = …;
TtsControllerImpl* TtsControllerImpl::GetInstance() { … }
void TtsControllerImpl::SkipAddNetworkChangeObserverForTests(bool enabled) { … }
void TtsControllerImpl::SetStopSpeakingWhenHidden(bool value) { … }
TtsControllerImpl::TtsControllerImpl() { … }
TtsControllerImpl::~TtsControllerImpl() { … }
void TtsControllerImpl::SpeakOrEnqueue(
std::unique_ptr<TtsUtterance> utterance) { … }
void TtsControllerImpl::SpeakOrEnqueueInternal(
std::unique_ptr<TtsUtterance> utterance) { … }
void TtsControllerImpl::Stop() { … }
void TtsControllerImpl::Stop(const GURL& source_url) { … }
void TtsControllerImpl::StopAndClearQueue(const GURL& source_url) { … }
bool TtsControllerImpl::StopCurrentUtteranceIfMatches(const GURL& source_url) { … }
void TtsControllerImpl::StopCurrentUtterance() { … }
void TtsControllerImpl::Pause() { … }
void TtsControllerImpl::Resume() { … }
void TtsControllerImpl::OnTtsEvent(int utterance_id,
TtsEventType event_type,
int char_index,
int length,
const std::string& error_message) { … }
void TtsControllerImpl::OnTtsUtteranceBecameInvalid(int utterance_id) { … }
void TtsControllerImpl::GetVoices(BrowserContext* browser_context,
const GURL& source_url,
std::vector<VoiceData>* out_voices) { … }
void TtsControllerImpl::GetVoicesInternal(BrowserContext* browser_context,
const GURL& source_url,
std::vector<VoiceData>* out_voices) { … }
bool TtsControllerImpl::IsSpeaking() { … }
void TtsControllerImpl::VoicesChanged() { … }
void TtsControllerImpl::AddVoicesChangedDelegate(
VoicesChangedDelegate* delegate) { … }
void TtsControllerImpl::RemoveVoicesChangedDelegate(
VoicesChangedDelegate* delegate) { … }
void TtsControllerImpl::RemoveUtteranceEventDelegate(
UtteranceEventDelegate* delegate) { … }
void TtsControllerImpl::SetTtsEngineDelegate(TtsEngineDelegate* delegate) { … }
TtsEngineDelegate* TtsControllerImpl::GetTtsEngineDelegate() { … }
void TtsControllerImpl::RefreshVoices() { … }
void TtsControllerImpl::Shutdown() { … }
void TtsControllerImpl::OnBrowserContextDestroyed(
BrowserContext* browser_context) { … }
void TtsControllerImpl::SetTtsPlatform(TtsPlatform* tts_platform) { … }
int TtsControllerImpl::QueueSize() { … }
TtsPlatform* TtsControllerImpl::GetTtsPlatform() { … }
bool TtsControllerImpl::TtsPlatformReady() { … }
bool TtsControllerImpl::TtsPlatformLoading() { … }
void TtsControllerImpl::SpeakNow(std::unique_ptr<TtsUtterance> utterance) { … }
void TtsControllerImpl::OnSpeakFinished(int utterance_id, bool success) { … }
void TtsControllerImpl::ClearUtteranceQueue(bool send_events) { … }
void TtsControllerImpl::FinishCurrentUtterance() { … }
void TtsControllerImpl::SpeakNextUtterance() { … }
void TtsControllerImpl::UpdateUtteranceDefaults(TtsUtterance* utterance) { … }
void TtsControllerImpl::StripSSML(
const std::string& utterance,
base::OnceCallback<void(const std::string&)> on_ssml_parsed) { … }
void TtsControllerImpl::StripSSMLHelper(
const std::string& utterance,
base::OnceCallback<void(const std::string&)> on_ssml_parsed,
data_decoder::DataDecoder::ValueOrError result) { … }
void TtsControllerImpl::PopulateParsedText(std::string* parsed_text,
const base::Value* element) { … }
int TtsControllerImpl::GetMatchingVoice(TtsUtterance* utterance,
const std::vector<VoiceData>& voices) { … }
void TtsControllerImpl::SetCurrentUtterance(
std::unique_ptr<TtsUtterance> utterance) { … }
void TtsControllerImpl::StopCurrentUtteranceAndRemoveUtterancesMatching(
WebContents* wc) { … }
void TtsControllerImpl::RemoveUtteranceAndStopIfNeeded(int utterance_id) { … }
bool TtsControllerImpl::StopCurrentUtteranceIfMatches(int utterance_id) { … }
bool TtsControllerImpl::ShouldSpeakUtterance(TtsUtterance* utterance) { … }
void TtsControllerImpl::WebContentsDestroyed() { … }
void TtsControllerImpl::OnVisibilityChanged(Visibility visibility) { … }
void TtsControllerImpl::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
TtsControllerDelegate* TtsControllerImpl::GetTtsControllerDelegate() {
if (delegate_)
return delegate_;
if (GetContentClient() && GetContentClient()->browser()) {
delegate_ = GetContentClient()->browser()->GetTtsControllerDelegate();
return delegate_;
}
return nullptr;
}
void TtsControllerImpl::SetTtsControllerDelegateForTesting(
TtsControllerDelegate* delegate) {
delegate_ = delegate;
}
#endif
void TtsControllerImpl::SetRemoteTtsEngineDelegate(
RemoteTtsEngineDelegate* delegate) { … }
}