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

Side by Side Diff: chrome/browser/resources/hotword/audio_client.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: More review comments. 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 (c) 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 'use strict'; 5 'use strict';
6 6
7 /** 7 /**
8 * @fileoverview This is the audio client content script injected into eligible 8 * @fileoverview This is the audio client content script injected into eligible
9 * Google.com and New tab pages for interaction between the Webpage and the 9 * Google.com and New tab pages for interaction between the Webpage and the
10 * Hotword extension. 10 * Hotword extension.
11 */ 11 */
12 12
13
14
15 (function() { 13 (function() {
16 /** 14 /**
17 * @constructor 15 * @constructor
18 */ 16 */
19 var AudioClient = function() { 17 var AudioClient = function() {
20 /** @private {Element} */ 18 /** @private {Element} */
21 this.speechOverlay_ = null; 19 this.speechOverlay_ = null;
22 20
23 /** @private {number} */ 21 /** @private {number} */
24 this.checkSpeechUiRetries_ = 0; 22 this.checkSpeechUiRetries_ = 0;
(...skipping 11 matching lines...) Expand all
36 */ 34 */
37 this.uiStatus_ = null; 35 this.uiStatus_ = null;
38 36
39 /** 37 /**
40 * Bound function used to handle commands sent from the page to this script. 38 * Bound function used to handle commands sent from the page to this script.
41 * @private {Function} 39 * @private {Function}
42 */ 40 */
43 this.handleCommandFromPageFunc_ = null; 41 this.handleCommandFromPageFunc_ = null;
44 }; 42 };
45 43
46
47 /** 44 /**
48 * Messages sent to the page to control the voice search UI. 45 * Messages sent to the page to control the voice search UI.
49 * @enum {string} 46 * @enum {string}
50 */ 47 */
51 AudioClient.CommandToPage = { 48 AudioClient.CommandToPage = {
52 HOTWORD_VOICE_TRIGGER: 'vt', 49 HOTWORD_VOICE_TRIGGER: 'vt',
53 HOTWORD_STARTED: 'hs', 50 HOTWORD_STARTED: 'hs',
54 HOTWORD_ENDED: 'hd', 51 HOTWORD_ENDED: 'hd',
55 HOTWORD_TIMEOUT: 'ht', 52 HOTWORD_TIMEOUT: 'ht',
56 HOTWORD_ERROR: 'he' 53 HOTWORD_ERROR: 'he'
57 }; 54 };
58 55
59
60 /** 56 /**
61 * Messages received from the page used to indicate voice search state. 57 * Messages received from the page used to indicate voice search state.
62 * @enum {string} 58 * @enum {string}
63 */ 59 */
64 AudioClient.CommandFromPage = { 60 AudioClient.CommandFromPage = {
65 SPEECH_START: 'ss', 61 SPEECH_START: 'ss',
66 SPEECH_END: 'se', 62 SPEECH_END: 'se',
67 SPEECH_RESET: 'sr', 63 SPEECH_RESET: 'sr',
68 SHOWING_HOTWORD_START: 'shs', 64 SHOWING_HOTWORD_START: 'shs',
69 SHOWING_ERROR_MESSAGE: 'sem', 65 SHOWING_ERROR_MESSAGE: 'sem',
70 SHOWING_TIMEOUT_MESSAGE: 'stm', 66 SHOWING_TIMEOUT_MESSAGE: 'stm',
71 CLICKED_RESUME: 'hcc', 67 CLICKED_RESUME: 'hcc',
72 CLICKED_RESTART: 'hcr', 68 CLICKED_RESTART: 'hcr',
73 CLICKED_DEBUG: 'hcd' 69 CLICKED_DEBUG: 'hcd'
74 }; 70 };
75 71
76
77 /** 72 /**
78 * Errors that are sent to the hotword extension. 73 * Errors that are sent to the hotword extension.
79 * @enum {string} 74 * @enum {string}
80 */ 75 */
81 AudioClient.Error = { 76 AudioClient.Error = {
82 NO_SPEECH_UI: 'ac1', 77 NO_SPEECH_UI: 'ac1',
83 NO_HOTWORD_STARTED_UI: 'ac2', 78 NO_HOTWORD_STARTED_UI: 'ac2',
84 NO_HOTWORD_TIMEOUT_UI: 'ac3', 79 NO_HOTWORD_TIMEOUT_UI: 'ac3',
85 NO_HOTWORD_ERROR_UI: 'ac4' 80 NO_HOTWORD_ERROR_UI: 'ac4'
86 }; 81 };
87 82
88
89 /** 83 /**
90 * @const {string} 84 * @const {string}
91 * @private 85 * @private
92 */ 86 */
93 AudioClient.HOTWORD_EXTENSION_ID_ = 'bepbmhgboaologfdajaanbcjmnhjmhfn'; 87 AudioClient.HOTWORD_EXTENSION_ID_ = 'nbpagnldghgfoolbancepceaanlmhfmd';
94
95 88
96 /** 89 /**
97 * Number of times to retry checking a transient error. 90 * Number of times to retry checking a transient error.
98 * @const {number} 91 * @const {number}
99 * @private 92 * @private
100 */ 93 */
101 AudioClient.MAX_RETRIES = 3; 94 AudioClient.MAX_RETRIES = 3;
102 95
103
104 /** 96 /**
105 * Delay to wait in milliseconds before rechecking for any transient errors. 97 * Delay to wait in milliseconds before rechecking for any transient errors.
106 * @const {number} 98 * @const {number}
107 * @private 99 * @private
108 */ 100 */
109 AudioClient.RETRY_TIME_MS_ = 2000; 101 AudioClient.RETRY_TIME_MS_ = 2000;
110 102
111
112 /** 103 /**
113 * DOM ID for the speech UI overlay. 104 * DOM ID for the speech UI overlay.
114 * @const {string} 105 * @const {string}
115 * @private 106 * @private
116 */ 107 */
117 AudioClient.SPEECH_UI_OVERLAY_ID_ = 'spch'; 108 AudioClient.SPEECH_UI_OVERLAY_ID_ = 'spch';
118 109
119
120 /** 110 /**
121 * @const {string} 111 * @const {string}
122 * @private 112 * @private
123 */ 113 */
124 AudioClient.HELP_CENTER_URL_ = 114 AudioClient.HELP_CENTER_URL_ =
125 'https://support.google.com/chrome/?p=ui_hotword_search'; 115 'https://support.google.com/chrome/?p=ui_hotword_search';
126 116
127
128 /** 117 /**
129 * @const {string} 118 * @const {string}
130 * @private 119 * @private
131 */ 120 */
132 AudioClient.CLIENT_PORT_NAME_ = 'chwcpn'; 121 AudioClient.CLIENT_PORT_NAME_ = 'chwcpn';
133 122
134 /** 123 /**
135 * Existence of the Audio Client. 124 * Existence of the Audio Client.
136 * @const {string} 125 * @const {string}
137 * @private 126 * @private
138 */ 127 */
139 AudioClient.EXISTS_ = 'chwace'; 128 AudioClient.EXISTS_ = 'chwace';
140 129
141
142 /** 130 /**
143 * Checks for the presence of speech overlay UI DOM elements. 131 * Checks for the presence of speech overlay UI DOM elements.
144 * @private 132 * @private
145 */ 133 */
146 AudioClient.prototype.checkSpeechOverlayUi_ = function() { 134 AudioClient.prototype.checkSpeechOverlayUi_ = function() {
147 if (!this.speechOverlay_) { 135 if (!this.speechOverlay_) {
148 window.setTimeout(this.delayedCheckSpeechOverlayUi_.bind(this), 136 window.setTimeout(this.delayedCheckSpeechOverlayUi_.bind(this),
149 AudioClient.RETRY_TIME_MS_); 137 AudioClient.RETRY_TIME_MS_);
150 } else { 138 } else {
151 this.checkSpeechUiRetries_ = 0; 139 this.checkSpeechUiRetries_ = 0;
152 } 140 }
153 }; 141 };
154 142
155
156 /** 143 /**
157 * Function called to check for the speech UI overlay after some time has 144 * Function called to check for the speech UI overlay after some time has
158 * passed since an initial check. Will either retry triggering the speech 145 * passed since an initial check. Will either retry triggering the speech
159 * or sends an error message depending on the number of retries. 146 * or sends an error message depending on the number of retries.
160 * @private 147 * @private
161 */ 148 */
162 AudioClient.prototype.delayedCheckSpeechOverlayUi_ = function() { 149 AudioClient.prototype.delayedCheckSpeechOverlayUi_ = function() {
163 this.speechOverlay_ = document.getElementById( 150 this.speechOverlay_ = document.getElementById(
164 AudioClient.SPEECH_UI_OVERLAY_ID_); 151 AudioClient.SPEECH_UI_OVERLAY_ID_);
165 if (!this.speechOverlay_) { 152 if (!this.speechOverlay_) {
166 if (this.checkSpeechUiRetries_++ < AudioClient.MAX_RETRIES) { 153 if (this.checkSpeechUiRetries_++ < AudioClient.MAX_RETRIES) {
167 this.sendCommandToPage_(AudioClient.CommandToPage.VOICE_TRIGGER); 154 this.sendCommandToPage_(AudioClient.CommandToPage.VOICE_TRIGGER);
168 this.checkSpeechOverlayUi_(); 155 this.checkSpeechOverlayUi_();
169 } else { 156 } else {
170 this.sendCommandToExtension_(AudioClient.Error.NO_SPEECH_UI); 157 this.sendCommandToExtension_(AudioClient.Error.NO_SPEECH_UI);
171 } 158 }
172 } else { 159 } else {
173 this.checkSpeechUiRetries_ = 0; 160 this.checkSpeechUiRetries_ = 0;
174 } 161 }
175 }; 162 };
176 163
177
178 /** 164 /**
179 * Checks that the triggered UI is actually displayed. 165 * Checks that the triggered UI is actually displayed.
180 * @param {AudioClient.CommandToPage} command Command that was send. 166 * @param {AudioClient.CommandToPage} command Command that was send.
181 * @private 167 * @private
182 */ 168 */
183 AudioClient.prototype.checkUi_ = function(command) { 169 AudioClient.prototype.checkUi_ = function(command) {
184 this.uiStatus_[command].timeoutId = 170 this.uiStatus_[command].timeoutId =
185 window.setTimeout(this.failedCheckUi_.bind(this, command), 171 window.setTimeout(this.failedCheckUi_.bind(this, command),
186 AudioClient.RETRY_TIME_MS_); 172 AudioClient.RETRY_TIME_MS_);
187 }; 173 };
188 174
189
190 /** 175 /**
191 * Function called when the UI verification is not called in time. Will either 176 * Function called when the UI verification is not called in time. Will either
192 * retry the command or sends an error message, depending on the number of 177 * retry the command or sends an error message, depending on the number of
193 * retries for the command. 178 * retries for the command.
194 * @param {AudioClient.CommandToPage} command Command that was sent. 179 * @param {AudioClient.CommandToPage} command Command that was sent.
195 * @private 180 * @private
196 */ 181 */
197 AudioClient.prototype.failedCheckUi_ = function(command) { 182 AudioClient.prototype.failedCheckUi_ = function(command) {
198 if (this.uiStatus_[command].tries++ < AudioClient.MAX_RETRIES) { 183 if (this.uiStatus_[command].tries++ < AudioClient.MAX_RETRIES) {
199 this.sendCommandToPage_(command); 184 this.sendCommandToPage_(command);
200 this.checkUi_(command); 185 this.checkUi_(command);
201 } else { 186 } else {
202 this.sendCommandToExtension_(this.uiStatus_[command].error); 187 this.sendCommandToExtension_(this.uiStatus_[command].error);
203 } 188 }
204 }; 189 };
205 190
206
207 /** 191 /**
208 * Confirm that an UI element has been shown. 192 * Confirm that an UI element has been shown.
209 * @param {AudioClient.CommandToPage} command UI to confirm. 193 * @param {AudioClient.CommandToPage} command UI to confirm.
210 * @private 194 * @private
211 */ 195 */
212 AudioClient.prototype.verifyUi_ = function(command) { 196 AudioClient.prototype.verifyUi_ = function(command) {
213 if (this.uiStatus_[command].timeoutId) { 197 if (this.uiStatus_[command].timeoutId) {
214 window.clearTimeout(this.uiStatus_[command].timeoutId); 198 window.clearTimeout(this.uiStatus_[command].timeoutId);
215 this.uiStatus_[command].timeoutId = null; 199 this.uiStatus_[command].timeoutId = null;
216 this.uiStatus_[command].tries = 0; 200 this.uiStatus_[command].tries = 0;
217 } 201 }
218 }; 202 };
219 203
220
221 /** 204 /**
222 * Sends a command to the audio manager. 205 * Sends a command to the audio manager.
223 * @param {string} commandStr command to send to plugin. 206 * @param {string} commandStr command to send to plugin.
224 * @private 207 * @private
225 */ 208 */
226 AudioClient.prototype.sendCommandToExtension_ = function(commandStr) { 209 AudioClient.prototype.sendCommandToExtension_ = function(commandStr) {
227 if (this.port_) 210 if (this.port_)
228 this.port_.postMessage({'cmd': commandStr}); 211 this.port_.postMessage({'cmd': commandStr});
229 }; 212 };
230 213
231
232 /** 214 /**
233 * Handles a message from the audio manager. 215 * Handles a message from the audio manager.
234 * @param {{cmd: string}} commandObj Command from the audio manager. 216 * @param {{cmd: string}} commandObj Command from the audio manager.
235 * @private 217 * @private
236 */ 218 */
237 AudioClient.prototype.handleCommandFromExtension_ = function(commandObj) { 219 AudioClient.prototype.handleCommandFromExtension_ = function(commandObj) {
238 var command = commandObj['cmd']; 220 var command = commandObj['cmd'];
239 if (command) { 221 if (command) {
240 switch (command) { 222 switch (command) {
241 case AudioClient.CommandToPage.HOTWORD_VOICE_TRIGGER: 223 case AudioClient.CommandToPage.HOTWORD_VOICE_TRIGGER:
(...skipping 12 matching lines...) Expand all
254 this.checkUi_(command); 236 this.checkUi_(command);
255 break; 237 break;
256 case AudioClient.CommandToPage.HOTWORD_ERROR: 238 case AudioClient.CommandToPage.HOTWORD_ERROR:
257 this.sendCommandToPage_(command); 239 this.sendCommandToPage_(command);
258 this.checkUi_(command); 240 this.checkUi_(command);
259 break; 241 break;
260 } 242 }
261 } 243 }
262 }; 244 };
263 245
264
265 /** 246 /**
266 * @param {AudioClient.CommandToPage} commandStr Command to send. 247 * @param {AudioClient.CommandToPage} commandStr Command to send.
267 * @private 248 * @private
268 */ 249 */
269 AudioClient.prototype.sendCommandToPage_ = function(commandStr) { 250 AudioClient.prototype.sendCommandToPage_ = function(commandStr) {
270 window.postMessage({'type': commandStr}, '*'); 251 window.postMessage({'type': commandStr}, '*');
271 }; 252 };
272 253
273
274 /** 254 /**
275 * Handles a message from the html window. 255 * Handles a message from the html window.
276 * @param {!MessageEvent} messageEvent Message event from the window. 256 * @param {!MessageEvent} messageEvent Message event from the window.
277 * @private 257 * @private
278 */ 258 */
279 AudioClient.prototype.handleCommandFromPage_ = function(messageEvent) { 259 AudioClient.prototype.handleCommandFromPage_ = function(messageEvent) {
280 if (messageEvent.source == window && messageEvent.data.type) { 260 if (messageEvent.source == window && messageEvent.data.type) {
281 var command = messageEvent.data.type; 261 var command = messageEvent.data.type;
282 switch (command) { 262 switch (command) {
283 case AudioClient.CommandFromPage.SPEECH_START: 263 case AudioClient.CommandFromPage.SPEECH_START:
(...skipping 27 matching lines...) Expand all
311 case AudioClient.CommandFromPage.SHOWING_ERROR_MESSAGE: 291 case AudioClient.CommandFromPage.SHOWING_ERROR_MESSAGE:
312 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_ERROR); 292 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_ERROR);
313 break; 293 break;
314 case AudioClient.CommandFromPage.SHOWING_TIMEOUT_MESSAGE: 294 case AudioClient.CommandFromPage.SHOWING_TIMEOUT_MESSAGE:
315 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_TIMEOUT); 295 this.verifyUi_(AudioClient.CommandToPage.HOTWORD_TIMEOUT);
316 break; 296 break;
317 } 297 }
318 } 298 }
319 }; 299 };
320 300
321
322 /** 301 /**
323 * Initialize the content script. 302 * Initialize the content script.
324 */ 303 */
325 AudioClient.prototype.initialize = function() { 304 AudioClient.prototype.initialize = function() {
326 if (AudioClient.EXISTS_ in window) 305 if (AudioClient.EXISTS_ in window)
327 return; 306 return;
328 window[AudioClient.EXISTS_] = true; 307 window[AudioClient.EXISTS_] = true;
329 308
330 // UI verification object. 309 // UI verification object.
331 this.uiStatus_ = {}; 310 this.uiStatus_ = {};
(...skipping 11 matching lines...) Expand all
343 timeoutId: null, 322 timeoutId: null,
344 tries: 0, 323 tries: 0,
345 error: AudioClient.Error.NO_HOTWORD_ERROR_UI 324 error: AudioClient.Error.NO_HOTWORD_ERROR_UI
346 }; 325 };
347 326
348 this.handleCommandFromPageFunc_ = this.handleCommandFromPage_.bind(this); 327 this.handleCommandFromPageFunc_ = this.handleCommandFromPage_.bind(this);
349 window.addEventListener('message', this.handleCommandFromPageFunc_, false); 328 window.addEventListener('message', this.handleCommandFromPageFunc_, false);
350 this.initPort_(); 329 this.initPort_();
351 }; 330 };
352 331
353
354 /** 332 /**
355 * Initialize the communications port with the audio manager. This 333 * Initialize the communications port with the audio manager. This
356 * function will be also be called again if the audio-manager 334 * function will be also be called again if the audio-manager
357 * disconnects for some reason (such as the extension 335 * disconnects for some reason (such as the extension
358 * background.html page being reloaded). 336 * background.html page being reloaded).
359 * @private 337 * @private
360 */ 338 */
361 AudioClient.prototype.initPort_ = function() { 339 AudioClient.prototype.initPort_ = function() {
362 this.port_ = chrome.runtime.connect( 340 this.port_ = chrome.runtime.connect(
363 AudioClient.HOTWORD_EXTENSION_ID_, 341 AudioClient.HOTWORD_EXTENSION_ID_,
(...skipping 10 matching lines...) Expand all
374 }).bind(this)); 352 }).bind(this));
375 353
376 // See note above. 354 // See note above.
377 this.port_.onMessage.addListener( 355 this.port_.onMessage.addListener(
378 this.handleCommandFromExtension_.bind(this)); 356 this.handleCommandFromExtension_.bind(this));
379 357
380 if (this.speechActive_) 358 if (this.speechActive_)
381 this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_START); 359 this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_START);
382 }; 360 };
383 361
384
385 // Initializes as soon as the code is ready, do not wait for the page. 362 // Initializes as soon as the code is ready, do not wait for the page.
386 new AudioClient().initialize(); 363 new AudioClient().initialize();
387 })(); 364 })();
OLDNEW
« no previous file with comments | « chrome/browser/resources/component_extension_resources.grd ('k') | chrome/browser/resources/hotword/constants.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698