mark a. foltz | 6faba39b | 2019-07-10 20:40:15 | [diff] [blame] | 1 | # Chrome Media Router |
| 2 | |
| 3 | ## Introduction |
| 4 | |
| 5 | *TODO: Update with integration with Remote Playback API* |
| 6 | |
| 7 | The media router is a component in Chrome responsible for matching clients that |
| 8 | wish to render media or URLs (_media sources_) on devices and endpoints capable |
| 9 | of rendering that content (_media sinks_). When a media source is linked with a |
| 10 | _media sink_, a _media route_ is created that allows two-way messaging between |
| 11 | the source and the sink. The media route allows the application to negotiate a |
| 12 | peer-to-peer media streaming session with the media sink via messaging (e.g., |
| 13 | via [WebRTC](http://www.webrtc.org/) or [Cast Streaming](https://cs.chromium.org/chromium/src/components/mirroring/)), |
| 14 | aka "mirroring." The media route can also be used to request the remote display |
| 15 | to render a URL without an associated peer-to-peer media streaming session, aka |
| 16 | "flinging". The media route can be terminated at user or browser request, |
| 17 | which denies access to the media sink from the application. |
| 18 | |
| 19 | The Web [Presentation API](http://w3c.github.io/presentation-api/) allows a Web |
| 20 | application to request display of Web content on a secondary (wired, or |
| 21 | wireless) screen. The content may be rendered locally and streamed to the |
| 22 | display or rendered remotely. The Web application controls the content by |
| 23 | two-way messaging. |
| 24 | |
| 25 | Note that the non-Blink parts of the media router will be implemented only in |
| 26 | desktop Chrome and ChromeOS. Presentation API functionality will be implemented |
| 27 | in Chrome for Android using analogous platform components such as the [Android |
| 28 | Media Route Provider |
| 29 | framework](https://developer.android.com/guide/topics/media/mediarouteprovider.html). |
| 30 | |
| 31 | *TODO: Add material on 1-UA mode, or add a separate document* |
| 32 | |
| 33 | Offscreen rendering, capture, and streaming of WebContents (required for full |
| 34 | Presentation API support) will be covered in a separate design document. |
| 35 | |
| 36 | ## Objectives |
| 37 | |
| 38 | The objectives of this project: |
| 39 | |
| 40 | * Allow use of media sinks from a multitude of clients, including: Web |
| 41 | applications via the Presentation API; |
| 42 | Chrome apps; the browser itself; and the Chrome OS system shell. |
| 43 | |
| 44 | * Support mirroring locally rendered content to external screens, including |
| 45 | on-screen and off-screen tabs, Chrome apps windows, and the system desktop. |
| 46 | |
| 47 | * Support "flinging" HTML5 documents to remote devices capable of rendering |
| 48 | them. |
| 49 | |
| 50 | * Support the [Cast Chrome Sender |
| 51 | SDK](https://developers.google.com/cast/docs/reference/chrome/) on desktop and |
| 52 | Android without any user installed extensions. |
| 53 | |
| 54 | * Allow new types of media sinks to be added to Chrome by implementing |
| 55 | additional Media Route Providers. |
| 56 | |
| 57 | The following are non-goals but may be objectives for future work: |
| 58 | |
| 59 | * Multicast of local content to multiple sinks at once. |
| 60 | |
| 61 | * Support for third party media route providers in Javascript or |
| 62 | run-time installation of media route providers. |
| 63 | |
| 64 | * Support for sinks that are not primarily intended to render media. |
| 65 | |
| 66 | ## Overview |
| 67 | |
| 68 | The media router consists of four distinct components: |
| 69 | |
| 70 | 1. The Chrome Media Router is a browser service exposed in-process via C++ API |
| 71 | and is exposed to other processes via a set of two Mojo interfaces: the |
| 72 | Presentation interface and the Media Router API interface. Its job is to field |
| 73 | requests from clients for media sink availability, media route |
| 74 | construction/destruction, and media route control via messaging. It also |
| 75 | controls the Media Router Dialog and delegates many functions to the Media |
| 76 | Router component extension. |
| 77 | |
| 78 | 2. *TODO: update* The Media Router extension is an external component extension |
| 79 | responsible for direct interaction with media sinks. The component extension |
| 80 | will initially support use of [Cast](http://www.google.com/cast/) and |
| 81 | [DIAL](http://www.dial-multiscreen.org/) devices with more types of sinks to be |
| 82 | added over time. The component extension interacts with the Chrome Media Router |
| 83 | via the Media Router API Mojo service, and uses some chrome.\* platform APIs, |
| 84 | such as chrome.dial, chrome.cast.channel, and chrome.mdns to implement network |
| 85 | level interaction with Cast and DIAL devices. |
| 86 | |
| 87 | 3. Users interact with the Chrome Media Router through the Media Router |
| 88 | Dialog. This dialog allows users to choose the destination media sink |
| 89 | for new media routes and view and stop active media routes. It may be pulled up |
| 90 | by the user clicking the Cast icon in the browser toolbar, or at the request of |
| 91 | a Web application via the Presentation API. It is implemented in Views. |
| 92 | |
| 93 | 4. The PresentationService mojo interface acts as a bridge between the Chrome |
| 94 | Media Router and the Blink implementations of the Presentation API ([launch |
| 95 | bug](https://code.google.com/p/chromium/issues/detail?id=412331)). |
| 96 | |
| 97 | ## Architecture |
| 98 | |
| 99 | The following diagram illustrates the architecture of the components described above. |
| 100 | |
| 101 | *TODO: update diagram* |
| 102 | |
| 103 | [](https://www.chromium.org/developers/design-documents/media-router/Chrome%20Media%20Router%20Architecture%20%281%29.png?attredirects=0) |
| 104 | |
| 105 | ### Chrome Media Router |
| 106 | |
| 107 | The Chrome Media Router is a browser-resident service that serves as a |
| 108 | media-protocol-agnostic platform for parties interested in media routing. It |
| 109 | provides its clients with a set of APIs for media routing related queries and |
| 110 | operations, including: |
| 111 | |
| 112 | * Register for notifications when a sink is available that can render a media |
| 113 | source. (Media sources are represented as URIs and can represent local media |
| 114 | or remotely hosted content.) |
| 115 | |
| 116 | * Request routing of media for that source, which will show the user the media |
| 117 | router dialog to select a compatible sink. If the user selects a sink, the |
| 118 | media route is returned to the application to allow it to control media |
| 119 | playback. |
| 120 | |
| 121 | * Accept media control actions from the Media Router Dialog for an active media |
| 122 | route and forwarding them to the associated route provider. |
| 123 | |
| 124 | * Send and receive arbitrary (string) messages between the application the media |
| 125 | sink. |
| 126 | |
| 127 | * Terminate media routes, and notify the client and media route provider when |
| 128 | that happens. |
| 129 | |
| 130 | The Chrome Media Router, itself, does not directly interact with media |
| 131 | sinks. *TODO: update* Instead it delegates these requests and responses to a |
| 132 | media route provider in the component extension. The Chrome Media Router will |
| 133 | contain bookkeeping of established routes, pending route requests, and other |
| 134 | related resources, so it does not have to request this information from the |
| 135 | route provider each time. |
| 136 | |
| 137 | The following pseudocode describes how a client of the Chrome Media Router |
| 138 | (through its C++ API) would use it to initiate and control a media sharing |
| 139 | session. |
| 140 | |
| 141 | ### Media Router API Example |
| 142 | |
| 143 | *TODO: update or remove* |
| 144 | |
| 145 | ``` |
| 146 | MediaRouter* media_router = MediaRouterImpl::GetInstance(); |
| 147 | |
| 148 | // Find out what screens are capable of rendering, e.g. www.youtube.com |
| 149 | MediaSource youtube_src = MediaSource::ForPresentationUrl("http://www.youtube.com"); |
| 150 | |
| 151 | // MyMediaSinksObserver should override MediaSinksObserver::OnSinksReceived to |
| 152 | // handle updates to the list of screens compatible with youtube_src |
| 153 | MediaSinksObserver* my_observer = new MyMediaSinksObserver(youtube_src); |
| 154 | media_router->RegisterObserver(my_observer); |
| 155 | |
| 156 | // Ask the user to pick a screen from the list passed to my_observer and |
| 157 | // capture the sink_id (code not shown) |
| 158 | |
| 159 | // Request routing of media for that source. |callback| is passed a |
| 160 | // MediaRouteResponse& that contains a MediaRoute result if successful. |
| 161 | media_router->StartRouteRequest(youtube_src, sink_id, callback); |
| 162 | |
| 163 | // The MediaRoute can be used to post messages to the sink. |
| 164 | media_router->PostMessage(media_route.media_route_id, "some data", "optional_extra_data_json"); |
| 165 | |
| 166 | // The MediaRoute can be closed which signals the sinkto terminate any remote |
| 167 | // app or media streaming session. |
| 168 | media_router->CloseRoute(media_route.media_route_id);` |
| 169 | ``` |
| 170 | |
| 171 | The Media Router interacts with the component extension via a Mojo service, the |
| 172 | Media Router API, that exposes functionality whose implementation is delegated |
| 173 | to the extension. |
| 174 | |
| 175 | ### Media Router API Mojo Interface |
| 176 | |
| 177 | *TODO: Update or replace with link* |
| 178 | |
| 179 | ``` |
| 180 | // Interface for sending messages from the MediaRouter (MR) to the Media |
| 181 | // Router Provider Manager (MRPM). |
| 182 | |
| 183 | interface MediaRouterApiClient { |
| 184 | // Signals the media route manager to route the media located |
| 185 | // at |source_urn| to |sink_id|. |
| 186 | RequestRoute(int64 request_id, string source, string sink_id); |
| 187 | |
| 188 | // Signals the media route manager to close the route specified by |route_id|. |
| 189 | CloseRoute(string route_id); |
| 190 | |
| 191 | // Signals the media route manager to start querying for sinks |
| 192 | // capable of displaying |source|. |
| 193 | AddMediaSinksQuery(string source); |
| 194 | |
| 195 | // Signals the media route manager to stop querying for sinks |
| 196 | // capable of displaying |source|. |
| 197 | RemoveMediaSinksQuery(string source); |
| 198 | |
| 199 | // Sends |message| with optional |extra_info_json| via the media route |
| 200 | // |media_route_id|. |
| 201 | // |extra_info_json| is an empty string if no extra info is provided. |
| 202 | PostMessage(string media_route_id, string message, string extra_info_json); |
| 203 | }; |
| 204 | |
| 205 | // Interface for sending messages from the MRPM to the MR. |
| 206 | [Client=MediaRouterApiClient] |
| 207 | interface MediaRouterApi { |
| 208 | // Called when the provider manager is ready. |
| 209 | OnProviderManagerReady(string extension_id); |
| 210 | |
| 211 | // Called when the Media Route Manager receives a new list of sinks. |
| 212 | OnSinksReceived(string source, |
| 213 | array<MediaSink> sinks, |
| 214 | array<MediaRoute> routes); |
| 215 | |
| 216 | // Called after a MediaRoute is established. |
| 217 | OnRouteResponseReceived(int64 request_id, MediaRoute route); |
| 218 | |
| 219 | // Called when route establishment fails. |
| 220 | OnRouteResponseError(int64 request_id, string error_text); |
| 221 | }; |
| 222 | ``` |
| 223 | |
| 224 | ### Media Router Component Extension |
| 225 | |
| 226 | *TODO: update to discuss in-browser MRPs and Mirroring Service* |
| 227 | |
| 228 | The component extension manages discovery of and network interaction with |
| 229 | individual media sinks. For the purposes of this discussion a sink is a |
| 230 | LAN-connected device that speaks the Cast or DIAL protocol, but in theory it |
| 231 | could be any other type of endpoint that supports media rendering and two-way |
| 232 | messaging. The extension consists of three types of components: |
| 233 | |
| 234 | * Media Route Providers: Each provider is a Javascript bundle that knows how to |
| 235 | find and communicate with a specific type of media sink. It communicates |
| 236 | with the media sink using HTTP/XHR or via device-specific network protocols |
| 237 | (e.g., Cast Channel and Cast Streaming). |
| 238 | |
| 239 | * Media Route Provider Manager: This is responsible for dispatching requests |
| 240 | from the Chrome Media Router to individual providers. It also registers |
| 241 | providers on startup. |
| 242 | |
| 243 | * Mirroring Service: If a media source is requested that represents the tab or |
| 244 | desktop contents, this service acts on the behalf of the application to |
| 245 | initiate the mirroring session. This is handled internally to the component |
| 246 | extension and is not exposed to the rest of the browser, it appears to be |
| 247 | just another media route. |
| 248 | |
| 249 | The component extension is written in JavaScript and includes code for multiple |
| 250 | media route providers. Initially Media Route Providers will be implemented for |
| 251 | Cast and DIAL devices with others to follow. Over time media route providers |
| 252 | that do not rely on proprietary protocols will be implemented in the Chromium |
| 253 | repository. |
| 254 | |
| 255 | As an external component, the extension is installed on the initial run of the |
| 256 | browser. It is built around an event page so it registers itself with the Media |
| 257 | Router, registers itself with discovery APIs to be notified of display |
| 258 | availability, and then suspends. The component extension will only be active |
| 259 | when there are applications with pending sink availability requests or media |
| 260 | routes, or when there is active network traffic between the extension and a |
| 261 | media sink. |
| 262 | |
| 263 | There are several modules to the extension that are loaded on-demand. The main |
| 264 | event page bundles are a few hundred kb. The extension is updated on the Chrome |
| 265 | release cycle with a branch made a week or two after the Chrome branch point. |
| 266 | |
| 267 | ## Tab/Desktop Mirroring |
| 268 | |
| 269 | *TODO: update with discussion of C++ MirroringService* |
| 270 | |
| 271 | Tab and desktop mirroring will request routing of a media source with URN like |
| 272 | urn:google:tab:3 representing tab contents. When the component extension |
| 273 | receives a request to route this source, the media route provider manager will |
| 274 | query route providers to enumerate sinks that can render streamed tab |
| 275 | contents. Once a sink is selected by the user, the mirroring service will create |
| 276 | the appropriate MediaStream using the chrome.tabCapture extension API. The |
| 277 | MediaStream will then be passed to a Cast Streaming or WebRTC session depending |
| 278 | on the preferred protocol of the selected sink. When the media route is |
| 279 | terminated, the associated streaming session and media capture are also |
| 280 | terminated. A similar approach will be used for desktop mirroring but using |
| 281 | chrome.desktopCapture instead. |
| 282 | |
| 283 | # Presentation API |
| 284 | |
| 285 | *TODO: Discuss 1-UA mode* |
| 286 | *TODO: Update for Onion Soup* |
| 287 | |
| 288 | Media routing of Web content will primarily be done through the Presentation |
| 289 | API. Some media sinks (e.g. Cast) can render a subset of Web content natively, |
| 290 | or render an equivalent app experience (e.g., via DIAL). For generic Web |
| 291 | documents, we plan on rendering it in an offscreen WebContents and then using |
| 292 | the Tab Mirroring approach outlined above. The design of the offscreen rendering |
| 293 | capability will be added later to this document. |
| 294 | |
| 295 | The Presentation API implementation in Blink will live in content/ and will |
| 296 | operate on the frame level. It will delegate the calls to the embedder's Media |
| 297 | Router implementation (Android Media Router / Chrome Media Router for Android / |
| 298 | Chrome, respectively) via a common PresentationServiceDelegate interface. A |
| 299 | draft Mojo interface follows (not yet complete): |
| 300 | |
| 301 | ## PresentationService mojo interface |
| 302 | |
| 303 | *TODO: Update or replace with link* |
| 304 | |
| 305 | ``` |
| 306 | interface PresentationService { |
| 307 | // Returns the last screen availability state if it’s changed since the last |
| 308 | // time the method was called. The client has to call this method again when |
| 309 | // handling the result (provided via Mojo callback) to get the next update |
| 310 | // about the availability status. |
| 311 | // May start discovery of the presentation screens. The implementation might |
| 312 | // stop discovery once there are no active calls to GetScreenAvailability. |
| 313 | // |presentation_url| can be specified to help the implementation to filter |
| 314 | // out incompatible screens. |
| 315 | GetScreenAvailability(string? presentation_url) => (bool available); |
| 316 | |
| 317 | // Called when the frame no longer listens to the |
| 318 | // |availablechange| event. |
| 319 | OnScreenAvailabilityListenerRemoved(); |
| 320 | }; |
| 321 | ``` |
| 322 | |
| 323 | *TODO: Update table with current flow, or remove this section* |
| 324 | |
| 325 | Here is how the presentation API will roughly map to Chrome Media Router API: |
| 326 | |
| 327 | **Presentation API** |
| 328 | |
| 329 | **Chrome Media Router** |
| 330 | |
| 331 | Adding onavailablechange listener |
| 332 | |
| 333 | RegisterObserver(), with result propagated back to the RenderFrame / Presentation API. |
| 334 | |
| 335 | startSession |
| 336 | |
| 337 | Opens Media Router Dialog (via MediaRouterDialogController) -> User action -> StartRouteRequest() |
| 338 | |
| 339 | joinSession |
| 340 | |
| 341 | StartRouteRequest() |
| 342 | |
| 343 | postMessage |
| 344 | |
| 345 | PostMessage() |
| 346 | |
| 347 | close |
| 348 | |
| 349 | CloseRoute() |
| 350 | |
| 351 | Adding onmessage listener |
| 352 | |
| 353 | RegisterMessageObserver() (tentative) |
| 354 | |
| 355 | Adding onstatechange listener |
| 356 | |
| 357 | RegisterRouteStateChangeObserver() (tentative) |
| 358 | |
| 359 | ## Media Router Dialog |
| 360 | |
| 361 | End user control of media routing is done through the Media Router Dialog. The |
| 362 | media router dialog is implemented in Views. |
| 363 | |
| 364 | The Media Router Dialog is activated by clicking on the Cast icon, which is |
| 365 | always available to the user. The Cast icon appears in the toolbar action menu |
| 366 | when there is an active media route, or when the user chooses to pin the icon |
| 367 | there permanently. |
| 368 | |
| 369 | ----------------------------------------------- |
| 370 | |
| 371 | *TODO: Update screenshot* |
| 372 | |
| 373 | [](https://www.chromium.org/developers/design-documents/media-router/media_router_overflow.jpg?attredirects=0) |
| 374 | |
| 375 | Clicking on the Cast icon brings up a menu of available media sinks that are |
| 376 | compatible with the current content. For Web documents not using the |
| 377 | Presentation API, these will include sinks that can render tab or desktop |
| 378 | capture. For Web documents, it will include media sinks compatible with the URL |
| 379 | requested to be presented through the Presentation API. |
| 380 | |
| 381 | ----------------------------------------------- |
| 382 | |
| 383 | *TODO: Update screenshot* |
| 384 | |
| 385 | [](https://www.chromium.org/developers/design-documents/media-router/media_router_screen_selector.jpg?attredirects=0) |
| 386 | |
| 387 | ----------------------------------------------- |
| 388 | |
| 389 | ## Offscreen Rendering |
| 390 | |
Jordan Bayles | 98d6d51f | 2022-03-10 20:53:16 | [diff] [blame] | 391 | *TODO: Add notes about off-screen rendering.* |
mark a. foltz | 6faba39b | 2019-07-10 20:40:15 | [diff] [blame] | 392 | |
| 393 | # Security |
| 394 | |
| 395 | *TODO: Update to discuss sandboxing of in-browser MRPs.* |
| 396 | |
| 397 | The entire project should be security reviewed from a holistic and architectural |
| 398 | perspective. Specific security-related aspects: |
| 399 | |
| 400 | * The Chrome Media Router will be designed to have a minimal processing of the |
| 401 | URIs and messages passed through it (perhaps only checking for syntactic |
| 402 | validity). |
| 403 | * The Media Router Dialog will allow the MRPs to inject custom |
| 404 | content into it, so for example, the inline controls for a game can differ |
| 405 | from those for a movie. This content will be rendered out-of-process in an |
| 406 | <extensionview> to prevent any escalation of privileges from compromised |
| 407 | content. |
| 408 | * The individual platform APIs used by the component extension MRPs |
| 409 | (chrome.dial, chrome.mdns, chrome.cast.channel, chrome.cast.streaming) have |
| 410 | been security reviewed previously. |
| 411 | |
| 412 | # Contact |
| 413 | |
| 414 | * [[email protected]](mailto:[email protected]) |
| 415 | |
| 416 | # Code location |
| 417 | |
| 418 | | Path | Description | |
| 419 | | ---------------------------------------|--------------------------------------| |
| 420 | | `chrome/browser/media/router` | Main implementation, in-browser MRPs | |
| 421 | | `chrome/common/media_router` | Mojo definitions, shared impl | |
| 422 | | `chrome/browser/ui/media_router/` | Media Router icon, dialog | |
| 423 | | `chrome/browser/ui/views/media_router/`| | |
| 424 | | `content/browser/presentation/` | Browser impl of Presentation API| |
| 425 | | `third_party/blink/renderer/modules/presentation/`| Blink impl of Presentaton API| |
| 426 | |
| 427 | # History |
| 428 | |
| 429 | | Date | Author | Description | |
| 430 | |------------|---------------------|--------------------------------------------------| |
| 431 | | 6-Feb-2015 | [email protected] | Initial publication | |
| 432 | | 8-Jul-2019 | [email protected] | Converted to markdown, obsolete material removed.| |