| OLD | NEW |
| (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 mediaRouter; | |
| 6 | |
| 7 define('media_router_bindings', [ | |
| 8 'content/public/renderer/frame_interfaces', | |
| 9 'chrome/browser/media/router/mojo/media_controller.mojom', | |
| 10 'chrome/browser/media/router/mojo/media_router.mojom', | |
| 11 'chrome/browser/media/router/mojo/media_status.mojom', | |
| 12 'extensions/common/mojo/keep_alive.mojom', | |
| 13 'mojo/common/time.mojom', | |
| 14 'mojo/public/js/bindings', | |
| 15 'net/interfaces/ip_address.mojom', | |
| 16 'url/mojo/origin.mojom', | |
| 17 'url/mojo/url.mojom', | |
| 18 ], function(frameInterfaces, | |
| 19 mediaControllerMojom, | |
| 20 mediaRouterMojom, | |
| 21 mediaStatusMojom, | |
| 22 keepAliveMojom, | |
| 23 timeMojom, | |
| 24 bindings, | |
| 25 ipAddressMojom, | |
| 26 originMojom, | |
| 27 urlMojom) { | |
| 28 'use strict'; | |
| 29 | |
| 30 /** | |
| 31 * Converts a media sink to a MediaSink Mojo object. | |
| 32 * @param {!MediaSink} sink A media sink. | |
| 33 * @return {!mediaRouterMojom.MediaSink} A Mojo MediaSink object. | |
| 34 */ | |
| 35 function sinkToMojo_(sink) { | |
| 36 return new mediaRouterMojom.MediaSink({ | |
| 37 'name': sink.friendlyName, | |
| 38 'description': sink.description, | |
| 39 'domain': sink.domain, | |
| 40 'sink_id': sink.id, | |
| 41 'icon_type': sinkIconTypeToMojo(sink.iconType), | |
| 42 }); | |
| 43 } | |
| 44 | |
| 45 /** | |
| 46 * Converts a media sink's icon type to a MediaSink.IconType Mojo object. | |
| 47 * @param {!MediaSink.IconType} type A media sink's icon type. | |
| 48 * @return {!mediaRouterMojom.MediaSink.IconType} A Mojo MediaSink.IconType | |
| 49 * object. | |
| 50 */ | |
| 51 function sinkIconTypeToMojo(type) { | |
| 52 switch (type) { | |
| 53 case 'cast': | |
| 54 return mediaRouterMojom.MediaSink.IconType.CAST; | |
| 55 case 'cast_audio': | |
| 56 return mediaRouterMojom.MediaSink.IconType.CAST_AUDIO; | |
| 57 case 'cast_audio_group': | |
| 58 return mediaRouterMojom.MediaSink.IconType.CAST_AUDIO_GROUP; | |
| 59 case 'generic': | |
| 60 return mediaRouterMojom.MediaSink.IconType.GENERIC; | |
| 61 case 'hangout': | |
| 62 return mediaRouterMojom.MediaSink.IconType.HANGOUT; | |
| 63 case 'meeting': | |
| 64 return mediaRouterMojom.MediaSink.IconType.MEETING; | |
| 65 default: | |
| 66 console.error('Unknown sink icon type : ' + type); | |
| 67 return mediaRouterMojom.MediaSink.IconType.GENERIC; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 /** | |
| 72 * Returns a Mojo MediaRoute object given a MediaRoute and a | |
| 73 * media sink name. | |
| 74 * @param {!MediaRoute} route | |
| 75 * @return {!mojo.MediaRoute} | |
| 76 */ | |
| 77 function routeToMojo_(route) { | |
| 78 return new mediaRouterMojom.MediaRoute({ | |
| 79 'media_route_id': route.id, | |
| 80 'media_source': route.mediaSource, | |
| 81 'media_sink_id': route.sinkId, | |
| 82 'description': route.description, | |
| 83 'icon_url': route.iconUrl, | |
| 84 'is_local': route.isLocal, | |
| 85 'custom_controller_path': route.customControllerPath, | |
| 86 // Begin newly added properties, followed by the milestone they were | |
| 87 // added. The guard should be safe to remove N+2 milestones later. | |
| 88 'for_display': route.forDisplay, // M47 | |
| 89 'is_incognito': !!route.offTheRecord, // M50 | |
| 90 'is_offscreen_presentation': !!route.isOffscreenPresentation // M56 | |
| 91 }); | |
| 92 } | |
| 93 | |
| 94 /** | |
| 95 * Converts a route message to a RouteMessage Mojo object. | |
| 96 * @param {!RouteMessage} message | |
| 97 * @return {!mediaRouterMojom.RouteMessage} A Mojo RouteMessage object. | |
| 98 */ | |
| 99 function messageToMojo_(message) { | |
| 100 if ("string" == typeof message.message) { | |
| 101 return new mediaRouterMojom.RouteMessage({ | |
| 102 'type': mediaRouterMojom.RouteMessage.Type.TEXT, | |
| 103 'message': message.message, | |
| 104 }); | |
| 105 } else { | |
| 106 return new mediaRouterMojom.RouteMessage({ | |
| 107 'type': mediaRouterMojom.RouteMessage.Type.BINARY, | |
| 108 'data': message.message, | |
| 109 }); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 /** | |
| 114 * Converts presentation connection state to Mojo enum value. | |
| 115 * @param {!string} state | |
| 116 * @return {!mediaRouterMojom.MediaRouter.PresentationConnectionState} | |
| 117 */ | |
| 118 function presentationConnectionStateToMojo_(state) { | |
| 119 var PresentationConnectionState = | |
| 120 mediaRouterMojom.MediaRouter.PresentationConnectionState; | |
| 121 switch (state) { | |
| 122 case 'connecting': | |
| 123 return PresentationConnectionState.CONNECTING; | |
| 124 case 'connected': | |
| 125 return PresentationConnectionState.CONNECTED; | |
| 126 case 'closed': | |
| 127 return PresentationConnectionState.CLOSED; | |
| 128 case 'terminated': | |
| 129 return PresentationConnectionState.TERMINATED; | |
| 130 default: | |
| 131 console.error('Unknown presentation connection state: ' + state); | |
| 132 return PresentationConnectionState.TERMINATED; | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 /** | |
| 137 * Converts presentation connection close reason to Mojo enum value. | |
| 138 * @param {!string} reason | |
| 139 * @return {!mediaRouterMojom.MediaRouter.PresentationConnectionCloseReason} | |
| 140 */ | |
| 141 function presentationConnectionCloseReasonToMojo_(reason) { | |
| 142 var PresentationConnectionCloseReason = | |
| 143 mediaRouterMojom.MediaRouter.PresentationConnectionCloseReason; | |
| 144 switch (reason) { | |
| 145 case 'error': | |
| 146 return PresentationConnectionCloseReason.CONNECTION_ERROR; | |
| 147 case 'closed': | |
| 148 return PresentationConnectionCloseReason.CLOSED; | |
| 149 case 'went_away': | |
| 150 return PresentationConnectionCloseReason.WENT_AWAY; | |
| 151 default: | |
| 152 console.error('Unknown presentation connection close reason : ' + | |
| 153 reason); | |
| 154 return PresentationConnectionCloseReason.CONNECTION_ERROR; | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 // TODO(crbug.com/688177): remove this conversion. | |
| 159 /** | |
| 160 * Converts Mojo origin to string. | |
| 161 * @param {!originMojom.Origin} Mojo origin | |
| 162 * @return {string} | |
| 163 */ | |
| 164 function mojoOriginToString_(origin) { | |
| 165 return origin.unique ? '' : | |
| 166 `${origin.scheme}:\/\/${origin.host}` + | |
| 167 `${origin.port ? `:${origin.port}` : ''}/` | |
| 168 } | |
| 169 | |
| 170 // TODO(crbug.com/688177): remove this conversion. | |
| 171 /** | |
| 172 * Converts string to Mojo origin. | |
| 173 * @param {string} origin | |
| 174 * @return {!originMojom.Origin} | |
| 175 */ | |
| 176 function stringToMojoOrigin_(origin) { | |
| 177 var url = new URL(origin); | |
| 178 var mojoOrigin = {}; | |
| 179 mojoOrigin.scheme = url.protocol.replace(':', ''); | |
| 180 mojoOrigin.host = url.hostname; | |
| 181 var port = url.port ? Number.parseInt(url.port) : 0; | |
| 182 switch (mojoOrigin.scheme) { | |
| 183 case 'http': | |
| 184 mojoOrigin.port = port || 80; | |
| 185 break; | |
| 186 case 'https': | |
| 187 mojoOrigin.port = port || 443; | |
| 188 break; | |
| 189 default: | |
| 190 throw new Error('Scheme must be http or https'); | |
| 191 } | |
| 192 return new originMojom.Origin(mojoOrigin); | |
| 193 } | |
| 194 | |
| 195 /** | |
| 196 * Parses the given route request Error object and converts it to the | |
| 197 * corresponding result code. | |
| 198 * @param {!Error} error | |
| 199 * @return {!mediaRouterMojom.RouteRequestResultCode} | |
| 200 */ | |
| 201 function getRouteRequestResultCode_(error) { | |
| 202 return error.errorCode ? error.errorCode : | |
| 203 mediaRouterMojom.RouteRequestResultCode.UNKNOWN_ERROR; | |
| 204 } | |
| 205 | |
| 206 /** | |
| 207 * Creates and returns a successful route response from given route. | |
| 208 * @param {!MediaRoute} route | |
| 209 * @return {!Object} | |
| 210 */ | |
| 211 function toSuccessRouteResponse_(route) { | |
| 212 return { | |
| 213 route: routeToMojo_(route), | |
| 214 result_code: mediaRouterMojom.RouteRequestResultCode.OK | |
| 215 }; | |
| 216 } | |
| 217 | |
| 218 /** | |
| 219 * Creates and returns a error route response from given Error object. | |
| 220 * @param {!Error} error | |
| 221 * @return {!Object} | |
| 222 */ | |
| 223 function toErrorRouteResponse_(error) { | |
| 224 return { | |
| 225 error_text: error.message, | |
| 226 result_code: getRouteRequestResultCode_(error) | |
| 227 }; | |
| 228 } | |
| 229 | |
| 230 /** | |
| 231 * Creates a new MediaRouter. | |
| 232 * Converts a route struct to its Mojo form. | |
| 233 * @param {!mediaRouterMojom.MediaRouterPtr} service | |
| 234 * @constructor | |
| 235 */ | |
| 236 function MediaRouter(service) { | |
| 237 /** | |
| 238 * The Mojo service proxy. Allows extension code to call methods that reside | |
| 239 * in the browser. | |
| 240 * @type {!mediaRouterMojom.MediaRouterPtr} | |
| 241 */ | |
| 242 this.service_ = service; | |
| 243 | |
| 244 /** | |
| 245 * The provider manager service delegate. Its methods are called by the | |
| 246 * browser-resident Mojo service. | |
| 247 * @type {!MediaRouter} | |
| 248 */ | |
| 249 this.mrpm_ = new MediaRouteProvider(this); | |
| 250 | |
| 251 /** | |
| 252 * Handle to a KeepAlive service object, which prevents the extension from | |
| 253 * being suspended as long as it remains in scope. | |
| 254 * @type {boolean} | |
| 255 */ | |
| 256 this.keepAlive_ = null; | |
| 257 | |
| 258 /** | |
| 259 * The bindings to bind the service delegate to the Mojo interface. | |
| 260 * Object must remain in scope for the lifetime of the connection to | |
| 261 * prevent the connection from closing automatically. | |
| 262 * @type {!bindings.Binding} | |
| 263 */ | |
| 264 this.mediaRouteProviderBinding_ = new bindings.Binding( | |
| 265 mediaRouterMojom.MediaRouteProvider, this.mrpm_); | |
| 266 } | |
| 267 | |
| 268 /** | |
| 269 * Returns definitions of Mojo core and generated Mojom classes that can be | |
| 270 * used directly by the component. | |
| 271 * @return {!Object} | |
| 272 * TODO(imcheng): We should export these along with MediaRouter. This requires | |
| 273 * us to modify the component to handle multiple exports. When that logic is | |
| 274 * baked in for a couple of milestones, we should be able to remove this | |
| 275 * method. | |
| 276 */ | |
| 277 MediaRouter.prototype.getMojoExports = function() { | |
| 278 return { | |
| 279 Binding: bindings.Binding, | |
| 280 DialMediaSink: mediaRouterMojom.DialMediaSink, | |
| 281 CastMediaSink: mediaRouterMojom.CastMediaSink, | |
| 282 IPAddress: ipAddressMojom.IPAddress, | |
| 283 InterfacePtrController: bindings.InterfacePtrController, | |
| 284 InterfaceRequest: bindings.InterfaceRequest, | |
| 285 MediaController: mediaControllerMojom.MediaController, | |
| 286 MediaStatus: mediaStatusMojom.MediaStatus, | |
| 287 MediaStatusObserverPtr: mediaStatusMojom.MediaStatusObserverPtr, | |
| 288 Sink: mediaRouterMojom.MediaSink, | |
| 289 SinkExtraData: mediaRouterMojom.MediaSinkExtraData, | |
| 290 TimeDelta: timeMojom.TimeDelta, | |
| 291 Url: urlMojom.Url, | |
| 292 }; | |
| 293 }; | |
| 294 | |
| 295 /** | |
| 296 * Registers the Media Router Provider Manager with the Media Router. | |
| 297 * @return {!Promise<string>} Instance ID for the Media Router. | |
| 298 */ | |
| 299 MediaRouter.prototype.start = function() { | |
| 300 return this.service_.registerMediaRouteProvider( | |
| 301 this.mediaRouteProviderBinding_.createInterfacePtrAndBind()).then( | |
| 302 function(result) { | |
| 303 return result.instance_id; | |
| 304 }.bind(this)); | |
| 305 } | |
| 306 | |
| 307 /** | |
| 308 * Sets the service delegate methods. | |
| 309 * @param {Object} handlers | |
| 310 */ | |
| 311 MediaRouter.prototype.setHandlers = function(handlers) { | |
| 312 this.mrpm_.setHandlers(handlers); | |
| 313 } | |
| 314 | |
| 315 /** | |
| 316 * The keep alive status. | |
| 317 * @return {boolean} | |
| 318 */ | |
| 319 MediaRouter.prototype.getKeepAlive = function() { | |
| 320 return this.keepAlive_ != null; | |
| 321 }; | |
| 322 | |
| 323 /** | |
| 324 * Called by the provider manager when a sink list for a given source is | |
| 325 * updated. | |
| 326 * @param {!string} sourceUrn | |
| 327 * @param {!Array<!MediaSink>} sinks | |
| 328 * @param {!Array<string>} origins | |
| 329 */ | |
| 330 MediaRouter.prototype.onSinksReceived = function(sourceUrn, sinks, | |
| 331 origins) { | |
| 332 this.service_.onSinksReceived(sourceUrn, sinks.map(sinkToMojo_), | |
| 333 origins.map(stringToMojoOrigin_)); | |
| 334 }; | |
| 335 | |
| 336 /** | |
| 337 * Called by the provider manager when a sink is found to notify the MR of the | |
| 338 * sink's ID. The actual sink will be returned through the normal sink list | |
| 339 * update process, so this helps the MR identify the search result in the | |
| 340 * list. | |
| 341 * @param {string} pseudoSinkId ID of the pseudo sink that started the | |
| 342 * search. | |
| 343 * @param {string} sinkId ID of the newly-found sink. | |
| 344 */ | |
| 345 MediaRouter.prototype.onSearchSinkIdReceived = function( | |
| 346 pseudoSinkId, sinkId) { | |
| 347 this.service_.onSearchSinkIdReceived(pseudoSinkId, sinkId); | |
| 348 }; | |
| 349 | |
| 350 /** | |
| 351 * Called by the provider manager to keep the extension from suspending | |
| 352 * if it enters a state where suspension is undesirable (e.g. there is an | |
| 353 * active MediaRoute.) | |
| 354 * If keepAlive is true, the extension is kept alive. | |
| 355 * If keepAlive is false, the extension is allowed to suspend. | |
| 356 * @param {boolean} keepAlive | |
| 357 */ | |
| 358 MediaRouter.prototype.setKeepAlive = function(keepAlive) { | |
| 359 if (keepAlive === false && this.keepAlive_) { | |
| 360 this.keepAlive_.ptr.reset(); | |
| 361 this.keepAlive_ = null; | |
| 362 } else if (keepAlive === true && !this.keepAlive_) { | |
| 363 this.keepAlive_ = new keepAliveMojom.KeepAlivePtr( | |
| 364 frameInterfaces.getInterface(keepAliveMojom.KeepAlive.name)); | |
| 365 } | |
| 366 }; | |
| 367 | |
| 368 /** | |
| 369 * Called by the provider manager to send an issue from a media route | |
| 370 * provider to the Media Router, to show the user. | |
| 371 * @param {!Object} issue The issue object. | |
| 372 */ | |
| 373 MediaRouter.prototype.onIssue = function(issue) { | |
| 374 function issueSeverityToMojo_(severity) { | |
| 375 switch (severity) { | |
| 376 case 'fatal': | |
| 377 return mediaRouterMojom.Issue.Severity.FATAL; | |
| 378 case 'warning': | |
| 379 return mediaRouterMojom.Issue.Severity.WARNING; | |
| 380 case 'notification': | |
| 381 return mediaRouterMojom.Issue.Severity.NOTIFICATION; | |
| 382 default: | |
| 383 console.error('Unknown issue severity: ' + severity); | |
| 384 return mediaRouterMojom.Issue.Severity.NOTIFICATION; | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 function issueActionToMojo_(action) { | |
| 389 switch (action) { | |
| 390 case 'dismiss': | |
| 391 return mediaRouterMojom.Issue.ActionType.DISMISS; | |
| 392 case 'learn_more': | |
| 393 return mediaRouterMojom.Issue.ActionType.LEARN_MORE; | |
| 394 default: | |
| 395 console.error('Unknown issue action type : ' + action); | |
| 396 return mediaRouterMojom.Issue.ActionType.OK; | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 var secondaryActions = (issue.secondaryActions || []).map(function(e) { | |
| 401 return issueActionToMojo_(e); | |
| 402 }); | |
| 403 this.service_.onIssue(new mediaRouterMojom.Issue({ | |
| 404 'route_id': issue.routeId, | |
| 405 'severity': issueSeverityToMojo_(issue.severity), | |
| 406 'title': issue.title, | |
| 407 'message': issue.message, | |
| 408 'default_action': issueActionToMojo_(issue.defaultAction), | |
| 409 'secondary_actions': secondaryActions, | |
| 410 'help_page_id': issue.helpPageId, | |
| 411 'is_blocking': issue.isBlocking | |
| 412 })); | |
| 413 }; | |
| 414 | |
| 415 /** | |
| 416 * Called by the provider manager when the set of active routes | |
| 417 * has been updated. | |
| 418 * @param {!Array<MediaRoute>} routes The active set of media routes. | |
| 419 * @param {string=} sourceUrn The sourceUrn associated with this route | |
| 420 * query. | |
| 421 * @param {Array<string>=} joinableRouteIds The active set of joinable | |
| 422 * media routes. | |
| 423 */ | |
| 424 MediaRouter.prototype.onRoutesUpdated = | |
| 425 function(routes, sourceUrn = '', joinableRouteIds = []) { | |
| 426 this.service_.onRoutesUpdated( | |
| 427 routes.map(routeToMojo_), | |
| 428 sourceUrn, | |
| 429 joinableRouteIds); | |
| 430 }; | |
| 431 | |
| 432 /** | |
| 433 * Called by the provider manager when sink availability has been updated. | |
| 434 * @param {!mediaRouterMojom.MediaRouter.SinkAvailability} availability | |
| 435 * The new sink availability. | |
| 436 */ | |
| 437 MediaRouter.prototype.onSinkAvailabilityUpdated = function(availability) { | |
| 438 this.service_.onSinkAvailabilityUpdated(availability); | |
| 439 }; | |
| 440 | |
| 441 /** | |
| 442 * Called by the provider manager when the state of a presentation connected | |
| 443 * to a route has changed. | |
| 444 * @param {string} routeId | |
| 445 * @param {string} state | |
| 446 */ | |
| 447 MediaRouter.prototype.onPresentationConnectionStateChanged = | |
| 448 function(routeId, state) { | |
| 449 this.service_.onPresentationConnectionStateChanged( | |
| 450 routeId, presentationConnectionStateToMojo_(state)); | |
| 451 }; | |
| 452 | |
| 453 /** | |
| 454 * Called by the provider manager when the state of a presentation connected | |
| 455 * to a route has closed. | |
| 456 * @param {string} routeId | |
| 457 * @param {string} reason | |
| 458 * @param {string} message | |
| 459 */ | |
| 460 MediaRouter.prototype.onPresentationConnectionClosed = | |
| 461 function(routeId, reason, message) { | |
| 462 this.service_.onPresentationConnectionClosed( | |
| 463 routeId, presentationConnectionCloseReasonToMojo_(reason), message); | |
| 464 }; | |
| 465 | |
| 466 /** | |
| 467 * @param {string} routeId | |
| 468 * @param {!Array<!RouteMessage>} mesages | |
| 469 */ | |
| 470 MediaRouter.prototype.onRouteMessagesReceived = function(routeId, messages) { | |
| 471 this.service_.onRouteMessagesReceived( | |
| 472 routeId, messages.map(messageToMojo_)); | |
| 473 }; | |
| 474 | |
| 475 /** | |
| 476 * Object containing callbacks set by the provider manager. | |
| 477 * | |
| 478 * @constructor | |
| 479 * @struct | |
| 480 */ | |
| 481 function MediaRouterHandlers() { | |
| 482 /** | |
| 483 * @type {function(!string, !string, !string, !string, !number)} | |
| 484 */ | |
| 485 this.createRoute = null; | |
| 486 | |
| 487 /** | |
| 488 * @type {function(!string, !string, !string, !number)} | |
| 489 */ | |
| 490 this.joinRoute = null; | |
| 491 | |
| 492 /** | |
| 493 * @type {function(string): Promise} | |
| 494 */ | |
| 495 this.terminateRoute = null; | |
| 496 | |
| 497 /** | |
| 498 * @type {function(string)} | |
| 499 */ | |
| 500 this.startObservingMediaSinks = null; | |
| 501 | |
| 502 /** | |
| 503 * @type {function(string)} | |
| 504 */ | |
| 505 this.stopObservingMediaSinks = null; | |
| 506 | |
| 507 /** | |
| 508 * @type {function(string, string): Promise} | |
| 509 */ | |
| 510 this.sendRouteMessage = null; | |
| 511 | |
| 512 /** | |
| 513 * @type {function(string, Uint8Array): Promise} | |
| 514 */ | |
| 515 this.sendRouteBinaryMessage = null; | |
| 516 | |
| 517 /** | |
| 518 * @type {function(string)} | |
| 519 */ | |
| 520 this.startListeningForRouteMessages = null; | |
| 521 | |
| 522 /** | |
| 523 * @type {function(string)} | |
| 524 */ | |
| 525 this.stopListeningForRouteMessages = null; | |
| 526 | |
| 527 /** | |
| 528 * @type {function(string)} | |
| 529 */ | |
| 530 this.detachRoute = null; | |
| 531 | |
| 532 /** | |
| 533 * @type {function()} | |
| 534 */ | |
| 535 this.startObservingMediaRoutes = null; | |
| 536 | |
| 537 /** | |
| 538 * @type {function()} | |
| 539 */ | |
| 540 this.stopObservingMediaRoutes = null; | |
| 541 | |
| 542 /** | |
| 543 * @type {function()} | |
| 544 */ | |
| 545 this.connectRouteByRouteId = null; | |
| 546 | |
| 547 /** | |
| 548 * @type {function()} | |
| 549 */ | |
| 550 this.enableMdnsDiscovery = null; | |
| 551 | |
| 552 /** | |
| 553 * @type {function()} | |
| 554 */ | |
| 555 this.updateMediaSinks = null; | |
| 556 | |
| 557 /** | |
| 558 * @type {function(string, string, !SinkSearchCriteria): string} | |
| 559 */ | |
| 560 this.searchSinks = null; | |
| 561 | |
| 562 /** | |
| 563 * @type {function()} | |
| 564 */ | |
| 565 this.provideSinks = null; | |
| 566 | |
| 567 /** | |
| 568 * @type {function(string, !bindings.InterfaceRequest): !Promise<boolean>} | |
| 569 */ | |
| 570 this.createMediaRouteController = null; | |
| 571 | |
| 572 /** | |
| 573 * @type {function(string, !mediaStatusMojom.MediaStatusObserverPtr)} | |
| 574 */ | |
| 575 this.setMediaRouteStatusObserver = null; | |
| 576 }; | |
| 577 | |
| 578 /** | |
| 579 * Routes calls from Media Router to the provider manager extension. | |
| 580 * Registered with the MediaRouter stub. | |
| 581 * @param {!MediaRouter} MediaRouter proxy to call into the | |
| 582 * Media Router mojo interface. | |
| 583 * @constructor | |
| 584 */ | |
| 585 function MediaRouteProvider(mediaRouter) { | |
| 586 /** | |
| 587 * Object containing JS callbacks into Provider Manager code. | |
| 588 * @type {!MediaRouterHandlers} | |
| 589 */ | |
| 590 this.handlers_ = new MediaRouterHandlers(); | |
| 591 | |
| 592 /** | |
| 593 * Proxy class to the browser's Media Router Mojo service. | |
| 594 * @type {!MediaRouter} | |
| 595 */ | |
| 596 this.mediaRouter_ = mediaRouter; | |
| 597 } | |
| 598 | |
| 599 /* | |
| 600 * Sets the callback handler used to invoke methods in the provider manager. | |
| 601 * | |
| 602 * @param {!MediaRouterHandlers} handlers | |
| 603 */ | |
| 604 MediaRouteProvider.prototype.setHandlers = function(handlers) { | |
| 605 // TODO(mfoltz): Remove when component that supports this method is | |
| 606 // rolled out to all Chrome channels in M56. | |
| 607 if (!handlers['onBeforeInvokeHandler']) | |
| 608 handlers['onBeforeInvokeHandler'] = () => {}; | |
| 609 this.handlers_ = handlers; | |
| 610 var requiredHandlers = [ | |
| 611 'stopObservingMediaRoutes', | |
| 612 'startObservingMediaRoutes', | |
| 613 'sendRouteMessage', | |
| 614 'sendRouteBinaryMessage', | |
| 615 'startListeningForRouteMessages', | |
| 616 'stopListeningForRouteMessages', | |
| 617 'detachRoute', | |
| 618 'terminateRoute', | |
| 619 'joinRoute', | |
| 620 'createRoute', | |
| 621 'stopObservingMediaSinks', | |
| 622 'startObservingMediaRoutes', | |
| 623 'connectRouteByRouteId', | |
| 624 'enableMdnsDiscovery', | |
| 625 'updateMediaSinks', | |
| 626 'searchSinks', | |
| 627 'provideSinks', | |
| 628 'createMediaRouteController', | |
| 629 'setMediaRouteStatusObserver', | |
| 630 'onBeforeInvokeHandler' | |
| 631 ]; | |
| 632 requiredHandlers.forEach(function(nextHandler) { | |
| 633 if (handlers[nextHandler] === undefined) { | |
| 634 console.error(nextHandler + ' handler not registered.'); | |
| 635 } | |
| 636 }); | |
| 637 } | |
| 638 | |
| 639 /** | |
| 640 * Starts querying for sinks capable of displaying the media source | |
| 641 * designated by |sourceUrn|. Results are returned by calling | |
| 642 * OnSinksReceived. | |
| 643 * @param {!string} sourceUrn | |
| 644 */ | |
| 645 MediaRouteProvider.prototype.startObservingMediaSinks = | |
| 646 function(sourceUrn) { | |
| 647 this.handlers_.onBeforeInvokeHandler(); | |
| 648 this.handlers_.startObservingMediaSinks(sourceUrn); | |
| 649 }; | |
| 650 | |
| 651 /** | |
| 652 * Stops querying for sinks capable of displaying |sourceUrn|. | |
| 653 * @param {!string} sourceUrn | |
| 654 */ | |
| 655 MediaRouteProvider.prototype.stopObservingMediaSinks = | |
| 656 function(sourceUrn) { | |
| 657 this.handlers_.onBeforeInvokeHandler(); | |
| 658 this.handlers_.stopObservingMediaSinks(sourceUrn); | |
| 659 }; | |
| 660 | |
| 661 /** | |
| 662 * Requests that |sinkId| render the media referenced by |sourceUrn|. If the | |
| 663 * request is from the Presentation API, then origin and tabId will | |
| 664 * be populated. | |
| 665 * @param {!string} sourceUrn Media source to render. | |
| 666 * @param {!string} sinkId Media sink ID. | |
| 667 * @param {!string} presentationId Presentation ID from the site | |
| 668 * requesting presentation. TODO(mfoltz): Remove. | |
| 669 * @param {!originMojom.Origin} origin Origin of site requesting presentation. | |
| 670 * @param {!number} tabId ID of tab requesting presentation. | |
| 671 * @param {!timeMojom.TimeDelta} timeout If positive, the timeout duration for | |
| 672 * the request. Otherwise, the default duration will be used. | |
| 673 * @param {!boolean} incognito If true, the route is being requested by | |
| 674 * an incognito profile. | |
| 675 * @return {!Promise.<!Object>} A Promise resolving to an object describing | |
| 676 * the newly created media route, or rejecting with an error message on | |
| 677 * failure. | |
| 678 */ | |
| 679 MediaRouteProvider.prototype.createRoute = | |
| 680 function(sourceUrn, sinkId, presentationId, origin, tabId, | |
| 681 timeout, incognito) { | |
| 682 this.handlers_.onBeforeInvokeHandler(); | |
| 683 return this.handlers_.createRoute( | |
| 684 sourceUrn, sinkId, presentationId, mojoOriginToString_(origin), tabId, | |
| 685 Math.floor(timeout.microseconds / 1000), incognito) | |
| 686 .then(function(route) { | |
| 687 return toSuccessRouteResponse_(route); | |
| 688 }, | |
| 689 function(err) { | |
| 690 return toErrorRouteResponse_(err); | |
| 691 }); | |
| 692 }; | |
| 693 | |
| 694 /** | |
| 695 * Handles a request via the Presentation API to join an existing route given | |
| 696 * by |sourceUrn| and |presentationId|. |origin| and |tabId| are used for | |
| 697 * validating same-origin/tab scope. | |
| 698 * @param {!string} sourceUrn Media source to render. | |
| 699 * @param {!string} presentationId Presentation ID to join. | |
| 700 * @param {!originMojom.Origin} origin Origin of site requesting join. | |
| 701 * @param {!number} tabId ID of tab requesting join. | |
| 702 * @param {!timeMojom.TimeDelta} timeout If positive, the timeout duration for | |
| 703 * the request. Otherwise, the default duration will be used. | |
| 704 * @param {!boolean} incognito If true, the route is being requested by | |
| 705 * an incognito profile. | |
| 706 * @return {!Promise.<!Object>} A Promise resolving to an object describing | |
| 707 * the newly created media route, or rejecting with an error message on | |
| 708 * failure. | |
| 709 */ | |
| 710 MediaRouteProvider.prototype.joinRoute = | |
| 711 function(sourceUrn, presentationId, origin, tabId, timeout, | |
| 712 incognito) { | |
| 713 this.handlers_.onBeforeInvokeHandler(); | |
| 714 return this.handlers_.joinRoute( | |
| 715 sourceUrn, presentationId, mojoOriginToString_(origin), tabId, | |
| 716 Math.floor(timeout.microseconds / 1000), incognito) | |
| 717 .then(function(route) { | |
| 718 return toSuccessRouteResponse_(route); | |
| 719 }, | |
| 720 function(err) { | |
| 721 return toErrorRouteResponse_(err); | |
| 722 }); | |
| 723 }; | |
| 724 | |
| 725 /** | |
| 726 * Handles a request via the Presentation API to join an existing route given | |
| 727 * by |sourceUrn| and |routeId|. |origin| and |tabId| are used for | |
| 728 * validating same-origin/tab scope. | |
| 729 * @param {!string} sourceUrn Media source to render. | |
| 730 * @param {!string} routeId Route ID to join. | |
| 731 * @param {!string} presentationId Presentation ID to join. | |
| 732 * @param {!originMojom.Origin} origin Origin of site requesting join. | |
| 733 * @param {!number} tabId ID of tab requesting join. | |
| 734 * @param {!timeMojom.TimeDelta} timeout If positive, the timeout duration for | |
| 735 * the request. Otherwise, the default duration will be used. | |
| 736 * @param {!boolean} incognito If true, the route is being requested by | |
| 737 * an incognito profile. | |
| 738 * @return {!Promise.<!Object>} A Promise resolving to an object describing | |
| 739 * the newly created media route, or rejecting with an error message on | |
| 740 * failure. | |
| 741 */ | |
| 742 MediaRouteProvider.prototype.connectRouteByRouteId = | |
| 743 function(sourceUrn, routeId, presentationId, origin, tabId, | |
| 744 timeout, incognito) { | |
| 745 this.handlers_.onBeforeInvokeHandler(); | |
| 746 return this.handlers_.connectRouteByRouteId( | |
| 747 sourceUrn, routeId, presentationId, mojoOriginToString_(origin), tabId, | |
| 748 Math.floor(timeout.microseconds / 1000), incognito) | |
| 749 .then(function(route) { | |
| 750 return toSuccessRouteResponse_(route); | |
| 751 }, | |
| 752 function(err) { | |
| 753 return toErrorRouteResponse_(err); | |
| 754 }); | |
| 755 }; | |
| 756 | |
| 757 /** | |
| 758 * Terminates the route specified by |routeId|. | |
| 759 * @param {!string} routeId | |
| 760 * @return {!Promise<!Object>} A Promise resolving to an object describing | |
| 761 * the result of the terminate operation, or rejecting with an error | |
| 762 * message and code if the operation failed. | |
| 763 */ | |
| 764 MediaRouteProvider.prototype.terminateRoute = function(routeId) { | |
| 765 this.handlers_.onBeforeInvokeHandler(); | |
| 766 return this.handlers_.terminateRoute(routeId).then( | |
| 767 () => ({result_code: mediaRouterMojom.RouteRequestResultCode.OK}), | |
| 768 (err) => toErrorRouteResponse_(err)); | |
| 769 }; | |
| 770 | |
| 771 /** | |
| 772 * Posts a message to the route designated by |routeId|. | |
| 773 * @param {!string} routeId | |
| 774 * @param {!string} message | |
| 775 * @return {!Promise.<boolean>} Resolved with true if the message was sent, | |
| 776 * or false on failure. | |
| 777 */ | |
| 778 MediaRouteProvider.prototype.sendRouteMessage = function( | |
| 779 routeId, message) { | |
| 780 this.handlers_.onBeforeInvokeHandler(); | |
| 781 return this.handlers_.sendRouteMessage(routeId, message) | |
| 782 .then(function() { | |
| 783 return {'sent': true}; | |
| 784 }, function() { | |
| 785 return {'sent': false}; | |
| 786 }); | |
| 787 }; | |
| 788 | |
| 789 /** | |
| 790 * Sends a binary message to the route designated by |routeId|. | |
| 791 * @param {!string} routeId | |
| 792 * @param {!Array<number>} data | |
| 793 * @return {!Promise.<boolean>} Resolved with true if the data was sent, | |
| 794 * or false on failure. | |
| 795 */ | |
| 796 MediaRouteProvider.prototype.sendRouteBinaryMessage = function( | |
| 797 routeId, data) { | |
| 798 this.handlers_.onBeforeInvokeHandler(); | |
| 799 return this.handlers_.sendRouteBinaryMessage(routeId, new Uint8Array(data)) | |
| 800 .then(function() { | |
| 801 return {'sent': true}; | |
| 802 }, function() { | |
| 803 return {'sent': false}; | |
| 804 }); | |
| 805 }; | |
| 806 | |
| 807 /** | |
| 808 * Listen for messages from a route. | |
| 809 * @param {!string} routeId | |
| 810 */ | |
| 811 MediaRouteProvider.prototype.startListeningForRouteMessages = function( | |
| 812 routeId) { | |
| 813 this.handlers_.onBeforeInvokeHandler(); | |
| 814 this.handlers_.startListeningForRouteMessages(routeId); | |
| 815 }; | |
| 816 | |
| 817 /** | |
| 818 * @param {!string} routeId | |
| 819 */ | |
| 820 MediaRouteProvider.prototype.stopListeningForRouteMessages = function( | |
| 821 routeId) { | |
| 822 this.handlers_.onBeforeInvokeHandler(); | |
| 823 this.handlers_.stopListeningForRouteMessages(routeId); | |
| 824 }; | |
| 825 | |
| 826 /** | |
| 827 * Indicates that the presentation connection that was connected to |routeId| | |
| 828 * is no longer connected to it. | |
| 829 * @param {!string} routeId | |
| 830 */ | |
| 831 MediaRouteProvider.prototype.detachRoute = function( | |
| 832 routeId) { | |
| 833 this.handlers_.detachRoute(routeId); | |
| 834 }; | |
| 835 | |
| 836 /** | |
| 837 * Requests that the provider manager start sending information about active | |
| 838 * media routes to the Media Router. | |
| 839 * @param {!string} sourceUrn | |
| 840 */ | |
| 841 MediaRouteProvider.prototype.startObservingMediaRoutes = function(sourceUrn) { | |
| 842 this.handlers_.onBeforeInvokeHandler(); | |
| 843 this.handlers_.startObservingMediaRoutes(sourceUrn); | |
| 844 }; | |
| 845 | |
| 846 /** | |
| 847 * Requests that the provider manager stop sending information about active | |
| 848 * media routes to the Media Router. | |
| 849 * @param {!string} sourceUrn | |
| 850 */ | |
| 851 MediaRouteProvider.prototype.stopObservingMediaRoutes = function(sourceUrn) { | |
| 852 this.handlers_.onBeforeInvokeHandler(); | |
| 853 this.handlers_.stopObservingMediaRoutes(sourceUrn); | |
| 854 }; | |
| 855 | |
| 856 /** | |
| 857 * Enables mDNS device discovery. | |
| 858 */ | |
| 859 MediaRouteProvider.prototype.enableMdnsDiscovery = function() { | |
| 860 this.handlers_.onBeforeInvokeHandler(); | |
| 861 this.handlers_.enableMdnsDiscovery(); | |
| 862 }; | |
| 863 | |
| 864 /** | |
| 865 * Requests that the provider manager update media sinks. | |
| 866 * @param {!string} sourceUrn | |
| 867 */ | |
| 868 MediaRouteProvider.prototype.updateMediaSinks = function(sourceUrn) { | |
| 869 this.handlers_.onBeforeInvokeHandler(); | |
| 870 this.handlers_.updateMediaSinks(sourceUrn); | |
| 871 }; | |
| 872 | |
| 873 /** | |
| 874 * Requests that the provider manager search its providers for a sink matching | |
| 875 * |searchCriteria| that is compatible with |sourceUrn|. If a sink is found | |
| 876 * that can be used immediately for route creation, its ID is returned. | |
| 877 * Otherwise the empty string is returned. | |
| 878 * | |
| 879 * @param {string} sinkId Sink ID of the pseudo sink generating the request. | |
| 880 * @param {string} sourceUrn Media source to be used with the sink. | |
| 881 * @param {!SinkSearchCriteria} searchCriteria Search criteria for the route | |
| 882 * providers. | |
| 883 * @return {!Promise.<!{sink_id: !string}>} A Promise resolving to either the | |
| 884 * sink ID of the sink found by the search that can be used for route | |
| 885 * creation, or the empty string if no route can be immediately created. | |
| 886 */ | |
| 887 MediaRouteProvider.prototype.searchSinks = function( | |
| 888 sinkId, sourceUrn, searchCriteria) { | |
| 889 this.handlers_.onBeforeInvokeHandler(); | |
| 890 const searchSinksResponse = | |
| 891 this.handlers_.searchSinks(sinkId, sourceUrn, searchCriteria); | |
| 892 | |
| 893 if ('string' == typeof searchSinksResponse) { | |
| 894 // TODO (zijiang): Remove this check when M59 is stable and the | |
| 895 // extension is always returning a promise. | |
| 896 return Promise.resolve({ | |
| 897 'sink_id': sink_id | |
| 898 }); | |
| 899 } | |
| 900 return searchSinksResponse.then( | |
| 901 sink_id => { | |
| 902 return { 'sink_id': sink_id }; | |
| 903 }, | |
| 904 () => { | |
| 905 return { 'sink_id': '' }; | |
| 906 }); | |
| 907 }; | |
| 908 | |
| 909 /** | |
| 910 * Notifies the provider manager that MediaRouter has discovered a list of | |
| 911 * sinks. | |
| 912 * @param {string} providerName | |
| 913 * @param {!Array<!mediaRouterMojom.MediaSink>} sinks | |
| 914 */ | |
| 915 MediaRouteProvider.prototype.provideSinks = function(providerName, sinks) { | |
| 916 this.handlers_.onBeforeInvokeHandler(); | |
| 917 this.handlers_.provideSinks(providerName, sinks); | |
| 918 }; | |
| 919 | |
| 920 /** | |
| 921 * Creates a controller for the given route and binds the given | |
| 922 * InterfaceRequest to it. | |
| 923 * @param {string} routeId | |
| 924 * @param {!bindings.InterfaceRequest} controllerRequest | |
| 925 * @return {!Promise<!{success: boolean}>} Resolves to true if a controller | |
| 926 * is created. Resolves to false if a controller cannot be created, or if | |
| 927 * the controller is already bound. | |
| 928 */ | |
| 929 MediaRouteProvider.prototype.createMediaRouteController = function( | |
| 930 routeId, controllerRequest) { | |
| 931 // TODO(imcheng): Remove this check when M59 is in stable. | |
| 932 if (!this.handlers_.createMediaRouteController) { | |
| 933 return Promise.resolve({success: false}); | |
| 934 } | |
| 935 | |
| 936 this.handlers_.onBeforeInvokeHandler(); | |
| 937 this.handlers_.createMediaRouteController(routeId, controllerRequest) | |
| 938 .then(controller => {success: true}, | |
| 939 e => {success: false}); | |
| 940 } | |
| 941 | |
| 942 /** | |
| 943 * Sets the MediaStatus oberver for a given route. MediaStatus updates are | |
| 944 * notified via the given observer interface. | |
| 945 * @param {string} routeId | |
| 946 * @param {!mediaStatusMojom.MediaStatusObserverPtr} observer | |
| 947 */ | |
| 948 MediaRouteProvider.prototype.setMediaRouteStatusObserver = function( | |
| 949 routeId, observer) { | |
| 950 // TODO(imcheng): Remove this check when M59 is in stable. | |
| 951 if (!this.handlers_.setMediaRouteStatusObserver) { | |
| 952 return; | |
| 953 } | |
| 954 this.handlers_.onBeforeInvokeHandler(); | |
| 955 this.handlers_.setMediaRouteStatusObserver(routeId, observer); | |
| 956 }; | |
| 957 | |
| 958 mediaRouter = new MediaRouter(new mediaRouterMojom.MediaRouterPtr( | |
| 959 frameInterfaces.getInterface(mediaRouterMojom.MediaRouter.name))); | |
| 960 | |
| 961 return mediaRouter; | |
| 962 }); | |
| OLD | NEW |