refactor: move text-to-speech out of chromium_src (#15024)
* chore: add tts patch and buildflag, makes tts work again * chore: add tts patch and buildflag, makes tts work again * fix: make things compile * build: add relevant tts files for linux * fix: update patch and patch description, should now compile on mac * build: move chrome specific sources under chromium_src:chrome target * build: enable_extensions again We are depending on them, check `//electron/chromium_src:chrome` target for more info. * fix: update tts.patch to receive notifications about browser context destruction * fix: extend browser process from chrome layer The global state g_browser_process is shared between //chrome and //electron. * spec: add basic speech synthesis test * spec: skip speech tests on ci * build: fix compilation on windows
This commit is contained in:
parent
5788600c46
commit
95696c9456
39 changed files with 625 additions and 3139 deletions
|
@ -1,198 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium 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 "chrome/renderer/tts_dispatcher.h"
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "chrome/common/tts_messages.h"
|
||||
#include "chrome/common/tts_utterance_request.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"
|
||||
|
||||
using blink::WebSpeechSynthesisUtterance;
|
||||
using blink::WebSpeechSynthesisVoice;
|
||||
using blink::WebSpeechSynthesizerClient;
|
||||
using blink::WebString;
|
||||
using blink::WebVector;
|
||||
using content::RenderThread;
|
||||
|
||||
int TtsDispatcher::next_utterance_id_ = 1;
|
||||
|
||||
TtsDispatcher::TtsDispatcher(WebSpeechSynthesizerClient* client)
|
||||
: synthesizer_client_(client) {
|
||||
RenderThread::Get()->AddObserver(this);
|
||||
}
|
||||
|
||||
TtsDispatcher::~TtsDispatcher() {
|
||||
RenderThread::Get()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
bool TtsDispatcher::OnControlMessageReceived(const IPC::Message& message) {
|
||||
IPC_BEGIN_MESSAGE_MAP(TtsDispatcher, 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 TtsDispatcher::UpdateVoiceList() {
|
||||
RenderThread::Get()->Send(new TtsHostMsg_InitializeVoiceList());
|
||||
}
|
||||
|
||||
void TtsDispatcher::Speak(const 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();
|
||||
utterance.lang = web_utterance.Lang().Utf8();
|
||||
utterance.voice = web_utterance.Voice().Utf8();
|
||||
utterance.volume = web_utterance.Volume();
|
||||
utterance.rate = web_utterance.Rate();
|
||||
utterance.pitch = web_utterance.Pitch();
|
||||
RenderThread::Get()->Send(new TtsHostMsg_Speak(utterance));
|
||||
}
|
||||
|
||||
void TtsDispatcher::Pause() {
|
||||
RenderThread::Get()->Send(new TtsHostMsg_Pause());
|
||||
}
|
||||
|
||||
void TtsDispatcher::Resume() {
|
||||
RenderThread::Get()->Send(new TtsHostMsg_Resume());
|
||||
}
|
||||
|
||||
void TtsDispatcher::Cancel() {
|
||||
RenderThread::Get()->Send(new TtsHostMsg_Cancel());
|
||||
}
|
||||
|
||||
WebSpeechSynthesisUtterance TtsDispatcher::FindUtterance(int utterance_id) {
|
||||
base::hash_map<int, WebSpeechSynthesisUtterance>::const_iterator iter =
|
||||
utterance_id_map_.find(utterance_id);
|
||||
if (iter == utterance_id_map_.end())
|
||||
return WebSpeechSynthesisUtterance();
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnSetVoiceList(const std::vector<TtsVoice>& voices) {
|
||||
WebVector<WebSpeechSynthesisVoice> out_voices(voices.size());
|
||||
for (size_t i = 0; i < voices.size(); ++i) {
|
||||
out_voices[i] = WebSpeechSynthesisVoice();
|
||||
out_voices[i].SetVoiceURI(WebString::FromUTF8(voices[i].voice_uri));
|
||||
out_voices[i].SetName(WebString::FromUTF8(voices[i].name));
|
||||
out_voices[i].SetLanguage(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 TtsDispatcher::OnDidStartSpeaking(int utterance_id) {
|
||||
if (utterance_id_map_.find(utterance_id) == utterance_id_map_.end())
|
||||
return;
|
||||
|
||||
WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
|
||||
if (utterance.IsNull())
|
||||
return;
|
||||
|
||||
synthesizer_client_->DidStartSpeaking(utterance);
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnDidFinishSpeaking(int utterance_id) {
|
||||
WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
|
||||
if (utterance.IsNull())
|
||||
return;
|
||||
|
||||
synthesizer_client_->DidFinishSpeaking(utterance);
|
||||
utterance_id_map_.erase(utterance_id);
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnDidPauseSpeaking(int utterance_id) {
|
||||
WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
|
||||
if (utterance.IsNull())
|
||||
return;
|
||||
|
||||
synthesizer_client_->DidPauseSpeaking(utterance);
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnDidResumeSpeaking(int utterance_id) {
|
||||
WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
|
||||
if (utterance.IsNull())
|
||||
return;
|
||||
|
||||
synthesizer_client_->DidResumeSpeaking(utterance);
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnWordBoundary(int utterance_id, int char_index) {
|
||||
CHECK(char_index >= 0);
|
||||
|
||||
WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
|
||||
if (utterance.IsNull())
|
||||
return;
|
||||
|
||||
synthesizer_client_->WordBoundaryEventOccurred(
|
||||
utterance, static_cast<unsigned>(char_index));
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnSentenceBoundary(int utterance_id, int char_index) {
|
||||
CHECK(char_index >= 0);
|
||||
|
||||
WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
|
||||
if (utterance.IsNull())
|
||||
return;
|
||||
|
||||
synthesizer_client_->SentenceBoundaryEventOccurred(
|
||||
utterance, static_cast<unsigned>(char_index));
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnMarkerEvent(int utterance_id, int char_index) {
|
||||
// Not supported yet.
|
||||
}
|
||||
|
||||
void TtsDispatcher::OnWasInterrupted(int utterance_id) {
|
||||
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 TtsDispatcher::OnWasCancelled(int utterance_id) {
|
||||
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 TtsDispatcher::OnSpeakingErrorOccurred(int utterance_id,
|
||||
const std::string& error_message) {
|
||||
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);
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium 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 CHROME_RENDERER_TTS_DISPATCHER_H_
|
||||
#define CHROME_RENDERER_TTS_DISPATCHER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/hash_tables.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;
|
||||
}
|
||||
|
||||
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 TtsDispatcher : public blink::WebSpeechSynthesizer,
|
||||
public content::RenderThreadObserver {
|
||||
public:
|
||||
explicit TtsDispatcher(blink::WebSpeechSynthesizerClient* client);
|
||||
~TtsDispatcher() override;
|
||||
|
||||
private:
|
||||
// RenderProcessObserver 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<TtsVoice>& 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.
|
||||
base::hash_map<int, blink::WebSpeechSynthesisUtterance> utterance_id_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TtsDispatcher);
|
||||
};
|
||||
|
||||
#endif // CHROME_RENDERER_TTS_DISPATCHER_H_
|
Loading…
Add table
Add a link
Reference in a new issue