Background-audio handoff for video + repository/player refactor

Hand video playback off to a native audio-only stream when the app is
backgrounded or locked, with no on-device video decode (UR-040). Adds
player_enter/exit_background_audio commands, an audio-only stream URL
for video items across the repository layer, and the frontend handoff
state machine wired into VideoPlayer. Includes accompanying
repository/offline/player refactoring and regenerates the traceability
matrix.
This commit is contained in:
2026-07-22 21:52:07 +02:00
parent 4e6ab017d4
commit 3fbf6afdbc
72 changed files with 6728 additions and 2338 deletions
@@ -0,0 +1,61 @@
import { describe, it, expect } from "vitest";
import {
computeHandoffPosition,
initialHandoffState,
shouldEnterBackgroundAudio,
shouldExitBackgroundAudio,
type BackgroundAudioState,
} from "./backgroundAudioHandoff";
// TRACES: UR-040 | DR-052 | UT-060
describe("backgroundAudioHandoff", () => {
describe("computeHandoffPosition", () => {
it("sums element time and transcode seekOffset (absolute position)", () => {
// Transcoded HLS resets element time to 0 after a reload; seekOffset carries
// the cumulative offset. The audio stream must resume at the absolute pos.
expect(computeHandoffPosition(12, 180)).toBe(192);
});
it("handles a direct stream with no offset", () => {
expect(computeHandoffPosition(45, 0)).toBe(45);
});
it("never returns a negative position", () => {
expect(computeHandoffPosition(-5, 0)).toBe(0);
});
});
describe("shouldEnterBackgroundAudio", () => {
it("enters when toggle is on and not already handed off", () => {
expect(shouldEnterBackgroundAudio(true, initialHandoffState)).toBe(true);
});
it("does not enter when the toggle is off", () => {
expect(shouldEnterBackgroundAudio(false, initialHandoffState)).toBe(false);
});
it("does not double-enter when already active", () => {
const active: BackgroundAudioState = { active: true, wasPlaying: true };
expect(shouldEnterBackgroundAudio(true, active)).toBe(false);
});
});
describe("shouldExitBackgroundAudio", () => {
it("exits when a handoff is active", () => {
const active: BackgroundAudioState = { active: true, wasPlaying: false };
expect(shouldExitBackgroundAudio(active)).toBe(true);
});
it("does not exit when no handoff happened", () => {
expect(shouldExitBackgroundAudio(initialHandoffState)).toBe(false);
});
it("exits even if the toggle was turned off while backgrounded", () => {
// shouldExit ignores the toggle by design, so turning it off mid-background
// still returns cleanly to video on foreground.
const active: BackgroundAudioState = { active: true, wasPlaying: true };
expect(shouldExitBackgroundAudio(active)).toBe(true);
});
});
});