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"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/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"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebCString.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebSpeechSynthesisUtterance.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebSpeechSynthesisVoice.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebString.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/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() {
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  RenderThread::Get()->RemoveObserver(this);
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool TtsDispatcher::OnControlMessageReceived(const IPC::Message& message) {
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool handled = true;
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(TtsDispatcher, message)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_SetVoiceList, OnSetVoiceList)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_DidStartSpeaking, OnDidStartSpeaking)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_DidFinishSpeaking, OnDidFinishSpeaking)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_DidPauseSpeaking, OnDidPauseSpeaking)
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_DidResumeSpeaking, OnDidResumeSpeaking)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_WordBoundary, OnWordBoundary)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_SentenceBoundary, OnSentenceBoundary)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_MarkerEvent, OnMarkerEvent)
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_WasInterrupted, OnWasInterrupted)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_WasCancelled, OnWasCancelled)
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_HANDLER(TtsMsg_SpeakingErrorOccurred, OnSpeakingErrorOccurred)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IPC_END_MESSAGE_MAP()
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return handled;
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::updateVoiceList() {
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RenderThread::Get()->Send(new TtsHostMsg_InitializeVoiceList());
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::speak(const WebSpeechSynthesisUtterance& web_utterance) {
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int id = next_utterance_id_++;
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance_id_map_[id] = web_utterance;
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TtsUtteranceRequest utterance;
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.id = id;
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.text = web_utterance.text().utf8();
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.lang = web_utterance.lang().utf8();
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.voice = web_utterance.voice().utf8();
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.volume = web_utterance.volume();
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.rate = web_utterance.rate();
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance.pitch = web_utterance.pitch();
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RenderThread::Get()->Send(new TtsHostMsg_Speak(utterance));
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::pause() {
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RenderThread::Get()->Send(new TtsHostMsg_Pause());
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::resume() {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RenderThread::Get()->Send(new TtsHostMsg_Resume());
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::cancel() {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RenderThread::Get()->Send(new TtsHostMsg_Cancel());
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)WebSpeechSynthesisUtterance TtsDispatcher::FindUtterance(int utterance_id) {
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::hash_map<int, WebSpeechSynthesisUtterance>::const_iterator iter =
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      utterance_id_map_.find(utterance_id);
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (iter == utterance_id_map_.end())
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return WebSpeechSynthesisUtterance();
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return iter->second;
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnSetVoiceList(const std::vector<TtsVoice>& voices) {
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebVector<WebSpeechSynthesisVoice> out_voices(voices.size());
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < voices.size(); ++i) {
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_voices[i] = WebSpeechSynthesisVoice();
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_voices[i].setVoiceURI(WebString::fromUTF8(voices[i].voice_uri));
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_voices[i].setName(WebString::fromUTF8(voices[i].name));
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_voices[i].setLanguage(WebString::fromUTF8(voices[i].lang));
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_voices[i].setIsLocalService(voices[i].local_service);
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_voices[i].setIsDefault(voices[i].is_default);
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->setVoiceList(out_voices);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnDidStartSpeaking(int utterance_id) {
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance_id_map_.find(utterance_id) == utterance_id_map_.end())
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->didStartSpeaking(utterance);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnDidFinishSpeaking(int utterance_id) {
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->didFinishSpeaking(utterance);
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance_id_map_.erase(utterance_id);
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnDidPauseSpeaking(int utterance_id) {
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->didPauseSpeaking(utterance);
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnDidResumeSpeaking(int utterance_id) {
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->didResumeSpeaking(utterance);
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnWordBoundary(int utterance_id, int char_index) {
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(char_index >= 0);
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->wordBoundaryEventOccurred(
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      utterance, static_cast<unsigned>(char_index));
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnSentenceBoundary(int utterance_id, int char_index) {
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(char_index >= 0);
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->sentenceBoundaryEventOccurred(
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      utterance, static_cast<unsigned>(char_index));
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnMarkerEvent(int utterance_id, int char_index) {
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Not supported yet.
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnWasInterrupted(int utterance_id) {
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The web speech API doesn't support "interrupted".
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->didFinishSpeaking(utterance);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance_id_map_.erase(utterance_id);
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnWasCancelled(int utterance_id) {
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The web speech API doesn't support "cancelled".
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->didFinishSpeaking(utterance);
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance_id_map_.erase(utterance_id);
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TtsDispatcher::OnSpeakingErrorOccurred(int utterance_id,
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            const std::string& error_message) {
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id);
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (utterance.isNull())
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The web speech API doesn't support an error message.
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  synthesizer_client_->speakingErrorOccurred(utterance);
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  utterance_id_map_.erase(utterance_id);
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
200