// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_
#include <queue>
#include <string>
#include "base/memory/singleton.h"
#include "base/task.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_tts_api_util.h"
// Abstract class that defines the native platform TTS interface.
class ExtensionTtsPlatformImpl {
public:
static ExtensionTtsPlatformImpl* GetInstance();
// Speak the given utterance with the given parameters if possible,
// and return true on success. Utterance will always be nonempty.
// If the user does not specify the other values, then locale and gender
// will be empty strings, and rate, pitch, and volume will be -1.0.
//
// The ExtensionTtsController will only try to speak one utterance at
// a time. If it wants to interrupt speech, it will always call Stop
// before speaking again, otherwise it will wait until IsSpeaking
// returns false before calling Speak again.
virtual bool Speak(
const std::string& utterance,
const std::string& locale,
const std::string& gender,
double rate,
double pitch,
double volume) = 0;
// Stop speaking immediately and return true on success.
virtual bool StopSpeaking() = 0;
// Return true if the synthesis engine is currently speaking.
virtual bool IsSpeaking() = 0;
virtual std::string error();
virtual void clear_error();
virtual void set_error(const std::string& error);
protected:
ExtensionTtsPlatformImpl() {}
virtual ~ExtensionTtsPlatformImpl() {}
std::string error_;
DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImpl);
};
// One speech utterance.
class Utterance {
public:
// Construct an utterance given a profile, the text to speak,
// the options passed to tts.speak, and a completion task to call
// when the utterance is done speaking.
Utterance(Profile* profile,
const std::string& text,
DictionaryValue* options,
Task* completion_task);
~Utterance();
// Calls the completion task and then destroys itself.
void FinishAndDestroy();
void set_error(const std::string& error) { error_ = error; }
void set_extension_id(const std::string& extension_id) {
extension_id_ = extension_id;
}
// Accessors
Profile* profile() { return profile_; }
const std::string& extension_id() { return extension_id_; }
int id() { return id_; }
const std::string& text() { return text_; }
const Value* options() { return options_.get(); }
const std::string& voice_name() { return voice_name_; }
const std::string& locale() { return locale_; }
const std::string& gender() { return gender_; }
double rate() { return rate_; }
double pitch() { return pitch_; }
double volume() { return volume_; }
bool can_enqueue() { return can_enqueue_; }
const std::string& error() { return error_; }
private:
// The profile that initiated this utterance.
Profile* profile_;
// The extension ID of the extension providing TTS for this utterance, or
// empty if native TTS is being used.
std::string extension_id_;
// The unique ID of this utterance, used to associate callback functions
// with utterances.
int id_;
// The id of the next utterance, so we can associate requests with
// responses.
static int next_utterance_id_;
// The text to speak.
std::string text_;
// The full options arg passed to tts.speak, which may include fields
// other than the ones we explicitly parse, below.
scoped_ptr<Value> options_;
// The parsed options.
std::string voice_name_;
std::string locale_;
std::string gender_;
double rate_;
double pitch_;
double volume_;
bool can_enqueue_;
// The error string to pass to the completion task. Will be empty if
// no error occurred.
std::string error_;
// The method to call when this utterance has completed speaking.
Task* completion_task_;
};
// Singleton class that manages text-to-speech.
class ExtensionTtsController {
public:
// Get the single instance of this class.
static ExtensionTtsController* GetInstance();
// Returns true if we're currently speaking an utterance.
bool IsSpeaking() const;
// Speak the given utterance. If the utterance's can_enqueue flag is true
// and another utterance is in progress, adds it to the end of the queue.
// Otherwise, interrupts any current utterance and speaks this one
// immediately.
void SpeakOrEnqueue(Utterance* utterance);
// Stop all utterances and flush the queue.
void Stop();
// Called when an extension finishes speaking an utterance.
void OnSpeechFinished(int request_id, const std::string& error_message);
// For unit testing.
void SetPlatformImpl(ExtensionTtsPlatformImpl* platform_impl);
private:
ExtensionTtsController();
virtual ~ExtensionTtsController();
// Get the platform TTS implementation (or injected mock).
ExtensionTtsPlatformImpl* GetPlatformImpl();
// Start speaking the given utterance. Will either take ownership of
// |utterance| or delete it if there's an error.
void SpeakNow(Utterance* utterance);
// Called periodically when speech is ongoing. Checks to see if the
// underlying platform speech system has finished the current utterance,
// and if so finishes it and pops the next utterance off the queue.
void CheckSpeechStatus();
// Clear the utterance queue.
void ClearUtteranceQueue();
// Finalize and delete the current utterance.
void FinishCurrentUtterance();
// Start speaking the next utterance in the queue.
void SpeakNextUtterance();
// Return the id string of the first extension with tts_voices in its
// manifest that matches the speech parameters of this utterance,
// or the empty string if none is found.
std::string GetMatchingExtensionId(Utterance* utterance);
ScopedRunnableMethodFactory<ExtensionTtsController> method_factory_;
friend struct DefaultSingletonTraits<ExtensionTtsController>;
// The current utterance being spoken.
Utterance* current_utterance_;
// A queue of utterances to speak after the current one finishes.
std::queue<Utterance*> utterance_queue_;
// A pointer to the platform implementation of text-to-speech, for
// dependency injection.
ExtensionTtsPlatformImpl* platform_impl_;
DISALLOW_COPY_AND_ASSIGN(ExtensionTtsController);
};
//
// Extension API function definitions
//
class ExtensionTtsSpeakFunction : public AsyncExtensionFunction {
private:
~ExtensionTtsSpeakFunction() {}
virtual bool RunImpl();
void SpeechFinished();
Utterance* utterance_;
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speak")
};
class ExtensionTtsStopSpeakingFunction : public SyncExtensionFunction {
private:
~ExtensionTtsStopSpeakingFunction() {}
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.stop")
};
class ExtensionTtsIsSpeakingFunction : public SyncExtensionFunction {
private:
~ExtensionTtsIsSpeakingFunction() {}
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.isSpeaking")
};
class ExtensionTtsSpeakCompletedFunction : public SyncExtensionFunction {
private:
~ExtensionTtsSpeakCompletedFunction() {}
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speakCompleted")
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_