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

Side by Side Diff: chrome/browser/resources/hotword_helper/audio_client.js

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

Powered by Google App Engine
This is Rietveld 408576698