summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcalamity <calamity@chromium.org>2015-04-07 01:33:05 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-07 08:33:36 +0000
commit509ce7f973d5755f1b59657325e03f31e6308af0 (patch)
tree69e43f7680122a36c6134e614a61412fd0a1ee5c
parent3a672fe050438bc787af3f9bb652048291558c6c (diff)
downloadchromium_src-509ce7f973d5755f1b59657325e03f31e6308af0.zip
chromium_src-509ce7f973d5755f1b59657325e03f31e6308af0.tar.gz
chromium_src-509ce7f973d5755f1b59657325e03f31e6308af0.tar.bz2
Notify hotwording extension of microphone state change.
This CL notifies the hotwording extension of a microphone state change by adding a hotwordPrivate.onMicrophoneStateChanged event which triggers an update of the hotwording state. It also moves the media device observation from HotwordServiceFactory to HotwordService. BUG=461787 TBR=estade@chromium.org Review URL: https://codereview.chromium.org/1047973003 Cr-Commit-Position: refs/heads/master@{#324024}
-rw-r--r--chrome/browser/extensions/api/hotword_private/hotword_private_api.cc12
-rw-r--r--chrome/browser/extensions/api/hotword_private/hotword_private_api.h4
-rw-r--r--chrome/browser/resources/hotword/page_audio_manager.js19
-rw-r--r--chrome/browser/search/hotword_service.cc41
-rw-r--r--chrome/browser/search/hotword_service.h21
-rw-r--r--chrome/browser/search/hotword_service_factory.cc31
-rw-r--r--chrome/browser/search/hotword_service_factory.h32
-rw-r--r--chrome/browser/ui/webui/voice_search_ui.cc8
-rw-r--r--chrome/common/extensions/api/hotword_private.idl3
9 files changed, 95 insertions, 76 deletions
diff --git a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
index d38013a..7ea2b0b 100644
--- a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
+++ b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
@@ -106,11 +106,21 @@ void HotwordPrivateEventService::OnSpeakerModelExists() {
SignalEvent(api::hotword_private::OnSpeakerModelExists::kEventName);
}
+void HotwordPrivateEventService::OnMicrophoneStateChanged(bool enabled) {
+ SignalEvent(api::hotword_private::OnMicrophoneStateChanged::kEventName,
+ api::hotword_private::OnMicrophoneStateChanged::Create(enabled));
+}
+
void HotwordPrivateEventService::SignalEvent(const std::string& event_name) {
+ SignalEvent(event_name, make_scoped_ptr(new base::ListValue()));
+}
+
+void HotwordPrivateEventService::SignalEvent(const std::string& event_name,
+ scoped_ptr<base::ListValue> args) {
EventRouter* router = EventRouter::Get(profile_);
if (!router || !router->HasEventListener(event_name))
return;
- scoped_ptr<base::ListValue> args(new base::ListValue());
+
scoped_ptr<Event> event(new Event(event_name, args.Pass()));
router->BroadcastEvent(event.Pass());
}
diff --git a/chrome/browser/extensions/api/hotword_private/hotword_private_api.h b/chrome/browser/extensions/api/hotword_private/hotword_private_api.h
index 1272ded..d25b5b7 100644
--- a/chrome/browser/extensions/api/hotword_private/hotword_private_api.h
+++ b/chrome/browser/extensions/api/hotword_private/hotword_private_api.h
@@ -44,10 +44,14 @@ class HotwordPrivateEventService : public BrowserContextKeyedAPI {
void OnSpeakerModelExists();
+ void OnMicrophoneStateChanged(bool enabled);
+
private:
friend class BrowserContextKeyedAPIFactory<HotwordPrivateEventService>;
void SignalEvent(const std::string& event_name);
+ void SignalEvent(const std::string& event_name,
+ scoped_ptr<base::ListValue> args);
Profile* profile_;
PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/resources/hotword/page_audio_manager.js b/chrome/browser/resources/hotword/page_audio_manager.js
index a845828..067ff4e 100644
--- a/chrome/browser/resources/hotword/page_audio_manager.js
+++ b/chrome/browser/resources/hotword/page_audio_manager.js
@@ -35,6 +35,8 @@ cr.define('hotword', function() {
this.tabCreatedListener_ = this.handleCreatedTab_.bind(this);
this.tabUpdatedListener_ = this.handleUpdatedTab_.bind(this);
this.tabActivatedListener_ = this.handleActivatedTab_.bind(this);
+ this.microphoneStateChangedListener_ =
+ this.handleMicrophoneStateChanged_.bind(this);
this.windowFocusChangedListener_ = this.handleChangedWindow_.bind(this);
this.messageListener_ = this.handleMessageFromPage_.bind(this);
@@ -237,6 +239,19 @@ cr.define('hotword', function() {
this.updateTabState_();
},
+ /**
+ * Handles the microphone state changing.
+ * @param {boolean} enabled Whether the microphone is now enabled.
+ * @private
+ */
+ handleMicrophoneStateChanged_: function(enabled) {
+ if (enabled) {
+ this.updateTabState_();
+ return;
+ }
+
+ this.stopHotwording_();
+ },
/**
* Handles a change in Chrome windows.
@@ -492,6 +507,8 @@ cr.define('hotword', function() {
chrome.tabs.onActivated.addListener(this.tabActivatedListener_);
chrome.windows.onFocusChanged.addListener(
this.windowFocusChangedListener_);
+ chrome.hotwordPrivate.onMicrophoneStateChanged.addListener(
+ this.microphoneStateChangedListener_);
if (chrome.runtime.onMessage.hasListener(this.messageListener_))
return;
chrome.runtime.onMessageExternal.addListener(
@@ -509,6 +526,8 @@ cr.define('hotword', function() {
chrome.tabs.onActivated.removeListener(this.tabActivatedListener_);
chrome.windows.onFocusChanged.removeListener(
this.windowFocusChangedListener_);
+ chrome.hotwordPrivate.onMicrophoneStateChanged.removeListener(
+ this.microphoneStateChangedListener_);
// Don't remove the Message listener, as we want them listening all
// the time,
},
diff --git a/chrome/browser/search/hotword_service.cc b/chrome/browser/search/hotword_service.cc
index 6ee699f..db9d85f 100644
--- a/chrome/browser/search/hotword_service.cc
+++ b/chrome/browser/search/hotword_service.cc
@@ -323,6 +323,8 @@ void HotwordService::HotwordWebstoreInstaller::Shutdown() {
HotwordService::HotwordService(Profile* profile)
: profile_(profile),
extension_registry_observer_(this),
+ microphone_available_(false),
+ audio_device_state_updated_(false),
client_(NULL),
error_message_(0),
reinstall_pending_(false),
@@ -386,6 +388,13 @@ HotwordService::HotwordService(Profile* profile)
session_observer_.get());
}
#endif
+
+ // Register with the device observer list to update the microphone
+ // availability.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&HotwordService::InitializeMicrophoneObserver,
+ base::Unretained(this)));
}
HotwordService::~HotwordService() {
@@ -456,6 +465,10 @@ std::string HotwordService::ReinstalledExtensionId() {
return extension_misc::kHotwordSharedModuleId;
}
+void HotwordService::InitializeMicrophoneObserver() {
+ MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this);
+}
+
void HotwordService::InstalledFromWebstoreCallback(
int num_tries,
bool success,
@@ -605,19 +618,16 @@ bool HotwordService::IsServiceAvailable() {
RecordErrorMetrics(error_message_);
- // Determine if the proper audio capabilities exist.
- // The first time this is called, it probably won't return in time, but that's
- // why it won't be included in the error calculation (i.e., the call to
- // IsAudioDeviceStateUpdated()). However, this use case is rare and typically
- // the devices will be initialized by the time a user goes to settings.
- bool audio_device_state_updated =
- HotwordServiceFactory::IsAudioDeviceStateUpdated();
+ // Determine if the proper audio capabilities exist. The first time this is
+ // called, it probably won't return in time, but that's why it won't be
+ // included in the error calculation. However, this use case is rare and
+ // typically the devices will be initialized by the time a user goes to
+ // settings.
HotwordServiceFactory::GetInstance()->UpdateMicrophoneState();
- if (audio_device_state_updated) {
+ if (audio_device_state_updated_) {
bool audio_capture_allowed =
profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed);
- if (!audio_capture_allowed ||
- !HotwordServiceFactory::IsMicrophoneAvailable())
+ if (!audio_capture_allowed || !microphone_available_)
error_message_ = IDS_HOTWORD_MICROPHONE_ERROR_MESSAGE;
}
@@ -772,6 +782,17 @@ void HotwordService::DisableHotwordPreferences() {
}
}
+void HotwordService::OnUpdateAudioDevices(
+ const content::MediaStreamDevices& devices) {
+ bool microphone_was_available = microphone_available_;
+ microphone_available_ = !devices.empty();
+ audio_device_state_updated_ = true;
+ HotwordPrivateEventService* event_service =
+ BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_);
+ if (event_service && microphone_was_available != microphone_available_)
+ event_service->OnMicrophoneStateChanged(microphone_available_);
+}
+
void HotwordService::OnHotwordAlwaysOnSearchEnabledChanged(
const std::string& pref_name) {
// If the pref for always on has been changed in some way, that means that
diff --git a/chrome/browser/search/hotword_service.h b/chrome/browser/search/hotword_service.h
index 9b22c84..2d2394a 100644
--- a/chrome/browser/search/hotword_service.h
+++ b/chrome/browser/search/hotword_service.h
@@ -12,6 +12,7 @@
#include "base/prefs/pref_change_registrar.h"
#include "base/scoped_observer.h"
#include "chrome/browser/extensions/webstore_startup_installer.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "chrome/common/extensions/webstore_install_result.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
@@ -38,7 +39,8 @@ extern const char kHotwordTrainingEnabled[];
// Provides an interface for the Hotword component that does voice triggered
// search.
-class HotwordService : public extensions::ExtensionRegistryObserver,
+class HotwordService : public MediaCaptureDevicesDispatcher::Observer,
+ public extensions::ExtensionRegistryObserver,
public KeyedService {
public:
// A simple subclass to allow for aborting an install during shutdown.
@@ -125,6 +127,8 @@ class HotwordService : public extensions::ExtensionRegistryObserver,
// no error.
int error_message() { return error_message_; }
+ bool microphone_available() { return microphone_available_; }
+
// These methods are for launching, and getting and setting the launch mode of
// the Hotword Audio Verification App.
//
@@ -174,6 +178,10 @@ class HotwordService : public extensions::ExtensionRegistryObserver,
// Turn off the currently enabled version of hotwording if one exists.
void DisableHotwordPreferences();
+ // Overridden from MediaCaptureDevicesDispatcher::Observer
+ void OnUpdateAudioDevices(
+ const content::MediaStreamDevices& devices) override;
+
protected:
// Used in test subclasses.
scoped_refptr<HotwordWebstoreInstaller> installer_;
@@ -181,6 +189,10 @@ class HotwordService : public extensions::ExtensionRegistryObserver,
private:
class HotwordUserSessionStateObserver;
+ // Must be called from the UI thread since the instance of
+ // MediaCaptureDevicesDispatcher can only be accessed on the UI thread.
+ void InitializeMicrophoneObserver();
+
// Callback for webstore extension installer.
void InstalledFromWebstoreCallback(
int num_tries,
@@ -207,6 +219,13 @@ class HotwordService : public extensions::ExtensionRegistryObserver,
scoped_ptr<HotwordAudioHistoryHandler> audio_history_handler_;
+ bool microphone_available_;
+
+ // Indicates if the check for audio devices has been run such that it can be
+ // included in the error checking. Audio checking is not done immediately
+ // upon start up because of the negative impact on performance.
+ bool audio_device_state_updated_;
+
HotwordClient* client_;
int error_message_;
bool reinstall_pending_;
diff --git a/chrome/browser/search/hotword_service_factory.cc b/chrome/browser/search/hotword_service_factory.cc
index 4baf2be..1aa72ac 100644
--- a/chrome/browser/search/hotword_service_factory.cc
+++ b/chrome/browser/search/hotword_service_factory.cc
@@ -59,45 +59,16 @@ int HotwordServiceFactory::GetCurrentError(BrowserContext* context) {
return hotword_service->error_message();
}
-// static
-bool HotwordServiceFactory::IsMicrophoneAvailable() {
- return GetInstance()->microphone_available();
-}
-
-// static
-bool HotwordServiceFactory::IsAudioDeviceStateUpdated() {
- return GetInstance()->audio_device_state_updated();
-}
-
HotwordServiceFactory::HotwordServiceFactory()
: BrowserContextKeyedServiceFactory(
"HotwordService",
- BrowserContextDependencyManager::GetInstance()),
- microphone_available_(false),
- audio_device_state_updated_(false) {
+ BrowserContextDependencyManager::GetInstance()) {
// No dependencies.
-
- // Register with the device observer list to update the microphone
- // availability.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&HotwordServiceFactory::InitializeMicrophoneObserver,
- base::Unretained(this)));
}
HotwordServiceFactory::~HotwordServiceFactory() {
}
-void HotwordServiceFactory::InitializeMicrophoneObserver() {
- MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this);
-}
-
-void HotwordServiceFactory::OnUpdateAudioDevices(
- const content::MediaStreamDevices& devices) {
- microphone_available_ = !devices.empty();
- audio_device_state_updated_ = true;
-}
-
void HotwordServiceFactory::UpdateMicrophoneState() {
// In order to trigger the monitor, just call getAudioCaptureDevices.
content::MediaStreamDevices devices =
diff --git a/chrome/browser/search/hotword_service_factory.h b/chrome/browser/search/hotword_service_factory.h
index 08d325f..3489296 100644
--- a/chrome/browser/search/hotword_service_factory.h
+++ b/chrome/browser/search/hotword_service_factory.h
@@ -6,15 +6,13 @@
#define CHROME_BROWSER_SEARCH_HOTWORD_SERVICE_FACTORY_H_
#include "base/memory/singleton.h"
-#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
class HotwordService;
class Profile;
// Singleton that owns all HotwordServices and associates them with Profiles.
-class HotwordServiceFactory : public MediaCaptureDevicesDispatcher::Observer,
- public BrowserContextKeyedServiceFactory {
+class HotwordServiceFactory : public BrowserContextKeyedServiceFactory {
public:
// Returns the HotwordService for |context|.
static HotwordService* GetForProfile(content::BrowserContext* context);
@@ -34,19 +32,6 @@ class HotwordServiceFactory : public MediaCaptureDevicesDispatcher::Observer,
// A value of 0 indicates no error.
static int GetCurrentError(content::BrowserContext* context);
- // Returns the current known state of the microphone. Since this state
- // is browser (not profile) specific, it resides in the factory.
- static bool IsMicrophoneAvailable();
-
- // Returns whether the state of the audio devices has been updated.
- // Essentially it indicates the validity of the return value from
- // IsMicrophoneAvailable().
- static bool IsAudioDeviceStateUpdated();
-
- // Overridden from MediaCaptureDevicesDispatcher::Observer
- void OnUpdateAudioDevices(
- const content::MediaStreamDevices& devices) override;
-
// This will kick off the monitor that calls OnUpdateAudioDevices when the
// number of audio devices changes (or is initialized). It needs to be a
// separate function so it can be called after the service is initialized
@@ -67,21 +52,6 @@ class HotwordServiceFactory : public MediaCaptureDevicesDispatcher::Observer,
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
- // Must be called from the UI thread since the instance of
- // MediaCaptureDevicesDispatcher can only be accessed on the UI thread.
- void InitializeMicrophoneObserver();
-
- bool microphone_available() { return microphone_available_; }
-
- bool microphone_available_;
-
- // Indicates if the check for audio devices has been run such that it can be
- // included in the error checking. Audio checking is not done immediately
- // upon start up because of the negative impact on performance.
- bool audio_device_state_updated_;
-
- bool audio_device_state_updated() { return audio_device_state_updated_; }
-
DISALLOW_COPY_AND_ASSIGN(HotwordServiceFactory);
};
diff --git a/chrome/browser/ui/webui/voice_search_ui.cc b/chrome/browser/ui/webui/voice_search_ui.cc
index 6731445..b676d3b 100644
--- a/chrome/browser/ui/webui/voice_search_ui.cc
+++ b/chrome/browser/ui/webui/voice_search_ui.cc
@@ -270,9 +270,11 @@ class VoiceSearchDomHandler : public WebUIMessageHandler {
AddPair(list, "NaCl Enabled", nacl_enabled);
- AddPair(list,
- "Microphone",
- HotwordServiceFactory::IsMicrophoneAvailable() ? "Yes" : "No");
+ HotwordService* hotword_service =
+ HotwordServiceFactory::GetForProfile(profile_);
+ AddPair(list, "Microphone",
+ hotword_service && hotword_service->microphone_available() ? "Yes"
+ : "No");
std::string audio_capture = "No";
if (profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed))
diff --git a/chrome/common/extensions/api/hotword_private.idl b/chrome/common/extensions/api/hotword_private.idl
index 012ad64..a7ffeb1 100644
--- a/chrome/common/extensions/api/hotword_private.idl
+++ b/chrome/common/extensions/api/hotword_private.idl
@@ -182,5 +182,8 @@ namespace hotwordPrivate {
// Fired when the browser wants to find out whether the speaker model
// exists.
static void onSpeakerModelExists();
+
+ // Fired when the microphone state changes.
+ static void onMicrophoneStateChanged(boolean enabled);
};
};