diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-03 04:39:33 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-03 04:39:33 +0000 |
commit | 7a06d289c1556534f0aeeab6c23fe5c54be1bf97 (patch) | |
tree | 6ac260409a611f32e799bf0d50be6b8294dd5e48 /chrome/renderer | |
parent | 4ff9040e2a5683bd778f31fb30770ce790c7ae4a (diff) | |
download | chromium_src-7a06d289c1556534f0aeeab6c23fe5c54be1bf97.zip chromium_src-7a06d289c1556534f0aeeab6c23fe5c54be1bf97.tar.gz chromium_src-7a06d289c1556534f0aeeab6c23fe5c54be1bf97.tar.bz2 |
Implement web speech synthesis.
Refactors TtsController a bit so that it can be used
both by Tts extensions and by web speech. Implements
almost all of the features of the web speech API.
Requires corresponding WebKit patch:
https://bugs.webkit.org/show_bug.cgi?id=111695
BUG=171887
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/12589005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198060 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/chrome_content_renderer_client.cc | 7 | ||||
-rw-r--r-- | chrome/renderer/chrome_content_renderer_client.h | 2 | ||||
-rw-r--r-- | chrome/renderer/tts_dispatcher.cc | 199 | ||||
-rw-r--r-- | chrome/renderer/tts_dispatcher.h | 76 |
4 files changed, 284 insertions, 0 deletions
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 732ad28a..34ed018 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc @@ -68,6 +68,7 @@ #include "chrome/renderer/searchbox/searchbox_extension.h" #include "chrome/renderer/spellchecker/spellcheck.h" #include "chrome/renderer/spellchecker/spellcheck_provider.h" +#include "chrome/renderer/tts_dispatcher.h" #include "chrome/renderer/validation_message_agent.h" #include "components/autofill/renderer/autofill_agent.h" #include "components/autofill/renderer/password_autofill_agent.h" @@ -1163,6 +1164,12 @@ void ChromeContentRendererClient::RegisterPPAPIInterfaceFactories( #endif } +WebKit::WebSpeechSynthesizer* +ChromeContentRendererClient::OverrideSpeechSynthesizer( + WebKit::WebSpeechSynthesizerClient* client) { + return new TtsDispatcher(client); +} + bool ChromeContentRendererClient::AllowBrowserPlugin( WebKit::WebPluginContainer* container) const { if (CommandLine::ForCurrentProcess()->HasSwitch( diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index fbf48ad..2aa2b30 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h @@ -120,6 +120,8 @@ class ChromeContentRendererClient : public content::ContentRendererClient { WebKit::WebPluginContainer* container) const OVERRIDE; virtual void RegisterPPAPIInterfaceFactories( webkit::ppapi::PpapiInterfaceFactoryManager* factory_manager) OVERRIDE; + virtual WebKit::WebSpeechSynthesizer* OverrideSpeechSynthesizer( + WebKit::WebSpeechSynthesizerClient* client) OVERRIDE; // For testing. void SetExtensionDispatcher(extensions::Dispatcher* extension_dispatcher); diff --git a/chrome/renderer/tts_dispatcher.cc b/chrome/renderer/tts_dispatcher.cc new file mode 100644 index 0000000..e1aa2ce --- /dev/null +++ b/chrome/renderer/tts_dispatcher.cc @@ -0,0 +1,199 @@ +// 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/basictypes.h" +#include "base/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/WebKit/Source/Platform/chromium/public/WebCString.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebSpeechSynthesisUtterance.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebSpeechSynthesisVoice.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebVector.h" + +using content::RenderThread; +using WebKit::WebSpeechSynthesizerClient; +using WebKit::WebSpeechSynthesisUtterance; +using WebKit::WebSpeechSynthesisVoice; +using WebKit::WebString; +using WebKit::WebVector; + +int TtsDispatcher::next_utterance_id_ = 1; + +TtsDispatcher::TtsDispatcher(WebSpeechSynthesizerClient* client) + : synthesizer_client_(client), + main_loop_(base::MessageLoopProxy::current()) { + RenderThread::Get()->AddFilter(this); +} + +TtsDispatcher::~TtsDispatcher() { +} + +bool TtsDispatcher::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + 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_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +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.text().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); +} diff --git a/chrome/renderer/tts_dispatcher.h b/chrome/renderer/tts_dispatcher.h new file mode 100644 index 0000000..77433e7 --- /dev/null +++ b/chrome/renderer/tts_dispatcher.h @@ -0,0 +1,76 @@ +// 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/basictypes.h" +#include "base/hash_tables.h" +#include "content/public/renderer/render_view.h" +#include "ipc/ipc_channel_proxy.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebSpeechSynthesizer.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebSpeechSynthesizerClient.h" + +class RenderViewImpl; +struct TtsVoice; + +// TtsDispatcher is a delegate for methods used by WebKit for +// speech synthesis APIs. It's the complement of +// TtsDispatcherHost (owned by RenderViewHost). +class TtsDispatcher + : public WebKit::WebSpeechSynthesizer, + public IPC::ChannelProxy::MessageFilter { + public: + explicit TtsDispatcher(WebKit::WebSpeechSynthesizerClient* client); + + private: + virtual ~TtsDispatcher(); + + // IPC::ChannelProxy::MessageFilter override. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // WebKit::WebSpeechSynthesizer implementation. + virtual void updateVoiceList() OVERRIDE; + virtual void speak(const WebKit::WebSpeechSynthesisUtterance& utterance) + OVERRIDE; + virtual void pause() OVERRIDE; + virtual void resume() OVERRIDE; + virtual void cancel() OVERRIDE; + + WebKit::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. + WebKit::WebSpeechSynthesizerClient* synthesizer_client_; + + // Message loop for the main render thread. Utilized to + // ensure that callbacks into WebKit happen on the main thread + // instead of the originating IO thread. + scoped_refptr<base::MessageLoopProxy> main_loop_; + + // 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, WebKit::WebSpeechSynthesisUtterance> utterance_id_map_; + + DISALLOW_COPY_AND_ASSIGN(TtsDispatcher); +}; + +#endif // CHROME_RENDERER_TTS_DISPATCHER_H_ |