|  | // Copyright 2014 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef CONTENT_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ | 
|  | #define CONTENT_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ | 
|  |  | 
|  | #include <list> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/gtest_prod_util.h" | 
|  | #include "base/json/json_reader.h" | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "base/memory/singleton.h" | 
|  | #include "base/metrics/histogram_macros.h" | 
|  | #include "base/metrics/user_metrics.h" | 
|  | #include "base/observer_list.h" | 
|  | #include "base/values.h" | 
|  | #include "build/build_config.h" | 
|  | #include "build/chromeos_buildflags.h" | 
|  | #include "content/common/content_export.h" | 
|  | #include "content/public/browser/tts_controller.h" | 
|  | #include "content/public/browser/tts_platform.h" | 
|  | #include "content/public/browser/web_contents_observer.h" | 
|  | #include "net/base/network_change_notifier.h" | 
|  | #include "services/data_decoder/public/cpp/data_decoder.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | namespace content { | 
|  | class BrowserContext; | 
|  |  | 
|  | #if BUILDFLAG(IS_CHROMEOS_ASH) | 
|  | class TtsControllerDelegate; | 
|  | #endif | 
|  |  | 
|  | // Singleton class that manages text-to-speech for all TTS engines and | 
|  | // APIs, maintaining a queue of pending utterances and keeping | 
|  | // track of all state. | 
|  | class CONTENT_EXPORT TtsControllerImpl | 
|  | : public TtsController, | 
|  | public WebContentsObserver, | 
|  | public net::NetworkChangeNotifier::NetworkChangeObserver { | 
|  | public: | 
|  | // Get the single instance of this class. | 
|  | static TtsControllerImpl* GetInstance(); | 
|  |  | 
|  | TtsControllerImpl(const TtsControllerImpl&) = delete; | 
|  | TtsControllerImpl& operator=(const TtsControllerImpl&) = delete; | 
|  |  | 
|  | static void SkipAddNetworkChangeObserverForTests(bool enabled); | 
|  |  | 
|  | void SetStopSpeakingWhenHidden(bool value); | 
|  |  | 
|  | // TtsController methods | 
|  | bool IsSpeaking() override; | 
|  | void SpeakOrEnqueue(std::unique_ptr<TtsUtterance> utterance) override; | 
|  | void Stop() override; | 
|  | void Stop(const GURL& source_url) override; | 
|  | void Pause() override; | 
|  | void Resume() override; | 
|  | void OnTtsEvent(int utterance_id, | 
|  | TtsEventType event_type, | 
|  | int char_index, | 
|  | int length, | 
|  | const std::string& error_message) override; | 
|  | void GetVoices(BrowserContext* browser_context, | 
|  | const GURL& source_url, | 
|  | std::vector<VoiceData>* out_voices) override; | 
|  | void VoicesChanged() override; | 
|  | void AddVoicesChangedDelegate(VoicesChangedDelegate* delegate) override; | 
|  | void RemoveVoicesChangedDelegate(VoicesChangedDelegate* delegate) override; | 
|  | void RemoveUtteranceEventDelegate(UtteranceEventDelegate* delegate) override; | 
|  | void SetTtsEngineDelegate(TtsEngineDelegate* delegate) override; | 
|  | TtsEngineDelegate* GetTtsEngineDelegate() override; | 
|  | void RefreshVoices() override; | 
|  |  | 
|  | void Shutdown(); | 
|  |  | 
|  | // Called directly by ~BrowserContext, because a raw BrowserContext pointer | 
|  | // is stored in an Utterance. | 
|  | void OnBrowserContextDestroyed(BrowserContext* browser_context); | 
|  |  | 
|  | // Testing methods | 
|  | void SetTtsPlatform(TtsPlatform* tts_platform) override; | 
|  | int QueueSize() override; | 
|  |  | 
|  | // Strips SSML so that tags are not output by speech engine. | 
|  | void StripSSML( | 
|  | const std::string& utterance, | 
|  | base::OnceCallback<void(const std::string&)> callback) override; | 
|  |  | 
|  | void SetRemoteTtsEngineDelegate(RemoteTtsEngineDelegate* delegate) override; | 
|  |  | 
|  | protected: | 
|  | TtsControllerImpl(); | 
|  | ~TtsControllerImpl() override; | 
|  |  | 
|  | // Exposed for unittest. | 
|  | bool IsPausedForTesting() const { return paused_; } | 
|  |  | 
|  | private: | 
|  | friend class TestTtsControllerImpl; | 
|  | friend struct base::DefaultSingletonTraits<TtsControllerImpl>; | 
|  |  | 
|  | void GetVoicesInternal(BrowserContext* browser_context, | 
|  | const GURL& source_url, | 
|  | std::vector<VoiceData>* out_voices); | 
|  |  | 
|  | // Get the platform TTS implementation (or injected mock). | 
|  | TtsPlatform* GetTtsPlatform(); | 
|  |  | 
|  | // Whether the platform implementation is supported and completed its | 
|  | // initialization. | 
|  | bool TtsPlatformReady(); | 
|  |  | 
|  | // Whether the platform implementation is supported, but still being | 
|  | // initialized. | 
|  | bool TtsPlatformLoading(); | 
|  |  | 
|  | // Start speaking the given utterance. Will either take ownership of | 
|  | // |utterance| or delete it if there's an error. Returns true on success. | 
|  | void SpeakNow(std::unique_ptr<TtsUtterance> utterance); | 
|  |  | 
|  | // If the current utterance matches |source_url|, it is stopped and the | 
|  | // utterance queue cleared. | 
|  | void StopAndClearQueue(const GURL& source_url); | 
|  |  | 
|  | // Stops the current utterance if it matches |source_url|. Returns true on | 
|  | // success, false if the current utterance does not match |source_url|. | 
|  | bool StopCurrentUtteranceIfMatches(const GURL& source_url); | 
|  |  | 
|  | // Clear the utterance queue. If send_events is true, will send | 
|  | // TTS_EVENT_CANCELLED events on each one. | 
|  | void ClearUtteranceQueue(bool send_events); | 
|  |  | 
|  | // Finalize and delete the current utterance. | 
|  | void FinishCurrentUtterance(); | 
|  |  | 
|  | // Start speaking the next utterance in the queue. | 
|  | void SpeakNextUtterance(); | 
|  |  | 
|  | // Updates the utterance to have default values for rate, pitch, and | 
|  | // volume if they have not yet been set. On Chrome OS, defaults are | 
|  | // pulled from user prefs, and may not be the same as other platforms. | 
|  | void UpdateUtteranceDefaults(TtsUtterance* utterance); | 
|  |  | 
|  | // Passed to Speak() as a callback. | 
|  | void OnSpeakFinished(int utterance_id, bool success); | 
|  |  | 
|  | // Static helper methods for StripSSML. | 
|  | static void StripSSMLHelper( | 
|  | const std::string& utterance, | 
|  | base::OnceCallback<void(const std::string&)> on_ssml_parsed, | 
|  | data_decoder::DataDecoder::ValueOrError result); | 
|  | static void PopulateParsedText(std::string* parsed_text, | 
|  | const base::Value* element); | 
|  |  | 
|  | int GetMatchingVoice(TtsUtterance* utterance, | 
|  | const std::vector<VoiceData>& voices); | 
|  |  | 
|  | // Called internally to set |current_utterance_|. | 
|  | void SetCurrentUtterance(std::unique_ptr<TtsUtterance> utterance); | 
|  |  | 
|  | // Used when the WebContents of the current utterance is destroyed/hidden. | 
|  | void StopCurrentUtteranceAndRemoveUtterancesMatching(WebContents* wc); | 
|  |  | 
|  | // Returns true if the utterance should be spoken. | 
|  | bool ShouldSpeakUtterance(TtsUtterance* utterance); | 
|  |  | 
|  | // WebContentsObserver methods | 
|  | void WebContentsDestroyed() override; | 
|  | void OnVisibilityChanged(Visibility visibility) override; | 
|  |  | 
|  | // net::NetworkChangeNotifier::NetworkChangeObserver | 
|  | void OnNetworkChanged( | 
|  | net::NetworkChangeNotifier::ConnectionType type) override; | 
|  |  | 
|  | #if BUILDFLAG(IS_CHROMEOS_ASH) | 
|  | TtsControllerDelegate* GetTtsControllerDelegate(); | 
|  | void SetTtsControllerDelegateForTesting(TtsControllerDelegate* delegate); | 
|  | TtsControllerDelegate* delegate_ = nullptr; | 
|  | RemoteTtsEngineDelegate* remote_engine_delegate_ = nullptr; | 
|  | #endif | 
|  |  | 
|  | raw_ptr<TtsEngineDelegate> engine_delegate_ = nullptr; | 
|  |  | 
|  | bool stop_speaking_when_hidden_ = false; | 
|  |  | 
|  | // A set of delegates that want to be notified when the voices change. | 
|  | base::ObserverList<VoicesChangedDelegate> voices_changed_delegates_; | 
|  |  | 
|  | // The current utterance being spoken. | 
|  | std::unique_ptr<TtsUtterance> current_utterance_; | 
|  |  | 
|  | // Whether the queue is paused or not. | 
|  | bool paused_ = false; | 
|  |  | 
|  | // A pointer to the platform implementation of text-to-speech, for | 
|  | // dependency injection. | 
|  | raw_ptr<TtsPlatform> tts_platform_ = nullptr; | 
|  |  | 
|  | // A queue of utterances to speak after the current one finishes. | 
|  | std::list<std::unique_ptr<TtsUtterance>> utterance_list_; | 
|  |  | 
|  | // Whether to allow remote voices. | 
|  | bool allow_remote_voices_ = false; | 
|  |  | 
|  | // Skip |AddNetworkChangeObserver| call during the creation of tts_controller | 
|  | // for unittests as network change notifier wouldn't have been created. | 
|  | static bool skip_add_network_change_observer_for_tests_; | 
|  | }; | 
|  |  | 
|  | }  // namespace content | 
|  |  | 
|  | #endif  // CONTENT_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ |