| 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 |