vidstack / player

UI components and hooks for building video/audio players on the web. Robust, customizable, and accessible. Modern alternative to JW Player and Video.js.
https://vidstack.io
MIT License
1.9k stars 114 forks source link

`onTimeUpdate`-event only triggering when browser tab playing the video is in focus #1332

Open bramdeba opened 5 days ago

bramdeba commented 5 days ago

Current Behavior:

When focusing the tab playing the video, the onTimeUpdate-event is triggering correctly. As soon as I switch to another tab, it stops.

Expected Behavior:

When a tab is not in focus, but the video is still playing, the onTimeUpdate-event should also still play.

Steps To Reproduce:

  1. Using latest Google Chrome/Edge on Windows/Mac.
  2. Start playing a video and log the current time by listening to the onTimeUpdate-event.
  3. Switch to another tab for 10 seconds, and then refocus the tab playing the video.
  4. Look at the logs and see 10 seconds of log data missing.

Environment:

Framework: React (Vite) Node: 18 Device: Macbook Pro / Microsoft Surface Pro Browser: Chrome (latest), Edge (latest)

mihar-22 commented 5 days ago

Thanks for reporting!

This is due to the fact that we use requestAnimationFrame to track time updates more precisely. The browser pauses animation frame updates when the tab is not active. This is kind of preferable as time updates throughout the player are relatively expensive as it effects many components (time slider, chapters, thumbnails, etc.).

To help me better understand, why are these time update events on tab change important to you? Is it causing an issue in the player or something on your end?

bramdeba commented 5 days ago

Not encountering this issue however when using:

  useEffect(() => {
    const player = playerRef?.current
    const video = player?.el?.querySelector('video')

    const handleVideoTimeUpdate = (e: Event) => {
      console.log('timeupdate', (e.target as HTMLVideoElement).currentTime)
    }

    video?.addEventListener('timeupdate', handleVideoTimeUpdate)

    return () => video?.removeEventListener('timeupdate', handleVideoTimeUpdate)
  }, [playerRef, handleTimeUpdate])

But afraid this will not work when e.g. casting.

bramdeba commented 5 days ago

@mihar-22 thanks for your response! We're trying to accurately monitor what parts of the video was watched in order to be able to hand out certificates (as part of a learning management system)

bramdeba commented 5 days ago

Users are not allowed to skip parts but they have to watch at least 95% of the video in order to get a certificate. Letting the video play in the background is allowed, however.

mihar-22 commented 5 days ago

Is the onEnd callback not a sufficient fallback to catch users who are tabbed out? Depends on the length of the videos I guess as that last 5% can be negligible or a lot.

I'll need to work in detecting tab visibility changes to fix this which shouldn't be too hard. I'm not a huge fan of running expensive updates while the tab is not active so I might need to figure out some middle ground or option. I'll keep thinking on it and look into it more tomorrow with some testing. Let me know if you think of anything :)