OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * @fileoverview Class to manage hotwording state. | |
Dan Beam
2014/08/27 20:08:37
nit: if it fits, one-liner -- /** ... */
Dan Beam
2014/08/27 20:08:37
this isn't a particularly useful comment and shoul
Anand Mistry (off Chromium)
2014/08/28 00:59:26
Done.
| |
7 */ | |
8 | |
Dan Beam
2014/08/27 20:08:37
remove \n
Anand Mistry (off Chromium)
2014/08/28 00:59:26
Done.
| |
9 cr.define('hotword', function() { | |
10 'use strict'; | |
11 | |
12 /** | |
13 * @constructor | |
14 * @struct | |
15 */ | |
16 function StateManager() { | |
17 /** | |
18 * Current state. | |
19 * @private {hotword.StateManager.State_} | |
20 */ | |
21 this.state_ = State_.STOPPED; | |
22 | |
23 /** | |
24 * Current hotwording status. | |
25 * @private {?chrome.hotwordPrivate.StatusDetails} | |
26 */ | |
27 this.hotwordStatus_ = null; | |
28 | |
29 /** | |
30 * NaCl plugin manager. | |
31 * @private {?hotword.NaClManager} | |
32 */ | |
33 this.pluginManager_ = null; | |
34 | |
35 // Get the initial status. | |
36 chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this)); | |
37 } | |
38 | |
39 /** | |
40 * @enum {number} | |
41 * @private | |
42 */ | |
43 StateManager.State_ = { | |
44 STOPPED: 0, | |
45 STARTING: 1, | |
46 RUNNING: 2, | |
47 ERROR: 3, | |
48 }; | |
49 var State_ = StateManager.State_; | |
50 | |
51 /** | |
52 * Request status details update. Intended to be called from the | |
53 * hotwordPrivate.onEnabledChanged() event. | |
54 */ | |
55 StateManager.prototype.updateStatus = function() { | |
Dan Beam
2014/08/27 20:08:37
nit: just assign whole prototype
StateManager.p
Anand Mistry (off Chromium)
2014/08/28 00:59:25
Done.
| |
56 chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this)); | |
57 }; | |
58 | |
59 /** | |
60 * Callback for hotwordPrivate.getStatus() function. | |
61 * @param {chrome.hotwordPrivate.StatusDetails} status Current hotword status. | |
62 * @private | |
63 */ | |
64 StateManager.prototype.handleStatus_ = function(status) { | |
65 this.hotwordStatus_ = status; | |
66 this.updateStateFromStatus_(); | |
67 }; | |
68 | |
69 /** | |
70 * Updates state based on the current status. | |
71 * @private | |
72 */ | |
73 StateManager.prototype.updateStateFromStatus_ = function() { | |
74 if (this.hotwordStatus_.enabled) { | |
75 // Hotwording is enabled. | |
76 // TODO(amistry): Have a separate alwaysOnEnabled flag. For now, treat | |
77 // "enabled" as "always on enabled". | |
78 this.startDetector_(); | |
79 } else { | |
80 // Not enabled. Shut down if running. | |
81 this.shutdownDetector_(); | |
82 } | |
83 }; | |
84 | |
85 /** | |
86 * Starts the hotword detector. | |
87 * @private | |
88 */ | |
89 StateManager.prototype.startDetector_ = function() { | |
90 // Last attempt to start detector resulted in an error. | |
91 if (this.state_ == State_.ERROR) { | |
92 // TODO(amistry): Do some error rate tracking here and disable the | |
93 // extension if we error too often. | |
94 } | |
95 | |
96 if (!this.pluginManager_) { | |
97 this.state_ = State_.STARTING; | |
98 this.pluginManager_ = new hotword.NaClManager(); | |
99 this.pluginManager_.addEventListener(hotword.constants.Event.READY, | |
100 this.onReady_.bind(this)); | |
101 this.pluginManager_.addEventListener(hotword.constants.Event.ERROR, | |
102 this.onError_.bind(this)); | |
103 this.pluginManager_.addEventListener(hotword.constants.Event.TRIGGER, | |
104 this.onTrigger_.bind(this)); | |
105 chrome.runtime.getPlatformInfo(function(platform) { | |
106 var naclArch = platform.nacl_arch; | |
107 | |
108 // googDucking set to false so that audio output level from other tabs | |
109 // is not affected when hotword is enabled. https://crbug.com/357773 | |
110 // content/common/media/media_stream_options.cc | |
111 var constraints = /** @type {googMediaStreamConstraints} */ | |
112 ({audio: {optional: [{googDucking: false}]}}); | |
113 navigator.webkitGetUserMedia( | |
114 /** @type {MediaStreamConstraints} */ (constraints), | |
115 function(stream) { | |
116 if (!this.pluginManager_.initialize(naclArch, stream)) { | |
117 this.state_ = State_.ERROR; | |
118 this.shutdownPluginManager_(); | |
119 } | |
120 }.bind(this), | |
121 function(error) { | |
122 this.state_ = State_.ERROR; | |
123 this.pluginManager_ = null; | |
124 }.bind(this)); | |
125 }.bind(this)); | |
126 } else if (this.state_ != State_.STARTING) { | |
127 // Don't try to start a starting detector. | |
128 this.state_ = State_.RUNNING; | |
129 this.pluginManager_.startRecognizer(); | |
130 } | |
131 }; | |
132 | |
133 /** | |
134 * Shuts down and removes the plugin manager, if it exists. | |
135 * @private | |
136 */ | |
137 StateManager.prototype.shutdownPluginManager_ = function() { | |
138 if (this.pluginManager_) { | |
139 this.pluginManager_.shutdown(); | |
140 this.pluginManager_ = null; | |
141 } | |
142 }; | |
143 | |
144 /** | |
145 * Shuts down the hotword detector. | |
146 * @private | |
147 */ | |
148 StateManager.prototype.shutdownDetector_ = function() { | |
149 this.state_ = State_.STOPPED; | |
150 this.shutdownPluginManager_(); | |
151 }; | |
152 | |
153 /** | |
154 * Handle the hotword plugin being ready to start. | |
155 * @private | |
156 */ | |
157 StateManager.prototype.onReady_ = function() { | |
158 if (this.state_ != State_.STARTING) { | |
159 // Shouldn't be running while starting. | |
Dan Beam
2014/08/27 20:08:37
this comment is confusing because you say the code
Anand Mistry (off Chromium)
2014/08/28 00:59:26
Done.
| |
160 assert(this.state_ != State_.RUNNING); | |
161 this.shutdownPluginManager_(); | |
162 return; | |
163 } | |
164 this.state_ = State_.RUNNING; | |
165 this.pluginManager_.startRecognizer(); | |
166 }; | |
167 | |
168 /** | |
169 * Handle an error from the hotword plugin. | |
170 * @private | |
171 */ | |
172 StateManager.prototype.onError_ = function() { | |
173 this.state_ = State_.ERROR; | |
174 this.shutdownPluginManager_(); | |
175 }; | |
176 | |
177 /** | |
178 * Handle hotword triggering. | |
179 * @private | |
180 */ | |
181 StateManager.prototype.onTrigger_ = function() { | |
182 assert(this.pluginManager_); | |
183 // Detector implicitly stops when the hotword is detected. | |
184 this.state_ = State_.STOPPED; | |
185 | |
186 chrome.hotwordPrivate.notifyHotwordRecognition('search', function() {}); | |
187 }; | |
188 | |
189 return { | |
190 StateManager: StateManager | |
191 }; | |
192 | |
Dan Beam
2014/08/27 20:08:37
nit: remove \n
Anand Mistry (off Chromium)
2014/08/28 00:59:25
Done.
| |
193 }); | |
OLD | NEW |