summaryrefslogtreecommitdiffstats
path: root/chrome/browser/speech/extension_api
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-30 15:17:21 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-30 15:17:21 +0000
commit5537ddf13de7f74c297306aa3f138e8665b73d17 (patch)
tree153f06e4ba76ec1eb6346728d2bbfcd4031ee443 /chrome/browser/speech/extension_api
parent938c2f86e8295b2ff599d47f441889418fc828be (diff)
downloadchromium_src-5537ddf13de7f74c297306aa3f138e8665b73d17.zip
chromium_src-5537ddf13de7f74c297306aa3f138e8665b73d17.tar.gz
chromium_src-5537ddf13de7f74c297306aa3f138e8665b73d17.tar.bz2
Add Pause and Resume to Web TTS & Extension TTS APIs
The web speech spec already includes pause and resume, this completes the implementation. For parity, this change also adds support for Pause and Resume to Chrome's TTS extension API and TTS Engine extension APIs. BUG=171887 Review URL: https://chromiumcodereview.appspot.com/15108002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203146 0039d316-1c4b-4281-b951-d872f2087c98
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());