Compare commits

...

3 Commits

Author SHA1 Message Date
kura
e98cd2844d 优化音视频的样式 2026-05-07 22:02:25 +08:00
kura
0de25a0544 优化显示 2026-05-07 21:21:50 +08:00
kura
ae36cb183b 修复视频空流 2026-05-07 21:21:45 +08:00
3 changed files with 1298 additions and 162 deletions

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,7 @@ const updateTasks = () => {
tasks.value = Array.from(
fileTransferMgrInstance
.getAllFileTransfers()
.flatMap((transfer) => transfer.getTasks())
.flatMap((transfer) => transfer.getTasks()),
);
// newTasks.forEach((task) => {
// const index = tasks.value.findIndex(
@ -109,7 +109,7 @@ updateTasks();
right: 0;
background: white;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
z-index: 10;
}
.transfer-header {

View File

@ -7,7 +7,7 @@ import {
TransferStatus,
TransferTask,
} from "./fileTransfer";
import { message, Modal, notification } from "ant-design-vue";
import { message, notification } from "ant-design-vue";
import {
randomChars,
sign2peerid,
@ -86,7 +86,10 @@ class Peer extends EventTarget {
// 保存 this 引用
const self = this;
let handled = false;
const onOk = async () => {
if (handled) return;
handled = true;
try {
let stream: MediaStream;
@ -104,7 +107,7 @@ class Peer extends EventTarget {
}
call.answer(stream);
self.setupMediaConnection(call, type, stream);
self.setupMediaConnection(call, type, stream, type !== "desktop");
self.dispatchEvent(
new CustomEvent(
@ -112,6 +115,7 @@ class Peer extends EventTarget {
{
detail: {
peerId: call.peer,
role: type === "desktop" ? "sharer" : "caller",
},
},
),
@ -126,20 +130,34 @@ class Peer extends EventTarget {
message.error("无法访问" + (type === "desktop" ? "屏幕" : "麦克风"));
}
};
const onReject = () => {
if (handled) return;
handled = true;
call.close();
message.info(
"已拒绝" + (type === "desktop" ? "屏幕共享" : "语音通话") + "请求",
);
};
if (getPermissionSet()[permission]) {
await onOk();
} else if (type === "call") {
this.dispatchEvent(
new CustomEvent("media-request", {
detail: {
peerId: call.peer,
type,
accept: onOk,
reject: onReject,
},
}),
);
} else {
confirmWin(title, content, "接受", "拒绝")
.then(async () => {
await onOk();
})
.catch(() => {
call.close();
message.info(
"已拒绝" +
(type === "desktop" ? "屏幕共享" : "语音通话") +
"请求",
);
onReject();
});
}
});
@ -199,23 +217,19 @@ class Peer extends EventTarget {
}
try {
// 创建一个静音的音频流作为占位
const emptyStream = new MediaStream();
// 将音频轨道静音
emptyStream.getAudioTracks().forEach((track) => {
track.enabled = false;
});
const offerStream = this.createDesktopOfferStream();
const call = this.peer.call(sign2peerid(id), emptyStream, {
const call = this.peer.call(sign2peerid(id), offerStream, {
metadata: { type: "desktop" },
});
this.setupMediaConnection(call, "desktop", emptyStream);
this.setupMediaConnection(call, "desktop", offerStream);
this.dispatchEvent(
new CustomEvent("desktop-started", {
detail: {
peerId: call.peer,
role: "viewer",
},
}),
);
@ -227,6 +241,22 @@ class Peer extends EventTarget {
}
}
private createDesktopOfferStream() {
const canvas = document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
const context = canvas.getContext("2d");
context?.fillRect(0, 0, 1, 1);
const stream = canvas.captureStream(1);
const [track] = stream.getVideoTracks();
if (!track) {
throw new Error("无法创建桌面协商视频轨");
}
track.enabled = false;
return stream;
}
async requestCall(id: string) {
if (!this.remoteConnection) {
notification.error({
@ -435,6 +465,7 @@ class Peer extends EventTarget {
call: MediaConnection,
type: MediaType,
localStream: MediaStream | null = null,
acceptRemoteStream = true,
) {
const peerId = call.peer;
this.updateMediaConnection(peerId, type, {
@ -444,6 +475,7 @@ class Peer extends EventTarget {
call.on("stream", (remoteStream: MediaStream) => {
console.log("stream", remoteStream);
if (!acceptRemoteStream) return;
// 只有当流中包含相应类型的轨道时才保存连接
const hasVideo = remoteStream.getVideoTracks().length > 0;
const hasAudio = remoteStream.getAudioTracks().length > 0;