Устранение гонки запуска live-камеры
This commit is contained in:
@@ -470,8 +470,6 @@ export function MseFmp4WebSocketPlayer({
|
|||||||
: "Подключение к локальному видеопотоку");
|
: "Подключение к локальному видеопотоку");
|
||||||
const mediaSource = new MediaSource();
|
const mediaSource = new MediaSource();
|
||||||
objectUrl = URL.createObjectURL(mediaSource);
|
objectUrl = URL.createObjectURL(mediaSource);
|
||||||
video.src = objectUrl;
|
|
||||||
startupWatchdog?.armFirstMedia();
|
|
||||||
|
|
||||||
const onSourceOpen = () => {
|
const onSourceOpen = () => {
|
||||||
if (!transportIsCurrent() || failed) return;
|
if (!transportIsCurrent() || failed) return;
|
||||||
@@ -562,7 +560,12 @@ export function MseFmp4WebSocketPlayer({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Register before assigning the object URL. `video.src` is the action that
|
||||||
|
// lets the browser open this MediaSource; a fast sequential MSE lease must
|
||||||
|
// not fire `sourceopen` in the gap before its only listener exists.
|
||||||
mediaSource.addEventListener("sourceopen", onSourceOpen, { once: true });
|
mediaSource.addEventListener("sourceopen", onSourceOpen, { once: true });
|
||||||
|
startupWatchdog?.armFirstMedia();
|
||||||
|
video.src = objectUrl;
|
||||||
|
|
||||||
const disposeTransport = () => {
|
const disposeTransport = () => {
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
|
import { readFile } from "node:fs/promises";
|
||||||
import { after, before, test } from "node:test";
|
import { after, before, test } from "node:test";
|
||||||
|
|
||||||
import { createElement } from "react";
|
import { createElement } from "react";
|
||||||
@@ -184,6 +185,24 @@ test("floating observation interaction captures resize and movable header pointe
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("live camera registers sourceopen before assigning the MSE object URL", async () => {
|
||||||
|
const source = await readFile(
|
||||||
|
new URL("../src/components/MseFmp4WebSocketPlayer.tsx", import.meta.url),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
const listenerIndex = source.indexOf(
|
||||||
|
'mediaSource.addEventListener("sourceopen", onSourceOpen, { once: true });',
|
||||||
|
);
|
||||||
|
const sourceAssignmentIndex = source.indexOf("video.src = objectUrl;");
|
||||||
|
|
||||||
|
assert.ok(listenerIndex >= 0, "sourceopen listener must remain explicit");
|
||||||
|
assert.ok(sourceAssignmentIndex >= 0, "MediaSource object URL assignment must remain explicit");
|
||||||
|
assert.ok(
|
||||||
|
listenerIndex < sourceAssignmentIndex,
|
||||||
|
"sourceopen listener must exist before video.src can open the MediaSource",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("recorded observation timeline clamps relative seek time without epoch precision in the UI", () => {
|
test("recorded observation timeline clamps relative seek time without epoch precision in the UI", () => {
|
||||||
const range = normalizeTimelineRange({
|
const range = normalizeTimelineRange({
|
||||||
min: 0,
|
min: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user