summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-03 04:39:33 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-03 04:39:33 +0000
commit7a06d289c1556534f0aeeab6c23fe5c54be1bf97 (patch)
tree6ac260409a611f32e799bf0d50be6b8294dd5e48 /chrome/renderer
parent4ff9040e2a5683bd778f31fb30770ce790c7ae4a (diff)
downloadchromium_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.cc7
-rw-r--r--chrome/renderer/chrome_content_renderer_client.h2
-rw-r--r--chrome/renderer/tts_dispatcher.cc199
-rw-r--r--chrome/renderer/tts_dispatcher.h76
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_