// 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.
#ifndef CHROME_BROWSER_SPEECH_TTS_CLIENT_LACROS_H_
#define CHROME_BROWSER_SPEECH_TTS_CLIENT_LACROS_H_
#include <memory>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "chromeos/crosapi/mojom/tts.mojom.h"
#include "content/public/browser/tts_controller.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "net/base/network_change_notifier.h"
namespace content {
class BrowserContext;
}
// Implements crosapi::mojom::TtsClient, which is called by ash to handle
// TTS requests to Lacros such as retrieving voice data, etc. It also manages
// To send TTS requests ash. TtsClientLacros is created per BrowserContext.
class TtsClientLacros
: public extensions::BrowserContextKeyedAPI,
public crosapi::mojom::TtsClient,
public net::NetworkChangeNotifier::NetworkChangeObserver,
public extensions::EventRouter::Observer {
public:
explicit TtsClientLacros(content::BrowserContext* context);
TtsClientLacros(const TtsClientLacros&) = delete;
TtsClientLacros& operator=(const TtsClientLacros&) = delete;
~TtsClientLacros() override;
// crosapi::mojom::TtsClient:
void VoicesChanged(
std::vector<crosapi::mojom::TtsVoicePtr> mojo_all_voices) override;
void SpeakWithLacrosVoice(
crosapi::mojom::TtsUtterancePtr utterance,
crosapi::mojom::TtsVoicePtr voice,
mojo::PendingRemote<crosapi::mojom::TtsUtteranceClient>
ash_utterance_client) override;
void Stop(const std::string& engine_id) override;
void Pause(const std::string& engine_id) override;
void Resume(const std::string& engine_id) override;
const base::UnguessableToken& browser_context_id() const {
return browser_context_id_;
}
// Returns the cached voices in |out_voices|, which are the voices available
// for Lacros including the ones provided by both Ash and Lacros.
void GetAllVoices(std::vector<content::VoiceData>* out_voices);
// Forwards the given utterance to Ash to be processed by Ash TtsController.
void SpeakOrEnqueue(std::unique_ptr<content::TtsUtterance> utterance);
// Forwards the Stop request (for stopping the current utterance if it matches
// the given |source_url|) to Ash.
void RequestStop(const GURL& source_url);
// Forwards the Pause request from Lacros Tts client (Tts extension api or
// speechSynthesis web api) to Ash, so that the request will be processed by
// Ash's TtsController.
void RequestPause();
// Forwards the Resume request from Lacros Tts client (Tts extension api or
// speechSynthesis web api) to Ash, so that the request will be processed by
// Ash's TtsController.
void RequestResume();
// Forwards the request to query Ash TtsController's IsSpeaking() state and
// returns the result in callback.
void IsSpeaking(base::OnceCallback<void(bool)> callback);
// Handle events received from the Lacros speech engine.
void OnLacrosSpeechEngineTtsEvent(int utterance_id,
content::TtsEventType event_type,
int char_index,
int length,
const std::string& error_message);
void OnAshUtteranceFinished(int utterance_id);
void OnAshUtteranceBecameInvalid(int utterance_id);
void DeletePendingUtteranceClient(int utterance_id);
content::BrowserContext* browser_context() { return browser_context_; }
static TtsClientLacros* GetForBrowserContext(
content::BrowserContext* context);
private:
class TtsUtteraneClient;
class AshUtteranceEventDelegate;
friend class extensions::BrowserContextKeyedAPIFactory<TtsClientLacros>;
// net::NetworkChangeNotifier::NetworkChangeObserver:
void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
// extensions::EventRouter::Observer:
void OnListenerAdded(const extensions::EventListenerInfo& details) override;
void OnListenerRemoved(const extensions::EventListenerInfo& details) override;
bool IsLoadedTtsEngine(const std::string& extension_id) const;
// Notifies Ash about Lacros voices change.
void NotifyLacrosVoicesChanged();
void OnGetAllVoices(std::vector<crosapi::mojom::TtsVoicePtr> mojo_voices);
// KeyedServivce:
void Shutdown() override;
raw_ptr<content::BrowserContext> browser_context_; // not owned.
base::UnguessableToken browser_context_id_;
mojo::Receiver<crosapi::mojom::TtsClient> receiver_{this};
// Cached voices for |browser_context_|, including both ash and lacros voices.
std::vector<content::VoiceData> all_voices_;
bool is_offline_;
// Pending Lacros Tts Utterance clients by by utterance id.
std::map<int, std::unique_ptr<TtsUtteraneClient>> pending_utterance_clients_;
// Pending Ash utterance to be spoken with Lacros speech engine.
std::unique_ptr<content::TtsUtterance> pending_ash_utterance_;
std::unique_ptr<AshUtteranceEventDelegate> ash_utterance_event_delegate_;
base::WeakPtrFactory<TtsClientLacros> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_SPEECH_TTS_CLIENT_LACROS_H_