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