Skip to content

fix(web): forward cues that already exist when a text track is added - #891

Open
tvanlaerhoven wants to merge 4 commits into
developfrom
devin/1786011178-web-addcue-ordering
Open

fix(web): forward cues that already exist when a text track is added#891
tvanlaerhoven wants to merge 4 commits into
developfrom
devin/1786011178-web-addcue-ordering

Conversation

@tvanlaerhoven

@tvanlaerhoven tvanlaerhoven commented Aug 6, 2026

Copy link
Copy Markdown
Member

Summary

WebEventForwarder.onAddTextTrack attached the track-level addcue listener only when addtrack fired, so any cue already present on the track at that moment produced no player-level TEXT_TRACK/addcue event. On iOS Safari the web SDK populates daterange cues before firing addtrack, so consumers listening on PlayerEventType.TEXT_TRACK never received them (the cues were only visible via event.track.cues on the TEXT_TRACK_LIST event).

Fix: after dispatching ADD_TRACK, replay the cues already on the track as ADD_CUE player events. Their uids are remembered so a native addcue arriving later for one of those same cues is not forwarded twice; a uid is dropped from that set on removecue, so a genuine remove/re-add still forwards. The set only ever holds cues that existed at addtrack time — cues arriving afterwards are forwarded with no bookkeeping.

   dispatchEvent(ADD_TRACK, fromNativeTextTrack(track));
+  track.cues?.forEach((cue) => dispatchEvent(ADD_CUE, track.uid, fromNativeCue(cue)));

Second, unrelated-but-adjacent fix: track listener removal never worked. onRemoveTextTrack / onRemoveMediaTrack called removeEventListener with a freshly created closure (this.onAddTextTrackCue(track)), a different function identity than the one registered — so cue and activequalitychanged listeners stayed attached for the life of the player, leaking and dispatching events for removed tracks. The listeners are now kept per track uid and the exact registered reference is removed; removeEventListeners() also detaches tracks that were never explicitly removed.

Note the same attach-on-ADD_TRACK pattern exists in the iOS (THEOplayerRCTTextTrackEventHandler) and Android (PlayerEventEmitter) handlers; those are left alone since the native SDKs fire addcue after addtrack.

Verification

No JS test framework exists in this repo, so this was verified with a standalone script driving the compiled forwarder against a fake player/track emitter, covering: cues present at addtrack are forwarded after ADD_TRACK; a duplicate native addcue for a replayed cue is suppressed; remove-then-re-add of the same cue is forwarded again; no cue events after removetrack. npm run lint, npm run prettier and tsc -p tsconfig.build.json pass.

Link to Devin session: https://dolby.devinenterprise.com/sessions/fc9bf7b3e83e4f2bafb75a3d70edcb3c
Requested by: @tvanlaerhoven


Open in Devin Review

@tvanlaerhoven tvanlaerhoven self-assigned this Aug 6, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1786011178-web-addcue-ordering branch from daf590e to f66dde5 Compare August 6, 2026 10:42
devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1786011178-web-addcue-ordering branch from 9504684 to 461c47e Compare August 12, 2026 19:27
devin-ai-integration[bot]

This comment was marked as resolved.

@tvanlaerhoven
tvanlaerhoven force-pushed the devin/1786011178-web-addcue-ordering branch from 461c47e to de6d634 Compare August 17, 2026 09:13
devin-ai-integration Bot and others added 3 commits September 1, 2026 01:07
Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1786011178-web-addcue-ordering branch from de6d634 to 8417b98 Compare September 1, 2026 08:10

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Devin Review

Comment on lines +366 to +373
track.addEventListener('addcue', listeners.addcue);
track.addEventListener('removecue', listeners.removecue);
track.addEventListener('entercue', listeners.entercue);
track.addEventListener('exitcue', listeners.exitcue);
this._facade.dispatchEvent(new DefaultTextTrackListEvent(TrackListEventType.ADD_TRACK, fromNativeTextTrack(track)));
track.cues?.forEach((cue) => {
this._facade.dispatchEvent(new DefaultTextTrackEvent(TextTrackEventType.ADD_CUE, track.uid, fromNativeCue(cue)));
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Pre-existing cues do not get entercue replay

Only ADD_CUE is replayed. If a cue that already exists at addtrack time is currently active (playhead inside its interval), no ENTER_CUE is forwarded because the native entercue fired before the listener was attached — the same class of gap the PR fixes for addcue. Consumers relying on ENTER_CUE for daterange handling on iOS Safari may still miss the first cue.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True — a cue already active at addtrack time gets no ENTER_CUE replay. Deliberately left out of this PR: replaying it correctly would need to consult track.activeCues (activeness, not just existence), and unconditionally synthesizing ENTER_CUE risks firing it for cues that aren't active, which is worse than the gap. ADD_CUE replay delivers the cue payload (including daterange data), which is what the reported issue needed. Can follow up with an activeCues-based ENTER_CUE replay if a consumer turns out to depend on it.

Co-Authored-By: tom.vanlaerhoven <tom.vanlaerhoven@dolby.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants