1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/renderer/tts_dispatcher.h" 6 7 #include "base/basictypes.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/common/tts_messages.h" 10 #include "chrome/common/tts_utterance_request.h" 11 #include "content/public/renderer/render_thread.h" 12 #include "third_party/WebKit/public/platform/WebCString.h" 13 #include "third_party/WebKit/public/platform/WebSpeechSynthesisUtterance.h" 14 #include "third_party/WebKit/public/platform/WebSpeechSynthesisVoice.h" 15 #include "third_party/WebKit/public/platform/WebString.h" 16 #include "third_party/WebKit/public/platform/WebVector.h" 17 18 using content::RenderThread; 19 using blink::WebSpeechSynthesizerClient; 20 using blink::WebSpeechSynthesisUtterance; 21 using blink::WebSpeechSynthesisVoice; 22 using blink::WebString; 23 using blink::WebVector; 24 25 int TtsDispatcher::next_utterance_id_ = 1; 26 27 TtsDispatcher::TtsDispatcher(WebSpeechSynthesizerClient* client) 28 : synthesizer_client_(client) { 29 RenderThread::Get()->AddObserver(this); 30 } 31 32 TtsDispatcher::~TtsDispatcher() { 33 RenderThread::Get()->RemoveObserver(this); 34 } 35 36 bool TtsDispatcher::OnControlMessageReceived(const IPC::Message& message) { 37 IPC_BEGIN_MESSAGE_MAP(TtsDispatcher, message) 38 IPC_MESSAGE_HANDLER(TtsMsg_SetVoiceList, OnSetVoiceList) 39 IPC_MESSAGE_HANDLER(TtsMsg_DidStartSpeaking, OnDidStartSpeaking) 40 IPC_MESSAGE_HANDLER(TtsMsg_DidFinishSpeaking, OnDidFinishSpeaking) 41 IPC_MESSAGE_HANDLER(TtsMsg_DidPauseSpeaking, OnDidPauseSpeaking) 42 IPC_MESSAGE_HANDLER(TtsMsg_DidResumeSpeaking, OnDidResumeSpeaking) 43 IPC_MESSAGE_HANDLER(TtsMsg_WordBoundary, OnWordBoundary) 44 IPC_MESSAGE_HANDLER(TtsMsg_SentenceBoundary, OnSentenceBoundary) 45 IPC_MESSAGE_HANDLER(TtsMsg_MarkerEvent, OnMarkerEvent) 46 IPC_MESSAGE_HANDLER(TtsMsg_WasInterrupted, OnWasInterrupted) 47 IPC_MESSAGE_HANDLER(TtsMsg_WasCancelled, OnWasCancelled) 48 IPC_MESSAGE_HANDLER(TtsMsg_SpeakingErrorOccurred, OnSpeakingErrorOccurred) 49 IPC_END_MESSAGE_MAP() 50 51 // Always return false because there may be multiple TtsDispatchers 52 // and we want them all to have a chance to handle this message. 53 return false; 54 } 55 56 void TtsDispatcher::updateVoiceList() { 57 RenderThread::Get()->Send(new TtsHostMsg_InitializeVoiceList()); 58 } 59 60 void TtsDispatcher::speak(const WebSpeechSynthesisUtterance& web_utterance) { 61 int id = next_utterance_id_++; 62 63 utterance_id_map_[id] = web_utterance; 64 65 TtsUtteranceRequest utterance; 66 utterance.id = id; 67 utterance.text = web_utterance.text().utf8(); 68 utterance.lang = web_utterance.lang().utf8(); 69 utterance.voice = web_utterance.voice().utf8(); 70 utterance.volume = web_utterance.volume(); 71 utterance.rate = web_utterance.rate(); 72 utterance.pitch = web_utterance.pitch(); 73 RenderThread::Get()->Send(new TtsHostMsg_Speak(utterance)); 74 } 75 76 void TtsDispatcher::pause() { 77 RenderThread::Get()->Send(new TtsHostMsg_Pause()); 78 } 79 80 void TtsDispatcher::resume() { 81 RenderThread::Get()->Send(new TtsHostMsg_Resume()); 82 } 83 84 void TtsDispatcher::cancel() { 85 RenderThread::Get()->Send(new TtsHostMsg_Cancel()); 86 } 87 88 WebSpeechSynthesisUtterance TtsDispatcher::FindUtterance(int utterance_id) { 89 base::hash_map<int, WebSpeechSynthesisUtterance>::const_iterator iter = 90 utterance_id_map_.find(utterance_id); 91 if (iter == utterance_id_map_.end()) 92 return WebSpeechSynthesisUtterance(); 93 return iter->second; 94 } 95 96 void TtsDispatcher::OnSetVoiceList(const std::vector<TtsVoice>& voices) { 97 WebVector<WebSpeechSynthesisVoice> out_voices(voices.size()); 98 for (size_t i = 0; i < voices.size(); ++i) { 99 out_voices[i] = WebSpeechSynthesisVoice(); 100 out_voices[i].setVoiceURI(WebString::fromUTF8(voices[i].voice_uri)); 101 out_voices[i].setName(WebString::fromUTF8(voices[i].name)); 102 out_voices[i].setLanguage(WebString::fromUTF8(voices[i].lang)); 103 out_voices[i].setIsLocalService(voices[i].local_service); 104 out_voices[i].setIsDefault(voices[i].is_default); 105 } 106 synthesizer_client_->setVoiceList(out_voices); 107 } 108 109 void TtsDispatcher::OnDidStartSpeaking(int utterance_id) { 110 if (utterance_id_map_.find(utterance_id) == utterance_id_map_.end()) 111 return; 112 113 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 114 if (utterance.isNull()) 115 return; 116 117 synthesizer_client_->didStartSpeaking(utterance); 118 } 119 120 void TtsDispatcher::OnDidFinishSpeaking(int utterance_id) { 121 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 122 if (utterance.isNull()) 123 return; 124 125 synthesizer_client_->didFinishSpeaking(utterance); 126 utterance_id_map_.erase(utterance_id); 127 } 128 129 void TtsDispatcher::OnDidPauseSpeaking(int utterance_id) { 130 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 131 if (utterance.isNull()) 132 return; 133 134 synthesizer_client_->didPauseSpeaking(utterance); 135 } 136 137 void TtsDispatcher::OnDidResumeSpeaking(int utterance_id) { 138 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 139 if (utterance.isNull()) 140 return; 141 142 synthesizer_client_->didResumeSpeaking(utterance); 143 } 144 145 void TtsDispatcher::OnWordBoundary(int utterance_id, int char_index) { 146 CHECK(char_index >= 0); 147 148 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 149 if (utterance.isNull()) 150 return; 151 152 synthesizer_client_->wordBoundaryEventOccurred( 153 utterance, static_cast<unsigned>(char_index)); 154 } 155 156 void TtsDispatcher::OnSentenceBoundary(int utterance_id, int char_index) { 157 CHECK(char_index >= 0); 158 159 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 160 if (utterance.isNull()) 161 return; 162 163 synthesizer_client_->sentenceBoundaryEventOccurred( 164 utterance, static_cast<unsigned>(char_index)); 165 } 166 167 void TtsDispatcher::OnMarkerEvent(int utterance_id, int char_index) { 168 // Not supported yet. 169 } 170 171 void TtsDispatcher::OnWasInterrupted(int utterance_id) { 172 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 173 if (utterance.isNull()) 174 return; 175 176 // The web speech API doesn't support "interrupted". 177 synthesizer_client_->didFinishSpeaking(utterance); 178 utterance_id_map_.erase(utterance_id); 179 } 180 181 void TtsDispatcher::OnWasCancelled(int utterance_id) { 182 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 183 if (utterance.isNull()) 184 return; 185 186 // The web speech API doesn't support "cancelled". 187 synthesizer_client_->didFinishSpeaking(utterance); 188 utterance_id_map_.erase(utterance_id); 189 } 190 191 void TtsDispatcher::OnSpeakingErrorOccurred(int utterance_id, 192 const std::string& error_message) { 193 WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); 194 if (utterance.isNull()) 195 return; 196 197 // The web speech API doesn't support an error message. 198 synthesizer_client_->speakingErrorOccurred(utterance); 199 utterance_id_map_.erase(utterance_id); 200 } 201