Index: chrome/browser/resources/hotword/state_manager.js |
diff --git a/chrome/browser/resources/hotword/state_manager.js b/chrome/browser/resources/hotword/state_manager.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..964e7dcf04abeb26bb26b57e7f31506253f9f33a |
--- /dev/null |
+++ b/chrome/browser/resources/hotword/state_manager.js |
@@ -0,0 +1,184 @@ |
+// Copyright (c) 2014 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. |
+ |
+/** |
+ * @fileoverview Class to manage hotwording state. |
+ */ |
+ |
+cr.define('hotword', function() { |
+'use strict'; |
Dan Beam
2014/08/26 18:40:51
this code should probably be indented because it's
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ |
+/** |
+ * @constructor |
+ * @struct |
+ */ |
+function StateManager() { |
+ /** |
+ * Current state. |
+ * @private {hotword.StateManager.State_} |
+ */ |
+ this.state_ = State_.STOPPED; |
+ |
+ /** |
+ * Current hotwording status. |
+ * @private {chrome.hotwordPrivate.StatusDetails} |
+ */ |
+ this.hotwordStatus_ = null; |
+ |
+ /** |
+ * NaCl plugin manager. |
+ * @private {?hotword.NaClManager} |
Dan Beam
2014/08/26 18:40:51
add ? to |this.hotwordStatus_|'s type or remove fr
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ */ |
+ this.pluginManager_ = null; |
+ |
+ // Get the initial status. |
+ chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this)); |
+} |
+ |
Dan Beam
2014/08/26 18:40:51
/**
* @enum {number}
* @private
*/
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+StateManager.State_ = { |
+ STOPPED: 0, |
+ STARTING: 1, |
+ RUNNING: 2, |
+ ERROR: 3, |
+}; |
+var State_ = StateManager.State_; |
+ |
+/** |
+ * Request status details update. Intended to be called from the |
+ * hotwordPrivate.onEnabledChanged() event. |
+ */ |
+StateManager.prototype.updateStatus = function() { |
+ chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this)); |
+}; |
+ |
+/** |
+ * Callback for hotwordPrivate.getStatus() function. |
+ * @param {chrome.hotwordPrivate.StatusDetails} status Current hotword status. |
+ * @private |
+ */ |
+StateManager.prototype.handleStatus_ = function(status) { |
+ this.hotwordStatus_ = status; |
+ this.updateStateFromStatus_(); |
+}; |
+ |
+/** |
+ * Updates state based on the current status. |
+ * @private |
+ */ |
+StateManager.prototype.updateStateFromStatus_ = function() { |
+ if (this.hotwordStatus_.enabled) { |
Dan Beam
2014/08/26 18:40:52
indent off (needs 1 more space)
Anand Mistry (off Chromium)
2014/08/27 07:10:56
WTF? How did that end up there? Done.
|
+ // Hotwording is enabled. |
+ // TODO(amistry): Have a separate alwaysOnEnabled flag. For now, treat |
+ // "enabled" as "always on enabled". |
+ this.startDetector_(); |
+ } else { |
+ // Not enabled. Shut down if running. |
+ this.shutdownDetector_(); |
+ } |
+}; |
+ |
+/** |
+ * Starts the hotword detector. |
+ * @private |
+ */ |
+StateManager.prototype.startDetector_ = function() { |
+ // Last attempt to start detector resulted in an error. |
+ if (this.state_ == State_.ERROR) { |
+ // TODO(amistry): Do some error rate tracking here and disable the extension |
+ // if we error too often. |
Dan Beam
2014/08/26 18:40:52
is there some code you meant to put here?
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Not yet. I'm not ready to fill in that kind of det
|
+ } |
+ |
+ if (this.pluginManager_ == null) { |
Dan Beam
2014/08/26 18:40:52
if (!this.pluginManager_) {
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ this.state_ = State_.STARTING; |
+ this.pluginManager_ = new hotword.NaClManager(); |
+ this.pluginManager_.addEventListener(hotword.constants.Event.READY, |
+ this.onReady_.bind(this)); |
Dan Beam
2014/08/26 18:40:52
indent off x 3
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ this.pluginManager_.addEventListener(hotword.constants.Event.ERROR, |
+ this.onError_.bind(this)); |
+ this.pluginManager_.addEventListener(hotword.constants.Event.TRIGGER, |
+ this.onTrigger_.bind(this)); |
+ chrome.runtime.getPlatformInfo(function(platform) { |
+ var naclArch = platform.nacl_arch; |
+ |
+ // googDucking set to false so that audio output level from other tabs is |
+ // not affected when hotword is enabled. https://crbug.com/357773 |
+ // src.chromium.org/svn/trunk/src/content/common/media/media_stream_options.cc |
Dan Beam
2014/08/26 18:40:52
use bit.ly or just put local path.
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ var constraints = /** @type {googMediaStreamConstraints} */ |
+ ({audio: {optional: [{ googDucking: false}] }}); |
Dan Beam
2014/08/26 18:40:52
no \s after { or }
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ navigator.webkitGetUserMedia( |
+ /** @type {MediaStreamConstraints} */ (constraints), |
+ function(stream) { |
+ if (!this.pluginManager_.initialize(naclArch, stream)) { |
+ this.state_ = State_.ERROR; |
+ this.pluginManager_.shutdown(); |
+ this.pluginManager_ = null; |
Dan Beam
2014/08/26 18:40:51
nit: this code seems to be repeated a lot:
this
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ } |
+ }.bind(this), |
+ function(error) { |
+ this.state_ = State_.ERROR; |
+ this.pluginManager_ = null; |
+ }.bind(this)); |
+ }.bind(this)); |
+ } else if (this.state_ != State_.STARTING) { |
+ // Don't try to start a starting detector. |
+ this.state_ = State_.RUNNING; |
+ this.pluginManager_.startRecognizer(); |
+ } |
+}; |
+ |
+/** |
+ * Shuts down the hotword detector. |
+ * @private |
+ */ |
+StateManager.prototype.shutdownDetector_ = function() { |
+ this.state_ = State_.STOPPED; |
+ if (this.pluginManager_ != null) { |
+ this.pluginManager_.shutdown(); |
+ this.pluginManager_ = null; |
+ } |
+}; |
+ |
+/** |
+ * Handle the hotword plugin being ready to start. |
+ * @private |
+ */ |
+StateManager.prototype.onReady_ = function() { |
+ if (this.state_ != State_.STARTING) { |
+ // Shouldn't be running while starting. |
+ assert(this.state_ != State_.RUNNING); |
+ this.pluginManager_.shutdown(); |
+ this.pluginManager_ = null; |
+ return; |
+ } |
+ this.state_ = State_.RUNNING; |
+ this.pluginManager_.startRecognizer(); |
+}; |
+ |
+/** |
+ * Handle an error from the hotword plugin. |
+ * @private |
+ */ |
+StateManager.prototype.onError_ = function() { |
+ this.state_ = State_.ERROR; |
+ this.pluginManager_.shutdown(); |
+ this.pluginManager_ = null; |
+}; |
+ |
+/** |
+ * Handle hotword triggering. |
+ * @private |
+ */ |
+StateManager.prototype.onTrigger_ = function() { |
+ assert(this.pluginManager_ != null); |
Dan Beam
2014/08/26 18:40:52
assert(this.pluginManager_)
Anand Mistry (off Chromium)
2014/08/27 07:10:56
Done.
|
+ // Detector implicitly stops when the hotword is detected. |
+ this.state_ = State_.STOPPED; |
+ |
+ chrome.hotwordPrivate.notifyHotwordRecognition('search', function() {}); |
+}; |
+ |
+return { |
+ StateManager: StateManager |
+}; |
+ |
+}); |