Skip to content

Commit 2d0b309

Browse files
karngyanclaude
andcommitted
fix(mux): bind videoRenditions change listener lazily and idempotently
el.videoRenditions is undefined at mount() (renditions populate after metadata loads), so the "change" listener never attached. Bind it on first syncFromEl once el.videoRenditions exists, guarded by renditionsBound; stash the reference and unbind in destroy(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0ccf593 commit 2d0b309

1 file changed

Lines changed: 13 additions & 3 deletions

File tree

src/mux/provider.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function createMuxProvider(opts: MuxProviderOptions): Provider {
3232
const ios = typeof navigator !== "undefined" && detectIOS(navigator.userAgent)
3333
let el: MuxVideoEl | null = null
3434
let renditions: MuxVideoEl["videoRenditions"] | null = null
35+
let renditionsBound = false
3536
let state: MediaState = {
3637
...defaultState(),
3738
rate: opts.defaultRate ?? 1,
@@ -76,8 +77,17 @@ export function createMuxProvider(opts: MuxProviderOptions): Provider {
7677
}
7778
return out
7879
}
80+
// Renditions populate after metadata loads, so el.videoRenditions is usually
81+
// undefined at mount time. Bind the "change" listener lazily and once.
82+
const bindRenditions = () => {
83+
if (renditionsBound || !el?.videoRenditions) return
84+
renditions = el.videoRenditions
85+
renditions.addEventListener("change", syncFromEl)
86+
renditionsBound = true
87+
}
7988
const syncFromEl = () => {
8089
if (!el) return
90+
bindRenditions()
8191
const ranges: Array<[number, number]> = []
8292
for (let i = 0; i < el.buffered.length; i++) ranges.push([el.buffered.start(i), el.buffered.end(i)])
8393
patch({
@@ -144,8 +154,7 @@ export function createMuxProvider(opts: MuxProviderOptions): Provider {
144154
}
145155
}
146156
for (const ev of MEDIA_EVENTS) el.addEventListener(ev, syncFromEl)
147-
renditions = el.videoRenditions ?? null
148-
renditions?.addEventListener("change", syncFromEl)
157+
// videoRenditions is not yet available here; bound lazily in syncFromEl.
149158
document.addEventListener("fullscreenchange", onFullscreenChange)
150159
el.addEventListener("enterpictureinpicture", onEnterPip)
151160
el.addEventListener("leavepictureinpicture", onLeavePip)
@@ -189,8 +198,9 @@ export function createMuxProvider(opts: MuxProviderOptions): Provider {
189198
actions,
190199
destroy() {
191200
document.removeEventListener("fullscreenchange", onFullscreenChange)
192-
renditions?.removeEventListener("change", syncFromEl)
201+
if (renditionsBound) renditions?.removeEventListener("change", syncFromEl)
193202
renditions = null
203+
renditionsBound = false
194204
if (el) {
195205
for (const ev of MEDIA_EVENTS) el.removeEventListener(ev, syncFromEl)
196206
el.removeEventListener("enterpictureinpicture", onEnterPip)

0 commit comments

Comments
 (0)