Chromium Code Reviews| Index: extensions/renderer/resources/media_router_bindings.js |
| diff --git a/extensions/renderer/resources/media_router_bindings.js b/extensions/renderer/resources/media_router_bindings.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..201e7400dc410e5bbb1fab4e93ce24c3e3e10e73 |
| --- /dev/null |
| +++ b/extensions/renderer/resources/media_router_bindings.js |
| @@ -0,0 +1,484 @@ |
| +// Copyright 2015 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. |
| + |
| +var mediaRouterObserver; |
| + |
| +define('media_router_bindings', [ |
| + 'mojo/public/js/bindings', |
| + 'mojo/public/js/core', |
| + 'content/public/renderer/service_provider', |
| + 'chrome/browser/media/router/media_router.mojom', |
| + 'extensions/common/mojo/keep_alive.mojom', |
| + 'mojo/public/js/connection', |
| + 'mojo/public/js/router', |
| +], function(bindings, |
| + core, |
| + serviceProvider, |
| + mediaRouterMojom, |
| + keepAliveMojom, |
| + connector, |
| + routerModule) { |
| + 'use strict'; |
| + |
|
haibinlu
2015/06/01 18:36:33
add @param and @return
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + function routeToMojo(route, opt_sinkName) { |
| + return new mediaRouterMojom.MediaRoute({ |
| + 'media_route_id': route.id, |
| + 'media_source': route.mediaSource, // nullable |
|
haibinlu
2015/06/01 18:36:33
is 'nullable' necessary? since mojo def already do
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + 'media_sink': new mediaRouterMojom.MediaSink({ |
| + 'sink_id': route.sinkId, |
| + 'name': opt_sinkName, |
|
haibinlu
2015/06/01 18:36:33
this "new mediaRouterMojom.MediaSink" can use a ut
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + }), |
| + 'description': route.description, |
| + 'icon_url': route.iconUrl, // nullable |
|
haibinlu
2015/06/01 18:36:32
ditto
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + 'is_local': route.isLocal |
| + }); |
| + } |
| + |
| + /** |
| + * @constructor |
|
haibinlu
2015/06/01 18:36:33
@param
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + */ |
| + function MediaRouterObserver(service) { |
| + /** |
| + * The Mojo service proxy. Allows extension code to call methods that reside |
|
haibinlu
2015/06/01 18:36:33
document type for each member.
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + * in the browser. |
| + */ |
| + this.observer_ = service; |
| + |
| + /** |
| + * The MRPM service delegate. Its methods are called by the browser-resident |
| + * Mojo service. |
| + */ |
| + this.mrpm_ = new MediaRouter(this); |
| + |
| + /** |
| + * The message pipe that connects the Media Router to mrpm_ across |
| + * browser/renderer IPC boundaries. |
| + * Object must remain in scope for the lifetime of the connection to |
| + * prevent the connection from closing automatically. |
| + */ |
| + this.pipe_ = core.createMessagePipe(); |
| + |
| + /** |
| + * Handle to a KeepAlive service object, which prevents the extension from |
| + * being suspended as long as it remains in scope |
| + */ |
| + this.keepAlive_ = null; |
| + |
| + // Define the stub used to bind this.mrpm_ to the Mojo interface. |
| + // Object must remain in scope for the lifetime of the connection to |
| + // prevent the connection from closing automatically. |
| + this.mediaRouterStub_ = connector.bindHandleToStub( |
| + this.pipe_.handle0, mediaRouterMojom.MediaRouter); |
| + |
| + // Link the stub to impl code. |
| + bindings.StubBindings(this.mediaRouterStub_).delegate = this.mrpm_; |
| + } |
| + |
| + |
| + /** |
| + * Starts the Media Router service. |
| + * @return {Promise<string>} instanceId |
|
haibinlu
2015/06/01 18:36:32
!Promise or Promsie?
haibinlu
2015/06/01 18:36:33
explain instanceId
Kevin Marshall
2015/06/02 14:33:41
Done.
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + */ |
| + MediaRouterObserver.prototype.start = function() { |
| + // Register the MRPM with the MR service by connecting it to one of the |
|
haibinlu
2015/06/01 18:36:33
can this comment be part of the method doc?
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + // pipe's handles. |
| + return this.observer_.provideMediaRouter(this.pipe_.handle1).then( |
| + function(result) { |
| + return result.instance_id; |
| + }.bind(this)); |
| + } |
| + |
| + |
| + /** |
| + * Converts a receiver object to a MediaSink Mojo object. |
| + * @param {Object} receiver |
|
haibinlu
2015/06/01 18:36:33
'receiver' to 'sink'. we should use the naming con
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + * @return {mediaRouterMojom.MediaSink} |
| + */ |
| + MediaRouterObserver.sinkToMojo_ = function(receiver) { |
| + return new mediaRouterMojom.MediaSink({ |
| + 'name': receiver.friendlyName, |
| + 'sink_id': receiver.id, |
| + }); |
| + } |
| + |
| + |
| + /** |
| + * Sets the service delegate methods. |
| + * @type {Object} |
|
haibinlu
2015/06/01 18:36:34
what is @type?
is the 'handlers' nullable?
Kevin Marshall
2015/06/02 14:33:40
It is nullable.
|
| + */ |
| + MediaRouterObserver.prototype.setHandlers = function(handlers) { |
| + this.mrpm_.setHandlers(handlers); |
| + } |
| + |
| + |
| + /** |
| + * Gets the keep alive status. |
| + * @return {boolean} |
| + */ |
| + MediaRouterObserver.prototype.getKeepAlive = function() { |
| + return this.keepAlive_ != null; |
| + }; |
| + |
| + |
| + /** |
| + * Called by the Provider Manager when a sink list for a given source is |
| + * updated. |
| + * @param {string} sourceUrn |
| + * @param {Array<Object>} sinks |
|
haibinlu
2015/06/01 18:36:32
Array or !Array?
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + */ |
| + MediaRouterObserver.prototype.onSinksReceived = function(sourceUrn, sinks) { |
| + this.observer_.onSinksReceived(sourceUrn, |
| + sinks.map(MediaRouterObserver.sinkToMojo_)); |
| + }; |
| + |
| + |
| + /** |
| + * Called by the Provider Manager to keep the extension from suspending |
| + * if it enters a state where suspension is undesirable (e.g. there is an |
| + * active MediaRoute.) |
| + * If keepAlive is true, the extension is kept alive. |
| + * If keepAlive is false, the extension is allowed to suspend. |
| + * |
| + * @param {boolean} keepAlive |
| + */ |
| + MediaRouterObserver.prototype.setKeepAlive = function(keepAlive) { |
| + if (keepAlive === false && this.keepAlive_) { |
| + this.keepAlive_.close(); |
| + this.keepAlive_ = null; |
| + } else if (keepAlive === true && !this.keepAlive_) { |
| + this.keepAlive_ = new routerModule.Router( |
| + serviceProvider.connectToService( |
| + keepAliveMojom.KeepAlive.name)); |
| + } |
| + }; |
| + |
| + |
| + /** |
| + * Sends a message to an active mediaRoute. |
|
haibinlu
2015/06/01 18:36:33
media route
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + * |
| + * @param {string} routeId |
| + * @param {Object} message |
|
haibinlu
2015/06/01 18:36:32
@param {!Object|string} message A message that can
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + */ |
| + MediaRouterObserver.prototype.onMessage = function(routeId, message) { |
| + this.observer_.onMessage(routeId, JSON.stringify(message)); |
| + }; |
| + |
| + |
| + /** |
| + * Reports an issue to the Media Router. |
| + * |
| + * @param {Object} issue |
|
haibinlu
2015/06/01 18:36:32
!Object
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + */ |
| + MediaRouterObserver.prototype.onIssue = function(issue) { |
| + function issueSeverityToMojo_(severity) { |
| + switch (severity) { |
| + case 'fatal': |
| + return mediaRouterMojom.Issue.Severity.FATAL; |
| + case 'warning': |
| + return mediaRouterMojom.Issue.Severity.WARNING; |
| + case 'notification': |
| + return mediaRouterMojom.Issue.Severity.NOTIFICATION; |
| + default: |
| + console.error('Unknown issue severity: ' + severity); |
| + return mediaRouterMojom.Issue.Severity.NOTIFICATION; |
| + } |
| + } |
| + |
| + function issueActionToMojo_(action) { |
| + switch (action) { |
| + case 'ok': |
| + return mediaRouterMojom.Issue.ActionType.OK; |
| + case 'cancel': |
| + return mediaRouterMojom.Issue.ActionType.CANCEL; |
| + case 'dismiss': |
| + return mediaRouterMojom.Issue.ActionType.DISMISS; |
| + case 'learn_more': |
| + return mediaRouterMojom.Issue.ActionType.LEARN_MORE; |
| + default: |
| + console.error('Unknown issue action type : ' + action); |
| + return mediaRouterMojom.Issue.ActionType.OK; |
| + } |
| + } |
| + |
| + var secondaryActions = (issue.secondaryActions || []).map(function(e) { |
| + return issueActionToMojo_(e); |
| + }); |
| + this.observer_.onIssue(new mediaRouterMojom.Issue({ |
| + 'route_id': issue.routeId, |
| + 'severity': issueSeverityToMojo_(issue.severity), |
| + 'title': issue.title, |
| + 'message': issue.message, |
| + 'default_action': issueActionToMojo_(issue.defaultAction), |
| + 'secondary_actions': secondaryActions, |
| + 'help_url': issue.helpUrl, |
| + 'is_blocking': issue.isBlocking |
| + })); |
| + }; |
| + |
| + |
|
haibinlu
2015/06/01 18:36:33
@param
Kevin Marshall
2015/06/02 14:33:41
Done.
|
| + MediaRouterObserver.prototype.onRoutesUpdated = function(routes, sinks) { |
| + // Create an inverted index relating sink IDs to their names. |
| + var sinkNameMap = {}; |
| + console.log('sinks: ' + JSON.stringify(sinks)); |
|
haibinlu
2015/06/01 18:36:33
do we always want to log sinks?
Kevin Marshall
2015/06/02 14:33:40
We don't, thanks.
|
| + for (var i = 0; i < sinks.length; i++) { |
| + sinkNameMap[sinks[i].id] = sinks[i].friendlyName; |
| + } |
| + |
| + // Convert mr.Routes to Mojo routes, and adding their sink names |
|
haibinlu
2015/06/01 18:36:33
the type, mr.Routes is not in Chromium.
Kevin Marshall
2015/06/02 14:33:40
done.
|
| + // via sinkNameMap. |
| + var mojoRoutes = []; |
| + for (var j = 0; j < routes.length; j++) { |
| + mojoRoutes.push(routeToMojo(routes[j], sinkNameMap[routes[j].sinkId])); |
| + } |
| + |
| + this.observer_.onRoutesUpdated( |
| + mojoRoutes, |
| + sinks.map(MediaRouterObserver.sinkToMojo_)); |
| + }; |
| + |
| + |
| + /** |
| + * Called by the Provider Manager when an error was encountered for a media |
| + * route. |
| + * |
| + * @param {string} requestId |
|
haibinlu
2015/06/01 18:36:33
document the requestId
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + * @param {string} error |
| + */ |
| + MediaRouterObserver.prototype.onRouteResponseError = |
| + function(requestId, error) { |
| + this.observer_.onRouteResponseError(requestId, error); |
| + }; |
| + |
| + |
| + MediaRouterObserver.prototype.onRouteResponseReceived = |
| + function(requestId, routeId) { |
| + this.observer_.onRouteResponseReceived(requestId, routeId); |
| + }; |
| + |
| + |
| + /** |
| + * Object containing JS callbacks into Provider Manager code. |
| + * @constructor |
| + * @struct |
| + */ |
| + function MediaRouterHandlers() { |
| + /** |
| + * @type {function(!string, !string, !string=, !string=, !number=} |
| + */ |
| + this.createRoute = null; |
| + |
| + /** |
| + * @type {function(!string, !string, !string, !number)} |
|
haibinlu
2015/06/01 18:36:33
use '!string' or 'string' consistently
Kevin Marshall
2015/06/02 14:33:40
Done.
|
| + */ |
| + this.joinRoute = null; |
| + |
| + /** |
| + * @type {function(string)} |
| + */ |
| + this.closeRoute = null; |
| + |
| + /** |
| + * @type {function(string)} |
| + */ |
| + this.startObservingMediaSinks = null; |
| + |
| + /** |
| + * @type {function(string)} |
| + */ |
| + this.stopObservingMediaSinks = null; |
| + |
| + /** |
| + * @type {function(string, string, string)} |
| + */ |
| + this.postMessage = null; |
| + |
| + /** |
| + * @type {function()} |
| + */ |
| + this.startObservingMediaRoutes = null; |
| + |
| + /** |
| + * @type {function()} |
| + */ |
| + this.stopObservingMediaRoutes = null; |
| + }; |
| + |
| + |
| + /** |
| + * Routes calls from Media Router to the Provider Manager extension. |
| + * Registered with the MediaRouter stub. |
| + * |
| + * @constructor |
| + */ |
| + function MediaRouter(mediaRouterObserver) { |
| + /** |
| + * Object containing JS callbacks into Provider Manager code. |
| + * @type {MediaRouterHandlers} |
|
haibinlu
2015/06/01 18:36:33
!MediaRouterHandlers
|
| + */ |
| + this.handlers_ = new MediaRouterHandlers(); |
| + |
| + /** |
| + * Proxy class to the browser's Media Router Mojo service. |
| + */ |
|
haibinlu
2015/06/01 18:36:34
@type
|
| + this.mediaRouter_ = mediaRouterObserver; |
| + } |
| + MediaRouter.prototype = Object.create( |
| + mediaRouterMojom.MediaRouter.stubClass.prototype); |
| + |
| + |
| + /* |
| + * Sets the callback handler used to invoke methods in the Provider Manager. |
| + * @param {MediaRouterHandlers} handlers |
| + */ |
| + MediaRouter.prototype.setHandlers = function(handlers) { |
| + this.handlers_ = handlers; |
|
haibinlu
2015/06/01 18:36:33
can you check all the required methods here instea
Kevin Marshall
2015/06/02 14:33:40
Good idea, done.
|
| + } |
| + |
| + |
| + /** |
| + * Starts querying for sinks capable of displaying the media |sourceUrn|. |
| + * Results are returned by calling OnSinksReceived. |
| + * @param {string} sourceUrn |
| + */ |
| + MediaRouter.prototype.startObservingMediaSinks = |
| + function(sourceUrn) { |
| + if (!this.handlers_ || !this.handlers_.startObservingMediaSinks) { |
| + console.error('startObservingMediaSinks handler not registered.'); |
| + return; |
| + } |
| + this.handlers_.startObservingMediaSinks(sourceUrn); |
| + }; |
| + |
| + |
| + /** |
| + * Stops querying for sinks capable of displaying the media |sourceUrn|. |
| + * @param {string} sourceUrn |
| + */ |
| + MediaRouter.prototype.stopObservingMediaSinks = |
| + function(sourceUrn) { |
| + if (!this.handlers_ || !this.handlers_.stopObservingMediaSinks) { |
| + console.error('stopObservingMediaSinks handler not registered.'); |
| + return; |
| + } |
| + this.handlers_.stopObservingMediaSinks(sourceUrn); |
| + }; |
| + |
| + |
| + /** |
| + * Requests that |sinkId| render the media referenced by |sourceUrn|. |
| + * @param {!string} sourceUrn |
| + * @param {!string} sinkId |
| + * @param {!string=} opt_presentationId |
| + * @param {!string=} opt_origin |
| + * @param {!number=} opt_tabId |
| + * @return {!Promise.<!Object>} |
|
haibinlu
2015/06/01 18:36:32
document that this will always resolve and never r
Kevin Marshall
2015/06/02 14:33:40
I don't think it's worth commenting, since this wo
|
| + */ |
| + MediaRouter.prototype.createRoute = |
| + function(sourceUrn, sinkId, opt_presentationId, opt_origin, opt_tabId) { |
| + if (!this.handlers_ || !this.handlers_.createRoute) { |
| + return Promise.resolve({ |
| + error_text: 'createRoute handler not registered.' |
| + }); |
| + } |
| + return this.handlers_.createRoute( |
| + sourceUrn, sinkId, opt_presentationId, opt_origin, opt_tabId) |
| + .then(function(route) { |
| + // Sink name is not used, so it is omitted here. |
| + return {route: routeToMojo(route, "")}; |
| + }.bind(this)) |
| + .catch(function(err) { |
| + return {error_text: err.message}; |
| + }); |
| + }; |
| + |
| + /** |
| + * Join an existing route given by |presentationId| and render media |
| + * referenced by |sourceUrn|. |origin| and |tabId| are used for checking |
| + * origin/tab scope. |
| + * @param {!string} sourceUrn |
| + * @param {!string} presentationId |
| + * @param {!string} origin |
| + * @param {!number} tabId |
| + * @return {!Promise.<!Object>} Resolved with the route on success, |
| + * or with an error message on failure. |
| + */ |
| + MediaRouter.prototype.joinRoute = |
| + function(sourceUrn, presentationId, origin, tabId) { |
| + if (!this.handlers_.joinRoute) { |
| + return Promise.resolve({error_text: 'joinRoute handler not registered.'}); |
| + } |
| + return this.handlers_.joinRoute(sourceUrn, presentationId, origin, tabId) |
| + .then(function(newRoute) { |
| + return {route: routeToMojo(newRoute)}; |
| + }, |
| + function(err) { |
| + return {error_text: 'Error joining route: ' + err.message}; |
| + }); |
| + }; |
| + |
| + |
| + /** |
| + * Closes route specified by |routeId| |
| + * @param {string} routeId |
| + */ |
| + MediaRouter.prototype.closeRoute = function(routeId) { |
| + if (!this.handlers_ || !this.handlers_.closeRoute) { |
| + console.error('closeRoute handler not registered.'); |
| + return; |
| + } |
| + this.handlers_.closeRoute(routeId); |
| + }; |
| + |
| + |
| + /** |
| + * Posts message to a sink connected by route with |routeId|. |
| + * @param {string} routeId |
| + * @param {string} message |
| + * @param {string} extraInfoJson |
| + */ |
| + MediaRouter.prototype.postMessage = function( |
| + routeId, message, extraInfoJson) { |
| + if (!this.handlers_ || !this.handlers_.postMessage) { |
| + console.error('postMessage handler not registered.'); |
| + return; |
| + } |
| + this.handlers_.postMessage(routeId, message, JSON.parse(extraInfoJson)); |
| + }; |
| + |
| + |
| + /** |
| + * Requests that the Provider Manager start sending information about active |
| + * media routes to the Media Router. |
| + */ |
| + MediaRouter.prototype.startObservingMediaRoutes = function() { |
| + if (!this.handlers_ || !this.handlers_.startObservingMediaRoutes) { |
| + console.error('startObservingMediaRoutes handler not registered.'); |
| + return; |
| + } |
| + |
| + this.handlers_.startObservingMediaRoutes(); |
| + }; |
| + |
| + |
| + /** |
| + * Requests that the Provider Manager stop sending information about active |
| + * media routes to the Media Router. |
| + */ |
| + MediaRouter.prototype.stopObservingMediaRoutes = function() { |
| + if (!this.handlers_ || !this.handlers_.stopObservingMediaRoutes) { |
| + console.error('stopObservingMediaRoutes handler not registered.'); |
| + return; |
| + } |
| + |
| + this.handlers_.stopObservingMediaRoutes(); |
| + }; |
| + |
| + mediaRouterObserver = new MediaRouterObserver(connector.bindHandleToProxy( |
| + serviceProvider.connectToService( |
| + mediaRouterMojom.MediaRouterObserver.name), |
| + mediaRouterMojom.MediaRouterObserver)); |
| + |
| + return mediaRouterObserver; |
| +}); |
| + |