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