无法触发 WebRTC 跟踪事件
2020-05-21
1353
我是 WebRTC 的新手,尝试在两个浏览器窗口之间建立对等连接。我在本地运行的 nodejs 中实现了简单的 websocket 服务器。在创建候选对象之前,一切似乎都很好。交换候选对象后,远程流没有启动。我搜索并运行了几个示例,但无法正常工作。
我的 UI 有一些用于通信的输入。以下是我调用时的操作:
-
在第一个窗口中输入用户名
user1
,在第一个窗口中输入远程用户名user2
-
在第二个窗口中输入用户名
user2
,在第二个窗口中输入远程用户名user1
-
在每两个窗口中单击
连接到服务器
按钮。(此后,信令服务器将知道它们)。 - 在第一个窗口中选择我的第一个摄像头设备,在第二个窗口中选择我的第二个摄像头设备。 (之后相机将启动)
- 在第一个窗口中单击调用
问题是:远程流显示在被调用方窗口(第二个窗口)上,但从调用方窗口(第一个窗口)的开发控制台中,我没有看到
onTrack
函数运行。因此远程流不会显示在调用方上。但是我看到了候选日志。
因此,调用者看不到被调用者,但被调用者可以看到调用者。
index.html
我在两个浏览器窗口中打开此文件两次(作为 file://...)。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Webrtc Test</title>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
</head>
<body>
<table border="2">
<tr>
<td>
<span>Signaling Server addres:</span>
<input type="text" id="serverAddress" value="localhost:3001" onload="window.serverAddress = this;" />
</td>
<td>
<span>Username:</span>
<input type="text" id="username" value="user1" onload="window.username = this;" />
</td>
<td>
<span>Target username:</span>
<input type="text" id="remoteUsername" value="user2" onload="window.remoteUsername = this;" />
</td>
<td>Devices</td>
</tr>
<tr>
<td>
<textarea
name="log"
id="log"
cols="50"
rows="10"
style="width: 100%; resize: vertical;"
></textarea>
</td>
<td>
<video
id="selfVideo"
autoplay
playsinline
muted
onload="window.selfVideo = this;"
></video>
</td>
<td>
<video id="remoteVideo" autoplay playsinline onload="window.remoteVideo = this;"></video deo>
</td>
<td rowspan="2">
<div>
<div>Video:<input id="videoCheck" type="checkbox" onload="window.videoCheck = this;" checked /></div>
<select
id="videoDevices"
size="5"
onload="window.videoDevices = this;"
onchange="startSelf();"
></select>
</div>
<div>
<div>Audio:<input id="audioCheck" type="checkbox" onload="window.audioCheck = this;" /></div>
<select
id="audioDevices"
size="5"
onload="window.audioDevices = this;"
onchange="startSelf();"
></select>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<div
style="width: 100%; display: flex; justify-content: space-evenly;"
>
<button id="connect" onclick="connect();">Connect to server</button>
<button id="call" onclick="call();">Call</button>
<button id="hangup" onclick="hangup();">Hang up</button>
</div>
</td>
</tr>
</table>
<!-- <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> -->
<script src="adapter.js"></script>
<script src="setup.js"></script>
<script src="socket.js"></script>
<script src="rtc.js"></script>
</body>
</html>
setup.js
用于检测输入设备并在页面加载时创建选项。
const detectDevices = (deviceInfos) => {
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i];
const element = document.createElement("option");
element.value = deviceInfo.deviceId;
if (deviceInfo.kind === "videoinput") {
element.innerText =
deviceInfo.label || `camera ${videoDevices.length + 1}`;
videoDevices.add(element);
} else if (deviceInfo.kind === "audioinput") {
element.innerText =
deviceInfo.label || `microphone ${audioDevices.length + 1}`;
audioDevices.add(element);
}
}
};
navigator.mediaDevices
.getUserMedia({ audio: true, video: true })
.then((stream) => {
window.localStream = stream;
return navigator.mediaDevices.enumerateDevices();
})
.then(detectDevices)
.then(() => {
localStream.getTracks().forEach((t) => t.stop());
delete localStream;
})
.catch((error) => console.log("Error detecting devices", error));
const startSelf = async () => {
if (videoCheck.checked && !videoDevices.value) {
videoDevices.selectedIndex = 0;
}
if (audioCheck.checked && !audioDevices.value) {
audioDevices.selectedIndex = 0;
}
const vDevId = videoDevices.value;
const aDevId = audioDevices.value;
// const constraints = {
// audio: { deviceId: aDevId ? { exact: aDevId } : undefined },
// video: { deviceId: vDevId ? { exact: vDevId } : undefined }
// };
const constraints = {};
if (videoCheck.checked) {
constraints.video = { deviceId: vDevId ? { exact: vDevId } : undefined };
}
if (audioCheck.checked) {
constraints.audio = { deviceId: aDevId ? { exact: aDevId } : undefined };
}
await navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
window.localStream = stream;
selfVideo.srcObject = stream;
})
.catch((error) => console.log("Error start self", error));
};
socket.js
let ws;
const send = (obj) => {
const message = {
from: username.value,
to: remoteUsername.value
};
message.data = btoa(JSON.stringify(obj));
ws.send(JSON.stringify(message));
};
const connect = () => {
ws = new WebSocket("ws://" + serverAddress.value);
registerEvents();
};
const registerEvents = () => {
ws.onopen = () => {
console.log("websocket open");
ws.send(JSON.stringify({ from: username.value, data: "merheba" }));
};
ws.onmessage = (m) => {
// parse message
const message = JSON.parse(m.data);
if (message.data === "siye de merheba") {
console.log("connected to server");
return;
}
const data = JSON.parse(atob(message.data));
message.data = data;
console.log("message: ", message);
switch (data.type) {
case "offer":
onReceiveOffer(data);
break;
case "answer":
onReceiveAnswer(data);
break;
case "candidate":
console.log("received ice candidate", data);
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
break;
}
};
};
rtc.js
用于 webrtc 调用函数
let pc;
const initSelf = async () => {
pc = new RTCPeerConnection();
pc.onicecandidate = onIceCandidate;
pc.ontrack = onTrack;
await startSelf();
pc.addStream(localStream);
};
const call = async () => {
if (!window.localStream || !pc) {
await initSelf();
}
// send offer
pc.createOffer().then((offer) => {
pc.setLocalDescription(offer);
console.log("sending offer");
send(offer);
});
};
const onReceiveOffer = async (receivedOffer) => {
console.log("offer receive", receivedOffer);
if (!window.localStream || !pc) {
initSelf();
}
pc.setRemoteDescription(new RTCSessionDescription(receivedOffer));
log.value = JSON.stringify(receivedOffer);
// answer
await pc.createAnswer().then((answer) => {
pc.setLocalDescription(answer);
console.log("answer created: ", answer);
send(answer);
});
};
const onReceiveAnswer = async (receivedAnswer) => {
console.log("answer receive", receivedAnswer);
pc.setRemoteDescription(new RTCSessionDescription(receivedAnswer));
log.value = JSON.stringify(receivedAnswer);
};
const onTrack = async (event) => {
console.log("Add track");
remoteVideo.srcObject = event.streams[0];
};
const onIceCandidate = async (event) => {
if (event.candidate) {
console.log("ICE candidate");
send({
type: "candidate",
candidate: event.candidate
});
}
};
const hangup = () => {
if (pc) {
pc.close();
pc = null;
}
localStream.getTracks().forEach((t) => t.stop());
delete localStream;
};
使用
node wsServer.js
运行的信令服务器
wsServer.js
const WebSocket = require("ws");
const wsserver = new WebSocket.Server({ port: 3001 }, () => {
console.log("server started");
});
let clients = [];
wsserver.on("connection", (socket) => {
socket.on("message", (message) => {
console.log("Message: %s", message);
let data;
try {
data = JSON.parse(message);
} catch (error) {
console.log("Invalid JSON");
data = {};
return;
}
if (!data.from || data.from === "") {
console.log("unknown sender");
return;
}
if (!clients[data.from]) {
console.log("client add: ", data.from);
clients[data.from] = socket;
}
if (data.data === "merheba") {
socket.send(JSON.stringify({ data: "siye de merheba" }));
clients[data.from] = socket;
return;
}
if (data.to) {
const target = clients[data.to];
if (target) {
console.log("forwarding to " + data.to);
// console.log(target);
target.send(message);
}
}
});
// socket.on("close", () => {
// if (socket.username) {
// delete clients[socket.from];
// }
// });
});
2个回答
这是语法:
RTCPeerConnection.ontrack = eventHandler;
因此,查看您的代码,它应该是这样的:
self.ontrack = onTrack;
您对 onicecandidate 执行的方式
smitkpatel
2020-05-21
我放了一些
window.localStream
并将
initSelf()
的内容移到了
startSelf()
内。我不知道为什么,但问题解决了。
const startSelf = async () => {
// creating pc object first
if (!pc) {
pc = new RTCPeerConnection();
pc.onicecandidate = onIceCandidate;
pc.ontrack = onTrack;
}
// some code ...
await navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
window.localStream = stream;
pc.addStream(window.localStream); // adding the stream before showing
selfVideo.srcObject = window.localStream;
})
.catch((error) => console.log("Error start self", error));
};
user12043
2020-05-25