Bug: Play event behavior does not match video play event
Opened this issue · 4 comments
Is there an existing issue for this?
- I have searched the existing issues
Which Mux Elements/Packages does this apply to? Select all that apply
mux-video
Which browsers are you using?
Chrome
Which operating systems are you using?
macOS
Description
In your docs, it's mentioned that the Mux player emits all of events available on the HTML5 video element & I would expect the same behaviors between both.
I've experienced 2 cases where there is a misalignment in behavior - both very similar.
The order of events emitted from the player is not the same - which is particularly problematic in the case of an error loading the video.
<mux-video />
=> https://stackblitz.com/edit/vitejs-vite-e37ply?file=src%2FApp.vue&terminal=dev
<video />
=> https://stackblitz.com/edit/vitejs-vite-mmoxmh?file=src%2FApp.vue&terminal=dev
Reduced test case
https://stackblitz.com/edit/vitejs-vite-e37ply?file=src%2FApp.vue&terminal=dev
Steps to reproduce
✅ Case 1 - A video successfully loads
Order of events for <video />
element
- Load video player
loadedmetadata
event is emitted first- Then
play
event is emitted
Order of events for <mux-video />
element
- Load mux video
play
event is emitted first- Then
loadedmetadata
event is emitted
❌ Case 2 - A video does not successfully load
Order of events for <video />
element
- Load video player
error
event is emitted
Order of events for <mux-video />
element
- Load mux video
play
event is emitted (even though the video isn't played)- Then
error
event is emitted
Current Behavior
The play
event is always emitted immediately when autoplay
is true
- even if the video is errored.
The play
event is emitted, before the loadedmetadata
- which should not be the case.
Expected Behavior
play
can & should only be emitted after the video successfully loads - both when autoplay
is true
& also if the user was to try & play the video before it loaded successfully.
Errors
No response
What version of the package are you using?
v0.17.5
I can confirm this is a different behavior, I'll bring this up with the team but it might be not sufficient reason to change.
The cause of this is that we explicitly call video.play() internally.
play can & should only be emitted after the video successfully loads - both when autoplay is true & also if the user was to try & play the video before it loaded successfully.
This quote is not fully correct. For the playing
event that would be true I believe.
The play
event is called whenever the play()
method is called, the returned promise doesn't even need to resolve.
https://codesandbox.io/p/sandbox/mux-video-vs-video-events-yhd22m?file=%2Findex.html%3A41%2C48
@luwes The problem arises when you want to tell, that the video has actually started playing from the beginning... Is there an alternative to doing that?
If we agree that the @play
event emits, even when the video hasn't played yet - so the alternative would be to use @playing
. But the @playing
event fires slightly "too late". The currentTime
is no longer 0
. Where as with @play
, when played from the start, still has a currentTime
of 0
.
Hey @andrewbrennanfr it might be helpful to understand the scenario you're trying to account for.
From your discussion, it sounds like you have a setup where you have autoplay set and you'd like to monitor if an error occurs when attempting to load and subsequently (auto)play the media. Is that correct? If yes, you may want to go with a less presumptuous monitoring condition, like:
const errorListener = (event) => {
console.log("AN ERROR OCCURRED BEFORE PLAYBACK", event);
};
muxVideoEl.addEventListener("error", errorListener);
// Condition to stop monitoring for an error
muxVideoEl.addEventListener(
"playing",
(_event) => {
muxVideoEl.removeEventListener("error", errorListener);
},
// Only listen for the first occurrence of "playing"
{ once: true }
);
This should account for errors before playback, regardless of autoplay, a user seek after loading media but before playing, etc.
Let us know if that is appropriately capturing your scenario. As @luwes points out, we do end up doing some programmatic work "under the hood," including invoking the underlying HTMLMediaElement::play()
method under certain conditions (particularly to try our best to autoplay given the various constraints on that behavior), so I'd be extremely hesitant to add code complexity or "swallow" events for these cases.
@luwes So what I'm trying to do is, add some logging, whenever the user plays from 0
.
So the once
also likely won't work here.
So for example:
I want to log something when:
- if the user plays from
0
- if the user replays the video from
0
- the video is autoplayed
I do not want to log something when:
- if the user pauses & seeks to
0.00001
& plays again - the video errors or otherwise fails to play
- the user seeks to
0
during playback
The play
solves this problem for me (in theory) - if it behaved like the video play event.
How I've "solved" it for now is a variation of:
let isLoading = true
const handlePlay = () => {
if (isLoading) { // don't continue if still loading
return
}
// log something based on `currentTime === 0`
}
const handleMetaDataLoaded = () => {
isLoading = false
handlePlay() // resume the play event
}
This way I'm sure the video has loaded successfully before playing. But it's a bit of a workaround, rather than a real fix.