Chromium Code Reviews| 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 * Session class that handles creation and teardown of a remoting session. | 7 * Session class that handles creation and teardown of a remoting 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 (function() { | |
|
Jamie
2011/10/18 00:19:27
JSCompiler doesn't recognise types inside anonymou
simonmorris
2011/10/18 00:55:36
OK.
| |
| 20 /** | 19 /** |
| 21 * @param {string} hostJid The jid of the host to connect to. | 20 * @param {string} hostJid The jid of the host to connect to. |
| 22 * @param {string} hostPublicKey The base64 encoded version of the host's | 21 * @param {string} hostPublicKey The base64 encoded version of the host's |
| 23 * public key. | 22 * public key. |
| 24 * @param {string} accessCode The access code for the IT2Me connection. | 23 * @param {string} accessCode The access code for the IT2Me connection. |
| 25 * @param {string} email The username for the talk network. | 24 * @param {string} email The username for the talk network. |
| 26 * @param {function(remoting.ClientSession.State):void} onStateChange | 25 * @param {function(remoting.ClientSession.State):void} onStateChange |
| 27 * The callback to invoke when the session changes state. This callback | 26 * The callback to invoke when the session changes state. This callback |
| 28 * occurs after the state changes and is passed the previous state; the | 27 * occurs after the state changes and is passed the previous state; the |
| 29 * new state is accessible via ClientSession's |state| property. | 28 * new state is accessible via ClientSession's |state| property. |
| 30 * @constructor | 29 * @constructor |
| 31 */ | 30 */ |
| 32 remoting.ClientSession = function(hostJid, hostPublicKey, accessCode, email, | 31 remoting.ClientSession = function(hostJid, hostPublicKey, accessCode, email, |
| 33 onStateChange) { | 32 onStateChange) { |
| 34 this.state = remoting.ClientSession.State.CREATED; | 33 this.state = remoting.ClientSession.State.CREATED; |
| 35 | 34 |
| 36 this.hostJid = hostJid; | 35 this.hostJid = hostJid; |
| 37 this.hostPublicKey = hostPublicKey; | 36 this.hostPublicKey = hostPublicKey; |
| 38 this.accessCode = accessCode; | 37 this.accessCode = accessCode; |
| 39 this.email = email; | 38 this.email = email; |
| 40 this.clientJid = ''; | 39 this.clientJid = ''; |
| 40 this.sessionId = ''; | |
| 41 /** @type {remoting.ViewerPlugin} */ this.plugin = null; | |
| 42 | |
| 41 this.onStateChange = onStateChange; | 43 this.onStateChange = onStateChange; |
| 42 }; | 44 }; |
| 43 | 45 |
| 44 /** @enum {number} */ | 46 /** @enum {number} */ |
| 45 remoting.ClientSession.State = { | 47 remoting.ClientSession.State = { |
| 46 UNKNOWN: 0, | 48 UNKNOWN: 0, |
| 47 CREATED: 1, | 49 CREATED: 1, |
| 48 BAD_PLUGIN_VERSION: 2, | 50 BAD_PLUGIN_VERSION: 2, |
| 49 UNKNOWN_PLUGIN_ERROR: 3, | 51 UNKNOWN_PLUGIN_ERROR: 3, |
| 50 CONNECTING: 4, | 52 CONNECTING: 4, |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 /** | 112 /** |
| 111 * The id of the client plugin | 113 * The id of the client plugin |
| 112 * | 114 * |
| 113 * @const | 115 * @const |
| 114 */ | 116 */ |
| 115 remoting.ClientSession.prototype.PLUGIN_ID = 'session-client-plugin'; | 117 remoting.ClientSession.prototype.PLUGIN_ID = 'session-client-plugin'; |
| 116 | 118 |
| 117 /** | 119 /** |
| 118 * Callback to invoke when the state is changed. | 120 * Callback to invoke when the state is changed. |
| 119 * | 121 * |
| 120 * @type {function(remoting.ClientSession.State):void} | 122 * @param {remoting.ClientSession.State} state The previous state. |
| 121 */ | 123 */ |
| 122 remoting.ClientSession.prototype.onStateChange = function(state) { }; | 124 remoting.ClientSession.prototype.onStateChange = function(state) { }; |
| 123 | 125 |
| 124 /** | 126 /** |
| 125 * Adds <embed> element to |container| and readies the sesion object. | 127 * Adds <embed> element to |container| and readies the sesion object. |
| 126 * | 128 * |
| 127 * @param {Element} container The element to add the plugin to. | 129 * @param {Element} container The element to add the plugin to. |
| 128 * @param {string} oauth2AccessToken A valid OAuth2 access token. | 130 * @param {string} oauth2AccessToken A valid OAuth2 access token. |
| 129 * @return {void} Nothing. | 131 * @return {void} Nothing. |
| 130 */ | 132 */ |
| 131 remoting.ClientSession.prototype.createPluginAndConnect = | 133 remoting.ClientSession.prototype.createPluginAndConnect = |
| 132 function(container, oauth2AccessToken) { | 134 function(container, oauth2AccessToken) { |
| 133 this.plugin = /** @type {remoting.ViewerPlugin} */ | 135 this.plugin = /** @type {remoting.ViewerPlugin} */ |
| 134 document.createElement('embed'); | 136 document.createElement('embed'); |
| 135 this.plugin.id = this.PLUGIN_ID; | 137 this.plugin.id = this.PLUGIN_ID; |
| 136 this.plugin.src = 'about://none'; | 138 this.plugin.src = 'about://none'; |
| 137 this.plugin.type = 'pepper-application/x-chromoting'; | 139 this.plugin.type = 'pepper-application/x-chromoting'; |
| 138 this.plugin.width = 0; | 140 this.plugin.width = 0; |
| 139 this.plugin.height = 0; | 141 this.plugin.height = 0; |
| 140 container.appendChild(this.plugin); | 142 container.appendChild(this.plugin); |
| 141 | 143 |
| 142 if (!this.isPluginVersionSupported_(this.plugin)) { | 144 if (!this.isPluginVersionSupported_(this.plugin)) { |
| 143 // TODO(ajwong): Remove from parent. | 145 // TODO(ajwong): Remove from parent. |
| 144 delete this.plugin; | 146 delete this.plugin; |
| 145 this.setState_(remoting.ClientSession.State.BAD_PLUGIN_VERSION); | 147 this.setState_(remoting.ClientSession.State.BAD_PLUGIN_VERSION); |
| 146 return; | 148 return; |
| 147 } | 149 } |
| 148 | 150 |
| 149 var that = this; | 151 /** @type {remoting.ClientSession} */ var that = this; |
|
Jamie
2011/10/18 00:19:27
I don't know why the compiler can't infer the type
simonmorris
2011/10/18 00:55:36
Probably because |this| is a keyword, not a variab
simonmorris
2011/10/18 00:55:36
No newline between "...*/" and "var ..."?
Jamie
2011/10/18 01:42:01
Good point about the callback behaviour. I'd forgo
simonmorris
2011/10/18 15:26:02
OK.
| |
| 152 /** @param {string} msg The IQ stanza to send. */ | |
| 150 this.plugin.sendIq = function(msg) { that.sendIq_(msg); }; | 153 this.plugin.sendIq = function(msg) { that.sendIq_(msg); }; |
| 154 /** @param {string} msg The message to log. */ | |
| 151 this.plugin.debugInfo = function(msg) { | 155 this.plugin.debugInfo = function(msg) { |
| 152 remoting.debug.log('plugin: ' + msg); | 156 remoting.debug.log('plugin: ' + msg); |
| 153 }; | 157 }; |
| 154 | 158 |
| 155 // TODO(ajwong): Is it even worth having this class handle these events? | 159 // TODO(ajwong): Is it even worth having this class handle these events? |
| 156 // Or would it be better to just allow users to pass in their own handlers | 160 // Or would it be better to just allow users to pass in their own handlers |
| 157 // and leave these blank by default? | 161 // and leave these blank by default? |
| 158 this.plugin.connectionInfoUpdate = function() { | 162 this.plugin.connectionInfoUpdate = function() { |
| 159 that.connectionInfoUpdateCallback(); | 163 that.connectionInfoUpdateCallback(); |
| 160 }; | 164 }; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 173 }; | 177 }; |
| 174 | 178 |
| 175 /** | 179 /** |
| 176 * Deletes the <embed> element from the container, without sending a | 180 * Deletes the <embed> element from the container, without sending a |
| 177 * session_terminate request. This is to be called when the session was | 181 * session_terminate request. This is to be called when the session was |
| 178 * disconnected by the Host. | 182 * disconnected by the Host. |
| 179 * | 183 * |
| 180 * @return {void} Nothing. | 184 * @return {void} Nothing. |
| 181 */ | 185 */ |
| 182 remoting.ClientSession.prototype.removePlugin = function() { | 186 remoting.ClientSession.prototype.removePlugin = function() { |
| 183 var plugin = document.getElementById(this.PLUGIN_ID); | 187 if (this.plugin) { |
|
Jamie
2011/10/18 00:19:27
We've stored the plugin already--not sure why we w
simonmorris
2011/10/18 00:55:36
Are you certain |this| is always what you think it
Jamie
2011/10/18 01:42:01
Previously the function referred to both this.plug
simonmorris
2011/10/18 15:26:02
Right - there's a |this.plugin| in the previous ve
| |
| 184 if (plugin) { | |
| 185 var parentNode = this.plugin.parentNode; | 188 var parentNode = this.plugin.parentNode; |
| 186 parentNode.removeChild(plugin); | 189 parentNode.removeChild(this.plugin); |
| 187 plugin = null; | 190 this.plugin = null; |
| 188 } | 191 } |
| 189 } | 192 }; |
| 190 | 193 |
| 191 /** | 194 /** |
| 192 * Deletes the <embed> element from the container and disconnects. | 195 * Deletes the <embed> element from the container and disconnects. |
| 193 * | 196 * |
| 194 * @return {void} Nothing. | 197 * @return {void} Nothing. |
| 195 */ | 198 */ |
| 196 remoting.ClientSession.prototype.disconnect = function() { | 199 remoting.ClientSession.prototype.disconnect = function() { |
| 197 if (remoting.wcs) { | 200 if (remoting.wcs) { |
| 198 remoting.wcs.setOnIq(function(stanza) {}); | 201 remoting.wcs.setOnIq(function(stanza) {}); |
| 199 } | 202 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 * @private | 262 * @private |
| 260 * @param {string} oauth2AccessToken A valid OAuth2 access token. | 263 * @param {string} oauth2AccessToken A valid OAuth2 access token. |
| 261 * @return {void} Nothing. | 264 * @return {void} Nothing. |
| 262 */ | 265 */ |
| 263 remoting.ClientSession.prototype.connectPluginToWcs_ = | 266 remoting.ClientSession.prototype.connectPluginToWcs_ = |
| 264 function(oauth2AccessToken) { | 267 function(oauth2AccessToken) { |
| 265 this.clientJid = remoting.wcs.getJid(); | 268 this.clientJid = remoting.wcs.getJid(); |
| 266 if (this.clientJid == '') { | 269 if (this.clientJid == '') { |
| 267 remoting.debug.log('Tried to connect without a full JID.'); | 270 remoting.debug.log('Tried to connect without a full JID.'); |
| 268 } | 271 } |
| 269 var that = this; | 272 /** @type {remoting.ClientSession} */ var that = this; |
| 270 remoting.wcs.setOnIq(function(stanza) { | 273 /** @param {string} stanza The IQ stanza received. */ |
| 271 remoting.debug.log('Receiving Iq: ' + stanza); | 274 var onIq = function(stanza) { |
|
Jamie
2011/10/18 00:19:27
It's fiddly to add type information to anonymous f
simonmorris
2011/10/18 00:55:36
OK.
| |
| 272 that.plugin.onIq(stanza); | 275 remoting.debug.log('Receiving Iq: ' + stanza); |
| 273 }); | 276 that.plugin.onIq(stanza); |
| 277 } | |
| 278 remoting.wcs.setOnIq(onIq); | |
| 274 that.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid, | 279 that.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid, |
| 275 this.accessCode); | 280 this.accessCode); |
| 276 }; | 281 }; |
| 277 | 282 |
| 278 /** | 283 /** |
| 279 * Callback that the plugin invokes to indicate that the connection | 284 * Callback that the plugin invokes to indicate that the connection |
| 280 * status has changed. | 285 * status has changed. |
| 281 */ | 286 */ |
| 282 remoting.ClientSession.prototype.connectionInfoUpdateCallback = function() { | 287 remoting.ClientSession.prototype.connectionInfoUpdateCallback = function() { |
| 283 var state = this.plugin.status; | 288 var state = this.plugin.status; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 295 } else if (state == this.plugin.STATUS_CLOSED) { | 300 } else if (state == this.plugin.STATUS_CLOSED) { |
| 296 this.setState_(remoting.ClientSession.State.CLOSED); | 301 this.setState_(remoting.ClientSession.State.CLOSED); |
| 297 } else if (state == this.plugin.STATUS_FAILED) { | 302 } else if (state == this.plugin.STATUS_FAILED) { |
| 298 var error = this.plugin.error; | 303 var error = this.plugin.error; |
| 299 if (error == this.plugin.ERROR_HOST_IS_OFFLINE) { | 304 if (error == this.plugin.ERROR_HOST_IS_OFFLINE) { |
| 300 error = remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE; | 305 error = remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE; |
| 301 } else if (error == this.plugin.ERROR_SESSION_REJECTED) { | 306 } else if (error == this.plugin.ERROR_SESSION_REJECTED) { |
| 302 error = remoting.ClientSession.ConnectionError.SESSION_REJECTED; | 307 error = remoting.ClientSession.ConnectionError.SESSION_REJECTED; |
| 303 } else if (error == this.plugin.ERROR_INCOMPATIBLE_PROTOCOL) { | 308 } else if (error == this.plugin.ERROR_INCOMPATIBLE_PROTOCOL) { |
| 304 error = remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL; | 309 error = remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL; |
| 305 } else if (error == this.plugin.NETWORK_FAILURE) { | 310 } else if (error == this.plugin.ERROR_NETWORK_FAILURE) { |
|
Jamie
2011/10/18 00:19:27
A genuine error! My efforts were not wasted after
| |
| 306 error = remoting.ClientSession.ConnectionError.NETWORK_FAILURE; | 311 error = remoting.ClientSession.ConnectionError.NETWORK_FAILURE; |
| 307 } else { | 312 } else { |
| 308 error = remoting.ClientSession.ConnectionError.OTHER; | 313 error = remoting.ClientSession.ConnectionError.OTHER; |
| 309 } | 314 } |
| 310 this.setState_(remoting.ClientSession.State.CONNECTION_FAILED); | 315 this.setState_(remoting.ClientSession.State.CONNECTION_FAILED); |
| 311 } | 316 } |
| 312 }; | 317 }; |
| 313 | 318 |
| 314 /** | 319 /** |
| 315 * @private | 320 * @private |
| 316 * @param {remoting.ClientSession.State} state The new state for the session. | 321 * @param {remoting.ClientSession.State} state The new state for the session. |
| 317 * @return {void} Nothing. | 322 * @return {void} Nothing. |
| 318 */ | 323 */ |
| 319 remoting.ClientSession.prototype.setState_ = function(state) { | 324 remoting.ClientSession.prototype.setState_ = function(state) { |
| 320 var oldState = this.state; | 325 var oldState = this.state; |
| 321 this.state = state; | 326 this.state = state; |
| 322 if (this.onStateChange) { | 327 if (this.onStateChange) { |
| 323 this.onStateChange(oldState); | 328 this.onStateChange(oldState); |
| 324 } | 329 } |
| 325 }; | 330 }; |
| 326 | 331 |
| 327 /** | 332 /** |
| 328 * This is a callback that gets called when the window is resized. | 333 * This is a callback that gets called when the window is resized. |
| 329 * | 334 * |
| 330 * @private | |
|
Jamie
2011/10/18 00:19:27
This is called externally.
| |
| 331 * @return {void} Nothing. | 335 * @return {void} Nothing. |
| 332 */ | 336 */ |
| 333 remoting.ClientSession.prototype.onWindowSizeChanged = function() { | 337 remoting.ClientSession.prototype.onWindowSizeChanged = function() { |
| 334 remoting.debug.log('window size changed: ' + | 338 remoting.debug.log('window size changed: ' + |
| 335 window.innerWidth + 'x' + | 339 window.innerWidth + 'x' + |
| 336 window.innerHeight); | 340 window.innerHeight); |
| 337 this.updateDimensions(); | 341 this.updateDimensions(); |
| 338 }; | 342 }; |
| 339 | 343 |
| 340 /** | 344 /** |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 // Resize the plugin if necessary. | 379 // Resize the plugin if necessary. |
| 376 this.plugin.width = this.plugin.desktopWidth * scale; | 380 this.plugin.width = this.plugin.desktopWidth * scale; |
| 377 this.plugin.height = this.plugin.desktopHeight * scale; | 381 this.plugin.height = this.plugin.desktopHeight * scale; |
| 378 | 382 |
| 379 // Position the container. | 383 // Position the container. |
| 380 // TODO(wez): We should take into account scrollbars when positioning. | 384 // TODO(wez): We should take into account scrollbars when positioning. |
| 381 var parentNode = this.plugin.parentNode; | 385 var parentNode = this.plugin.parentNode; |
| 382 if (this.plugin.width < windowWidth) | 386 if (this.plugin.width < windowWidth) |
| 383 parentNode.style.left = (windowWidth - this.plugin.width) / 2 + 'px'; | 387 parentNode.style.left = (windowWidth - this.plugin.width) / 2 + 'px'; |
| 384 else | 388 else |
| 385 parentNode.style.left = 0; | 389 parentNode.style.left = '0'; |
|
Jamie
2011/10/18 00:19:27
Setting this to 0 works fine, but the property sho
| |
| 386 if (this.plugin.height < windowHeight) | 390 if (this.plugin.height < windowHeight) |
| 387 parentNode.style.top = (windowHeight - this.plugin.height) / 2 + 'px'; | 391 parentNode.style.top = (windowHeight - this.plugin.height) / 2 + 'px'; |
| 388 else | 392 else |
| 389 parentNode.style.top = 0; | 393 parentNode.style.top = '0'; |
| 390 | 394 |
| 391 remoting.debug.log('plugin dimensions: ' + | 395 remoting.debug.log('plugin dimensions: ' + |
| 392 parentNode.style.left + ',' + | 396 parentNode.style.left + ',' + |
| 393 parentNode.style.top + '-' + | 397 parentNode.style.top + '-' + |
| 394 this.plugin.width + 'x' + this.plugin.height + '.'); | 398 this.plugin.width + 'x' + this.plugin.height + '.'); |
| 395 this.plugin.setScaleToFit(remoting.scaleToFit); | 399 this.plugin.setScaleToFit(remoting.scaleToFit); |
| 396 }; | 400 }; |
| 397 | 401 |
| 398 /** | 402 /** |
| 399 * Returns an associative array with a set of stats for this connection. | 403 * Returns an associative array with a set of stats for this connection. |
| 400 * | 404 * |
| 401 * @return {Object} The connection statistics. | 405 * @return {Object.<string, number>} The connection statistics. |
| 402 */ | 406 */ |
| 403 remoting.ClientSession.prototype.stats = function() { | 407 remoting.ClientSession.prototype.stats = function() { |
| 404 return { | 408 return { |
| 405 'video_bandwidth': this.plugin.videoBandwidth, | 409 'video_bandwidth': this.plugin.videoBandwidth, |
| 406 'capture_latency': this.plugin.videoCaptureLatency, | 410 'capture_latency': this.plugin.videoCaptureLatency, |
| 407 'encode_latency': this.plugin.videoEncodeLatency, | 411 'encode_latency': this.plugin.videoEncodeLatency, |
| 408 'decode_latency': this.plugin.videoDecodeLatency, | 412 'decode_latency': this.plugin.videoDecodeLatency, |
| 409 'render_latency': this.plugin.videoRenderLatency, | 413 'render_latency': this.plugin.videoRenderLatency, |
| 410 'roundtrip_latency': this.plugin.roundTripLatency | 414 'roundtrip_latency': this.plugin.roundTripLatency |
| 411 }; | 415 }; |
| 412 }; | 416 }; |
| 413 | |
| 414 }()); | |
| OLD | NEW |