fix(player): tell the native backend's caller what it actually did
Two defects found by running on an Android tablet, both invisible on the desktop, and both the same mistake: a rule written for the webview applied to a backend that is not one. The quality picker froze on the first stream. `StreamQualityResponse::Native` carried only a position, so nothing replaced the selection the UI holds after a native quality change. The picker derives the rung in force from that selection's rendition, and a transcode always has a rendition — so the fallback that would have used the requested value was never reached. The stream changed and the menu did not. The native variant now carries the `StreamSelection` the backend opened, like the HTML5 variant already did. This was invisible on the desktop because the webview path replaces the selection as a side effect of reloading its element. It looked correct there for a reason that does not generalise. A quality change restarted playback from zero. The resume position came from `videoElement.currentTime`, which the frontend cannot supply on a native backend — there is no `<video>` element, so it correctly sends null and the backend substituted 0. Reading it from the DOM at all inverts the rule that the player is the authority on playback state; the fallback now asks the controller where it is. Captured before the negotiation round-trip, so it resumes a few hundred milliseconds behind rather than ahead, which is the right direction to err. Also from the tablet, and NOT fixed here because it changes playback behaviour and deserves its own change: `audio_forces_transcode` judges against `WEBVIEW_AUDIO_CODECS` on every platform, and `video_audio_codecs` narrows the advertised direct-play audio set to that same webview list. On Android the decoder is ExoPlayer. The tablet reports dts among its platform codecs, has it stripped from the profile, and then has the webview rule force a transcode for it. That is the third instance of a decode capability tied to the wrong renderer, and it is what DR-233 exists to collapse — evidence now, not a design preference. It also corrects the record on this branch's headline number. The measured 85% direct-play rate used a hypothetical Android profile including ac3/eac3; this tablet's MediaCodecList reports neither, so eac3 content — about a third of the sampled library — correctly transcodes here. 85% was the ceiling of a profile the app does not send, on hardware that could not use it. The negotiation and the contract are sound; the figure was not a measurement of what ships.
This commit is contained in:
@@ -2415,11 +2415,18 @@
|
||||
mediaSourceId ?? null,
|
||||
selectedAudioTrackIndex,
|
||||
);
|
||||
// The HTML5 path reloads through the adapter, which already set the new
|
||||
// selection via the bridge. The native path reloads inside Rust and
|
||||
// returns nothing, so record what was asked for as the ceiling in force.
|
||||
if (!negotiated) {
|
||||
defaultQuality = quality;
|
||||
// Adopt whatever the backend says it opened. The HTML5 path has already
|
||||
// set this via the adapter bridge, so this is a no-op there; the native
|
||||
// path reloads inside Rust and this is the only thing that updates the UI.
|
||||
//
|
||||
// Assigning it is what keeps the picker honest: `selectedQuality` reads
|
||||
// the selection's rendition, and a transcode always has one — so without
|
||||
// this the menu stayed on the first stream's rung while the stream itself
|
||||
// changed underneath.
|
||||
//
|
||||
// TRACES: UR-074, UR-079 | DR-225, DR-226
|
||||
if (negotiated) {
|
||||
currentSelection = negotiated;
|
||||
}
|
||||
if (videoElement && !videoElement.paused) {
|
||||
startTimeUpdates();
|
||||
|
||||
Reference in New Issue
Block a user