fix(player): a stale session answer can no longer stop the playback that won
- The engine tracks the request out per item: A, then B, then back to A sent a second request for A beside the one still out. - A hardware transcode superseded during its fallback answered with the NEWER session; the losing request's player then stopped it as stale. It now answers with its own (dead) session. - A replaced hls.js instance's late manifest no longer marks the player ready or plays the outgoing media. - A pause given after the answer stands: the manifest and the first canplay read the live intent. - The debounced A/V-offset restart is dropped on an item change instead of restarting the previous item under the next one's title.
This commit is contained in:
@@ -515,3 +515,56 @@ it("tells React only when the snapshot really changed", async () => {
|
||||
expect(seen.mock.calls.length).toBe(after);
|
||||
await asks[0]!.resolve(direct("A"));
|
||||
});
|
||||
|
||||
describe("an item the viewer comes back to while its request is still out", () => {
|
||||
it("waits for that request instead of sending a second one beside it (A → B → A)", async () => {
|
||||
// The in-flight request was tracked in one slot: B's request took it, and the way back to A
|
||||
// sent A2 next to the A1 still out — two spawns for one item, and the loser's answer could
|
||||
// name the winner's session for the stop.
|
||||
const { engine, asks } = setup();
|
||||
engine.start("A", 0);
|
||||
engine.leaveItem();
|
||||
engine.start("B", 0);
|
||||
engine.leaveItem();
|
||||
engine.start("A", 0);
|
||||
expect(asks.map((a) => a.id)).toEqual(["A", "B"]);
|
||||
await asks[0]!.resolve(hls("A", 0, "s1"));
|
||||
expect(asks.map((a) => a.id)).toEqual(["A", "B", "A"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("a session that was replaced before its manifest parsed", () => {
|
||||
it("neither marks the player ready nor plays the outgoing media", async () => {
|
||||
const { engine, asks, hlses, media } = setup();
|
||||
engine.start("A", 0);
|
||||
await asks[0]!.resolve(hls("A"));
|
||||
engine.seek("A", 900); // nothing seekable yet: a restart
|
||||
const plays = media.plays;
|
||||
hlses[0]!.handlers.onManifestParsed(); // the replaced instance parses late
|
||||
expect(engine.getSnapshot().ready).toBe(false);
|
||||
expect(media.plays).toBe(plays);
|
||||
});
|
||||
});
|
||||
|
||||
describe("a pause given after the answer, before the media can play", () => {
|
||||
it("stands: neither the manifest nor the first canplay plays it again", async () => {
|
||||
const { engine, asks, hlses, media } = setup();
|
||||
engine.start("A", 0);
|
||||
await asks[0]!.resolve(hls("A"));
|
||||
engine.requestPlay(false);
|
||||
hlses[0]!.handlers.onManifestParsed();
|
||||
expect(media.paused).toBe(true);
|
||||
media.fire("canplay");
|
||||
expect(media.paused).toBe(true);
|
||||
});
|
||||
|
||||
it("stands after the manifest played it too", async () => {
|
||||
const { engine, asks, hlses, media } = setup();
|
||||
engine.start("A", 0);
|
||||
await asks[0]!.resolve(hls("A"));
|
||||
hlses[0]!.handlers.onManifestParsed();
|
||||
engine.requestPlay(false);
|
||||
media.fire("canplay");
|
||||
expect(media.paused).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user