Multipeer 连接 onicecandidate 事件不会触发
Multipeer connection onicecandidate event won't fire
我在构建 webRTC 多对等连接处理背后的逻辑时遇到问题。
基本上,我试图在视频电话会议中让一个房间里挤满了人。
我使用的是 js 提供的基本 WebSocket 库,前端使用 React,后端使用 Java (spring boot)。
根据我现在的理解,这是我设法写下的内容(根据我“认为”相关的内容进行过滤)
这是我的网络套接字初始化方法(添加监听器)
let webSocketConnection = new WebSocket(webSocketUrl);
webSocketConnection.onmessage = (msg) => {
const message = JSON.parse(msg.data);
switch (message.type) {
case "offer":
handleOfferMessage(message);
break;
case "text":
handleReceivedTextMessage(message);
break;
case "answer":
handleAnswerMessage(message);
break;
case "ice":
handleNewICECandidateMessage(message);
break;
case "join":
initFirstUserMedia(message);
break;
case "room":
setRoomID(message.data);
break;
case "peer-init":
handlePeerConnection(message);
break;
default:
console.error("Wrong type message received from server");
}
当然还有 'on error'、'on close' 和 'on open' 听众
这是处理传入报价的方法
const handleOfferMessage = (message) => {
console.log("Accepting Offer Message");
console.log(message);
let desc = new RTCSessionDescription(message.sdp);
let newPeerConnection = new RTCPeerConnection(peerConnectionConfig);
newPeerConnection.onicecandidate = handleICECandidateEvent;
newPeerConnection.ontrack = handleTrackEvent;
if (desc != null && message.sdp != null) {
console.log("RTC Signalling state: " + newPeerConnection.signalingState);
newPeerConnection
.setRemoteDescription(desc)
.then(function () {
console.log("Set up local media stream");
return navigator.mediaDevices.getUserMedia(mediaConstraints);
})
.then(function (stream) {
console.log("-- Local video stream obtained");
localStream = stream;
try {
videoSelf.current.srcObject = localStream;
} catch (error) {
videoSelf.current.src = window.URL.createObjectURL(stream);
}
console.log("-- Adding stream to the RTCPeerConnection");
localStream
.getTracks()
.forEach((track) => newPeerConnection.addTrack(track, localStream));
})
.then(function () {
console.log("-- Creating answer");
return newPeerConnection.createAnswer();
})
.then(function (answer) {
console.log("-- Setting local description after creating answer");
return newPeerConnection.setLocalDescription(answer);
})
.then(function () {
console.log("Sending answer packet back to other peer");
webSocketConnection.send(
JSON.stringify({
from: user,
type: "answer",
sdp: newPeerConnection.localDescription,
destination: message.from
})
);
})
.catch(handleErrorMessage);
}
peerConnections[message.from.id] = newPeerConnection;
console.log("Peer connections updated now ", peerConnections);
};
SN:我将对等连接定义为由用户唯一 ID 索引的 RTCPeerConnection 数组
let [peerConnections, setPeerConnections] = useState([]);
下面是我认为我理解有误的部分
const handleAnswerMessage = (message) => {
console.log("The peer has accepted request");
let currentPeerConnection = peerConnections[message.from.id];
if (currentPeerConnection) {
currentPeerConnection.setRemoteDescription(message.sdp).catch(handleErrorMessage);
peerConnections[message.from.id] = currentPeerConnection;
} else {
console.error("No user was found with id ", message.from.id);
}
console.log("Peer connections updated now ", peerConnections);
};
currentPeerConnection.setRemoteDescription(message.sdp).catch(handleErrorMessage);
peerConnections[message.from.id] = currentPeerConnection;
console.log("Peer connections updated now ", peerConnections);
};
答案和要约工作完美,我可以清楚地看到两个同行通过发送要约和另一个回应答复来交流。唯一的问题是在那之后没有任何反应,但根据我对 webRTC 的了解,它实际上应该在设置本地描述后立即开始收集 ice candidates。
我能理解为什么处理答案的同行(呼叫者)实际上没有启动 iceecandidate,这可能是因为我没有在答案消息上设置本地描述(我不知道它是否正确) .另一方面,被叫方处理报价消息实际上应该开始收集 iceecandidates,我正在那里设置本地描述。
这是一些可能有用的附加代码
function getMedia(constraints, peerCnnct, initiator) {
if (localStream) {
localStream.getTracks().forEach((track) => {
track.stop();
});
}
navigator.mediaDevices
.getUserMedia(constraints)
.then(stream => {
return getLocalMediaStream(stream, peerCnnct, initiator);
})
.catch(handleGetUserMediaError);
}
function getLocalMediaStream(mediaStream, peerConnection, initiator) {
localStream = mediaStream;
const video = videoSelf.current;
if (video) {
video.srcObject = mediaStream;
video.play();
}
//localVideo.srcObject = mediaStream;
console.log("Adding stream tracks to the peer connection: ", peerConnection);
if (!initiator) {
localStream
.getTracks()
.forEach((track) => peerConnection.addTrack(track, localStream));
}
}
const handlePeerConnection = (message) => {
console.info("Creating new peer connection for user ", message.from);
let newPeerConnection = new RTCPeerConnection(peerConnectionConfig);
// event handlers for the ICE negotiation process
newPeerConnection.ontrack = handleTrackEvent;
newPeerConnection.onicecandidate = handleICECandidateEvent;
getMedia(mediaConstraints, newPeerConnection, false);
newPeerConnection.onnegotiationneeded = handleNegotiationNeededEvent(newPeerConnection, webSocketConnection, user, message.from);
peerConnections[message.from.id] = newPeerConnection;
};
在这里你可以清楚地看到我为了发送报价而拼命寻找解决方案和创建对等连接的尝试。
我无法为没有最终用户的对等连接建立索引,因为我需要他的 ID,只有在我第一次加入房间时收到他的回答后我才会收到。
(后端应该可以工作,但无论哪种方式将调试器放在 ice 候选处理程序方法上,我都可以清楚地看到它没有被触发)
我做错了什么?
编辑:现在 WebSocketMessage 服务器端也有一个目标用户。这样,连接到房间的新对等方接收到与已连接对等方一样多的 peer-init 消息。然后继续为每个同行提供一个报价,将其设置为目的地。
问题仍然存在
这感觉实际上很奇怪,但我修复了调用 getUserMedia() 的问题(这意味着在将 onicecandidate 事件定义添加到 peerConnection 之前调用 addTrack。
这至少解决了我的问题
我在构建 webRTC 多对等连接处理背后的逻辑时遇到问题。 基本上,我试图在视频电话会议中让一个房间里挤满了人。 我使用的是 js 提供的基本 WebSocket 库,前端使用 React,后端使用 Java (spring boot)。
根据我现在的理解,这是我设法写下的内容(根据我“认为”相关的内容进行过滤)
这是我的网络套接字初始化方法(添加监听器)
let webSocketConnection = new WebSocket(webSocketUrl);
webSocketConnection.onmessage = (msg) => {
const message = JSON.parse(msg.data);
switch (message.type) {
case "offer":
handleOfferMessage(message);
break;
case "text":
handleReceivedTextMessage(message);
break;
case "answer":
handleAnswerMessage(message);
break;
case "ice":
handleNewICECandidateMessage(message);
break;
case "join":
initFirstUserMedia(message);
break;
case "room":
setRoomID(message.data);
break;
case "peer-init":
handlePeerConnection(message);
break;
default:
console.error("Wrong type message received from server");
}
当然还有 'on error'、'on close' 和 'on open' 听众 这是处理传入报价的方法
const handleOfferMessage = (message) => {
console.log("Accepting Offer Message");
console.log(message);
let desc = new RTCSessionDescription(message.sdp);
let newPeerConnection = new RTCPeerConnection(peerConnectionConfig);
newPeerConnection.onicecandidate = handleICECandidateEvent;
newPeerConnection.ontrack = handleTrackEvent;
if (desc != null && message.sdp != null) {
console.log("RTC Signalling state: " + newPeerConnection.signalingState);
newPeerConnection
.setRemoteDescription(desc)
.then(function () {
console.log("Set up local media stream");
return navigator.mediaDevices.getUserMedia(mediaConstraints);
})
.then(function (stream) {
console.log("-- Local video stream obtained");
localStream = stream;
try {
videoSelf.current.srcObject = localStream;
} catch (error) {
videoSelf.current.src = window.URL.createObjectURL(stream);
}
console.log("-- Adding stream to the RTCPeerConnection");
localStream
.getTracks()
.forEach((track) => newPeerConnection.addTrack(track, localStream));
})
.then(function () {
console.log("-- Creating answer");
return newPeerConnection.createAnswer();
})
.then(function (answer) {
console.log("-- Setting local description after creating answer");
return newPeerConnection.setLocalDescription(answer);
})
.then(function () {
console.log("Sending answer packet back to other peer");
webSocketConnection.send(
JSON.stringify({
from: user,
type: "answer",
sdp: newPeerConnection.localDescription,
destination: message.from
})
);
})
.catch(handleErrorMessage);
}
peerConnections[message.from.id] = newPeerConnection;
console.log("Peer connections updated now ", peerConnections);
};
SN:我将对等连接定义为由用户唯一 ID 索引的 RTCPeerConnection 数组
let [peerConnections, setPeerConnections] = useState([]);
下面是我认为我理解有误的部分
const handleAnswerMessage = (message) => {
console.log("The peer has accepted request");
let currentPeerConnection = peerConnections[message.from.id];
if (currentPeerConnection) {
currentPeerConnection.setRemoteDescription(message.sdp).catch(handleErrorMessage);
peerConnections[message.from.id] = currentPeerConnection;
} else {
console.error("No user was found with id ", message.from.id);
}
console.log("Peer connections updated now ", peerConnections);
};
currentPeerConnection.setRemoteDescription(message.sdp).catch(handleErrorMessage);
peerConnections[message.from.id] = currentPeerConnection;
console.log("Peer connections updated now ", peerConnections);
};
答案和要约工作完美,我可以清楚地看到两个同行通过发送要约和另一个回应答复来交流。唯一的问题是在那之后没有任何反应,但根据我对 webRTC 的了解,它实际上应该在设置本地描述后立即开始收集 ice candidates。
我能理解为什么处理答案的同行(呼叫者)实际上没有启动 iceecandidate,这可能是因为我没有在答案消息上设置本地描述(我不知道它是否正确) .另一方面,被叫方处理报价消息实际上应该开始收集 iceecandidates,我正在那里设置本地描述。
这是一些可能有用的附加代码
function getMedia(constraints, peerCnnct, initiator) {
if (localStream) {
localStream.getTracks().forEach((track) => {
track.stop();
});
}
navigator.mediaDevices
.getUserMedia(constraints)
.then(stream => {
return getLocalMediaStream(stream, peerCnnct, initiator);
})
.catch(handleGetUserMediaError);
}
function getLocalMediaStream(mediaStream, peerConnection, initiator) {
localStream = mediaStream;
const video = videoSelf.current;
if (video) {
video.srcObject = mediaStream;
video.play();
}
//localVideo.srcObject = mediaStream;
console.log("Adding stream tracks to the peer connection: ", peerConnection);
if (!initiator) {
localStream
.getTracks()
.forEach((track) => peerConnection.addTrack(track, localStream));
}
}
const handlePeerConnection = (message) => {
console.info("Creating new peer connection for user ", message.from);
let newPeerConnection = new RTCPeerConnection(peerConnectionConfig);
// event handlers for the ICE negotiation process
newPeerConnection.ontrack = handleTrackEvent;
newPeerConnection.onicecandidate = handleICECandidateEvent;
getMedia(mediaConstraints, newPeerConnection, false);
newPeerConnection.onnegotiationneeded = handleNegotiationNeededEvent(newPeerConnection, webSocketConnection, user, message.from);
peerConnections[message.from.id] = newPeerConnection;
};
在这里你可以清楚地看到我为了发送报价而拼命寻找解决方案和创建对等连接的尝试。 我无法为没有最终用户的对等连接建立索引,因为我需要他的 ID,只有在我第一次加入房间时收到他的回答后我才会收到。
(后端应该可以工作,但无论哪种方式将调试器放在 ice 候选处理程序方法上,我都可以清楚地看到它没有被触发)
我做错了什么?
编辑:现在 WebSocketMessage 服务器端也有一个目标用户。这样,连接到房间的新对等方接收到与已连接对等方一样多的 peer-init 消息。然后继续为每个同行提供一个报价,将其设置为目的地。
问题仍然存在
这感觉实际上很奇怪,但我修复了调用 getUserMedia() 的问题(这意味着在将 onicecandidate 事件定义添加到 peerConnection 之前调用 addTrack。
这至少解决了我的问题