OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Class handling creation and teardown of a remoting client session. | 7 * Class handling creation and teardown of a remoting client session. |
8 * | 8 * |
9 * This abstracts a <embed> element and controls the plugin which does the | 9 * This abstracts a <embed> element and controls the plugin which does the |
10 * actual remoting work. There should be no UI code inside this class. It | 10 * actual remoting work. There should be no UI code inside this class. It |
11 * should be purely thought of as a controller of sorts. | 11 * should be purely thought of as a controller of sorts. |
12 */ | 12 */ |
13 | 13 |
14 'use strict'; | 14 'use strict'; |
15 | 15 |
16 /** @suppress {duplicate} */ | 16 /** @suppress {duplicate} */ |
17 var remoting = remoting || {}; | 17 var remoting = remoting || {}; |
18 | 18 |
19 /** | 19 /** |
20 * @param {string} hostJid The jid of the host to connect to. | 20 * @param {string} hostJid The jid of the host to connect to. |
21 * @param {string} hostPublicKey The base64 encoded version of the host's | 21 * @param {string} hostPublicKey The base64 encoded version of the host's |
22 * public key. | 22 * public key. |
23 * @param {string} accessCode The access code for the IT2Me connection. | 23 * @param {string} accessCode The access code for the IT2Me connection. |
24 * @param {string} email The username for the talk network. | 24 * @param {string} email The username for the talk network. |
25 * @param {function(remoting.ClientSession.State):void} onStateChange | 25 * @param {function(remoting.ClientSession.State, |
26 * The callback to invoke when the session changes state. This callback | 26 remoting.ClientSession.State):void} onStateChange |
27 * occurs after the state changes and is passed the previous state; the | 27 * The callback to invoke when the session changes state. |
28 * new state is accessible via ClientSession's |state| property. | |
29 * @constructor | 28 * @constructor |
30 */ | 29 */ |
31 remoting.ClientSession = function(hostJid, hostPublicKey, accessCode, email, | 30 remoting.ClientSession = function(hostJid, hostPublicKey, accessCode, email, |
32 onStateChange) { | 31 onStateChange) { |
33 this.state = remoting.ClientSession.State.CREATED; | 32 this.state = remoting.ClientSession.State.CREATED; |
34 | 33 |
35 this.hostJid = hostJid; | 34 this.hostJid = hostJid; |
36 this.hostPublicKey = hostPublicKey; | 35 this.hostPublicKey = hostPublicKey; |
37 this.accessCode = accessCode; | 36 this.accessCode = accessCode; |
38 this.email = email; | 37 this.email = email; |
39 this.clientJid = ''; | 38 this.clientJid = ''; |
40 this.sessionId = ''; | 39 this.sessionId = ''; |
41 /** @type {remoting.ViewerPlugin} */ this.plugin = null; | 40 /** @type {remoting.ViewerPlugin} */ this.plugin = null; |
42 this.logToServer = new remoting.LogToServer(); | 41 this.logToServer = new remoting.LogToServer(); |
43 this.onStateChange = onStateChange; | 42 this.onStateChange = onStateChange; |
44 }; | 43 }; |
45 | 44 |
| 45 // Note that the positive values in both of these enums are copied directly |
| 46 // from chromoting_scriptable_object.h and must be kept in sync. The negative |
| 47 // values represent states transitions that occur within the web-app that have |
| 48 // no corresponding plugin state transition. |
46 /** @enum {number} */ | 49 /** @enum {number} */ |
47 remoting.ClientSession.State = { | 50 remoting.ClientSession.State = { |
| 51 CREATED: -3, |
| 52 BAD_PLUGIN_VERSION: -2, |
| 53 UNKNOWN_PLUGIN_ERROR: -1, |
48 UNKNOWN: 0, | 54 UNKNOWN: 0, |
49 CREATED: 1, | 55 CONNECTING: 1, |
50 BAD_PLUGIN_VERSION: 2, | 56 INITIALIZING: 2, |
51 UNKNOWN_PLUGIN_ERROR: 3, | 57 CONNECTED: 3, |
52 CONNECTING: 4, | 58 CLOSED: 4, |
53 INITIALIZING: 5, | 59 CONNECTION_FAILED: 5 |
54 CONNECTED: 6, | |
55 CLOSED: 7, | |
56 CONNECTION_FAILED: 8 | |
57 }; | 60 }; |
58 | 61 |
59 /** @enum {number} */ | 62 /** @enum {number} */ |
60 remoting.ClientSession.ConnectionError = { | 63 remoting.ClientSession.ConnectionError = { |
61 NONE: 0, | 64 NONE: 0, |
62 HOST_IS_OFFLINE: 1, | 65 HOST_IS_OFFLINE: 1, |
63 SESSION_REJECTED: 2, | 66 SESSION_REJECTED: 2, |
64 INCOMPATIBLE_PROTOCOL: 3, | 67 INCOMPATIBLE_PROTOCOL: 3, |
65 NETWORK_FAILURE: 4, | 68 NETWORK_FAILURE: 4 |
66 OTHER: 5 | |
67 }; | 69 }; |
68 | 70 |
69 /** | 71 /** |
70 * The current state of the session. | 72 * The current state of the session. |
71 * @type {remoting.ClientSession.State} | 73 * @type {remoting.ClientSession.State} |
72 */ | 74 */ |
73 remoting.ClientSession.prototype.state = remoting.ClientSession.State.UNKNOWN; | 75 remoting.ClientSession.prototype.state = remoting.ClientSession.State.UNKNOWN; |
74 | 76 |
75 /** | 77 /** |
76 * The last connection error. Set when state is set to CONNECTION_FAILED. | 78 * The last connection error. Set when state is set to CONNECTION_FAILED. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 /** | 114 /** |
113 * The id of the client plugin | 115 * The id of the client plugin |
114 * | 116 * |
115 * @const | 117 * @const |
116 */ | 118 */ |
117 remoting.ClientSession.prototype.PLUGIN_ID = 'session-client-plugin'; | 119 remoting.ClientSession.prototype.PLUGIN_ID = 'session-client-plugin'; |
118 | 120 |
119 /** | 121 /** |
120 * Callback to invoke when the state is changed. | 122 * Callback to invoke when the state is changed. |
121 * | 123 * |
122 * @param {remoting.ClientSession.State} state The previous state. | 124 * @param {remoting.ClientSession.State} oldState The previous state. |
| 125 * @param {remoting.ClientSession.State} newState The current state. |
123 */ | 126 */ |
124 remoting.ClientSession.prototype.onStateChange = function(state) { }; | 127 remoting.ClientSession.prototype.onStateChange = |
| 128 function(oldState, newState) { }; |
125 | 129 |
126 /** | 130 /** |
127 * Adds <embed> element to |container| and readies the sesion object. | 131 * Adds <embed> element to |container| and readies the sesion object. |
128 * | 132 * |
129 * @param {Element} container The element to add the plugin to. | 133 * @param {Element} container The element to add the plugin to. |
130 * @param {string} oauth2AccessToken A valid OAuth2 access token. | 134 * @param {string} oauth2AccessToken A valid OAuth2 access token. |
131 * @return {void} Nothing. | 135 * @return {void} Nothing. |
132 */ | 136 */ |
133 remoting.ClientSession.prototype.createPluginAndConnect = | 137 remoting.ClientSession.prototype.createPluginAndConnect = |
134 function(container, oauth2AccessToken) { | 138 function(container, oauth2AccessToken) { |
(...skipping 17 matching lines...) Expand all Loading... |
152 /** @param {string} msg The IQ stanza to send. */ | 156 /** @param {string} msg The IQ stanza to send. */ |
153 this.plugin.sendIq = function(msg) { that.sendIq_(msg); }; | 157 this.plugin.sendIq = function(msg) { that.sendIq_(msg); }; |
154 /** @param {string} msg The message to log. */ | 158 /** @param {string} msg The message to log. */ |
155 this.plugin.debugInfo = function(msg) { | 159 this.plugin.debugInfo = function(msg) { |
156 remoting.debug.log('plugin: ' + msg); | 160 remoting.debug.log('plugin: ' + msg); |
157 }; | 161 }; |
158 | 162 |
159 // TODO(ajwong): Is it even worth having this class handle these events? | 163 // TODO(ajwong): Is it even worth having this class handle these events? |
160 // Or would it be better to just allow users to pass in their own handlers | 164 // Or would it be better to just allow users to pass in their own handlers |
161 // and leave these blank by default? | 165 // and leave these blank by default? |
162 this.plugin.connectionInfoUpdate = function() { | 166 /** |
163 that.connectionInfoUpdateCallback(); | 167 * @param {number} status The plugin status. |
| 168 * @param {number} error The plugin error status, if any. |
| 169 */ |
| 170 this.plugin.connectionInfoUpdate = function(status, error) { |
| 171 that.connectionInfoUpdateCallback(status, error); |
164 }; | 172 }; |
165 this.plugin.desktopSizeUpdate = function() { that.onDesktopSizeChanged_(); }; | 173 this.plugin.desktopSizeUpdate = function() { that.onDesktopSizeChanged_(); }; |
166 | 174 |
167 // TODO(garykac): Clean exit if |connect| isn't a function. | 175 // TODO(garykac): Clean exit if |connect| isn't a function. |
168 if (typeof this.plugin.connect === 'function') { | 176 if (typeof this.plugin.connect === 'function') { |
169 this.connectPluginToWcs_(oauth2AccessToken); | 177 this.connectPluginToWcs_(oauth2AccessToken); |
170 } else { | 178 } else { |
171 remoting.debug.log('ERROR: remoting plugin not loaded'); | 179 remoting.debug.log('ERROR: remoting plugin not loaded'); |
172 this.setState_(remoting.ClientSession.State.UNKNOWN_PLUGIN_ERROR); | 180 this.setState_(remoting.ClientSession.State.UNKNOWN_PLUGIN_ERROR); |
173 } | 181 } |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 } | 291 } |
284 } | 292 } |
285 remoting.wcs.setOnIq(onIq); | 293 remoting.wcs.setOnIq(onIq); |
286 that.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid, | 294 that.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid, |
287 this.accessCode); | 295 this.accessCode); |
288 }; | 296 }; |
289 | 297 |
290 /** | 298 /** |
291 * Callback that the plugin invokes to indicate that the connection | 299 * Callback that the plugin invokes to indicate that the connection |
292 * status has changed. | 300 * status has changed. |
| 301 * |
| 302 * @param {number} status The plugin's status. |
| 303 * @param {number} error The plugin's error state, if any. |
293 */ | 304 */ |
294 remoting.ClientSession.prototype.connectionInfoUpdateCallback = function() { | 305 remoting.ClientSession.prototype.connectionInfoUpdateCallback = |
295 var state = this.plugin.status; | 306 function(status, error) { |
| 307 // Old plugins didn't pass the status and error values, so get them directly. |
| 308 // Note that there is a race condition inherent in this approach. |
| 309 if (typeof(status) == 'undefined') { |
| 310 status = this.plugin.status; |
| 311 } |
| 312 if (typeof(error) == 'undefined') { |
| 313 error = this.plugin.error; |
| 314 } |
296 | 315 |
297 // TODO(ajwong): We're doing silly type translation here. Any way to avoid? | 316 if (status == this.plugin.STATUS_CONNECTED) { |
298 if (state == this.plugin.STATUS_UNKNOWN) { | |
299 this.setState_(remoting.ClientSession.State.UNKNOWN); | |
300 } else if (state == this.plugin.STATUS_CONNECTING) { | |
301 this.setState_(remoting.ClientSession.State.CONNECTING); | |
302 } else if (state == this.plugin.STATUS_INITIALIZING) { | |
303 this.setState_(remoting.ClientSession.State.INITIALIZING); | |
304 } else if (state == this.plugin.STATUS_CONNECTED) { | |
305 this.onDesktopSizeChanged_(); | 317 this.onDesktopSizeChanged_(); |
306 this.setState_(remoting.ClientSession.State.CONNECTED); | 318 } else if (status == this.plugin.STATUS_FAILED) { |
307 } else if (state == this.plugin.STATUS_CLOSED) { | 319 this.error = /** @type {remoting.ClientSession.ConnectionError} */ (error); |
308 this.setState_(remoting.ClientSession.State.CLOSED); | |
309 } else if (state == this.plugin.STATUS_FAILED) { | |
310 var error = this.plugin.error; | |
311 if (error == this.plugin.ERROR_HOST_IS_OFFLINE) { | |
312 this.error = remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE; | |
313 } else if (error == this.plugin.ERROR_SESSION_REJECTED) { | |
314 this.error = remoting.ClientSession.ConnectionError.SESSION_REJECTED; | |
315 } else if (error == this.plugin.ERROR_INCOMPATIBLE_PROTOCOL) { | |
316 this.error = remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL; | |
317 } else if (error == this.plugin.ERROR_NETWORK_FAILURE) { | |
318 this.error = remoting.ClientSession.ConnectionError.NETWORK_FAILURE; | |
319 } else { | |
320 this.error = remoting.ClientSession.ConnectionError.OTHER; | |
321 } | |
322 this.setState_(remoting.ClientSession.State.CONNECTION_FAILED); | |
323 } | 320 } |
| 321 this.setState_(/** @type {remoting.ClientSession.State} */ (status)); |
324 }; | 322 }; |
325 | 323 |
326 /** | 324 /** |
327 * @private | 325 * @private |
328 * @param {remoting.ClientSession.State} state The new state for the session. | 326 * @param {remoting.ClientSession.State} newState The new state for the session. |
329 * @return {void} Nothing. | 327 * @return {void} Nothing. |
330 */ | 328 */ |
331 remoting.ClientSession.prototype.setState_ = function(state) { | 329 remoting.ClientSession.prototype.setState_ = function(newState) { |
332 var oldState = this.state; | 330 var oldState = this.state; |
333 this.state = state; | 331 this.state = newState; |
334 if (this.onStateChange) { | 332 if (this.onStateChange) { |
335 this.onStateChange(oldState); | 333 this.onStateChange(oldState, newState); |
336 } | 334 } |
337 this.logToServer.logClientSessionStateChange(this.state, this.error); | 335 this.logToServer.logClientSessionStateChange(this.state, this.error); |
338 }; | 336 }; |
339 | 337 |
340 /** | 338 /** |
341 * This is a callback that gets called when the window is resized. | 339 * This is a callback that gets called when the window is resized. |
342 * | 340 * |
343 * @return {void} Nothing. | 341 * @return {void} Nothing. |
344 */ | 342 */ |
345 remoting.ClientSession.prototype.onWindowSizeChanged = function() { | 343 remoting.ClientSession.prototype.onWindowSizeChanged = function() { |
346 remoting.debug.log('window size changed: ' + | |
347 window.innerWidth + 'x' + | |
348 window.innerHeight); | |
349 this.updateDimensions(); | 344 this.updateDimensions(); |
350 }; | 345 }; |
351 | 346 |
352 /** | 347 /** |
353 * This is a callback that gets called when the plugin notifies us of a change | 348 * This is a callback that gets called when the plugin notifies us of a change |
354 * in the size of the remote desktop. | 349 * in the size of the remote desktop. |
355 * | 350 * |
356 * @private | 351 * @private |
357 * @return {void} Nothing. | 352 * @return {void} Nothing. |
358 */ | 353 */ |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 return { | 411 return { |
417 'video_bandwidth': this.plugin.videoBandwidth, | 412 'video_bandwidth': this.plugin.videoBandwidth, |
418 'video_frame_rate': this.plugin.videoFrameRate, | 413 'video_frame_rate': this.plugin.videoFrameRate, |
419 'capture_latency': this.plugin.videoCaptureLatency, | 414 'capture_latency': this.plugin.videoCaptureLatency, |
420 'encode_latency': this.plugin.videoEncodeLatency, | 415 'encode_latency': this.plugin.videoEncodeLatency, |
421 'decode_latency': this.plugin.videoDecodeLatency, | 416 'decode_latency': this.plugin.videoDecodeLatency, |
422 'render_latency': this.plugin.videoRenderLatency, | 417 'render_latency': this.plugin.videoRenderLatency, |
423 'roundtrip_latency': this.plugin.roundTripLatency | 418 'roundtrip_latency': this.plugin.roundTripLatency |
424 }; | 419 }; |
425 }; | 420 }; |
OLD | NEW |