Skip to content

feat(web-ui): add lightweight HLS MSE playback and refactor mpegts#524

Merged
stackia merged 11 commits into
mainfrom
cursor/hls-mse-player
Jun 12, 2026
Merged

feat(web-ui): add lightweight HLS MSE playback and refactor mpegts#524
stackia merged 11 commits into
mainfrom
cursor/hls-mse-player

Conversation

@stackia

@stackia stackia commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

Application-layer HLS playback

  • Implement HLS playback in the worker (minimal m3u8 parsing, live playlist refresh with dedupe, VOD seek, fMP4 passthrough with EXT-X-MAP / moov codec extraction) and route all sources through the unified MSE player shell.
  • Remove the native hls-player fallback and trim unused mpegts demux/remux/metadata code (~2.9k lines removed, player bundle ~15 kB smaller).
  • Add SegmentSource abstraction so static catchup and HLS share the same transmux pipeline.
  • Throttle HLS VOD fetching with forward-buffer watermarks (pause at 30 s ahead, resume at 15 s).

iOS / ManagedMediaSource reliability

  • Properly drive ManagedMediaSource: gate appends on the streaming property, flush pending init/media segments on startstreaming, attach via URL.createObjectURL.
  • Replace the polling startup stall jumper with an event-driven one triggered on SourceBuffer updateend (iOS does not reliably fire progress/stalled), fixing playback stuck on "Loading" after the first frame.
  • Make live sync stable on iOS: adaptive latency backoff raises the target latency on each genuine live-edge underrun, and waiting immediately resets playback rate to 1x, breaking the catch-up → rebuffer loop.
  • Survive background suspension: handle unexpected MediaSource close (iOS reclaims media resources in background) without InvalidStateError storms, pause the worker, and on return to foreground auto-resume or reload the stream at the live edge / last position.
  • Integrate Media Session API (lock screen / control center metadata and play–pause) and respect Picture-in-Picture and explicit user pauses in the recovery logic.

Review feedback (Copilot / Codex)

  • Quote codec lists in the MSE MIME type so muxed fMP4 renditions (comma-separated CODECS) work.
  • Resume the worker when seeking an HLS VOD outside the buffer while watermark-paused; measure forward buffer within the range containing the playhead.
  • Guard the fMP4 init-segment fetch against superseded runs (stale init append after seek/reload).
  • Correct m3u8 parser docs: EXT-X-PLAYLIST-TYPE is ignored; playlists without EXT-X-ENDLIST are treated as live.

Test plan

  • TS live multicast playback (existing path)
  • Catchup multi-segment splice
  • HLS VOD with TS segments
  • HLS VOD with fMP4 + EXT-X-MAP
  • HLS live playlist refresh
  • Chrome / Safari / Firefox smoke test
  • iOS Safari: TS live startup (no stall), live sync stability
  • iOS Safari: background → foreground recovery (>30 s in background so MediaSource is reclaimed)
  • pnpm run type-check:tsc and pnpm run web-ui:build (embedded header rebuild)

Made with Cursor using Fable 5

stackia and others added 2 commits June 12, 2026 16:12
Replace native HLS fallback with worker-side playlist parsing, segment
scheduling, and fMP4 passthrough while trimming unused demux/remux code.

Co-authored-by: Cursor <cursoragent@cursor.com>
…cancels

Reuse playlist text from content-type detection and gate pause between
discrete segments instead of aborting in-flight fetches.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@stackia stackia marked this pull request as ready for review June 12, 2026 08:22
@stackia stackia requested a review from Copilot June 12, 2026 08:22

Copilot AI 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.

Pull request overview

This PR adds an application-layer HLS playback path (playlist parsing + refresh + optional fMP4 passthrough) inside the existing transmux worker and simplifies/downsizes the mpegts stack by removing legacy HLS fallback code and a large amount of unused demux/metadata functionality.

Changes:

  • Add lightweight HLS support in the worker via new HlsSource + minimal m3u8 parser, routed through the unified MSE player.
  • Refactor the transmux pipeline around a SegmentSource abstraction and add worker-side seek support for HLS VOD.
  • Remove legacy/unused utilities and demux metadata paths (SCTE35/KLV/PGS/etc.), and simplify browser detection.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
web-ui/src/mpegts/worker/transmux-worker.ts Switch worker events to hls-info and add seek command wiring.
web-ui/src/mpegts/worker/segment-source.ts Introduce SegmentSource + StaticSegmentSource abstraction for segment iteration.
web-ui/src/mpegts/worker/pipeline.ts Major refactor: segment-driven load loop, HLS integration, fMP4 passthrough path, and seek/reset handling.
web-ui/src/mpegts/worker/messages.ts Update worker command/event union types (add seek, replace hls detection event).
web-ui/src/mpegts/utils/utf8-conv.ts Remove unused UTF-8 conversion helper.
web-ui/src/mpegts/utils/typedarray-equality.ts Remove unused typedarray equality helper.
web-ui/src/mpegts/utils/browser.ts Replace heavyweight browser-detection object with isSafari/isFirefox.
web-ui/src/mpegts/types.ts Remove onHLSDetected from internal player interface.
web-ui/src/mpegts/remux/mp4-remuxer.ts Simplify old browser workarounds and add setDtsBaseOffset() for timeline anchoring.
web-ui/src/mpegts/remux/mp4-generator.ts Trim unsupported/unused codec/container box generation paths.
web-ui/src/mpegts/player/mse.ts Add setDuration() and buffer-availability signaling; simplify codec handling.
web-ui/src/mpegts/player/mpegts-player.ts Handle hls-info, add VOD forward-buffer throttling and HLS VOD worker seek path.
web-ui/src/mpegts/player/hls-player.ts Remove native HLS fallback player implementation.
web-ui/src/mpegts/io/fetch-loader.ts Improve HLS content-type detection (reuse fetched playlist text) and simplify abort logic.
web-ui/src/mpegts/index.ts Remove impl switching; always use unified mpegts/MSE player path.
web-ui/src/mpegts/hls/m3u8.ts Add minimal media/multivariant m3u8 parsing.
web-ui/src/mpegts/hls/hls-source.ts Add playlist-driven SegmentSource with live refresh and variant selection.
web-ui/src/mpegts/hls/fmp4.ts Add minimal BMFF probing + init parsing for fMP4 passthrough.
web-ui/src/mpegts/demux/ts-demuxer.ts Large demux simplification: remove BaseDemuxer/MediaInfo + metadata side paths, keep core A/V parsing.
web-ui/src/mpegts/demux/smpte2038.ts Remove SMPTE2038 parsing/types.
web-ui/src/mpegts/demux/scte35.ts Remove SCTE35 parsing/types.
web-ui/src/mpegts/demux/pgs-data.ts Remove PGS data types.
web-ui/src/mpegts/demux/pes-private-data.ts Remove PES private data types.
web-ui/src/mpegts/demux/pat-pmt-pes.ts Remove stream-type/constants and PMT fields for removed metadata paths.
web-ui/src/mpegts/demux/klv.ts Remove KLV parsing/types.
web-ui/src/mpegts/demux/base-demuxer.ts Remove BaseDemuxer abstraction (callbacks now directly on TSDemuxer).
web-ui/src/mpegts/core/media-info.ts Remove MediaInfo model (no longer surfaced from worker).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web-ui/src/mpegts/worker/pipeline.ts Outdated
Comment thread web-ui/src/mpegts/hls/m3u8.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e597b7ffb9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web-ui/src/mpegts/worker/pipeline.ts
Comment thread web-ui/src/mpegts/player/mpegts-player.ts
Flush pending segments on startstreaming, append first init segments immediately,
and wire worker pause/resume to MMS streaming hints.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

- quote codec lists in MSE mimeType (muxed fMP4 with comma-separated codecs)
- resume worker on HLS VOD seek while watermark-paused; measure forward
  buffer within the range containing currentTime
- guard _loadFmp4Init against superseded runs (stale init segment append)
- correct m3u8 parser doc: EXT-X-PLAYLIST-TYPE is ignored, not parsed

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net

@stackia stackia merged commit b42f385 into main Jun 12, 2026
10 checks passed
@stackia stackia deleted the cursor/hls-mse-player branch June 12, 2026 09:57
stackia added a commit that referenced this pull request Jun 12, 2026
…eation from racing media engine init

Each worker message is delivered in its own event-loop task. Appending the
video init segment and then yielding lets the UA finish parsing it and lock
the SourceBuffer set, so the audio addSourceBuffer that arrives in the next
task throws QuotaExceededError ("reached the limit of SourceBuffer objects")
and the stream plays without sound. Reproduced 100% on Chrome with any
TS audio+video stream since the worker-based pipeline (#524).

The player now stashes init-segment messages and flushes them together right
before the first non-init message, creating all SourceBuffers in a single
task — the buffer append algorithm runs as a queued task, so no init segment
parse can complete in between.

Also switch mid-stream codec changes to SourceBuffer.changeType(): calling
addSourceBuffer for an existing track always throws once the media engine
has initialized.

Co-authored-by: Cursor <cursoragent@cursor.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