Playback fix
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 4m28s
Traceability Validation / Check Requirement Traces (push) Successful in 22s
🏗️ Build and Test JellyTau / Build Android APK (push) Successful in 18m37s
Build & Release / Run Tests (push) Successful in 4m12s
Build & Release / Build Linux (push) Successful in 16m20s
Build & Release / Build Android (push) Successful in 18m57s
Build & Release / Create Release (push) Successful in 13s
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 4m28s
Traceability Validation / Check Requirement Traces (push) Successful in 22s
🏗️ Build and Test JellyTau / Build Android APK (push) Successful in 18m37s
Build & Release / Run Tests (push) Successful in 4m12s
Build & Release / Build Linux (push) Successful in 16m20s
Build & Release / Build Android (push) Successful in 18m57s
Build & Release / Create Release (push) Successful in 13s
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* HTML5 <video> → Rust reporting adapter ("html5+rust internal module").
|
||||
*
|
||||
* On platforms where video renders in the webview (Linux WebKitGTK HTML5
|
||||
* <video>; and, per the current interim behavior, Android too), the real player
|
||||
* is the DOM element, which the Rust backend cannot observe directly. This
|
||||
* module is the single place that reports the element's lifecycle back into
|
||||
* Rust, so the `PlayerController` stays the source of truth and the frontend
|
||||
* `player` store is fed from ONE pipeline (playerEvents.ts) in both native and
|
||||
* HTML5 modes.
|
||||
*
|
||||
* The VideoPlayer component owns the element and its UI; it calls these
|
||||
* functions from its DOM event handlers. Keeping the `commands.playerReport*`
|
||||
* calls here (rather than scattered in the component) is the boundary: UI code
|
||||
* never talks to the report commands directly.
|
||||
*
|
||||
* TRACES: UR-003, UR-005 | DR-001, DR-028
|
||||
*/
|
||||
|
||||
import { commands } from "$lib/api/bindings";
|
||||
|
||||
/** Player states mirrored to Rust (must match the strings playerEvents.ts handles). */
|
||||
export type Html5PlayerState = "playing" | "paused" | "loading" | "stopped" | "idle";
|
||||
|
||||
/**
|
||||
* Report an HTML5 <video> state transition to Rust. The controller re-emits a
|
||||
* `StateChanged` event identical to the native backends', so the frontend
|
||||
* player store updates through its normal path.
|
||||
*/
|
||||
export async function reportState(
|
||||
state: Html5PlayerState,
|
||||
mediaId: string | null
|
||||
): Promise<void> {
|
||||
try {
|
||||
await commands.playerReportState(state, mediaId);
|
||||
} catch (err) {
|
||||
console.warn("[html5Adapter] Failed to report state:", err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Position reporting is throttled to ~250ms to match the native backends'
|
||||
* cadence and avoid flooding the IPC channel from the 60fps RAF loop.
|
||||
*/
|
||||
let lastPositionReport = 0;
|
||||
const POSITION_REPORT_INTERVAL_MS = 250;
|
||||
|
||||
/**
|
||||
* Report an HTML5 <video> position tick to Rust (throttled). Safe to call every
|
||||
* animation frame; only forwards at most every {@link POSITION_REPORT_INTERVAL_MS}.
|
||||
*/
|
||||
export async function reportPosition(
|
||||
position: number,
|
||||
duration: number,
|
||||
{ force = false }: { force?: boolean } = {}
|
||||
): Promise<void> {
|
||||
const now = Date.now();
|
||||
if (!force && now - lastPositionReport < POSITION_REPORT_INTERVAL_MS) {
|
||||
return;
|
||||
}
|
||||
lastPositionReport = now;
|
||||
try {
|
||||
await commands.playerReportPosition(position, Number.isFinite(duration) ? duration : 0);
|
||||
} catch (err) {
|
||||
console.warn("[html5Adapter] Failed to report position:", err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report that the HTML5 <video> finished loading metadata and knows its
|
||||
* duration. Mirrors the native `MediaLoaded` event.
|
||||
*/
|
||||
export async function reportMediaLoaded(duration: number): Promise<void> {
|
||||
try {
|
||||
await commands.playerReportMediaLoaded(Number.isFinite(duration) ? duration : 0);
|
||||
} catch (err) {
|
||||
console.warn("[html5Adapter] Failed to report media loaded:", err);
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset internal throttle state (call when a new stream loads). */
|
||||
export function resetReporting(): void {
|
||||
lastPositionReport = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user