Skip to content

Add optional quality field to first_frame beacon#38

Open
stevenlyons wants to merge 2 commits into
mainfrom
feature/initial-rendition
Open

Add optional quality field to first_frame beacon#38
stevenlyons wants to merge 2 commits into
mainfrom
feature/initial-rendition

Conversation

@stevenlyons
Copy link
Copy Markdown
Owner

Summary

  • Captures the initial rendition at first-frame time across all integrations (Rust core, Hls.js, Shaka, dash.js, AVPlayer, Media3)
  • Quality is omitted entirely (key absent) when an integration cannot determine the rendition — no degraded data is sent
  • Reuses the existing QualityLevel type; no beacon schema changes beyond making the field available on first_frame

Changes

  • crates/plinth-core: FirstFrame event becomes a struct variant carrying Option<QualityLevel>; beacon copies quality when present; 3 new core tests
  • packages/web/plinth-js: PlayerEvent type updated with optional quality on first_frame
  • packages/web/plinth-hlsjs: reads hls.levels[hls.currentLevel] at first frame; falls back to no quality when currentLevel=-1
  • packages/web/plinth-shaka: reads active variant via getVariantTracks() using extracted qualityFromTrack helper
  • packages/web/plinth-dashjs: uses lastRepresentation cached by the quality-change handler
  • packages/apple/plinth-avplayer: reads presentationSize + access log indicatedBitrate from AVPlayerItem
  • packages/android/plinth-media3: reads player.videoFormat in onRenderedFirstFrame
  • docs/reference: beacon-payload.md and beacon-payload.schema.json updated to document optional quality on first_frame
  • Also fixes pre-existing bug: seekStart was serialized as "seek_start" in Swift but Rust expects "seek"

Test plan

  • Rust: cargo test -p plinth-core — 143 tests pass, including 3 new first_frame quality tests
  • Web: pnpm -r test — 38/38 hlsjs, 38/38 shaka, 35/35 dashjs
  • Swift: swift test (from packages/apple/plinth-apple/) — 21 tests pass
  • Android: ./gradlew :plinth-media3:test — requires JDK+Android SDK; 5 new tests for first_frame quality
  • Edge case: integration with no rendition info at first frame emits {"type":"first_frame"} with no quality key
  • Edge case: subsequent quality_change beacons are not suppressed by the initial quality capture

Captures the initial rendition at first-frame time across all
integrations, giving a complete quality picture from the start of
playback — not just from the first ABR switch.

- plinth-core: FirstFrame event becomes a struct variant carrying
  Option<QualityLevel>; first_frame beacon copies quality when present
- plinth-js: PlayerEvent type updated to include optional quality
- plinth-hlsjs: reads hls.levels[hls.currentLevel] at first frame
- plinth-shaka: reads active variant track via getVariantTracks()
- plinth-dashjs: uses lastRepresentation cached by quality_change handler
- plinth-avplayer: reads presentationSize + access log indicatedBitrate
- plinth-media3: reads player.videoFormat at onRenderedFirstFrame

Quality is omitted (key absent) when the integration cannot determine
the rendition (e.g. no access log entry yet, currentLevel=-1, no format).

Also fixes a pre-existing bug: seekStart was serialized as "seek_start"
in Swift but Rust expects "seek"; corrected encoding and updated tests.
Hls.js: LEVEL_SWITCHED fires for the initial level immediately after
first_frame, emitting a redundant quality_change at identical quality.
Fix: track lastQualityBitrate; skip LEVEL_SWITCHED if bitrate matches
what was captured at first_frame. Set lastQualityBitrate in onPlaying
alongside the first_frame emission. Two new tests cover this.

dash.js: QUALITY_CHANGE_REQUESTED fires after first_frame in practice,
so lastRepresentation was null when onPlaying ran. Fix: call
getCurrentRepresentationForType('video') directly at first_frame time
(always reflects the current rendition). Set lastQualityIndex from the
result so subsequent QUALITY_CHANGE_REQUESTED for the same index is
deduped. Tests 5 and 5a updated; new test 5b covers dedup after capture.
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.

1 participant