diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-15 04:04:20 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-15 04:04:20 +0000 |
commit | a11c5b6f8af29722d014f94d86ac0e4559b1f8f4 (patch) | |
tree | 5449c0327acf90f48bc0d3a843413fd0400314df | |
parent | d0dc9d004602783b07b0b9686837d3318b111236 (diff) | |
download | chromium_src-a11c5b6f8af29722d014f94d86ac0e4559b1f8f4.zip chromium_src-a11c5b6f8af29722d014f94d86ac0e4559b1f8f4.tar.gz chromium_src-a11c5b6f8af29722d014f94d86ac0e4559b1f8f4.tar.bz2 |
Make remoting.ClientPlugin an abstract interface.
Now remoting.ClientPlugin is an abstract interface for the plugin
intgration code. ClientPluginV1 implements the current version of the
plugin interface. Messaging-based interface will be added in a separate
CL.
BUG=88353
Review URL: http://codereview.chromium.org/9395020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122027 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | remoting/remoting.gyp | 1 | ||||
-rw-r--r-- | remoting/webapp/choice.html | 2 | ||||
-rw-r--r-- | remoting/webapp/client_plugin.js | 221 | ||||
-rw-r--r-- | remoting/webapp/client_plugin_v1.js | 221 | ||||
-rw-r--r-- | remoting/webapp/client_screen.js | 2 | ||||
-rw-r--r-- | remoting/webapp/client_session.js | 86 | ||||
-rw-r--r-- | remoting/webapp/debug_log.js | 72 | ||||
-rw-r--r-- | remoting/webapp/log_to_server.js | 2 | ||||
-rw-r--r-- | remoting/webapp/server_log_entry.js | 2 | ||||
-rw-r--r-- | remoting/webapp/viewer_plugin_proto.js | 3 |
10 files changed, 376 insertions, 236 deletions
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index e14a3c4..20cb1f3 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -110,6 +110,7 @@ 'webapp/choice.css', 'webapp/choice.html', 'webapp/client_plugin.js', + 'webapp/client_plugin_v1.js', 'webapp/client_screen.js', 'webapp/client_session.js', 'webapp/cs_oauth2_trampoline.js', diff --git a/remoting/webapp/choice.html b/remoting/webapp/choice.html index 3f066c5..e0289f9 100644 --- a/remoting/webapp/choice.html +++ b/remoting/webapp/choice.html @@ -15,8 +15,8 @@ found in the LICENSE file. <link rel="stylesheet" href="main.css" /> <link rel="stylesheet" href="choice.css" /> <link rel="stylesheet" href="toolbar.css" /> - <script src="client_plugin.js"></script> <script src="ask_pin_dialog.js"></script> + <script src="client_plugin_v1.js"></script> <script src="client_screen.js"></script> <script src="client_session.js"></script> <script src="daemon_plugin.js"></script> diff --git a/remoting/webapp/client_plugin.js b/remoting/webapp/client_plugin.js index 9430115..23be145 100644 --- a/remoting/webapp/client_plugin.js +++ b/remoting/webapp/client_plugin.js @@ -2,181 +2,72 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** - * @fileoverview - * Class that wraps low-level details of interacting with the client plugin. - * - * This abstracts a <embed> element and controls the plugin which does - * the actual remoting work. It also handles differences between - * client plugins versions when it is necessary. - */ - -'use strict'; - /** @suppress {duplicate} */ var remoting = remoting || {}; /** - * @param {Element} container The element to add the plugin to. - * @param {string} id Id to use for the plugin element . - * @constructor - */ -remoting.ClientPlugin = function(container, id) { - this.plugin = /** @type {remoting.ViewerPlugin} */ - document.createElement('embed'); - - this.plugin.id = id; - this.plugin.src = 'about://none'; - this.plugin.type = 'application/vnd.chromium.remoting-viewer'; - this.plugin.width = 0; - this.plugin.height = 0; - this.plugin.tabIndex = 0; // Required, otherwise focus() doesn't work. - container.appendChild(this.plugin); - - this.desktopWidth = 0; - this.desktopHeight = 0; - - /** @param {string} iq The Iq stanza received from the host. */ - this.onOutgoingIqHandler = function (iq) {}; - /** @param {string} message Log message. */ - this.onDebugMessageHandler = function (message) {}; - /** - * @param {number} status The plugin status. - * @param {number} error The plugin error status, if any. - */ - this.onConnectionStatusUpdateHandler = function(status, error) {}; - this.onDesktopSizeUpdateHandler = function () {}; - - // Connect Event Handlers - - /** @type {remoting.ClientPlugin} */ - var that = this; - - /** @param {string} iq The IQ stanza to send. */ - this.plugin.sendIq = function(iq) { that.onSendIq_(iq); }; - - /** @param {string} msg The message to log. */ - this.plugin.debugInfo = function(msg) { that.onDebugInfo_(msg); }; - - /** - * @param {number} status The plugin status. - * @param {number} error The plugin error status, if any. - */ - this.plugin.connectionInfoUpdate = function(status, error) { - that.onConnectionInfoUpdate_(status, error); - }; - this.plugin.desktopSizeUpdate = function() { that.onDesktopSizeUpdate_(); }; -}; - -/** @param {string} iq The Iq stanza received from the host. */ -remoting.ClientPlugin.prototype.onSendIq_ = function(iq) { - this.onOutgoingIqHandler(iq); -} - - /** @param {string} message The IQ stanza to send. */ -remoting.ClientPlugin.prototype.onDebugInfo_ = function(message) { - this.onDebugMessageHandler(message); -} - -/** - * @param {number} status The plugin status. - * @param {number} error The plugin error status, if any. + * Interface used for ClientPlugin objects. + * @interface */ -remoting.ClientPlugin.prototype.onConnectionInfoUpdate_= - function(status, error) { - // Old plugins didn't pass the status and error values, so get - // them directly. Note that there is a race condition inherent in - // this approach. - if (typeof(status) == 'undefined') - status = this.plugin.status; - if (typeof(error) == 'undefined') - error = this.plugin.error; - this.onConnectionStatusUpdateHandler(status, error); +remoting.ClientPlugin = function() { }; -remoting.ClientPlugin.prototype.onDesktopSizeUpdate_ = function() { - this.desktopWidth = this.plugin.desktopWidth; - this.desktopHeight = this.plugin.desktopHeight; - this.onDesktopSizeUpdateHandler(); -} +/** @type {number} Desktop width */ +remoting.ClientPlugin.prototype.desktopWidth; +/** @type {number} Desktop height */ +remoting.ClientPlugin.prototype.desktopHeight; -/** - * Chromoting session API version (for this javascript). - * This is compared with the plugin API version to verify that they are - * compatible. - * - * @const - * @private - */ -remoting.ClientPlugin.prototype.API_VERSION_ = 4; +/** @type {function(string): void} Outgoing signaling message callback. */ +remoting.ClientPlugin.prototype.onOutgoingIqHandler; +/** @type {function(string): void} Debug messages callback. */ +remoting.ClientPlugin.prototype.onDebugMessageHandler; +/** @type {function(number, number): void} State change callback. */ +remoting.ClientPlugin.prototype.onConnectionStatusUpdateHandler; +/** @type {function(): void} Desktop size change callback. */ +remoting.ClientPlugin.prototype.onDesktopSizeUpdateHandler; /** - * The oldest API version that we support. - * This will differ from the |API_VERSION_| if we maintain backward - * compatibility with older API versions. + * Initializes the plugin asynchronously and calls specified function + * when done. * - * @const - * @private - */ -remoting.ClientPlugin.prototype.API_MIN_VERSION_ = 2; - - -/** - * Deletes the plugin. + * @param {function(boolean): void} onDone Function to be called when + * the plugin is initialized. Parameter is set to true when the plugin + * is loaded successfully. */ -remoting.ClientPlugin.prototype.cleanup = function() { - this.plugin.parentNode.removeChild(this.plugin); -}; +remoting.ClientPlugin.prototype.initialize = function(onDone) {}; /** - * @return {HTMLElement} HTML element that correspods to the plugin. + * @return {boolean} True if the plugin and web-app versions are compatible. */ -remoting.ClientPlugin.prototype.element = function() { - return this.plugin; -}; +remoting.ClientPlugin.prototype.isSupportedVersion = function() {}; /** - * @return {boolean} True if the plugin was loaded succesfully. + * @return {Element} HTML element that correspods to the plugin. */ -remoting.ClientPlugin.prototype.isLoaded = function() { - return typeof this.plugin.connect === 'function'; -} +remoting.ClientPlugin.prototype.element = function() {}; /** - * @return {boolean} True if the plugin and web-app versions are compatible. + * Deletes the plugin. */ -remoting.ClientPlugin.prototype.isSupportedVersion = function() { - return this.API_VERSION_ >= this.plugin.apiMinVersion && - this.plugin.apiVersion >= this.API_MIN_VERSION_; -}; +remoting.ClientPlugin.prototype.cleanup = function() {}; /** * @return {boolean} True if the plugin supports high-quality scaling. */ -remoting.ClientPlugin.prototype.isHiQualityScalingSupported = function() { - return this.plugin.apiVersion >= 3; -}; +remoting.ClientPlugin.prototype.isHiQualityScalingSupported = + function() {}; /** + * Must be called for each incoming stanza received from the host. * @param {string} iq Incoming IQ stanza. */ -remoting.ClientPlugin.prototype.onIncomingIq = function(iq) { - if (this.plugin && this.plugin.onIq) { - this.plugin.onIq(iq); - } else { - // plugin.onIq may not be set after the plugin has been shut - // down. Particularly this happens when we receive response to - // session-terminate stanza. - remoting.debug.log( - 'plugin.onIq is not set so dropping incoming message.'); - } -}; +remoting.ClientPlugin.prototype.onIncomingIq = function(iq) {}; /** * @param {string} hostJid The jid of the host to connect to. * @param {string} hostPublicKey The base64 encoded version of the host's * public key. - * @param {string} clientJid Local jid. + * @param {string} localJid Local jid. * @param {string} sharedSecret The access code for IT2Me or the PIN * for Me2Me. * @param {string} authenticationMethods Comma-separated list of @@ -185,55 +76,23 @@ remoting.ClientPlugin.prototype.onIncomingIq = function(iq) { * authentication hashes. */ remoting.ClientPlugin.prototype.connect = function( - hostJid, hostPublicKey, clientJid, sharedSecret, - authenticationMethods, authenticationTag) { - if (this.plugin.apiVersion < 4) { - // Client plugin versions prior to 4 didn't support the last two - // parameters. - this.plugin.connect(hostJid, hostPublicKey, clientJid, sharedSecret); - } else { - this.plugin.connect(hostJid, hostPublicKey, clientJid, sharedSecret, - authenticationMethods, authenticationTag); - } -} + hostJid, hostPublicKey, localJid, sharedSecret, + authenticationMethods, authenticationTag) {}; /** * @param {boolean} scaleToFit True if scale-to-fit should be enabled. */ -remoting.ClientPlugin.prototype.setScaleToFit = function(scaleToFit) { - // scaleToFit() will be removed in future versions of the plugin. - if (!!this.plugin && typeof this.plugin.setScaleToFit === 'function') - this.plugin.setScaleToFit(scaleToFit); -}; - +remoting.ClientPlugin.prototype.setScaleToFit = + function(scaleToFit) {}; /** - * + * Release all currently pressed keys. */ -remoting.ClientPlugin.prototype.releaseAllKeys = function() { - this.plugin.releaseAllKeys(); -}; +remoting.ClientPlugin.prototype.releaseAllKeys = function() {}; /** * Returns an associative array with a set of stats for this connection. * - * @return {Object.<string, number>} The connection statistics. + * @return {remoting.ClientSession.PerfStats} The connection statistics. */ -remoting.ClientPlugin.prototype.getPerfStats = function() { - var dict = {}; - dict[remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH] = - this.plugin.videoBandwidth; - dict[remoting.ClientSession.STATS_KEY_VIDEO_FRAME_RATE] = - this.plugin.videoFrameRate; - dict[remoting.ClientSession.STATS_KEY_CAPTURE_LATENCY] = - this.plugin.videoCaptureLatency; - dict[remoting.ClientSession.STATS_KEY_ENCODE_LATENCY] = - this.plugin.videoEncodeLatency; - dict[remoting.ClientSession.STATS_KEY_DECODE_LATENCY] = - this.plugin.videoDecodeLatency; - dict[remoting.ClientSession.STATS_KEY_RENDER_LATENCY] = - this.plugin.videoRenderLatency; - dict[remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY] = - this.plugin.roundTripLatency; - return dict; -}; +remoting.ClientPlugin.prototype.getPerfStats = function() {}; diff --git a/remoting/webapp/client_plugin_v1.js b/remoting/webapp/client_plugin_v1.js new file mode 100644 index 0000000..c4785e2 --- /dev/null +++ b/remoting/webapp/client_plugin_v1.js @@ -0,0 +1,221 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Class that wraps low-level details of interacting with the client plugin. + * + * This abstracts a <embed> element and controls the plugin which does + * the actual remoting work. It also handles differences between + * client plugins versions when it is necessary. + */ + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +/** + * @param {remoting.ViewerPlugin} plugin The plugin embed element. + * @constructor + * @implements {remoting.ClientPlugin} + */ +remoting.ClientPluginV1 = function(plugin) { + this.plugin = plugin; + + this.desktopWidth = 0; + this.desktopHeight = 0; + + /** @param {string} iq The Iq stanza received from the host. */ + this.onOutgoingIqHandler = function (iq) {}; + /** @param {string} message Log message. */ + this.onDebugMessageHandler = function (message) {}; + /** + * @param {number} status The plugin status. + * @param {number} error The plugin error status, if any. + */ + this.onConnectionStatusUpdateHandler = function(status, error) {}; + this.onDesktopSizeUpdateHandler = function () {}; + + // Connect event handlers. + + /** @type {remoting.ClientPluginV1} */ + var that = this; + + /** @param {string} iq The IQ stanza to send. */ + this.plugin.sendIq = function(iq) { that.onSendIq_(iq); }; + + /** @param {string} msg The message to log. */ + this.plugin.debugInfo = function(msg) { that.onDebugInfo_(msg); }; + + /** + * @param {number} status The plugin status. + * @param {number} error The plugin error status, if any. + */ + this.plugin.connectionInfoUpdate = function(status, error) { + that.onConnectionInfoUpdate_(status, error); + }; + this.plugin.desktopSizeUpdate = function() { that.onDesktopSizeUpdate_(); }; +}; + +/** + * Chromoting session API version (for this javascript). + * This is compared with the plugin API version to verify that they are + * compatible. + * + * @const + * @private + */ +remoting.ClientPluginV1.prototype.API_VERSION_ = 4; + +/** + * The oldest API version that we support. + * This will differ from the |API_VERSION_| if we maintain backward + * compatibility with older API versions. + * + * @const + * @private + */ +remoting.ClientPluginV1.prototype.API_MIN_VERSION_ = 2; + +/** @param {string} iq The Iq stanza received from the host. */ +remoting.ClientPluginV1.prototype.onSendIq_ = function(iq) { + this.onOutgoingIqHandler(iq); +} + + /** @param {string} message The IQ stanza to send. */ +remoting.ClientPluginV1.prototype.onDebugInfo_ = function(message) { + this.onDebugMessageHandler(message); +} + +/** + * @param {number} status The plugin status. + * @param {number} error The plugin error status, if any. + */ +remoting.ClientPluginV1.prototype.onConnectionInfoUpdate_= + function(status, error) { + // Old plugins didn't pass the status and error values, so get + // them directly. Note that there is a race condition inherent in + // this approach. + if (typeof(status) == 'undefined') + status = this.plugin.status; + if (typeof(error) == 'undefined') + error = this.plugin.error; + this.onConnectionStatusUpdateHandler(status, error); +}; + +remoting.ClientPluginV1.prototype.onDesktopSizeUpdate_ = function() { + this.desktopWidth = this.plugin.desktopWidth; + this.desktopHeight = this.plugin.desktopHeight; + this.onDesktopSizeUpdateHandler(); +} + +/** + * Deletes the plugin. + */ +remoting.ClientPluginV1.prototype.cleanup = function() { + this.plugin.parentNode.removeChild(this.plugin); +}; + +/** + * @return {Element} HTML element that correspods to the plugin. + */ +remoting.ClientPluginV1.prototype.element = function() { + return this.plugin; +}; + +/** + * @param {function(boolean): void} onDone + */ +remoting.ClientPluginV1.prototype.initialize = function(onDone) { + onDone(typeof this.plugin.connect === 'function'); +}; + +/** + * @return {boolean} True if the plugin and web-app versions are compatible. + */ +remoting.ClientPluginV1.prototype.isSupportedVersion = function() { + return this.API_VERSION_ >= this.plugin.apiMinVersion && + this.plugin.apiVersion >= this.API_MIN_VERSION_; +}; + +/** + * @return {boolean} True if the plugin supports high-quality scaling. + */ +remoting.ClientPluginV1.prototype.isHiQualityScalingSupported = function() { + return this.plugin.apiVersion >= 3; +}; + +/** + * @param {string} iq Incoming IQ stanza. + */ +remoting.ClientPluginV1.prototype.onIncomingIq = function(iq) { + if (this.plugin && this.plugin.onIq) { + this.plugin.onIq(iq); + } else { + // plugin.onIq may not be set after the plugin has been shut + // down. Particularly this happens when we receive response to + // session-terminate stanza. + remoting.debug.log( + 'plugin.onIq is not set so dropping incoming message.'); + } +}; + +/** + * @param {string} hostJid The jid of the host to connect to. + * @param {string} hostPublicKey The base64 encoded version of the host's + * public key. + * @param {string} clientJid Local jid. + * @param {string} sharedSecret The access code for IT2Me or the PIN + * for Me2Me. + * @param {string} authenticationMethods Comma-separated list of + * authentication methods the client should attempt to use. + * @param {string} authenticationTag A host-specific tag to mix into + * authentication hashes. + */ +remoting.ClientPluginV1.prototype.connect = function( + hostJid, hostPublicKey, clientJid, sharedSecret, + authenticationMethods, authenticationTag) { + if (this.plugin.apiVersion < 4) { + // Client plugin versions prior to 4 didn't support the last two + // parameters. + this.plugin.connect(hostJid, hostPublicKey, clientJid, sharedSecret); + } else { + this.plugin.connect(hostJid, hostPublicKey, clientJid, sharedSecret, + authenticationMethods, authenticationTag); + } +}; + +/** + * @param {boolean} scaleToFit True if scale-to-fit should be enabled. + */ +remoting.ClientPluginV1.prototype.setScaleToFit = function(scaleToFit) { + // scaleToFit() will be removed in future versions of the plugin. + if (!!this.plugin && typeof this.plugin.setScaleToFit === 'function') + this.plugin.setScaleToFit(scaleToFit); +}; + + +/** + * Release all currently pressed keys. + */ +remoting.ClientPluginV1.prototype.releaseAllKeys = function() { + this.plugin.releaseAllKeys(); +}; + +/** + * Returns an associative array with a set of stats for this connection. + * + * @return {remoting.ClientSession.PerfStats} The connection statistics. + */ +remoting.ClientPluginV1.prototype.getPerfStats = function() { + /** @type {remoting.ClientSession.PerfStats} */ + return { videoBandwidth: this.plugin.videoBandwidth, + videoFrameRate: this.plugin.videoFrameRate, + captureLatency: this.plugin.videoCaptureLatency, + encodeLatency: this.plugin.videoEncodeLatency, + decodeLatency: this.plugin.videoDecodeLatency, + renderLatency: this.plugin.videoRenderLatency, + roundtripLatency: this.plugin.roundTripLatency }; +}; diff --git a/remoting/webapp/client_screen.js b/remoting/webapp/client_screen.js index 3e6ae7c..8d68fbb 100644 --- a/remoting/webapp/client_screen.js +++ b/remoting/webapp/client_screen.js @@ -231,7 +231,7 @@ function onClientStateChange_(oldState, newState) { showConnectError_(remoting.Error.INVALID_ACCESS_CODE); } - } else if (newState == remoting.ClientSession.State.CONNECTION_FAILED) { + } else if (newState == remoting.ClientSession.State.FAILED) { remoting.debug.log('Client plugin reported connection failed: ' + remoting.clientSession.error); clearPin = true; diff --git a/remoting/webapp/client_session.js b/remoting/webapp/client_session.js index f6d2e2e..c7318d7 100644 --- a/remoting/webapp/client_session.js +++ b/remoting/webapp/client_session.js @@ -78,7 +78,7 @@ remoting.ClientSession.State = { INITIALIZING: 2, CONNECTED: 3, CLOSED: 4, - CONNECTION_FAILED: 5 + FAILED: 5 }; /** @enum {number} */ @@ -97,14 +97,34 @@ remoting.ClientSession.Mode = { ME2ME: 1 }; +/** + * Type used for performance statistics collected by the plugin. + * @constructor + */ +remoting.ClientSession.PerfStats = function() {}; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.videoBandwidth; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.videoFrameRate; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.captureLatency; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.encodeLatency; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.decodeLatency; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.renderLatency; +/** @type {number} */ +remoting.ClientSession.PerfStats.prototype.roundtripLatency; + // Keys for connection statistics. -remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH = 'video_bandwidth'; -remoting.ClientSession.STATS_KEY_VIDEO_FRAME_RATE = 'video_frame_rate'; -remoting.ClientSession.STATS_KEY_CAPTURE_LATENCY = 'capture_latency'; -remoting.ClientSession.STATS_KEY_ENCODE_LATENCY = 'encode_latency'; -remoting.ClientSession.STATS_KEY_DECODE_LATENCY = 'decode_latency'; -remoting.ClientSession.STATS_KEY_RENDER_LATENCY = 'render_latency'; -remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY = 'roundtrip_latency'; +remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH = 'videoBandwidth'; +remoting.ClientSession.STATS_KEY_VIDEO_FRAME_RATE = 'videoFrameRate'; +remoting.ClientSession.STATS_KEY_CAPTURE_LATENCY = 'captureLatency'; +remoting.ClientSession.STATS_KEY_ENCODE_LATENCY = 'encodeLatency'; +remoting.ClientSession.STATS_KEY_DECODE_LATENCY = 'decodeLatency'; +remoting.ClientSession.STATS_KEY_RENDER_LATENCY = 'renderLatency'; +remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY = 'roundtripLatency'; /** * The current state of the session. @@ -113,7 +133,7 @@ remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY = 'roundtrip_latency'; remoting.ClientSession.prototype.state = remoting.ClientSession.State.UNKNOWN; /** - * The last connection error. Set when state is set to CONNECTION_FAILED. + * The last connection error. Set when state is set to FAILED. * @type {remoting.ClientSession.ConnectionError} */ remoting.ClientSession.prototype.error = @@ -136,20 +156,54 @@ remoting.ClientSession.prototype.onStateChange = function(oldState, newState) { }; /** + * @param {Element} container The element to add the plugin to. + * @param {string} id Id to use for the plugin element . + * @return {remoting.ClientPlugin} Create plugin object for the locally + * installed plugin. + */ +remoting.ClientSession.prototype.createClientPlugin_ = function(container, id) { + var plugin = /** @type {remoting.ViewerPlugin} */ + document.createElement('embed'); + + plugin.id = id; + plugin.src = 'about://none'; + plugin.type = 'application/vnd.chromium.remoting-viewer'; + plugin.width = 0; + plugin.height = 0; + plugin.tabIndex = 0; // Required, otherwise focus() doesn't work. + container.appendChild(plugin); + + return new remoting.ClientPluginV1(plugin); +}; + +/** * Adds <embed> element to |container| and readies the sesion object. * * @param {Element} container The element to add the plugin to. * @param {string} oauth2AccessToken A valid OAuth2 access token. - * @return {void} Nothing. */ remoting.ClientSession.prototype.createPluginAndConnect = function(container, oauth2AccessToken) { - this.plugin = new remoting.ClientPlugin(container, this.PLUGIN_ID); + this.plugin = this.createClientPlugin_(container, this.PLUGIN_ID); this.plugin.element().focus(); this.plugin.element().addEventListener('blur', this.refocusPlugin_, false); - if (!this.plugin.isLoaded()) { + /** @type {remoting.ClientSession} */ + var that = this; + /** @param {boolean} result */ + this.plugin.initialize(function(result) { + that.onPluginInitialized_(oauth2AccessToken, result); + }); +}; + +/** + * @param {string} oauth2AccessToken + * @param {boolean} initialized + */ +remoting.ClientSession.prototype.onPluginInitialized_ = + function(oauth2AccessToken, initialized) { + if (!initialized) { remoting.debug.log('ERROR: remoting plugin not loaded'); this.plugin.cleanup(); delete this.plugin; @@ -281,7 +335,7 @@ remoting.ClientSession.prototype.sendIq_ = function(msg) { remoting.wcs.sendIq(msg); } else { remoting.debug.log('Tried to send IQ before WCS was ready.'); - this.setState_(remoting.ClientSession.State.CONNECTION_FAILED); + this.setState_(remoting.ClientSession.State.FAILED); } }; @@ -323,7 +377,7 @@ remoting.ClientSession.prototype.connectionStatusUpdateCallback = function(status, error) { if (status == remoting.ClientSession.State.CONNECTED) { this.onDesktopSizeChanged_(); - } else if (status == remoting.ClientSession.State.CONNECTION_FAILED) { + } else if (status == remoting.ClientSession.State.FAILED) { this.error = /** @type {remoting.ClientSession.ConnectionError} */ (error); } this.setState_(/** @type {remoting.ClientSession.State} */ (status)); @@ -422,7 +476,7 @@ remoting.ClientSession.prototype.updateDimensions = function() { /** * Returns an associative array with a set of stats for this connection. * - * @return {Object.<string, number>} The connection statistics. + * @return {remoting.ClientSession.PerfStats} The connection statistics. */ remoting.ClientSession.prototype.getPerfStats = function() { return this.plugin.getPerfStats(); @@ -431,7 +485,7 @@ remoting.ClientSession.prototype.getPerfStats = function() { /** * Logs statistics. * - * @param {Object.<string, number>} stats + * @param {remoting.ClientSession.PerfStats} stats */ remoting.ClientSession.prototype.logStatistics = function(stats) { this.logToServer.logStatistics(stats, this.mode); diff --git a/remoting/webapp/debug_log.js b/remoting/webapp/debug_log.js index a7a13e4..8cbdf39 100644 --- a/remoting/webapp/debug_log.js +++ b/remoting/webapp/debug_log.js @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -86,46 +86,48 @@ remoting.DebugLog.prototype.toggle = function() { /** * Update the statistics panel. - * @param {Object.<string, number>} stats The connection statistics. + * @param {remoting.ClientSession.PerfStats} stats The connection statistics. */ remoting.DebugLog.prototype.updateStatistics = function(stats) { var units = ''; - var videoBandwidth = stats[remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH]; - if (videoBandwidth < 1024) { - units = 'Bps'; - } else if (videoBandwidth < 1048576) { - units = 'KiBps'; - videoBandwidth = videoBandwidth / 1024; - } else if (videoBandwidth < 1073741824) { - units = 'MiBps'; - videoBandwidth = videoBandwidth / 1048576; - } else { - units = 'GiBps'; - videoBandwidth = videoBandwidth / 1073741824; + var videoBandwidth = stats.videoBandwidth; + if (videoBandwidth != undefined) { + if (videoBandwidth < 1024) { + units = 'Bps'; + } else if (videoBandwidth < 1048576) { + units = 'KiBps'; + videoBandwidth = videoBandwidth / 1024; + } else if (videoBandwidth < 1073741824) { + units = 'MiBps'; + videoBandwidth = videoBandwidth / 1048576; + } else { + units = 'GiBps'; + videoBandwidth = videoBandwidth / 1073741824; + } + } + + /** + * @param {number} value + * @param {string} units + * @returns {string} Formatted number. + */ + function formatStatNumber(value, units) { + if (value != undefined) { + return value.toFixed(2) + ' ' + units; + } else { + return "n/a"; + } } var statistics = document.getElementById('statistics'); - this.statsElement.innerText = - 'Bandwidth: ' + videoBandwidth.toFixed(2) + units + - ', Frame Rate: ' + - (stats[remoting.ClientSession.STATS_KEY_VIDEO_FRAME_RATE] ? - stats[remoting.ClientSession.STATS_KEY_VIDEO_FRAME_RATE].toFixed(2) - + ' fps' : 'n/a') + - ', Capture: ' + - stats[remoting.ClientSession.STATS_KEY_CAPTURE_LATENCY].toFixed(2) + - 'ms' + - ', Encode: ' + - stats[remoting.ClientSession.STATS_KEY_ENCODE_LATENCY].toFixed(2) + - 'ms' + - ', Decode: ' + - stats[remoting.ClientSession.STATS_KEY_DECODE_LATENCY].toFixed(2) + - 'ms' + - ', Render: ' + - stats[remoting.ClientSession.STATS_KEY_RENDER_LATENCY].toFixed(2) + - 'ms' + - ', Latency: ' + - stats[remoting.ClientSession.STATS_KEY_ROUNDTRIP_LATENCY].toFixed(2) + - 'ms'; + this.statsElement.innerText = ( + 'Bandwidth: ' + formatStatNumber(videoBandwidth, units) + + ', Frame Rate: ' + formatStatNumber(stats.videoFrameRate, 'fps') + + ', Capture: ' + formatStatNumber(stats.captureLatency, 'ms') + + ', Encode: ' + formatStatNumber(stats.encodeLatency, 'ms') + + ', Decode: ' + formatStatNumber(stats.decodeLatency, 'ms') + + ', Render: ' + formatStatNumber(stats.renderLatency, 'ms') + + ', Latency: ' + formatStatNumber(stats.roundtripLatency, 'ms')); }; /** diff --git a/remoting/webapp/log_to_server.js b/remoting/webapp/log_to_server.js index cc2310f..83d623e 100644 --- a/remoting/webapp/log_to_server.js +++ b/remoting/webapp/log_to_server.js @@ -109,7 +109,7 @@ remoting.LogToServer.isStartOfSession = function(state) { */ remoting.LogToServer.isEndOfSession = function(state) { return ((state == remoting.ClientSession.State.CLOSED) || - (state == remoting.ClientSession.State.CONNECTION_FAILED)); + (state == remoting.ClientSession.State.FAILED)); }; /** diff --git a/remoting/webapp/server_log_entry.js b/remoting/webapp/server_log_entry.js index cdc0b1e..ad0379b 100644 --- a/remoting/webapp/server_log_entry.js +++ b/remoting/webapp/server_log_entry.js @@ -60,7 +60,7 @@ remoting.ServerLogEntry.getValueForSessionState = function(state) { return 'connected'; case remoting.ClientSession.State.CLOSED: return 'closed'; - case remoting.ClientSession.State.CONNECTION_FAILED: + case remoting.ClientSession.State.FAILED: return 'connection-failed'; default: return 'undefined-' + state; diff --git a/remoting/webapp/viewer_plugin_proto.js b/remoting/webapp/viewer_plugin_proto.js index df725a5..786f408 100644 --- a/remoting/webapp/viewer_plugin_proto.js +++ b/remoting/webapp/viewer_plugin_proto.js @@ -13,6 +13,9 @@ var remoting = remoting || {}; */ remoting.ViewerPlugin = function() { }; +/** @param {string} message The message to send to the host. */ +remoting.ViewerPlugin.prototype.postMessage = function(message) {}; + /** @param {string} iq The Iq stanza received from the host. */ remoting.ViewerPlugin.prototype.onIq = function(iq) {}; |