15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/speech/extension_api/tts_engine_extension_api.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/event_router.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_host.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_process_manager.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
17a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/speech/extension_api/tts_extension_api.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/speech/extension_api/tts_extension_api_constants.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/speech/tts_controller.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/extension_messages.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/common/console_message_level.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using extensions::EventRouter;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension;
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using extensions::ExtensionSystem;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace constants = tts_extension_api_constants;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace tts_engine_events {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kOnSpeak[] = "ttsEngine.onSpeak";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kOnStop[] = "ttsEngine.onStop";
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kOnPause[] = "ttsEngine.onPause";
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kOnResume[] = "ttsEngine.onResume";
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};  // namespace tts_engine_events
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void WarnIfMissingPauseOrResumeListener(
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Profile* profile, EventRouter* event_router, std::string extension_id) {
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool has_onpause = event_router->ExtensionHasEventListener(
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_id, tts_engine_events::kOnPause);
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool has_onresume = event_router->ExtensionHasEventListener(
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_id, tts_engine_events::kOnResume);
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (has_onpause == has_onresume)
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ExtensionProcessManager* process_manager =
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ExtensionSystem::Get(profile)->process_manager();
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  extensions::ExtensionHost* host =
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      process_manager->GetBackgroundHostForExtension(extension_id);
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  host->render_process_host()->Send(new ExtensionMsg_AddMessageToConsole(
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      host->render_view_host()->GetRoutingID(),
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      content::CONSOLE_MESSAGE_LEVEL_WARNING,
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      constants::kErrorMissingPauseOrResume));
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // anonymous namespace
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void GetExtensionVoices(Profile* profile, std::vector<VoiceData>* out_voices) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionService* service = profile->GetExtensionService();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(service);
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EventRouter* event_router =
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ExtensionSystem::Get(profile)->event_router();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(event_router);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ExtensionSet* extensions = service->extensions();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionSet::const_iterator iter;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = extensions->begin(); iter != extensions->end(); ++iter) {
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const Extension* extension = iter->get();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!event_router->ExtensionHasEventListener(
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            extension->id(), tts_engine_events::kOnSpeak) ||
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !event_router->ExtensionHasEventListener(
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            extension->id(), tts_engine_events::kOnStop)) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<extensions::TtsVoice>* tts_voices =
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::TtsVoice::GetTtsVoices(extension);
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!tts_voices)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < tts_voices->size(); ++i) {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const extensions::TtsVoice& voice = tts_voices->at(i);
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      out_voices->push_back(VoiceData());
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      VoiceData& result_voice = out_voices->back();
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      result_voice.native = false;
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result_voice.name = voice.voice_name;
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result_voice.lang = voice.lang;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result_voice.extension_id = extension->id();
95a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (voice.gender == constants::kGenderMale)
96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        result_voice.gender = TTS_GENDER_MALE;
97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      else if (voice.gender == constants::kGenderFemale)
98a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        result_voice.gender = TTS_GENDER_FEMALE;
99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      else
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        result_voice.gender = TTS_GENDER_NONE;
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::set<std::string>::const_iterator iter =
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               voice.event_types.begin();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           iter != voice.event_types.end();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           ++iter) {
106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        result_voice.events.insert(TtsEventTypeFromString(*iter));
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the extension sends end events, the controller will handle
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // queueing and send interrupted and cancelled events.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (voice.event_types.find(constants::kEventTypeEnd) !=
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          voice.event_types.end()) {
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        result_voice.events.insert(TTS_EVENT_CANCELLED);
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        result_voice.events.insert(TTS_EVENT_INTERRUPTED);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExtensionTtsEngineSpeak(Utterance* utterance, const VoiceData& voice) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if the engine supports the "end" event; if so, we can keep the
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // utterance around and track it. If not, we're finished with this
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // utterance now.
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  bool sends_end_event = voice.events.find(TTS_EVENT_END) != voice.events.end();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Set(0, Value::CreateStringValue(utterance->text()));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pass through most options to the speech engine, but remove some
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that are handled internally.
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<DictionaryValue> options(static_cast<DictionaryValue*>(
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      utterance->options()->DeepCopy()));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options->HasKey(constants::kRequiredEventTypesKey))
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options->Remove(constants::kRequiredEventTypesKey, NULL);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options->HasKey(constants::kDesiredEventTypesKey))
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options->Remove(constants::kDesiredEventTypesKey, NULL);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sends_end_event && options->HasKey(constants::kEnqueueKey))
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options->Remove(constants::kEnqueueKey, NULL);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options->HasKey(constants::kSrcIdKey))
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options->Remove(constants::kSrcIdKey, NULL);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options->HasKey(constants::kIsFinalEventKey))
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options->Remove(constants::kIsFinalEventKey, NULL);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options->HasKey(constants::kOnEventKey))
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options->Remove(constants::kOnEventKey, NULL);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  args->Set(1, options.release());
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->Set(2, Value::CreateIntegerValue(utterance->id()));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tts_engine_events::kOnSpeak, args.Pass()));
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->restrict_to_profile = utterance->profile();
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ExtensionSystem::Get(utterance->profile())->event_router()->
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DispatchEventToExtension(utterance->extension_id(), event.Pass());
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionTtsEngineStop(Utterance* utterance) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tts_engine_events::kOnStop, args.Pass()));
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->restrict_to_profile = utterance->profile();
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ExtensionSystem::Get(utterance->profile())->event_router()->
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DispatchEventToExtension(utterance->extension_id(), event.Pass());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ExtensionTtsEnginePause(Utterance* utterance) {
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      tts_engine_events::kOnPause, args.Pass()));
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Profile* profile = utterance->profile();
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  event->restrict_to_profile = profile;
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string id = utterance->extension_id();
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  event_router->DispatchEventToExtension(id, event.Pass());
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  WarnIfMissingPauseOrResumeListener(profile, event_router, id);
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ExtensionTtsEngineResume(Utterance* utterance) {
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<ListValue> args(new ListValue());
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      tts_engine_events::kOnResume, args.Pass()));
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Profile* profile = utterance->profile();
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  event->restrict_to_profile = profile;
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string id = utterance->extension_id();
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  event_router->DispatchEventToExtension(id, event.Pass());
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  WarnIfMissingPauseOrResumeListener(profile, event_router, id);
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionTtsEngineSendTtsEventFunction::RunImpl() {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int utterance_id;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &utterance_id));
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* event;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &event));
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string event_type;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event->GetString(constants::kEventTypeKey, &event_type));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int char_index = 0;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->HasKey(constants::kCharIndexKey)) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXTENSION_FUNCTION_VALIDATE(
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        event->GetInteger(constants::kCharIndexKey, &char_index));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the extension has included this event type in its manifest.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool event_type_allowed = false;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = GetExtension();
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::vector<extensions::TtsVoice>* tts_voices =
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::TtsVoice::GetTtsVoices(extension);
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!tts_voices) {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_ = constants::kErrorUndeclaredEventType;
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < tts_voices->size(); i++) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const extensions::TtsVoice& voice = tts_voices->at(i);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (voice.event_types.find(event_type) != voice.event_types.end()) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_type_allowed = true;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!event_type_allowed) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = constants::kErrorUndeclaredEventType;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TtsController* controller = TtsController::GetInstance();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event_type == constants::kEventTypeStart) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->OnTtsEvent(
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        utterance_id, TTS_EVENT_START, char_index, std::string());
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event_type == constants::kEventTypeEnd) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->OnTtsEvent(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        utterance_id, TTS_EVENT_END, char_index, std::string());
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event_type == constants::kEventTypeWord) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->OnTtsEvent(
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        utterance_id, TTS_EVENT_WORD, char_index, std::string());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event_type == constants::kEventTypeSentence) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->OnTtsEvent(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        utterance_id, TTS_EVENT_SENTENCE, char_index, std::string());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event_type == constants::kEventTypeMarker) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->OnTtsEvent(
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        utterance_id, TTS_EVENT_MARKER, char_index, std::string());
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event_type == constants::kEventTypeError) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string error_message;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event->GetString(constants::kErrorMessageKey, &error_message);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->OnTtsEvent(
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        utterance_id, TTS_EVENT_ERROR, char_index, error_message);
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (event_type == constants::kEventTypePause) {
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    controller->OnTtsEvent(
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        utterance_id, TTS_EVENT_PAUSE, char_index, std::string());
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (event_type == constants::kEventTypeResume) {
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    controller->OnTtsEvent(
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        utterance_id, TTS_EVENT_RESUME, char_index, std::string());
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXTENSION_FUNCTION_VALIDATE(false);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
261