Skip to content

feat(cmcd): upgrade to CMCD v2 using @svta/cml-cmcd CmcdReporter#7725

Draft
littlespex wants to merge 12 commits intovideo-dev:masterfrom
littlespex:issue/7723-cmcd-v2
Draft

feat(cmcd): upgrade to CMCD v2 using @svta/cml-cmcd CmcdReporter#7725
littlespex wants to merge 12 commits intovideo-dev:masterfrom
littlespex:issue/7723-cmcd-v2

Conversation

@littlespex
Copy link
Collaborator

@littlespex littlespex commented Feb 12, 2026

Summary

Implements CMCD v2 support by migrating from @svta/common-media-library to the dedicated @svta/cml-* packages and fully delegating CMCD encoding to CmcdReporter from @svta/cml-cmcd.

Resolves #7723.

Changes

  • Migrate dependencies: Replace @svta/common-media-library with @svta/cml-cmcd, @svta/cml-id3, @svta/cml-utils, and @svta/cml-structured-field-values
  • CMCD v2 data fields: Add version, st (stream type), sta (player state), sn (sequence number) to CMCD output. Inner list encoding for br, tb, bl, mtp, nor per v2 spec
  • CmcdReporter integration: Delegate all CMCD request encoding to CmcdReporter.createRequestReport(), removing manual appendCmcdHeaders/appendCmcdQuery calls and the createData() method
  • Event-mode reporting: Support v2 event targets for play state changes (PLAY_STATE), fatal errors (ERROR), and bitrate changes (BITRATE_CHANGE)
  • Configuration: Add version, enabledKeys, and eventTargets to CMCDControllerConfig. Default enabledKeys to CMCD_V1_KEYS (v1) or CMCD_KEYS (v2)
  • Exported types: Re-export CMCD v2 types (CmcdVersion, CmcdPlayerState, CmcdStreamType, etc.) from exports-named.ts
  • Tests: Comprehensive unit test coverage for v1 defaults, v2 fields (query and headers modes), stream type detection, event reporting, and reporter lifecycle

Behavioral notes

  • v=1 is omitted from output per CMCD spec (it is the default)
  • sn (sequence number) is automatically included in v2 output, filtered out for v1
  • nor uses root-relative paths (via url.origin as baseUrl) instead of path-relative
  • Inner list values (bl, tb) are guarded against NaN to prevent Structured Fields serialization errors

Test plan

  • All 912 unit tests pass
  • Manual verification with a CMCD v1 configuration (query and headers modes)
  • Manual verification with a CMCD v2 configuration (query, headers, and event modes)
  • Verify no source map warnings in downstream bundlers (Vite/Nuxt)

claude and others added 6 commits February 8, 2026 17:45
…d v2 version support

Replace the monolithic @svta/common-media-library package with the scoped
@svta/cml-cmcd@2.1.0 and @svta/cml-utils@1.3.0 packages for CMCD
functionality. The old package is retained for non-CMCD imports (ID3, UTF8).

Add a `version` option to CMCDControllerConfig (defaults to 1 for backwards
compatibility) that controls CMCD encoding version. When set to 2, the
controller uses CMCD v2 Structured Field Value encoding via the new library.

Key changes:
- Update all CMCD imports to use @svta/cml-cmcd single entry point
- Update uuid import to use @svta/cml-utils
- Update tsconfig moduleResolution to "bundler" for exports field support
- Adapt CMCD data fields (br, bl, mtp, tb, nor) to v2 array types
- Pass version through to CmcdEncodeOptions for version-aware encoding

https://claude.ai/code/session_01FmnN6xNSm9Qo17tp52ag3U
Phase 3: Add new CMCD v2 data fields to the controller:
- Stream type (st): Detect VOD/LIVE/LOW_LATENCY from level details
  based on live flag, canBlockReload, and canSkipUntil properties
- Player state (sta): Track player state transitions via media element
  events (waiting, playing, pause, seeking, ended) and hls.js ERROR
  events for fatal errors. Maps to CmcdPlayerState enum values.
- Both fields are only included when version >= 2

Phase 4: Integrate CmcdReporter for event-mode reporting:
- Add eventTargets config option (CmcdEventReportConfig[]) for v2
  event reporting endpoints
- Instantiate CmcdReporter when version >= 2 and eventTargets are
  configured, with session/content ID and transmission mode
- Record PLAY_STATE events on player state transitions
- Record ERROR events on fatal hls.js errors
- Record BITRATE_CHANGE events on level switches
- Stop and flush reporter on controller destroy

Add unit tests for v2 version encoding, stream type detection (VOD,
LIVE, LOW_LATENCY), and player state inclusion.

https://claude.ai/code/session_01FmnN6xNSm9Qo17tp52ag3U
Phase 6: Re-export CMCD types and constants from exports-named.ts for
ESM consumers: CmcdObjectType, CmcdStreamType, CmcdStreamingFormat,
CmcdPlayerState, CmcdEventType, CmcdHeaderField, CMCD_V1, CMCD_V2,
and type exports for Cmcd, CmcdEncodeOptions, CmcdEventReportConfig,
CmcdVersion. Add @svta/cml-cmcd, @svta/cml-utils, and
@svta/cml-structured-field-values to api-extractor bundledPackages
so external types are inlined in the rolled-up dist/hls.d.ts.

Phase 7: Add tests for:
- v2 fragment data includes version, stream type, and player state
- v2 headers mode includes v2 fields in CMCD headers
- Reporter is not created without eventTargets or for v1
- Reporter is created with v2 + eventTargets
- Reporter.stop(true) is called on destroy
- Play state events are recorded on state transitions
- Error events are recorded on fatal hls.js errors
- Duplicate player state events are deduplicated

Phase 8: Verified TypeScript type-check, all Rollup build configs
(full, fullEsm, light), and api-extractor declaration bundling.

https://claude.ai/code/session_01FmnN6xNSm9Qo17tp52ag3U
Comment on lines +236 to +239
// TODO: Is this the best way to determine the low-latency stream type?
if (details.canBlockReload || details.canSkipUntil) {
return CmcdStreamType.LOW_LATENCY;
}
Copy link
Collaborator Author

@littlespex littlespex Feb 12, 2026

Choose a reason for hiding this comment

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

@robwalch I'm not sure about this check. Is there a better way to determine if a stream is low latency?

Comment on lines +75 to +77
enabledKeys: cmcd.includeKeys ?? [
...(version >= CMCD_V2 ? CMCD_KEYS : CMCD_V1_KEYS),
],
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@cotid-qualabs, @dsilhavy, @nicolaslevy, @robwalch

An open question for both hls.js and dash.js: In CMCD version 1, all keys were enabled by default, and filtering keys via includeKeys/enabledKeys was opt-in. Version 2 introduces a number of new keys, and enabling them all by default would result in ~40 fields. To ensure backwards compatibility, we would at minimum need to enable all keys if the version property is 1. What should we do for version 2 reports? Enabling all keys would create large payloads, but not enabling then creates a more complicated use case for end users "If v1 you don't need to provide an allowed list, but if v2 you do".

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