即使handleTrackEvent函数将轨道类型记录为“video”并成功将轨道添加到remoteStream,远程视频也不会显示在remoteVideoEl元素中。轨道类型在handleTrackEvent中记录为“video”,表示视频接收到音轨,该音轨已添加到remoteStream中,但remoteVideoEl为空,不显示远端视频。
视频聊天.html
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="Main" style="height: 100%; background-color: rgb(156, 177, 255)">
<div
id="video-players-div"
style="
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
height: 50%;
background-color:rgb(0, 102, 255);
"
>
<video id="local-video" style="width: 50%; height: 100%; border: solid white 2px;" autoplay playsinline></video>
<video id="remote-video" style="width: 50%; height: 100%; border: solid black 2px;" autoplay playsinline></video>
</div>
<p id="Room-Information" ></p>
<button id="New-Chat" > New Chat</button>
<div id="user-name"></div>
</div>
<script src="https://unpkg.com/[email protected]/dist/peerjs.min.js"></script>
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js" integrity="sha384-2huaZvOR9iDzHqslqwpR87isEmrfxqyWOF7hr7BY6KG0+hVKLoEXMPUJw3ynWuhO" crossorigin="anonymous"></script>
<script src="./client.js"></script>
</body>
</html>
客户端.js
let localStream;
let remoteStream;
let remoteRandomId;
let myPeerConnection;
let roomName;
let offer_;
let answer_;
let randomId;
let didIOffer = false;
const localVideoEl = document.querySelector("#local-video");
const remoteVideoEl = document.querySelector("#remote-video");
const showVideoButton = document.querySelector("#showVideo");
let remoteIceCandidate;
let mediaConstraints = {
//audio: true,
video: {
width: 1080,
height: 540,
},
};
if (!window.sessionStorage.getItem("randomId")) {
randomId = "randomId-" + Math.floor(Math.random() * 100000);
window.sessionStorage.setItem("randomId", randomId);
}
const socket = io.connect(`http://localhost:5010`, {
auth: {
randomId: window.sessionStorage.getItem("randomId"),
},
});
document.getElementById("New-Chat").addEventListener("click", () => {
console.log(`New-Chat Button Clicked \n`);
socket.emit("find-partner", {
randomId: randomId,
});
call();
});
socket.on("room-joined", (data) => {
console.log(JSON.stringify(data), " - data , listening to room-joined event");
for (const i of data.participants) {
if (i.randomId !== window.sessionStorage.getItem("randomId")) {
remoteRandomId = i.randomId;
window.sessionStorage.setItem("remoteRandomId", remoteRandomId);
}
}
roomName = data.roomName;
window.sessionStorage.setItem("roomName", roomName);
window.sessionStorage.setItem("remoteRandomId", remoteRandomId);
});
const call = () => {
if (myPeerConnection) {
alert("You cannot start a call because you have got already one open\n");
} else {
createPeerConnection();
navigator.mediaDevices
.getUserMedia(mediaConstraints)
.then((localStream) => {
localVideoEl.srcObject = localStream;
localStream
.getTracks()
.forEach((track) => myPeerConnection.addTrack(track, localStream));
})
.catch((error) => {
console.log(`${error} --- error happened while adding tracks \n`);
});
}
};
function createPeerConnection() {
myPeerConnection = new RTCPeerConnection({
iceServers: [
{
urls: [
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
],
},
],
});
myPeerConnection.onicecandidate = handleICECandidateEvent;
myPeerConnection.ontrack = handleTrackEvent;
myPeerConnection.onnegotiationneeded = handleNegotiationNeededEvent;
myPeerConnection.oniceconnectionstatechange =
handleICEConnectionStateChangeEvent;
}
function handleICECandidateEvent(e) {
console.log("...Ice candidate found!....");
console.log(e, " e in handleICECandidate");
if (e.candiate) {
socket.emit("new-ice-candidate", {
target: remoteRandomId,
candiate: e.candidate,
});
}
}
function handleTrackEvent(ev) {
console.log(`new track coming in , ev -- ${JSON.stringify(ev)}`);
/*if (ev.streams && ev.streams[0]) {
remoteVideoEl.srcObject = ev.streams[0];
} else {
remoteStream = new MediaStream(ev.track);
remoteVideoEl.srcObject = remoteStream;
}*/
if (!remoteStream) {
remoteStream = new MediaStream();
}
remoteStream.addTrack(ev.track);
console.log("Track kind:", ev.track.kind); // "audio" or "video"
remoteVideoEl.srcObject = remoteStream;
}
function handleNegotiationNeededEvent() {
myPeerConnection.createOffer().then((offer) => {
offer_ = offer;
console.log(
`setting local description as offer --- ${JSON.stringify(offer)} \n`
);
return myPeerConnection
.setLocalDescription(offer)
.then(() => {
console.log(
myPeerConnection.localDescription,
" localDescription after it was set to offer"
);
const msg = {
randomId: window.sessionStorage.getItem("randomId"),
remoteRandomId: window.sessionStorage.getItem("remoteRandomId"),
description: "offer",
sdp: myPeerConnection.localDescription, //this becomes null, dont know why
};
socket.emit("video-offer", msg);
})
.catch((error) => {
console.log(`ran into error when creating offer - ${error}`);
}); //sdp
});
}
function handleICEConnectionStateChangeEvent(event) {
console.log(myPeerConnection.iceConnectionState , "---iceConnectionState---")
switch (myPeerConnection.iceConnectionState) {
case "closed":
case "failed":
closeVideoCall();
break;
}
}
socket.on("video-offer", (data) => {
//in this case you are the callee....
console.log(`${JSON.stringify(data)} --- from the caller `);
if (data.remoteRandomId === window.sessionStorage.getItem("randomId")) {
//you are the callee
console.log("call intended for you , you are the callee");
let remoteRandomId_;
remoteRandomId_ = data.remoteRandomId;
createPeerConnection();
const desc = new RTCSessionDescription(data.sdp);
myPeerConnection
.setRemoteDescription(desc)
.then(() => navigator.mediaDevices.getUserMedia(mediaConstraints))
.then((stream) => {
localStream = stream;
localVideoEl.srcObject = localStream;
localStream
.getTracks()
.forEach((track) => myPeerConnection.addTrack(track, localStream));
})
.then(() => myPeerConnection.createAnswer())
.then((answer) => {
return myPeerConnection
.setLocalDescription(answer)
.then(() => {
console.log(
myPeerConnection.localDescription,
" localDescription after it was set to answer "
);
const msg = {
randomId: window.sessionStorage.getItem("randomId"),
remoteRandomId: window.sessionStorage.getItem("remoteRandomId"),
description: "answer",
sdp: myPeerConnection.localDescription, //this becomes null, dont know why
};
socket.emit("video-answer", msg);
})
.catch((error) => console.log(`${error} ran into some error `));
});
}
});
socket.on("video-answer", async (msg) => {
//in this case you are the caller...
console.log(`listening to video-answer event -- ${JSON.stringify(msg)} \n`);
await myPeerConnection.setRemoteDescription(msg.sdp);
});
socket.on("new-ice-candidate", (msg) => {
console.log(`listening to new-ice-candidate event`);
handleNewICECandidateMsg(msg);
});
function handleNewICECandidateMsg(msg) {
/*
{
target: remoteRandomId,
candiate: e.candidate,
} this is going to be the format of the msg object
*/
console.log(msg, `msg inside new-ice-candidate`);
const candidate = new RTCIceCandidate(msg.candidate);
myPeerConnection.addIceCandidate(candidate).catch((error) => {
console.log(`${error} happened while adding ice candidates `);
});
}
main.js(信令服务器)
import fs from "fs";
import express from "express";
import { createServer } from "http";
import { Server } from "socket.io";
const app = express();
const server = createServer(app);
let allUniqueUsers = new Set();
const io = new Server(server, {
cors: {
origin: [
],
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
socket.on("find-partner", async (data) => {
console.log(`listening to the find-partner event ${JSON.stringify(socket.handshake.auth)} \n`);
const allActiveSockets = await io.fetchSockets();
for (const i of allActiveSockets) {
console.log(i.handshake.auth.randomId , "randomId in loop" , socket.handshake.auth.randomId , " current random Id")
if (i.handshake.auth.randomId !== socket.handshake.auth.randomId && socket.inRoom === undefined ) {
const allRooms = io.sockets.adapter.rooms;
if (!i.inRoom) {
createRoom(socket, i);
}
}
}
});
socket.on("video-offer" , async (msg) => {
/*some socket is sending the sdp relay to the receiver ---task
send it to the callee...*/
console.log(`listening to video-offer event --- ${JSON.stringify(msg)}`);
const allActiveSockets = await io.fetchSockets();
for ( const i of allActiveSockets) {
console.log(`${i.handshake.auth.randomId} --- randomId in loop ${msg.randomId} -- sender's randomId`)
if (i.handshake.auth.randomId !== msg.randomId) {
i.emit("video-offer", msg);
}
}
} )
socket.on("new-ice-candidate", async (data) => {
//where to send this???
//send the delivered ice candidate information to the target ( also there in the data)
console.log(`listening to new-ice-candidate event \n`);
const allActiveSockets = await io.fetchSockets();
for ( const i of allActiveSockets) {
if (i.handshake.auth.randomId === data.target) {
socket.emit("new-ice-candidate", data);
}
}
});
socket.on("video-answer", async (data) => {
const allActiveSockets = await io.fetchSockets();
for (const i of allActiveSockets) {
if (i.handshake.auth.randomId === data.remoteRandomId) {
i.emit("video-answer", data);
}
}
});
});
function createRoom(callerSocketObject, calleeSocketObject) {
let currentRandomId = callerSocketObject.handshake.auth.randomId;
let randomId = calleeSocketObject.handshake.auth.randomId;
let roomName =
currentRandomId > randomId
? `${currentRandomId}:${randomId}`
: `${randomId}:${currentRandomId}`;
callerSocketObject.join(roomName);
calleeSocketObject.join(roomName);
callerSocketObject.inRoom = true;
calleeSocketObject.inRoom = true;
io.to(roomName).emit("room-joined", {
roomName: roomName,
participants: [
{
randomId: currentRandomId,
type: "sender",
},
{ randomId: randomId, type: "receiver" },
],
});
}
const PORT = 5010;
server.listen(PORT, () => {
console.log(`server listening on port ${PORT} `);
});
您的问题解决了吗?我遇到了完全相同的问题。如果您能分享您的解决方案,我将不胜感激。谢谢