// 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/WebKit/public/platform/WebCString.h" #include "third_party/WebKit/public/platform/WebSpeechSynthesisUtterance.h" #include "third_party/WebKit/public/platform/WebSpeechSynthesisVoice.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebVector.h" using content::RenderThread; using blink::WebSpeechSynthesizerClient; using blink::WebSpeechSynthesisUtterance; using blink::WebSpeechSynthesisVoice; using blink::WebString; using blink::WebVector; 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.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::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& voices) { WebVector 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(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(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); }