-
Notifications
You must be signed in to change notification settings - Fork 115
Description
I got an error in my Sentry logs and Seer suggested it's an issue with media-chrome. Here's the issue it generated. Hopefully this is enough context:
The Mux Player's Picture-in-Picture feature fails when triggered by user clicks because the internal event handling introduces an asynchronous delay that breaks the browser's user gesture context requirement.
Error
NotAllowedError: Failed to execute 'requestPictureInPicture' on 'HTMLVideoElement': Must be handling a user gesture if there isn't already an element in Picture-in-Picture.
Root Cause Analysis
Based on the stack trace, the issue occurs in this sequence:
- User clicks on the video player (valid user gesture)
- HTMLElement.handleClick processes the initial click
- Internal mediaenterpiprequest event is triggered
- Event goes through Object.dispatch mechanism (introduces async delay)
- Finally requestPictureInPicture is called, but browser no longer considers it a direct user gesture
- The critical issue is in step 4: the internal event dispatching mechanism breaks the synchronous link between the user's click and the requestPictureInPicture call.
Browser Requirements
According to the HTML specification, requestPictureInPicture() must be called synchronously within a user gesture event handler. Any asynchronous operations (promises, timeouts, event dispatching) will cause the browser to reject the call with a NotAllowedError.
Stack Trace
[as requestPictureInPicture] in file /assets/epic-video-hJ3IuML-.js [Line 115, column 608] (In app)
Object.set in file /assets/epic-video-hJ3IuML-.js [Line 303, column 20152] (In app)
Object.mediaenterpiprequest in file /assets/epic-video-hJ3IuML-.js [Line 303, column 27938] (In app)
Object.dispatch in file /assets/epic-video-hJ3IuML-.js [Line 303, column 32124] (In app)
HTMLElement.<anonymous> in file /assets/epic-video-hJ3IuML-.js [Line 303, column 33888] (In app)
HTMLElement.handleClick in file /assets/epic-video-hJ3IuML-.js [Line 1113, column 735] (In app)
Expected Behavior
Picture-in-Picture should work when users click the PiP button, similar to how it works in native browser video controls.
Suggested Fix
The PiP request should be made synchronously within the click event handler, without going through internal event dispatching mechanisms. For example:
// Instead of dispatching events, call PiP directly in the click handler
handlePipClick(event) {
event.preventDefault();
if (this.mediaEl && document.pictureInPictureEnabled) {
if (document.pictureInPictureElement) {
document.exitPictureInPicture();
} else {
this.mediaEl.requestPictureInPicture();
}
}
}Environment
Mux Player React version: @mux/mux-player-react@3.5.1
Browser: Chrome/Edge (Chromium-based browsers)
Framework: React with React Router
Workaround
Currently implementing a custom PiP button that bypasses Mux Player's internal handling:
const handlePipClick = () => {
const video = muxPlayerRef.current?.mediaEl
if (video && document.pictureInPictureEnabled) {
if (document.pictureInPictureElement) {
document.exitPictureInPicture()
} else {
video.requestPictureInPicture()
}
}
}
This workaround requires hiding the default PiP button and implementing a custom one, which is not ideal for maintaining consistency with the player's UI.