Interstitial asset scheduling accuracy
Is your feature request related to a problem? Please describe.
Scheduling interstitial assets loading and playing is currently triggered by the timeupdate event of the video element, which leads to inaccurate scheduling since timeupdate event is triggered at most every few hundred ms.
For scenario such as ad replacement accuracy is critical for user experience.
Describe the solution you'd like
A solution could be to rely on the requestVideoFrameCallback() API, if available, to be frame accurate.
If requestVideoFrameCallback() API is not available, a fallback solution could be to set a timer as we are getting close to the intersitial time, without waiting for next behindhand timeupdate event.
Additional context
No response
HLS.js uses TextTrack cue "enter" events to improve the timing of interstitial scheduling, which is significantly more accurate than timeupdate.
We could add support for requestVideoFrameCallback and/or requestAnimationFrame to try to improve timing of interstitial schedule changes, but both would be less performant, and neither would prevent rendering of buffered content past DateRange start times as the event loop execution is not strictly bound to the rendering pipeline.
In your testing, please try observing the timing of cue "enter" events: https://github.com/video-dev/hls.js/blob/b21b6de9f67b02ded0e6dcb6330785ad168bc8e0/src/controller/id3-track-controller.ts#L497-L499
https://github.com/video-dev/hls.js/blob/b21b6de9f67b02ded0e6dcb6330785ad168bc8e0/src/controller/interstitials-controller.ts#L972-L973
- Does the callback execute when you expect - where on the timeline and with what frame rendered?
- Does the interstitial-controller update the schedule in this callback stack (as opposed to waiting for currentTime to advance further in an upcoming "timeupdate" event)?
- Does the resulting media element transition immediately interrupt primary playback, or is there additional delay in tearing down the rendering pipeline after the schedule change is initiated?
- Please list results for each browser or device that you are focusing testing on.
Thanks!
Thanks @robwalch for your answer.
My bad, there was a misconfiguration in the used test (on-demand) stream (PROGRAM-DATE-TIME set to 1/1/1970) which led to missing cue events.
Indeed, cue events seems to be accurate enough and requestVideoFrameCallback may not improve that much.
Nevertheless I notice difference between the metadata.mediaTime of the requestVideoFrameCallback and the <video>.currentTime.
For example, on latest chrome (139.0.7258.139) on windows desktop, with an on-demand stream and interstitial event starting at second 5.00:
with triggering of interstitial based on cue event:
### timeupdate 4.708224
### videoframe mediaTime: 4.723222 currentTime 4.716432 => requestVideoFrameCallback() handler
### videoframe mediaTime: 4.7399 currentTime 4.73443
### videoframe mediaTime: 4.756566 currentTime 4.750046
### videoframe mediaTime: 4.773222 currentTime 4.766443
### videoframe mediaTime: 4.7899 currentTime 4.783305
### videoframe mediaTime: 4.806555 currentTime 4.799951
### videoframe mediaTime: 4.823233 currentTime 4.816629
### videoframe mediaTime: 4.8399 currentTime 4.83316
### videoframe mediaTime: 4.856566 currentTime 4.849771
### videoframe mediaTime: 4.873222 currentTime 4.866674
### videoframe mediaTime: 4.8899 currentTime 4.883199
### videoframe mediaTime: 4.906566 currentTime 4.899984
### videoframe mediaTime: 4.923222 currentTime 4.91672
### videoframe mediaTime: 4.9399 currentTime 4.933299
### videoframe mediaTime: 4.956555 currentTime 4.950235
### videoframe mediaTime: 4.973222 currentTime 4.966485
### timeupdate 4.974206
### videoframe mediaTime: 4.9899 currentTime 4.983294
### videoframe mediaTime: 5.006566 currentTime 4.99988
### cueenter currentTime:5.006017
### timeupdate 5.006017
[log] > [interstitials]: setSchedulePosition 1, undefined (["ad": 5.000-32.279])
[log] > [interstitials]: INTERSTITIAL_STARTED ["ad": 5.000-32.279]
and with triggering of interstitial based on requestVideoFrameCallback event:
### videoframe mediaTime: 4.7399 currentTime 4.72169 => requestVideoFrameCallback() handler
### timeupdate 4.722676
### videoframe mediaTime: 4.756566 currentTime 4.739691
### videoframe mediaTime: 4.773222 currentTime 4.755592
### videoframe mediaTime: 4.7899 currentTime 4.771638
### videoframe mediaTime: 4.806555 currentTime 4.788413
### videoframe mediaTime: 4.823233 currentTime 4.804963
### videoframe mediaTime: 4.8399 currentTime 4.821726
### videoframe mediaTime: 4.856566 currentTime 4.838499
### videoframe mediaTime: 4.873222 currentTime 4.855021
### videoframe mediaTime: 4.8899 currentTime 4.87178
### videoframe mediaTime: 4.906566 currentTime 4.888557
### videoframe mediaTime: 4.923222 currentTime 4.904907
### videoframe mediaTime: 4.9399 currentTime 4.921656
### videoframe mediaTime: 4.956555 currentTime 4.938606
### videoframe mediaTime: 4.973222 currentTime 4.954937
### videoframe mediaTime: 4.9899 currentTime 4.971851
### timeupdate 4.985799
### videoframe mediaTime: 5.006566 currentTime 4.989068
[log] > [interstitials]: setSchedulePosition 1, undefined (["ad": 5.000-32.279])
[log] > [interstitials]: INTERSTITIAL_STARTED ["ad": 5.000-32.279]