blob: 8f12a68f8070a9ca5b63ba9017d73f93d091a7b0 [file] [log] [blame]
// Copyright (c) 2012 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_SPEECH_SPEECH_INPUT_EXTENSION_MANAGER_H_
#define CHROME_BROWSER_SPEECH_SPEECH_INPUT_EXTENSION_MANAGER_H_
#include <string>
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/speech_recognition_event_listener.h"
class Profile;
namespace base {
class ListValue;
}
namespace content {
class NotificationRegistrar;
struct SpeechRecognitionError;
class SpeechRecognitionManager;
struct SpeechRecognitionResult;
}
namespace net {
class URLRequestContextGetter;
}
// Used for API tests.
class SpeechInputExtensionInterface {
public:
SpeechInputExtensionInterface();
virtual ~SpeechInputExtensionInterface();
// Called from the IO thread.
virtual void StartRecording(
content::SpeechRecognitionEventListener* listener,
net::URLRequestContextGetter* context_getter,
const std::string& extension_name,
const std::string& language,
const std::string& grammar,
bool filter_profanities,
int render_process_id) = 0;
virtual void StopRecording(bool recognition_failed) = 0;
virtual bool HasAudioInputDevices() = 0;
virtual bool IsCapturingAudio() = 0;
// Called from the UI thread.
virtual bool HasValidRecognizer() = 0;
};
// Manages the speech input requests and responses from the extensions
// associated to the given profile.
class SpeechInputExtensionManager
: public base::RefCountedThreadSafe<SpeechInputExtensionManager>,
public content::SpeechRecognitionEventListener,
public content::NotificationObserver,
private SpeechInputExtensionInterface {
public:
enum State {
kIdle = 0,
kStarting,
kRecording,
kStopping,
kShutdown // Internal sink state when the profile is destroyed on shutdown.
};
// Structure containing the details of the speech input failed notification.
struct ExtensionError {
std::string extension_id_;
std::string error_;
ExtensionError(const std::string& extension_id, const std::string& error)
: extension_id_(extension_id), error_(error) {}
};
typedef base::Callback<void(bool)> IsRecordingCallback;
// Should not be used directly. Managed by a ProfileKeyedServiceFactory.
explicit SpeechInputExtensionManager(Profile* profile);
// Returns the corresponding manager for the given profile, creating
// a new one if required.
static SpeechInputExtensionManager* GetForProfile(Profile* profile);
// Initialize the ProfileKeyedServiceFactory.
static void InitializeFactory();
// Request to start speech recognition for the provided extension.
bool Start(const std::string& extension_id,
const std::string& language,
const std::string& grammar,
bool filter_profanities,
std::string* error);
// Request to stop an ongoing speech recognition.
bool Stop(const std::string& extension_id, std::string* error);
// Retrieve the actual state of the API manager.
State state() const { return state_; }
// Check if recording is currently ongoing in Chrome.
// This method is expected to be called from the UI thread.
// The callback will be invoked with the result on this same thread.
void IsRecording(const IsRecordingCallback& callback);
// Called by internal ProfileKeyedService class.
void ShutdownOnUIThread();
// Methods from content::NotificationObserver.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Methods from SpeechRecognitionEventListener.
virtual void OnRecognitionStart(int session_id) OVERRIDE;
virtual void OnAudioStart(int session_id) OVERRIDE;
virtual void OnEnvironmentEstimationComplete(int session_id) OVERRIDE;
virtual void OnSoundStart(int session_id) OVERRIDE;
virtual void OnSoundEnd(int session_id) OVERRIDE;
virtual void OnAudioEnd(int session_id) OVERRIDE;
virtual void OnRecognitionResult(
int session_id, const content::SpeechRecognitionResult& result) OVERRIDE;
virtual void OnRecognitionError(
int session_id, const content::SpeechRecognitionError& error) OVERRIDE;
virtual void OnAudioLevelsChange(int session_id, float volume,
float noise_volume) OVERRIDE;
virtual void OnRecognitionEnd(int session_id) OVERRIDE;
// Methods for API testing.
void SetSpeechInputExtensionInterface(
SpeechInputExtensionInterface* speech_interface);
SpeechInputExtensionInterface* GetSpeechInputExtensionInterface();
private:
// SpeechInputExtensionInterface methods:
virtual bool IsCapturingAudio() OVERRIDE;
virtual bool HasAudioInputDevices() OVERRIDE;
virtual bool HasValidRecognizer() OVERRIDE;
virtual void StartRecording(
content::SpeechRecognitionEventListener* listener,
net::URLRequestContextGetter* context_getter,
const std::string& extension_name,
const std::string& language,
const std::string& grammar,
bool filter_profanities,
int render_process_id) OVERRIDE;
virtual void StopRecording(bool recognition_failed) OVERRIDE;
// Internal methods.
void StartOnIOThread(
scoped_refptr<net::URLRequestContextGetter> context_getter,
const std::string& extension_name,
const std::string& language,
const std::string& grammar,
bool filter_profanities,
int render_process_id);
void ForceStopOnIOThread();
void IsRecordingOnIOThread(const IsRecordingCallback& callback);
void SetRecognitionResultOnUIThread(
const content::SpeechRecognitionResult& result,
const std::string& extension_id);
void DidStartReceivingAudioOnUIThread();
void StopSucceededOnUIThread();
void IsRecordingOnUIThread(const IsRecordingCallback& callback, bool result);
void DispatchError(const std::string& error, bool dispatch_event);
void DispatchEventToExtension(const std::string& extension_id,
const std::string& event,
scoped_ptr<base::ListValue> event_args);
void ExtensionUnloaded(const std::string& extension_id);
void ResetToIdleState();
void AbortAllSessionsOnIOThread();
int GetRenderProcessIDForExtension(const std::string& extension_id) const;
virtual ~SpeechInputExtensionManager();
friend class base::RefCountedThreadSafe<SpeechInputExtensionManager>;
class Factory;
// Lock used to allow exclusive access to the state variable and methods that
// either read or write on it. This is required since the speech code
// operates in the IO thread while the extension code uses the UI thread.
base::Lock state_lock_;
// Used in the UI thread but also its raw value as notification
// source in the IO thread, guarded by the state lock and value.
Profile* profile_;
// Used in both threads, guarded by the state lock.
State state_;
std::string extension_id_in_use_;
// Used in the UI thread.
scoped_ptr<content::NotificationRegistrar> registrar_;
SpeechInputExtensionInterface* speech_interface_;
// Used in the IO thread.
bool is_recognition_in_progress_;
int speech_recognition_session_id_;
};
#endif // CHROME_BROWSER_SPEECH_SPEECH_INPUT_EXTENSION_MANAGER_H_