Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(980)

Side by Side Diff: extensions/renderer/resources/media_router_bindings.js

Issue 1162243002: Add Media Router JS Gin module. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporated mfoltz's improvements to comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 var mediaRouterObserver;
6
7 define('media_router_bindings', [
8 'mojo/public/js/bindings',
9 'mojo/public/js/core',
10 'content/public/renderer/service_provider',
11 'chrome/browser/media/router/media_router.mojom',
12 'extensions/common/mojo/keep_alive.mojom',
13 'mojo/public/js/connection',
14 'mojo/public/js/router',
15 ], function(bindings,
16 core,
17 serviceProvider,
18 mediaRouterMojom,
19 keepAliveMojom,
20 connector,
21 routerModule) {
22 'use strict';
23
24 /**
25 * Converts a media sink to a MediaSink Mojo object.
26 * @param {!MediaSink} sink A media sink.
27 * @return {!mediaRouterMojom.MediaSink} A Mojo MediaSink object.
28 */
29 function sinkToMojo_(sink) {
30 return new mediaRouterMojom.MediaSink({
31 'name': sink.friendlyName,
32 'sink_id': sink.id,
33 });
34 }
35
36 /**
37 * Returns a Mojo MediaRoute object given a MediaRoute and a
38 * media sink name.
39 * @param {!MediaRoute} route
40 * @param {!string=} opt_sinkName
41 * @return {!mojo.MediaRoute}
42 */
43 function routeToMojo_(route, opt_sinkName) {
44 return new mediaRouterMojom.MediaRoute({
45 'media_route_id': route.id,
46 'media_source': route.mediaSource,
47 'media_sink': new mediaRouterMojom.MediaSink({
48 'sink_id': route.sinkId,
49 'name': opt_sinkName,
50 }),
51 'description': route.description,
52 'icon_url': route.iconUrl,
53 'is_local': route.isLocal
54 });
55 }
56
57 /**
58 * Creates a new MediaRouterObserver.
59 * Converts a route struct to its Mojo form.
60 * @param {!MediaRouterService} service
61 * @constructor
62 */
63 function MediaRouterObserver(service) {
64 /**
65 * The Mojo service proxy. Allows extension code to call methods that reside
66 * in the browser.
67 * @type {!MediaRouterService}
68 */
69 this.service_ = service;
70
71 /**
72 * The provider manager service delegate. Its methods are called by the
73 * browser-resident Mojo service.
74 * @type {!MediaRouter}
75 */
76 this.mrpm_ = new MediaRouter(this);
77
78 /**
79 * The message pipe that connects the Media Router to mrpm_ across
80 * browser/renderer IPC boundaries. Object must remain in scope for the
81 * lifetime of the connection to prevent the connection from closing
82 * automatically.
83 * @type {!mojo.MessagePipe}
84 */
85 this.pipe_ = core.createMessagePipe();
86
87 /**
88 * Handle to a KeepAlive service object, which prevents the extension from
89 * being suspended as long as it remains in scope.
90 * @type {boolean}
91 */
92 this.keepAlive_ = null;
93
94 /**
95 * The stub used to bind the service delegate to the Mojo interface.
96 * Object must remain in scope for the lifetime of the connection to
97 * prevent the connection from closing automatically.
98 * @type {!mojom.MediaRouter}
99 */
100 this.mediaRouterStub_ = connector.bindHandleToStub(
101 this.pipe_.handle0, mediaRouterMojom.MediaRouter);
102
103 // Link mediaRouterStub_ to the provider manager delegate.
104 bindings.StubBindings(this.mediaRouterStub_).delegate = this.mrpm_;
105 }
106
107 /**
108 * Registers the Media Router Provider Manager with the Media Router.
109 * @return {!Promise<string>} Instance ID for the Media Router.
110 */
111 MediaRouterObserver.prototype.start = function() {
112 return this.service_.provideMediaRouter(this.pipe_.handle1).then(
113 function(result) {
114 return result.instance_id;
115 }.bind(this));
116 }
117
118 /**
119 * Sets the service delegate methods.
120 * @param {Object} handlers
121 */
122 MediaRouterObserver.prototype.setHandlers = function(handlers) {
123 this.mrpm_.setHandlers(handlers);
124 }
125
126 /**
127 * The keep alive status.
128 * @return {boolean}
129 */
130 MediaRouterObserver.prototype.getKeepAlive = function() {
131 return this.keepAlive_ != null;
132 };
133
134 /**
135 * Called by the provider manager when a sink list for a given source is
136 * updated.
137 * @param {!string} sourceUrn
138 * @param {!Array<!MediaSink>} sinks
139 */
140 MediaRouterObserver.prototype.onSinksReceived = function(sourceUrn, sinks) {
141 this.service_.onSinksReceived(sourceUrn,
142 sinks.map(sinkToMojo_));
143 };
144
145 /**
146 * Called by the provider manager to keep the extension from suspending
147 * if it enters a state where suspension is undesirable (e.g. there is an
148 * active MediaRoute.)
149 * If keepAlive is true, the extension is kept alive.
150 * If keepAlive is false, the extension is allowed to suspend.
151 * @param {boolean} keepAlive
152 */
153 MediaRouterObserver.prototype.setKeepAlive = function(keepAlive) {
154 if (keepAlive === false && this.keepAlive_) {
155 this.keepAlive_.close();
156 this.keepAlive_ = null;
157 } else if (keepAlive === true && !this.keepAlive_) {
158 this.keepAlive_ = new routerModule.Router(
159 serviceProvider.connectToService(
160 keepAliveMojom.KeepAlive.name));
161 }
162 };
163
164 /**
165 * Sends a message to an active media route.
166 * @param {!string} routeId
167 * @param {!Object|string} message A message that can be converted to a JSON
168 * string.
169 */
170 MediaRouterObserver.prototype.onMessage = function(routeId, message) {
171 // TODO(mfoltz): Handle binary messages (ArrayBuffer, Blob).
172 this.service_.onMessage(routeId, JSON.stringify(message));
173 };
174
175 /**
176 * Called by the provider manager to send an issue from a media route
177 * provider to the Media Router, to show the user.
178 * @param {!Object} issue The issue object.
179 */
180 MediaRouterObserver.prototype.onIssue = function(issue) {
181 function issueSeverityToMojo_(severity) {
182 switch (severity) {
183 case 'fatal':
184 return mediaRouterMojom.Issue.Severity.FATAL;
185 case 'warning':
186 return mediaRouterMojom.Issue.Severity.WARNING;
187 case 'notification':
188 return mediaRouterMojom.Issue.Severity.NOTIFICATION;
189 default:
190 console.error('Unknown issue severity: ' + severity);
191 return mediaRouterMojom.Issue.Severity.NOTIFICATION;
192 }
193 }
194
195 function issueActionToMojo_(action) {
196 switch (action) {
197 case 'ok':
198 return mediaRouterMojom.Issue.ActionType.OK;
199 case 'cancel':
200 return mediaRouterMojom.Issue.ActionType.CANCEL;
201 case 'dismiss':
202 return mediaRouterMojom.Issue.ActionType.DISMISS;
203 case 'learn_more':
204 return mediaRouterMojom.Issue.ActionType.LEARN_MORE;
205 default:
206 console.error('Unknown issue action type : ' + action);
207 return mediaRouterMojom.Issue.ActionType.OK;
208 }
209 }
210
211 var secondaryActions = (issue.secondaryActions || []).map(function(e) {
212 return issueActionToMojo_(e);
213 });
214 this.service_.onIssue(new mediaRouterMojom.Issue({
215 'route_id': issue.routeId,
216 'severity': issueSeverityToMojo_(issue.severity),
217 'title': issue.title,
218 'message': issue.message,
219 'default_action': issueActionToMojo_(issue.defaultAction),
220 'secondary_actions': secondaryActions,
221 'help_url': issue.helpUrl,
222 'is_blocking': issue.isBlocking
223 }));
224 };
225
226 /**
227 * Called by the provider manager when the set of active routes
228 * has been updated.
229 * @param {!Array<MediaRoute>} routes The active set of media routes.
230 * @param {!Array<MediaSink>} sinks The active set of media sinks.
231 */
232 MediaRouterObserver.prototype.onRoutesUpdated = function(routes, sinks) {
233 // Create an inverted index relating sink IDs to their names.
234 var sinkNameMap = {};
235 for (var i = 0; i < sinks.length; i++) {
236 sinkNameMap[sinks[i].id] = sinks[i].friendlyName;
237 }
238
239 // Convert MediaRoutes to Mojo objects and add their sink names
240 // via sinkNameMap.
241 var mojoRoutes = routes.map(function(route) {
242 return routeToMojo_(routes[j], sinkNameMap[routes[j].sinkId]);
243 });
244
245 this.service_.onRoutesUpdated(
246 mojoRoutes,
247 sinks.map(MediaRouterObserver.sinkToMojo_));
248 };
249
250 /**
251 * Called by the Provider Manager when an error was encountered in response
252 * to a media route creation request.
253 * @param {!string} requestId The request id.
254 * @param {!string} error The error.
255 */
256 MediaRouterObserver.prototype.onRouteResponseError =
257 function(requestId, error) {
258 this.service_.onRouteResponseError(requestId, error);
259 };
260
261 /**
262 * Called by the provider manager when a route was able to be created by a
263 * media route provider.
264 *
265 * @param {string} requestId The media route request id.
266 * @param {string} routeId The id of the media route that was created.
267 */
268 MediaRouterObserver.prototype.onRouteResponseReceived =
269 function(requestId, routeId) {
270 this.service_.onRouteResponseReceived(requestId, routeId);
271 };
272
273 /**
274 * Object containing callbacks set by the provider manager.
275 * TODO(mfoltz): Better named ProviderManagerDelegate?
276 *
277 * @constructor
278 * @struct
279 */
280 function MediaRouterHandlers() {
281 /**
282 * @type {function(!string, !string, !string=, !string=, !number=}
283 */
284 this.createRoute = null;
285
286 /**
287 * @type {function(!string, !string, !string, !number)}
288 */
289 this.joinRoute = null;
290
291 /**
292 * @type {function(string)}
293 */
294 this.closeRoute = null;
295
296 /**
297 * @type {function(string)}
298 */
299 this.startObservingMediaSinks = null;
300
301 /**
302 * @type {function(string)}
303 */
304 this.stopObservingMediaSinks = null;
305
306 /**
307 * @type {function(string, string, string)}
308 */
309 this.postMessage = null;
310
311 /**
312 * @type {function()}
313 */
314 this.startObservingMediaRoutes = null;
315
316 /**
317 * @type {function()}
318 */
319 this.stopObservingMediaRoutes = null;
320 };
321
322 /**
323 * Routes calls from Media Router to the provider manager extension.
324 * Registered with the MediaRouter stub.
325 * @param {!MediaRouterObserver} mediaRouterObserver API to call into the
326 * Media Router mojo interface.
327 * @constructor
328 */
329 function MediaRouter(mediaRouterObserver) {
330 /**
331 * Object containing JS callbacks into Provider Manager code.
332 * @type {!MediaRouterHandlers}
333 */
334 this.handlers_ = new MediaRouterHandlers();
335
336 /**
337 * Proxy class to the browser's Media Router Mojo service.
338 * @type {!MediaRouterObserver}
339 */
340 this.mediaRouter_ = mediaRouterObserver;
341 }
342 MediaRouter.prototype = Object.create(
343 mediaRouterMojom.MediaRouter.stubClass.prototype);
344
345 /*
346 * Sets the callback handler used to invoke methods in the provider manager.
347 *
348 * TODO(mfoltz): Rename to something more explicit?
349 * @param {!MediaRouterHandlers} handlers
350 */
351 MediaRouter.prototype.setHandlers = function(handlers) {
352 this.handlers_ = handlers;
353 var requiredHandlers = [
354 'stopObservingMediaRoutes',
355 'startObservingMediaRoutes',
356 'postMessage',
357 'closeRoute',
358 'joinRoute',
359 'createRoute',
360 'stopObservingMediaSinks',
361 'startObservingMediaRoutes'
362 ];
363 requiredHandlers.forEach(function(nextHandler) {
364 if (!handlers.hasOwnProperty(nextHandler)) {
365 console.error(nextHandler + ' handler not registered.');
366 }
367 });
368 }
369
370 /**
371 * Starts querying for sinks capable of displaying the media source
372 * designated by |sourceUrn|. Results are returned by calling
373 * OnSinksReceived.
374 * @param {!string} sourceUrn
375 */
376 MediaRouter.prototype.startObservingMediaSinks =
377 function(sourceUrn) {
378 this.handlers_.startObservingMediaSinks(sourceUrn);
379 };
380
381 /**
382 * Stops querying for sinks capable of displaying |sourceUrn|.
383 * @param {!string} sourceUrn
384 */
385 MediaRouter.prototype.stopObservingMediaSinks =
386 function(sourceUrn) {
387 this.handlers_.stopObservingMediaSinks(sourceUrn);
388 };
389
390 /**
391 * Requests that |sinkId| render the media referenced by |sourceUrn|. If the
392 * request is from the Presentation API, then opt_origin and opt_tabId will
393 * be populated.
394 * @param {!string} sourceUrn The media source to render.
395 * @param {!string} sinkId The media sink ID.
396 * @param {!string=} opt_presentationId Presentation ID from the site
397 * requesting presentation. TODO(mfoltz): Remove.
398 * @param {!string=} opt_origin The origin of the site requesting
399 * presentation.
400 * @param {!number=} opt_tabId ID of the tab that requested presentation.
401 * @return {!Promise.<!Object>} A Promise resolving to an object describing
402 * the newly created media route.
403 */
404 MediaRouter.prototype.createRoute =
405 function(sourceUrn, sinkId, opt_presentationId, opt_origin, opt_tabId) {
406 return this.handlers_.createRoute(
407 sourceUrn, sinkId, opt_presentationId, opt_origin, opt_tabId)
408 .then(function(route) {
409 // Sink name is not used, so it is omitted here.
410 return {route: routeToMojo_(route, "")};
411 }.bind(this))
412 .catch(function(err) {
413 return {error_text: err.message};
414 });
415 };
416
417 /**
418 * Handles a request via the Presentation API to join an existing route given
419 * by |sourceUrn| and |presentationId|. |origin| and |tabId| are used so the
420 * media route provider can limit the scope by origin or tab.
421 * @param {!string} sourceUrn The media source to render.
422 * @param {!string} presentationId The presentation ID to join.
423 * @param {!string} origin The origin of the site requesting join.
424 * @param {!number} tabId The ID of the tab requesting join.
425 * @return {!Promise.<!Object>} Resolved with the route on success,
426 * or with an error message on failure.
427 */
428 MediaRouter.prototype.joinRoute =
429 function(sourceUrn, presentationId, origin, tabId) {
430 return this.handlers_.joinRoute(sourceUrn, presentationId, origin, tabId)
431 .then(function(newRoute) {
432 return {route: routeToMojo_(newRoute)};
433 },
434 function(err) {
435 return {error_text: 'Error joining route: ' + err.message};
436 });
437 };
438
439 /**
440 * Closes the route specified by |routeId|.
441 * @param {!string} routeId
442 */
443 MediaRouter.prototype.closeRoute = function(routeId) {
444 this.handlers_.closeRoute(routeId);
445 };
446
447 /**
448 * Posts a message to the route designated by |routeId|.
449 * @param {!string} routeId
450 * @param {!string} message
451 * @param {string} extraInfoJson
452 */
453 MediaRouter.prototype.postMessage = function(
454 routeId, message, extraInfoJson) {
455 // TODO(mfoltz): Remove extraInfoJson if no longer needed.
456 this.handlers_.postMessage(routeId, message, JSON.parse(extraInfoJson));
457 };
458
459 /**
460 * Requests that the provider manager start sending information about active
461 * media routes to the Media Router.
462 */
463 MediaRouter.prototype.startObservingMediaRoutes = function() {
464 this.handlers_.startObservingMediaRoutes();
465 };
466
467 /**
468 * Requests that the provider manager stop sending information about active
469 * media routes to the Media Router.
470 */
471 MediaRouter.prototype.stopObservingMediaRoutes = function() {
472 this.handlers_.stopObservingMediaRoutes();
473 };
474
475 mediaRouterObserver = new MediaRouterObserver(connector.bindHandleToProxy(
476 serviceProvider.connectToService(
477 mediaRouterMojom.MediaRouterObserver.name),
478 mediaRouterMojom.MediaRouterObserver));
479
480 return mediaRouterObserver;
481 });
482
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698