summaryrefslogtreecommitdiffstats
path: root/chrome/browser/speech/extension_api
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/speech/extension_api')
-rw-r--r--chrome/browser/speech/extension_api/tts_engine_extension_api.cc69
-rw-r--r--chrome/browser/speech/extension_api/tts_engine_extension_api.h8
-rw-r--r--chrome/browser/speech/extension_api/tts_extension_api.cc51
-rw-r--r--chrome/browser/speech/extension_api/tts_extension_api.h14
-rw-r--r--chrome/browser/speech/extension_api/tts_extension_api_constants.cc5
-rw-r--r--chrome/browser/speech/extension_api/tts_extension_api_constants.h3
-rw-r--r--chrome/browser/speech/extension_api/tts_extension_apitest.cc47
7 files changed, 164 insertions, 33 deletions
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
index 4c9b8d5..fa7f944 100644
--- a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
@@ -9,6 +9,8 @@
#include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
@@ -17,21 +19,50 @@
#include "chrome/browser/speech/tts_controller.h"
#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/common/console_message_level.h"
+using extensions::EventRouter;
using extensions::Extension;
+using extensions::ExtensionSystem;
namespace constants = tts_extension_api_constants;
namespace tts_engine_events {
const char kOnSpeak[] = "ttsEngine.onSpeak";
const char kOnStop[] = "ttsEngine.onStop";
+const char kOnPause[] = "ttsEngine.onPause";
+const char kOnResume[] = "ttsEngine.onResume";
}; // namespace tts_engine_events
+namespace {
+void WarnIfMissingPauseOrResumeListener(
+ Profile* profile, EventRouter* event_router, std::string extension_id) {
+ bool has_onpause = event_router->ExtensionHasEventListener(
+ extension_id, tts_engine_events::kOnPause);
+ bool has_onresume = event_router->ExtensionHasEventListener(
+ extension_id, tts_engine_events::kOnResume);
+ if (has_onpause == has_onresume)
+ return;
+
+ ExtensionProcessManager* process_manager =
+ ExtensionSystem::Get(profile)->process_manager();
+ extensions::ExtensionHost* host =
+ process_manager->GetBackgroundHostForExtension(extension_id);
+ host->render_process_host()->Send(new ExtensionMsg_AddMessageToConsole(
+ host->render_view_host()->GetRoutingID(),
+ content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ constants::kErrorMissingPauseOrResume));
+};
+} // anonymous namespace
+
void GetExtensionVoices(Profile* profile, std::vector<VoiceData>* out_voices) {
ExtensionService* service = profile->GetExtensionService();
DCHECK(service);
- extensions::EventRouter* event_router =
- extensions::ExtensionSystem::Get(profile)->event_router();
+ EventRouter* event_router =
+ ExtensionSystem::Get(profile)->event_router();
DCHECK(event_router);
const ExtensionSet* extensions = service->extensions();
@@ -118,7 +149,7 @@ void ExtensionTtsEngineSpeak(Utterance* utterance, const VoiceData& voice) {
scoped_ptr<extensions::Event> event(new extensions::Event(
tts_engine_events::kOnSpeak, args.Pass()));
event->restrict_to_profile = utterance->profile();
- extensions::ExtensionSystem::Get(utterance->profile())->event_router()->
+ ExtensionSystem::Get(utterance->profile())->event_router()->
DispatchEventToExtension(utterance->extension_id(), event.Pass());
}
@@ -127,10 +158,34 @@ void ExtensionTtsEngineStop(Utterance* utterance) {
scoped_ptr<extensions::Event> event(new extensions::Event(
tts_engine_events::kOnStop, args.Pass()));
event->restrict_to_profile = utterance->profile();
- extensions::ExtensionSystem::Get(utterance->profile())->event_router()->
+ ExtensionSystem::Get(utterance->profile())->event_router()->
DispatchEventToExtension(utterance->extension_id(), event.Pass());
}
+void ExtensionTtsEnginePause(Utterance* utterance) {
+ scoped_ptr<ListValue> args(new ListValue());
+ scoped_ptr<extensions::Event> event(new extensions::Event(
+ tts_engine_events::kOnPause, args.Pass()));
+ Profile* profile = utterance->profile();
+ event->restrict_to_profile = profile;
+ EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
+ std::string id = utterance->extension_id();
+ event_router->DispatchEventToExtension(id, event.Pass());
+ WarnIfMissingPauseOrResumeListener(profile, event_router, id);
+}
+
+void ExtensionTtsEngineResume(Utterance* utterance) {
+ scoped_ptr<ListValue> args(new ListValue());
+ scoped_ptr<extensions::Event> event(new extensions::Event(
+ tts_engine_events::kOnResume, args.Pass()));
+ Profile* profile = utterance->profile();
+ event->restrict_to_profile = profile;
+ EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
+ std::string id = utterance->extension_id();
+ event_router->DispatchEventToExtension(id, event.Pass());
+ WarnIfMissingPauseOrResumeListener(profile, event_router, id);
+}
+
bool ExtensionTtsEngineSendTtsEventFunction::RunImpl() {
int utterance_id;
std::string error_message;
@@ -192,6 +247,12 @@ bool ExtensionTtsEngineSendTtsEventFunction::RunImpl() {
event->GetString(constants::kErrorMessageKey, &error_message);
controller->OnTtsEvent(
utterance_id, TTS_EVENT_ERROR, char_index, error_message);
+ } else if (event_type == constants::kEventTypePause) {
+ controller->OnTtsEvent(
+ utterance_id, TTS_EVENT_PAUSE, char_index, std::string());
+ } else if (event_type == constants::kEventTypeResume) {
+ controller->OnTtsEvent(
+ utterance_id, TTS_EVENT_RESUME, char_index, std::string());
} else {
EXTENSION_FUNCTION_VALIDATE(false);
}
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.h b/chrome/browser/speech/extension_api/tts_engine_extension_api.h
index b87de3a..b77f4d9 100644
--- a/chrome/browser/speech/extension_api/tts_engine_extension_api.h
+++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.h
@@ -24,6 +24,8 @@ class Extension;
namespace tts_engine_events {
extern const char kOnSpeak[];
extern const char kOnStop[];
+extern const char kOnPause[];
+extern const char kOnResume[];
}
// Return a list of all available voices registered by extensions.
@@ -47,6 +49,12 @@ void ExtensionTtsEngineSpeak(Utterance* utterance,
// associated with this utterance.
void ExtensionTtsEngineStop(Utterance* utterance);
+// Pause in the middle of speaking this utterance.
+void ExtensionTtsEnginePause(Utterance* utterance);
+
+// Resume speaking this utterance.
+void ExtensionTtsEngineResume(Utterance* utterance);
+
// Hidden/internal extension function used to allow TTS engine extensions
// to send events back to the client that's calling tts.speak().
class ExtensionTtsEngineSendTtsEventFunction : public SyncExtensionFunction {
diff --git a/chrome/browser/speech/extension_api/tts_extension_api.cc b/chrome/browser/speech/extension_api/tts_extension_api.cc
index 117bf732..4137421 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_extension_api.cc
@@ -40,6 +40,10 @@ const char *TtsEventTypeToString(TtsEventType event_type) {
return constants::kEventTypeCancelled;
case TTS_EVENT_ERROR:
return constants::kEventTypeError;
+ case TTS_EVENT_PAUSE:
+ return constants::kEventTypePause;
+ case TTS_EVENT_RESUME:
+ return constants::kEventTypeResume;
default:
NOTREACHED();
return constants::kEventTypeError;
@@ -63,6 +67,10 @@ TtsEventType TtsEventTypeFromString(const std::string& str) {
return TTS_EVENT_CANCELLED;
if (str == constants::kEventTypeError)
return TTS_EVENT_ERROR;
+ if (str == constants::kEventTypePause)
+ return TTS_EVENT_PAUSE;
+ if (str == constants::kEventTypeResume)
+ return TTS_EVENT_RESUME;
NOTREACHED();
return TTS_EVENT_ERROR;
@@ -274,6 +282,16 @@ bool TtsStopSpeakingFunction::RunImpl() {
return true;
}
+bool TtsPauseFunction::RunImpl() {
+ TtsController::GetInstance()->Pause();
+ return true;
+}
+
+bool TtsResumeFunction::RunImpl() {
+ TtsController::GetInstance()->Resume();
+ return true;
+}
+
bool TtsIsSpeakingFunction::RunImpl() {
SetResult(Value::CreateBooleanValue(
TtsController::GetInstance()->IsSpeaking()));
@@ -301,35 +319,8 @@ bool TtsGetVoicesFunction::RunImpl() {
ListValue* event_types = new ListValue();
for (std::set<TtsEventType>::iterator iter = voice.events.begin();
iter != voice.events.end(); ++iter) {
- const char* event_name_constant = NULL;
- switch (*iter) {
- case TTS_EVENT_START:
- event_name_constant = constants::kEventTypeStart;
- break;
- case TTS_EVENT_END:
- event_name_constant = constants::kEventTypeEnd;
- break;
- case TTS_EVENT_WORD:
- event_name_constant = constants::kEventTypeWord;
- break;
- case TTS_EVENT_SENTENCE:
- event_name_constant = constants::kEventTypeSentence;
- break;
- case TTS_EVENT_MARKER:
- event_name_constant = constants::kEventTypeMarker;
- break;
- case TTS_EVENT_INTERRUPTED:
- event_name_constant = constants::kEventTypeInterrupted;
- break;
- case TTS_EVENT_CANCELLED:
- event_name_constant = constants::kEventTypeCancelled;
- break;
- case TTS_EVENT_ERROR:
- event_name_constant = constants::kEventTypeError;
- break;
- }
- if (event_name_constant)
- event_types->Append(Value::CreateStringValue(event_name_constant));
+ const char* event_name_constant = TtsEventTypeToString(*iter);
+ event_types->Append(Value::CreateStringValue(event_name_constant));
}
result_voice->Set(constants::kEventTypesKey, event_types);
@@ -353,6 +344,8 @@ TtsAPI::TtsAPI(Profile* profile) {
registry->RegisterFunction<TtsIsSpeakingFunction>();
registry->RegisterFunction<TtsSpeakFunction>();
registry->RegisterFunction<TtsStopSpeakingFunction>();
+ registry->RegisterFunction<TtsPauseFunction>();
+ registry->RegisterFunction<TtsResumeFunction>();
}
TtsAPI::~TtsAPI() {
diff --git a/chrome/browser/speech/extension_api/tts_extension_api.h b/chrome/browser/speech/extension_api/tts_extension_api.h
index a70d95e..e2ed95c 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api.h
+++ b/chrome/browser/speech/extension_api/tts_extension_api.h
@@ -33,6 +33,20 @@ class TtsStopSpeakingFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION("tts.stop", TTS_STOP)
};
+class TtsPauseFunction : public SyncExtensionFunction {
+ private:
+ virtual ~TtsPauseFunction() {}
+ virtual bool RunImpl() OVERRIDE;
+ DECLARE_EXTENSION_FUNCTION("tts.pause", TTS_PAUSE)
+};
+
+class TtsResumeFunction : public SyncExtensionFunction {
+ private:
+ virtual ~TtsResumeFunction() {}
+ virtual bool RunImpl() OVERRIDE;
+ DECLARE_EXTENSION_FUNCTION("tts.resume", TTS_RESUME)
+};
+
class TtsIsSpeakingFunction : public SyncExtensionFunction {
private:
virtual ~TtsIsSpeakingFunction() {}
diff --git a/chrome/browser/speech/extension_api/tts_extension_api_constants.cc b/chrome/browser/speech/extension_api/tts_extension_api_constants.cc
index 3568a8d..7b8c45b 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api_constants.cc
+++ b/chrome/browser/speech/extension_api/tts_extension_api_constants.cc
@@ -35,6 +35,8 @@ const char kEventTypeMarker[] = "marker";
const char kEventTypeInterrupted[] = "interrupted";
const char kEventTypeCancelled[] = "cancelled";
const char kEventTypeError[] = "error";
+const char kEventTypePause[] = "pause";
+const char kEventTypeResume[] = "resume";
const char kErrorUndeclaredEventType[] =
"Cannot send an event type that is not declared in the extension manifest.";
@@ -44,5 +46,8 @@ const char kErrorInvalidGender[] = "Invalid gender.";
const char kErrorInvalidRate[] = "Invalid rate.";
const char kErrorInvalidPitch[] = "Invalid pitch.";
const char kErrorInvalidVolume[] = "Invalid volume.";
+const char kErrorMissingPauseOrResume[] =
+ "A TTS engine extension should either listen for both onPause and onResume "
+ "events, or neither.";
} // namespace tts_extension_api_constants.
diff --git a/chrome/browser/speech/extension_api/tts_extension_api_constants.h b/chrome/browser/speech/extension_api/tts_extension_api_constants.h
index 3270e97..0809473 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api_constants.h
+++ b/chrome/browser/speech/extension_api/tts_extension_api_constants.h
@@ -40,6 +40,8 @@ extern const char kEventTypeMarker[];
extern const char kEventTypeInterrupted[];
extern const char kEventTypeCancelled[];
extern const char kEventTypeError[];
+extern const char kEventTypePause[];
+extern const char kEventTypeResume[];
extern const char kErrorUndeclaredEventType[];
extern const char kErrorUtteranceTooLong[];
@@ -48,6 +50,7 @@ extern const char kErrorInvalidGender[];
extern const char kErrorInvalidRate[];
extern const char kErrorInvalidPitch[];
extern const char kErrorInvalidVolume[];
+extern const char kErrorMissingPauseOrResume[];
} // namespace tts_extension_api_constants.
#endif // CHROME_BROWSER_SPEECH_EXTENSION_API_TTS_EXTENSION_API_CONSTANTS_H_
diff --git a/chrome/browser/speech/extension_api/tts_extension_apitest.cc b/chrome/browser/speech/extension_api/tts_extension_apitest.cc
index dc4dc90..fcf86b1 100644
--- a/chrome/browser/speech/extension_api/tts_extension_apitest.cc
+++ b/chrome/browser/speech/extension_api/tts_extension_apitest.cc
@@ -24,9 +24,14 @@ using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;
+using ::testing::SaveArg;
using ::testing::StrictMock;
using ::testing::_;
+namespace {
+int g_saved_utterance_id;
+}
+
class MockTtsPlatformImpl : public TtsPlatformImpl {
public:
MockTtsPlatformImpl()
@@ -45,6 +50,10 @@ class MockTtsPlatformImpl : public TtsPlatformImpl {
MOCK_METHOD0(StopSpeaking, bool(void));
+ MOCK_METHOD0(Pause, void(void));
+
+ MOCK_METHOD0(Resume, void(void));
+
MOCK_METHOD0(IsSpeaking, bool(void));
MOCK_METHOD1(GetVoices, void(std::vector<VoiceData>*));
@@ -53,6 +62,15 @@ class MockTtsPlatformImpl : public TtsPlatformImpl {
set_error("epic fail");
}
+ void SendEndEventOnSavedUtteranceId() {
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(
+ &MockTtsPlatformImpl::SendEvent,
+ ptr_factory_.GetWeakPtr(),
+ false, g_saved_utterance_id, TTS_EVENT_END, 0, std::string()),
+ base::TimeDelta());
+ }
+
void SendEndEvent(int utterance_id,
const std::string& utterance,
const std::string& lang,
@@ -276,6 +294,35 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformWordCallbacks) {
ASSERT_TRUE(RunExtensionTest("tts/word_callbacks")) << message_;
}
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformPauseResume) {
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .Times(AnyNumber());
+
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, Speak(_, "test 1", _, _, _))
+ .WillOnce(DoAll(
+ Invoke(&mock_platform_impl_,
+ &MockTtsPlatformImpl::SendEndEvent),
+ Return(true)));
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak(_, "test 2", _, _, _))
+ .WillOnce(DoAll(
+ SaveArg<0>(&g_saved_utterance_id),
+ Return(true)));
+ EXPECT_CALL(mock_platform_impl_, Pause());
+ EXPECT_CALL(mock_platform_impl_, Resume())
+ .WillOnce(
+ InvokeWithoutArgs(
+ &mock_platform_impl_,
+ &MockTtsPlatformImpl::SendEndEventOnSavedUtteranceId));
+ ASSERT_TRUE(RunExtensionTest("tts/pause_resume")) << message_;
+}
+
+//
+// TTS Engine tests.
+//
+
IN_PROC_BROWSER_TEST_F(TtsApiTest, RegisterEngine) {
EXPECT_CALL(mock_platform_impl_, IsSpeaking())
.Times(AnyNumber());