We built a video-streaming MCP App to see how far video can go inside a widget: a Bitmovin player with VOD, live, DRM, and a Netflix-style browse UI. A lot of it already works. MSE, Web Workers, WASM, muted autoplay, and EME/DRM (Widevine) all run fine in the sandbox.
@Isalomon asked me on Discord to write up the use cases and requirements, so here they are.
Two mechanisms already cover part of this, and I want to be clear I'm building on them rather than proposing something from scratch:
- Display modes (
fullscreen / pip) resize the host container.
- Permission-policy negotiation grants
camera, microphone, geolocation, clipboard-write, since those were what people asked for so far.
The request is to add the media features to that same negotiation list, plus fix one specific gap in the fullscreen display mode.
Use cases
1. Fullscreen that fills the display
Video wants the whole screen for couch or TV viewing, with the host and OS chrome out of the way. We used the host fullscreen display mode instead of calling the Fullscreen API ourselves. What we measured is that the widget only grew to the host browser viewport, roughly 1280×1272 in our setup, and never reached the 2560×1440 monitor. That makes sense: from a windowed browser tab the display mode can't grow past the window itself. Only the Fullscreen API can take over the physical screen.
So for real fullscreen video we'd need one of two things: the fullscreen display mode able to reach true screen fill, or fullscreen added to the permission negotiation so the app can call requestFullscreen(). The second one is the reliable path for our case.
2. Casting to a TV
Users expect to send a stream to a Chromecast. In our widget the Cast sender SDK loads and chrome.cast.isAvailable returns true, but CastContext.getCastState() stays at NO_DEVICES_AVAILABLE and no receiver ever shows up, because the frame has no allow="presentation". I checked this with a real Chromecast on the same network in a normal Chrome window, and the result is identical whether the player runs at the top level or inside an iframe. The only difference is the missing permission.
Adding presentation (and remote-playback for the Remote Playback API) to the negotiation would cover this. One caveat worth raising early: presentation only helps if the host runtime actually has a Media Router. If that isn't guaranteed across hosts, a host-mediated handoff might be the more robust design, where the app passes a stream URL plus DRM info and start position to the host, and the host owns the device picker and the cast session.
3. Picture-in-Picture
Let someone keep watching while they do something else in the host. This needs picture-in-picture.
4. DRM / encrypted-media
Widevine playback works today, which suggests encrypted-media is already granted or EME is running same-origin. I'd like it to become an explicit, negotiable feature so DRM content behaves the same across hosts rather than depending on current behavior.
5. Autoplay with sound
Muted autoplay works. Adding autoplay would let a user-initiated play start with sound.
Proposed shape
Extend the existing permission-policy negotiation (the same path as camera / microphone / geolocation) with fullscreen, presentation, remote-playback, picture-in-picture, encrypted-media, and autoplay, each behind the consent surface where that fits. Most of these are extra tokens on the allow list and don't need new architecture. Casting is the one that may need more thought because of the runtime dependency.
Repro
We have a small capability-probe widget that live-tests EME key systems, MSE-in-worker, fullscreen confinement, Presentation and Remote Playback availability, and autoplay policy. Happy to share it if a reproducible harness would help with scoping.
We built a video-streaming MCP App to see how far video can go inside a widget: a Bitmovin player with VOD, live, DRM, and a Netflix-style browse UI. A lot of it already works. MSE, Web Workers, WASM, muted autoplay, and EME/DRM (Widevine) all run fine in the sandbox.
@Isalomon asked me on Discord to write up the use cases and requirements, so here they are.
Two mechanisms already cover part of this, and I want to be clear I'm building on them rather than proposing something from scratch:
fullscreen/pip) resize the host container.camera,microphone,geolocation,clipboard-write, since those were what people asked for so far.The request is to add the media features to that same negotiation list, plus fix one specific gap in the fullscreen display mode.
Use cases
1. Fullscreen that fills the display
Video wants the whole screen for couch or TV viewing, with the host and OS chrome out of the way. We used the host
fullscreendisplay mode instead of calling the Fullscreen API ourselves. What we measured is that the widget only grew to the host browser viewport, roughly 1280×1272 in our setup, and never reached the 2560×1440 monitor. That makes sense: from a windowed browser tab the display mode can't grow past the window itself. Only the Fullscreen API can take over the physical screen.So for real fullscreen video we'd need one of two things: the
fullscreendisplay mode able to reach true screen fill, orfullscreenadded to the permission negotiation so the app can callrequestFullscreen(). The second one is the reliable path for our case.2. Casting to a TV
Users expect to send a stream to a Chromecast. In our widget the Cast sender SDK loads and
chrome.cast.isAvailablereturns true, butCastContext.getCastState()stays atNO_DEVICES_AVAILABLEand no receiver ever shows up, because the frame has noallow="presentation". I checked this with a real Chromecast on the same network in a normal Chrome window, and the result is identical whether the player runs at the top level or inside an iframe. The only difference is the missing permission.Adding
presentation(andremote-playbackfor the Remote Playback API) to the negotiation would cover this. One caveat worth raising early:presentationonly helps if the host runtime actually has a Media Router. If that isn't guaranteed across hosts, a host-mediated handoff might be the more robust design, where the app passes a stream URL plus DRM info and start position to the host, and the host owns the device picker and the cast session.3. Picture-in-Picture
Let someone keep watching while they do something else in the host. This needs
picture-in-picture.4. DRM / encrypted-media
Widevine playback works today, which suggests
encrypted-mediais already granted or EME is running same-origin. I'd like it to become an explicit, negotiable feature so DRM content behaves the same across hosts rather than depending on current behavior.5. Autoplay with sound
Muted autoplay works. Adding
autoplaywould let a user-initiated play start with sound.Proposed shape
Extend the existing permission-policy negotiation (the same path as
camera/microphone/geolocation) withfullscreen,presentation,remote-playback,picture-in-picture,encrypted-media, andautoplay, each behind the consent surface where that fits. Most of these are extra tokens on the allow list and don't need new architecture. Casting is the one that may need more thought because of the runtime dependency.Repro
We have a small capability-probe widget that live-tests EME key systems, MSE-in-worker, fullscreen confinement, Presentation and Remote Playback availability, and autoplay policy. Happy to share it if a reproducible harness would help with scoping.