Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(260)

Side by Side Diff: chrome/browser/resources/hotword/state_manager.js

Issue 600523004: Support hotwording on google.com and the new tab page. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove extra blank lines. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('hotword', function() { 5 cr.define('hotword', function() {
6 'use strict'; 6 'use strict';
7 7
8 /** 8 /**
9 * Trivial container class for session information.
Dan Beam 2014/10/11 00:54:36 @param x 3
Anand Mistry (off Chromium) 2014/10/13 19:30:21 Done.
10 * @constructor
11 * @struct
12 * @private
13 */
14 function Session_(source, triggerCb, startedCb) {
15 /**
16 * Source of the hotword session request.
17 * @protected {!hotword.constants.SessionSource}
Dan Beam 2014/10/11 00:54:35 nit: ehhh, I'd just make this @private if it's onl
Anand Mistry (off Chromium) 2014/10/13 19:30:21 Done.
18 */
19 this.source = source;
20
21 /**
22 * Callback invoked when the hotword has triggered.
23 * @protected {!function()}
24 */
25 this.triggerCb = triggerCb;
26
27 /**
28 * Callback invoked when the session has been started successfully.
29 * @protected {?function()}
30 */
31 this.startedCb = startedCb;
32 }
33
34 /**
9 * Class to manage hotwording state. Starts/stops the hotword detector based 35 * Class to manage hotwording state. Starts/stops the hotword detector based
10 * on user settings, session requests, and any other factors that play into 36 * on user settings, session requests, and any other factors that play into
11 * whether or not hotwording should be running. 37 * whether or not hotwording should be running.
12 * @constructor 38 * @constructor
13 * @struct 39 * @struct
14 */ 40 */
15 function StateManager() { 41 function StateManager() {
16 /** 42 /**
17 * Current state. 43 * Current state.
18 * @private {hotword.StateManager.State_} 44 * @private {hotword.StateManager.State_}
19 */ 45 */
20 this.state_ = State_.STOPPED; 46 this.state_ = State_.STOPPED;
21 47
22 /** 48 /**
23 * Current hotwording status. 49 * Current hotwording status.
24 * @private {?chrome.hotwordPrivate.StatusDetails} 50 * @private {?chrome.hotwordPrivate.StatusDetails}
25 */ 51 */
26 this.hotwordStatus_ = null; 52 this.hotwordStatus_ = null;
27 53
28 /** 54 /**
29 * NaCl plugin manager. 55 * NaCl plugin manager.
30 * @private {?hotword.NaClManager} 56 * @private {?hotword.NaClManager}
31 */ 57 */
32 this.pluginManager_ = null; 58 this.pluginManager_ = null;
33 59
34 /** 60 /**
35 * Source of the current hotword session. 61 * Currently active hotwording sessions.
36 * @private {?hotword.constants.SessionSource} 62 * @private {!Array.<hotword.Session_>}
37 */ 63 */
38 this.sessionSource_ = null; 64 this.sessions_ = [];
39 65
40 /** 66 /**
41 * Callback to run when the hotword detector has successfully started. 67 * Event that fires when the hotwording status has changed.
Dan Beam 2014/10/11 00:54:36 @type
Anand Mistry (off Chromium) 2014/10/13 19:30:21 Done.
42 * @private {!function()}
43 */ 68 */
44 this.sessionStartedCb_ = null; 69 this.onStatusChanged = new chrome.Event();
45 70
46 /** 71 /**
47 * Hotword trigger audio notification... a.k.a The Chime (tm). 72 * Hotword trigger audio notification... a.k.a The Chime (tm).
48 * @private {!Audio} 73 * @private {!Audio}
49 */ 74 */
50 this.chime_ = document.createElement('audio'); 75 this.chime_ = document.createElement('audio');
51 76
52 // Get the initial status. 77 // Get the initial status.
53 chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this)); 78 chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this));
54 79
(...skipping 18 matching lines...) Expand all
73 StateManager.prototype = { 98 StateManager.prototype = {
74 /** 99 /**
75 * Request status details update. Intended to be called from the 100 * Request status details update. Intended to be called from the
76 * hotwordPrivate.onEnabledChanged() event. 101 * hotwordPrivate.onEnabledChanged() event.
77 */ 102 */
78 updateStatus: function() { 103 updateStatus: function() {
79 chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this)); 104 chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this));
80 }, 105 },
81 106
82 /** 107 /**
108 * @return {boolean} True if hotwording is enabled.
109 */
110 isEnabled: function() {
111 assert(this.hotwordStatus_);
112 return this.hotwordStatus_.enabled;
113 },
114
115 /**
116 * @return {boolean} True if always-on hotwording is enabled.
117 */
118 isAlwaysOnEnabled: function() {
119 assert(this.hotwordStatus_);
120 return this.hotwordStatus_.enabled &&
121 this.hotwordStatus_.alwaysOnEnabled;
122 },
123
124 /**
83 * Callback for hotwordPrivate.getStatus() function. 125 * Callback for hotwordPrivate.getStatus() function.
84 * @param {chrome.hotwordPrivate.StatusDetails} status Current hotword 126 * @param {chrome.hotwordPrivate.StatusDetails} status Current hotword
85 * status. 127 * status.
86 * @private 128 * @private
87 */ 129 */
88 handleStatus_: function(status) { 130 handleStatus_: function(status) {
89 hotword.debug('New hotword status', status); 131 hotword.debug('New hotword status', status);
90 this.hotwordStatus_ = status; 132 this.hotwordStatus_ = status;
91 this.updateStateFromStatus_(); 133 this.updateStateFromStatus_();
134
135 this.onStatusChanged.dispatch();
92 }, 136 },
93 137
94 /** 138 /**
95 * Updates state based on the current status. 139 * Updates state based on the current status.
96 * @private 140 * @private
97 */ 141 */
98 updateStateFromStatus_: function() { 142 updateStateFromStatus_: function() {
99 if (!this.hotwordStatus_) 143 if (!this.hotwordStatus_)
100 return; 144 return;
101 145
102 if (this.hotwordStatus_.enabled) { 146 if (this.hotwordStatus_.enabled) {
103 // Start the detector if there's a session, and shut it down if there 147 // Start the detector if there's a session, and shut it down if there
104 // isn't. 148 // isn't.
105 // TODO(amistry): Support stacking sessions. This can happen when the
106 // user opens google.com or the NTP, then opens the launcher. Opening
107 // google.com will create one session, and opening the launcher will
108 // create the second. Closing the launcher should re-activate the
109 // google.com session.
110 // NOTE(amistry): With always-on, we want a different behaviour with 149 // NOTE(amistry): With always-on, we want a different behaviour with
111 // sessions since the detector should always be running. The exception 150 // sessions since the detector should always be running. The exception
112 // being when the user triggers by saying 'Ok Google'. In that case, the 151 // being when the user triggers by saying 'Ok Google'. In that case, the
113 // detector stops, so starting/stopping the launcher session should 152 // detector stops, so starting/stopping the launcher session should
114 // restart the detector. 153 // restart the detector.
115 if (this.sessionSource_) 154 if (this.sessions_.length)
116 this.startDetector_(); 155 this.startDetector_();
117 else 156 else
118 this.shutdownDetector_(); 157 this.shutdownDetector_();
119 } else { 158 } else {
120 // Not enabled. Shut down if running. 159 // Not enabled. Shut down if running.
121 this.shutdownDetector_(); 160 this.shutdownDetector_();
122 } 161 }
123 }, 162 },
124 163
125 /** 164 /**
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 * Start the recognizer plugin. Assumes the plugin has been loaded and is 212 * Start the recognizer plugin. Assumes the plugin has been loaded and is
174 * ready to start. 213 * ready to start.
175 * @private 214 * @private
176 */ 215 */
177 startRecognizer_: function() { 216 startRecognizer_: function() {
178 assert(this.pluginManager_, 'No NaCl plugin loaded'); 217 assert(this.pluginManager_, 'No NaCl plugin loaded');
179 if (this.state_ != State_.RUNNING) { 218 if (this.state_ != State_.RUNNING) {
180 this.state_ = State_.RUNNING; 219 this.state_ = State_.RUNNING;
181 this.pluginManager_.startRecognizer(); 220 this.pluginManager_.startRecognizer();
182 } 221 }
183 if (this.sessionStartedCb_) { 222 for (var i = 0; i < this.sessions_.length; i++) {
184 this.sessionStartedCb_(); 223 var session = this.sessions_[i];
185 this.sessionStartedCb_ = null; 224 if (session.startedCb) {
225 session.startedCb();
226 session.startedCb = null;
227 }
186 } 228 }
187 }, 229 },
188 230
189 /** 231 /**
190 * Shuts down and removes the plugin manager, if it exists. 232 * Shuts down and removes the plugin manager, if it exists.
191 * @private 233 * @private
192 */ 234 */
193 shutdownPluginManager_: function() { 235 shutdownPluginManager_: function() {
194 if (this.pluginManager_) { 236 if (this.pluginManager_) {
195 this.pluginManager_.shutdown(); 237 this.pluginManager_.shutdown();
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 */ 278 */
237 onTrigger_: function() { 279 onTrigger_: function() {
238 hotword.debug('Hotword triggered!'); 280 hotword.debug('Hotword triggered!');
239 assert(this.pluginManager_, 'No NaCl plugin loaded on trigger'); 281 assert(this.pluginManager_, 'No NaCl plugin loaded on trigger');
240 // Detector implicitly stops when the hotword is detected. 282 // Detector implicitly stops when the hotword is detected.
241 this.state_ = State_.STOPPED; 283 this.state_ = State_.STOPPED;
242 284
243 // Play the chime. 285 // Play the chime.
244 this.chime_.play(); 286 this.chime_.play();
245 287
246 chrome.hotwordPrivate.notifyHotwordRecognition('search', function() {}); 288 // Implicitly clear the top session. A session needs to be started in
247 289 // order to restart the detector.
248 // Implicitly clear the session. A session needs to be started in order to 290 if (this.sessions_.length) {
249 // restart the detector. 291 var session = this.sessions_.pop();
250 this.sessionSource_ = null; 292 if (session.triggerCb)
251 this.sessionStartedCb_ = null; 293 session.triggerCb();
294 }
252 }, 295 },
253 296
254 /** 297 /**
298 * Remove a hotwording session from the given source.
299 * @param {!hotword.constants.SessionSource} source Source of the hotword
300 * session request.
301 * @private
302 */
303 removeSession_: function(source) {
304 for (var i = 0; i < this.sessions_.length; i++) {
305 if (this.sessions_[i].source == source) {
306 this.sessions_.splice(i, 1);
307 break;
308 }
309 }
310 },
311
312 /**
255 * Start a hotwording session. 313 * Start a hotwording session.
256 * @param {!hotword.constants.SessionSource} source Source of the hotword 314 * @param {!hotword.constants.SessionSource} source Source of the hotword
257 * session request. 315 * session request.
258 * @param {!function()} startedCb Callback invoked when the session has 316 * @param {!function()} startedCb Callback invoked when the session has
259 * been started successfully. 317 * been started successfully.
318 * @param {!function()} triggerCb Callback invoked when the hotword has
319 * triggered.
260 */ 320 */
261 startSession: function(source, startedCb) { 321 startSession: function(source, startedCb, triggerCb) {
262 hotword.debug('Starting session for source: ' + source); 322 hotword.debug('Starting session for source: ' + source);
263 this.sessionSource_ = source; 323 this.removeSession_(source);
264 this.sessionStartedCb_ = startedCb; 324 this.sessions_.push(new Session_(source, triggerCb, startedCb));
265 this.updateStateFromStatus_(); 325 this.updateStateFromStatus_();
266 }, 326 },
267 327
268 /** 328 /**
269 * Stops a hotwording session. 329 * Stops a hotwording session.
270 * @param {!hotword.constants.SessionSource} source Source of the hotword 330 * @param {!hotword.constants.SessionSource} source Source of the hotword
271 * session request. 331 * session request.
272 */ 332 */
273 stopSession: function(source) { 333 stopSession: function(source) {
274 hotword.debug('Stopping session for source: ' + source); 334 hotword.debug('Stopping session for source: ' + source);
275 this.sessionSource_ = null; 335 this.removeSession_(source);
276 this.sessionStartedCb_ = null;
277 this.updateStateFromStatus_(); 336 this.updateStateFromStatus_();
278 } 337 }
279 }; 338 };
280 339
281 return { 340 return {
282 StateManager: StateManager 341 StateManager: StateManager
283 }; 342 };
284 }); 343 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698