fix live camera runtime refresh and title recovery

这个提交包含在:
cryptocommuniums-afk
2026-03-16 23:53:10 +08:00
父节点 634a4704c7
当前提交 8e9e4915e2
修改 3 个文件,包含 176 行新增22 行删除

查看文件

@@ -866,6 +866,73 @@ export async function installAppMocks(
return points;
};
class FakeVideoTrack {
kind = "video";
enabled = true;
muted = false;
readyState = "live";
id = "fake-video-track";
label = "Fake Camera";
stop() {}
getSettings() {
return {
facingMode: "environment",
width: 1280,
height: 720,
frameRate: 30,
};
}
getCapabilities() {
return {};
}
async applyConstraints() {
return undefined;
}
}
class FakeAudioTrack {
kind = "audio";
enabled = true;
muted = false;
readyState = "live";
id = "fake-audio-track";
label = "Fake Mic";
stop() {}
getSettings() {
return {};
}
getCapabilities() {
return {};
}
async applyConstraints() {
return undefined;
}
}
const createFakeMediaStream = (withAudio = false) => {
const videoTrack = new FakeVideoTrack();
const audioTrack = withAudio ? new FakeAudioTrack() : null;
const tracks = audioTrack ? [videoTrack, audioTrack] : [videoTrack];
return {
active: true,
id: `fake-stream-${Math.random().toString(36).slice(2)}`,
getTracks: () => tracks,
getVideoTracks: () => [videoTrack],
getAudioTracks: () => (audioTrack ? [audioTrack] : []),
addTrack: () => undefined,
removeTrack: () => undefined,
clone: () => createFakeMediaStream(withAudio),
} as unknown as MediaStream;
};
class FakePose {
callback = null;
@@ -894,9 +961,19 @@ export async function installAppMocks(
value: async () => undefined,
});
Object.defineProperty(HTMLMediaElement.prototype, "srcObject", {
configurable: true,
get() {
return (this as HTMLMediaElement & { __srcObject?: MediaStream }).__srcObject ?? null;
},
set(value) {
(this as HTMLMediaElement & { __srcObject?: MediaStream }).__srcObject = value as MediaStream;
},
});
Object.defineProperty(HTMLCanvasElement.prototype, "captureStream", {
configurable: true,
value: () => new MediaStream(),
value: () => createFakeMediaStream(),
});
class FakeMediaRecorder extends EventTarget {
@@ -961,7 +1038,7 @@ export async function installAppMocks(
async setRemoteDescription(description: { type: string; sdp: string }) {
this.remoteDescription = description;
this.connectionState = "connected";
this.ontrack?.({ streams: [new MediaStream()] });
this.ontrack?.({ streams: [createFakeMediaStream()] });
this.onconnectionstatechange?.();
}
@@ -984,7 +1061,7 @@ export async function installAppMocks(
Object.defineProperty(navigator, "mediaDevices", {
configurable: true,
value: {
getUserMedia: async () => new MediaStream(),
getUserMedia: async (constraints?: { audio?: unknown }) => createFakeMediaStream(Boolean(constraints?.audio)),
enumerateDevices: async () => [
{ deviceId: "cam-1", kind: "videoinput", label: "Front Camera", groupId: "g1" },
{ deviceId: "cam-2", kind: "videoinput", label: "Back Camera", groupId: "g1" },