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/browser/speech/tts_message_filter.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "content/public/browser/browser_context.h"
10#include "content/public/browser/render_process_host.h"
11
12using content::BrowserThread;
13
14TtsMessageFilter::TtsMessageFilter(int render_process_id,
15                                   content::BrowserContext* browser_context)
16    : BrowserMessageFilter(TtsMsgStart),
17      render_process_id_(render_process_id),
18      browser_context_(browser_context),
19      weak_ptr_factory_(this) {
20  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
21  TtsController::GetInstance()->AddVoicesChangedDelegate(this);
22
23  // Balanced in OnChannelClosingInUIThread() to keep the ref-count be non-zero
24  // until all WeakPtr's are invalidated.
25  AddRef();
26}
27
28void TtsMessageFilter::OverrideThreadForMessage(
29    const IPC::Message& message, BrowserThread::ID* thread) {
30  switch (message.type()) {
31  case TtsHostMsg_InitializeVoiceList::ID:
32  case TtsHostMsg_Speak::ID:
33  case TtsHostMsg_Pause::ID:
34  case TtsHostMsg_Resume::ID:
35  case TtsHostMsg_Cancel::ID:
36    *thread = BrowserThread::UI;
37    break;
38  }
39}
40
41bool TtsMessageFilter::OnMessageReceived(const IPC::Message& message) {
42  bool handled = true;
43  IPC_BEGIN_MESSAGE_MAP(TtsMessageFilter, message)
44    IPC_MESSAGE_HANDLER(TtsHostMsg_InitializeVoiceList, OnInitializeVoiceList)
45    IPC_MESSAGE_HANDLER(TtsHostMsg_Speak, OnSpeak)
46    IPC_MESSAGE_HANDLER(TtsHostMsg_Pause, OnPause)
47    IPC_MESSAGE_HANDLER(TtsHostMsg_Resume, OnResume)
48    IPC_MESSAGE_HANDLER(TtsHostMsg_Cancel, OnCancel)
49    IPC_MESSAGE_UNHANDLED(handled = false)
50  IPC_END_MESSAGE_MAP()
51  return handled;
52}
53
54void TtsMessageFilter::OnChannelClosing() {
55  BrowserThread::PostTask(
56      BrowserThread::UI, FROM_HERE,
57      base::Bind(&TtsMessageFilter::OnChannelClosingInUIThread, this));
58}
59
60void TtsMessageFilter::OnDestruct() const {
61  BrowserThread::DeleteOnUIThread::Destruct(this);
62}
63
64void TtsMessageFilter::OnInitializeVoiceList() {
65  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66  TtsController* tts_controller = TtsController::GetInstance();
67  std::vector<VoiceData> voices;
68  tts_controller->GetVoices(browser_context_, &voices);
69
70  std::vector<TtsVoice> out_voices;
71  out_voices.resize(voices.size());
72  for (size_t i = 0; i < voices.size(); ++i) {
73    TtsVoice& out_voice = out_voices[i];
74    out_voice.voice_uri = voices[i].name;
75    out_voice.name = voices[i].name;
76    out_voice.lang = voices[i].lang;
77    out_voice.local_service = !voices[i].remote;
78    out_voice.is_default = (i == 0);
79  }
80  Send(new TtsMsg_SetVoiceList(out_voices));
81}
82
83void TtsMessageFilter::OnSpeak(const TtsUtteranceRequest& request) {
84  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
85
86  scoped_ptr<Utterance> utterance(new Utterance(browser_context_));
87  utterance->set_src_id(request.id);
88  utterance->set_text(request.text);
89  utterance->set_lang(request.lang);
90  utterance->set_voice_name(request.voice);
91  utterance->set_can_enqueue(true);
92
93  UtteranceContinuousParameters params;
94  params.rate = request.rate;
95  params.pitch = request.pitch;
96  params.volume = request.volume;
97  utterance->set_continuous_parameters(params);
98
99  utterance->set_event_delegate(weak_ptr_factory_.GetWeakPtr());
100
101  TtsController::GetInstance()->SpeakOrEnqueue(utterance.release());
102}
103
104void TtsMessageFilter::OnPause() {
105  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
106  TtsController::GetInstance()->Pause();
107}
108
109void TtsMessageFilter::OnResume() {
110  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111  TtsController::GetInstance()->Resume();
112}
113
114void TtsMessageFilter::OnCancel() {
115  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
116  TtsController::GetInstance()->Stop();
117}
118
119void TtsMessageFilter::OnTtsEvent(Utterance* utterance,
120                                  TtsEventType event_type,
121                                  int char_index,
122                                  const std::string& error_message) {
123  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
124  switch (event_type) {
125    case TTS_EVENT_START:
126      Send(new TtsMsg_DidStartSpeaking(utterance->src_id()));
127      break;
128    case TTS_EVENT_END:
129      Send(new TtsMsg_DidFinishSpeaking(utterance->src_id()));
130      break;
131    case TTS_EVENT_WORD:
132      Send(new TtsMsg_WordBoundary(utterance->src_id(), char_index));
133      break;
134    case TTS_EVENT_SENTENCE:
135      Send(new TtsMsg_SentenceBoundary(utterance->src_id(), char_index));
136      break;
137    case TTS_EVENT_MARKER:
138      Send(new TtsMsg_MarkerEvent(utterance->src_id(), char_index));
139      break;
140    case TTS_EVENT_INTERRUPTED:
141      Send(new TtsMsg_WasInterrupted(utterance->src_id()));
142      break;
143    case TTS_EVENT_CANCELLED:
144      Send(new TtsMsg_WasCancelled(utterance->src_id()));
145      break;
146    case TTS_EVENT_ERROR:
147      Send(new TtsMsg_SpeakingErrorOccurred(
148          utterance->src_id(), error_message));
149      break;
150    case TTS_EVENT_PAUSE:
151      Send(new TtsMsg_DidPauseSpeaking(utterance->src_id()));
152      break;
153    case TTS_EVENT_RESUME:
154      Send(new TtsMsg_DidResumeSpeaking(utterance->src_id()));
155      break;
156  }
157}
158
159void TtsMessageFilter::OnVoicesChanged() {
160  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
161  OnInitializeVoiceList();
162}
163
164void TtsMessageFilter::OnChannelClosingInUIThread() {
165  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166  TtsController::GetInstance()->RemoveVoicesChangedDelegate(this);
167
168  weak_ptr_factory_.InvalidateWeakPtrs();
169  Release();  // Balanced in TtsMessageFilter().
170}
171
172TtsMessageFilter::~TtsMessageFilter() {
173  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174  DCHECK(!weak_ptr_factory_.HasWeakPtrs());
175  TtsController::GetInstance()->RemoveVoicesChangedDelegate(this);
176}
177