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() { | |
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; |
| 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) { |
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) { |
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) { |
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 | |
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'; |
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 |