- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试学习 WebRTC,我已经实现了在同一页面中连接两个 RTCPeerConnection,现在我正尝试将它们分成两个单独的页面并连接它们。但是,在编写代码并交换报价和答案之后,我注意到 initiator.html 上的 addIceCandidate() 将始终使用 null 参数抛出此问题
队列中的 addIceCandidate 出错:类型错误:无法在“RTCPeerConnection”上执行“addIceCandidate”:sdpMid 和 sdpMLineIndex 的候选缺失值
在 processCandidateQueue (initiator.html:69)
经过一些阅读,我了解到 null 用于指示 ICE 候选人收集完成,示例如下:https://webrtc.github.io/samples/src/content/peerconnection/pc1/收集完成时,还会使用参数 null 执行“addIceCandidate”。但我不明白为什么我此时会看到我看到的错误。
我尝试过的:
结果:
启动器.html
<!doctype html>
<html lang="en">
<head>
<title>First WebRTC Project</title>
<link href="common.css" rel="stylesheet" />
</head>
<body>
<div class="log-display"></div>
<div class="func-list">
Initiating host
<div class="func">
<button onclick="onPrepareMedia(this)">Prepare media</button>
<video class="dump"></video>
</div>
<div class="func">
<button onclick="onCreatePeerConnection(this)">onCreatePeerConnection()</button>
<textarea class="dump"></textarea>
</div>
<div class="func">
<button onclick="onCreateOffer(this)">onCreateOffer()</button>
<textarea class="dump"></textarea>
</div>
<div class="func">
<button onclick="onSetLocalDescription(this)">onSetLocalDescription()</button>
<textarea class="dump"></textarea>
</div>
<div class="func">
<button onclick="onSetRemoteDescription(this, answerReceived)">onSetRemoteDescription() // set answerReceived variable manually</button>
<textarea class="dump"></textarea>
</div>
</div>
<script src="common.js"></script>
<script>
localStorage.removeItem("FirstWebRTC_offer");
localStorage.removeItem("FirstWebRTC_answer");
var constraints = { video: true, audio: true };
var stream = null;
var peerConn = null;
var offer = null, offerReceived = null;
var answer = null, answerReceived = null;
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
};
candidateQueue = [];
var onIceCandidate = async function(e) {
window.log("onIceCandidate", e);
if(peerConn.remoteDescription) {
var rslt = e.candidate && await peerConn.addIceCandidate(e.candidate).catch(e => onError("addIceCandidate", e));
} else {
candidateQueue.push(e.candidate);
}
window.log(JSON.stringify(rslt));
};
var onIceConnectionStateChange = function(e) {
window.log("onIceConnectionStateChange", e);
};
var onNegotiationNeeded = function(e) {
console.log("-----", e);
}
var processCandidateQueue = async function() {
for(var i in candidateQueue) {
var candidate = candidateQueue[i];
await peerConn.addIceCandidate(candidate).catch(e => onError("addIceCandidate from queue", e));
}
}
async function onPrepareMedia(e) {
stream = await navigator.mediaDevices.getUserMedia(constraints);
e.parentElement.children[1].value = dumpProperty(stream)
video = e.parentElement.children[1];
video.srcObject = stream;
video.play();
}
function onCreatePeerConnection(e) {
peerConn = new RTCPeerConnection({});
// Setup ICE event handlers
peerConn.onicecandidate = onIceCandidate;
peerConn.oniceconnectionstatechange = onIceConnectionStateChange;
peerConn.onnegotiationneeded = onNegotiationNeeded
// Add tracks to be transmitted
stream.getTracks().forEach(track => peerConn.addTrack(track, stream));
e.parentElement.children[1].value = dumpProperty(peerConn)
}
async function onCreateOffer(e) {
offer = await peerConn.createOffer(offerOptions)
localStorage.setItem("FirstWebRTC_offer", JSON.stringify(offer))
e.parentElement.children[1].value = dumpProperty(offer)
}
async function onSetLocalDescription(e) {
var rslt = await peerConn.setLocalDescription(offer)
e.parentElement.children[1].value = dumpProperty(rslt)
}
async function onSetRemoteDescription(e) {
answerReceived = JSON.parse(localStorage.getItem("FirstWebRTC_answer"));
rslt = await peerConn.setRemoteDescription(answerReceived)
e.parentElement.children[1].value = dumpProperty(rslt)
processCandidateQueue();
}
</script>
</body>
</html>
receiver.html
<!doctype html>
<html lang="en">
<head>
<title>First WebRTC Project</title>
<link href="common.css" rel="stylesheet" />
</head>
<body>
<div class="log-display"></div>
<div class="func-list">
Receiving host
<div class="func">
<button >Received video</button>
<video class="dump"></video>
</div>
<div class="func">
<button onclick="onCreatePeerConnection(this)">onCreatePeerConnection()</button>
<textarea class="dump"></textarea>
</div>
<div class="func">
<button onclick="onSetRemoteDescription(this)">onSetRemoteDescription()</button>
<textarea class="dump"></textarea>
</div>
<div class="func">
<button onclick="onCreateAnswer(this)">onCreateAnswer()</button>
<textarea class="dump"></textarea>
</div>
<div class="func">
<button onclick="onSetLocalDescription(this)">onSetLocalDescription()</button>
<textarea class="dump"></textarea>
</div>
</div>
<script src="common.js"></script>
<script>
localStorage.removeItem("FirstWebRTC_offer");
localStorage.removeItem("FirstWebRTC_answer");
var constraints = { video: true, audio: true };
var stream = null;
var peerConn = null;
var offer = null, offerReceived = null;
var answer = null, answerReceived = null;
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
};
var onTrack = function(e) {
console.log(e);
video = document.querySelector("video")
if (video.srcObject !== e.streams[0]) {
video.srcObject = e.streams[0];
video.play();
console.log('received and playing remote stream');
}
}
var onIceCandidate = async function(e) {
window.log("onIceCandidate", e);
var rslt = e.candidate && await peerConn.addIceCandidate(e.candidate).catch(e => onError("addIceCandidate", e));
window.log(JSON.stringify(rslt));
};
var onIceConnectionStateChange = function(e) {
window.log("onIceConnectionStateChange", e);
};
function onCreatePeerConnection(e) {
peerConn = new RTCPeerConnection({});
// Setup ICE event handlers
peerConn.onicecandidate = onIceCandidate;
peerConn.oniceconnectionstatechange = onIceConnectionStateChange;
peerConn.ontrack = onTrack;
e.parentElement.children[1].value = dumpProperty(peerConn);
}
async function onSetRemoteDescription(e) {
offerReceived = JSON.parse(localStorage.getItem("FirstWebRTC_offer"));
rslt = await peerConn.setRemoteDescription(offerReceived);
e.parentElement.children[1].value = dumpProperty(rslt);
}
async function onCreateAnswer(e) {
answer = await peerConn.createAnswer(offerReceived);
localStorage.setItem("FirstWebRTC_answer", JSON.stringify(answer));
e.parentElement.children[1].value = dumpProperty(answer);
}
async function onSetLocalDescription(e) {
var rslt = await peerConn.setLocalDescription(answer);
e.parentElement.children[1].value = dumpProperty(rslt);
}
</script>
</body>
</html>
通用.js
function dumpProperty(obj, noJSON) {
var output = JSON.stringify(obj);
if(output == "{}" || noJSON) {
output = ""
for (var property in obj) {
output += property + ': ' + obj[property]+';\n';
}
}
return output;
}
function onError(name, e) {
console.warn("Error at " + name + ": ", e);
}
window.log = function(str, obj) {
var logDisplay = document.getElementsByClassName('log-display')[0];
if(logDisplay) {
var newLog = document.createElement("div");
newLog.innerText = str + " : " + dumpProperty(obj);
logDisplay.appendChild(newLog);
}
console.log(str, obj);
}
通用.css
.connection-flow-diagram {
display: flex;
text-align: center;
}
.func-list {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-around;
width: 50%;
margin-left: auto;
margin-right: auto;
text-align: center;
}
.func {
padding: 1rem;
display: flex;
flex-direction: column;
border: 1px dashed black;
}
.func button {
}
.func .dump {
height: 180px;
}
.log-display {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
color: rgba(0,0,0,0.4);
}
最佳答案
Why does supplying addIceCandidate with null result in error while the example code works fine?
这是因为您的浏览器不符合规范。addIceCandidate(null)
在 latest spec 中有效,并且与 addIceCandidate()
和 addIceCandidate({})
没有区别。它们都从远端发出候选人结束信号。
WebRTC samples工作是因为他们使用 adapter.js ,它在旧版浏览器上填充了正确的规范行为。
关于javascript - 参数为 null 的 addIceCandidate 导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55840870/
在几乎所有关于 WebRTC 的教程中,来自 onicecandidate 回调的候选人在 createOffer() 之前通过信令服务器发送给对等方。然后,对等方通过 addicecandidate
我正在尝试调用: peerConn.addIceCandidate(其中 peerConn 是 RtcPeerConnection 的实例) 我得到: NotSupportedError:内部 Dar
我正在尝试学习 WebRTC,我已经实现了在同一页面中连接两个 RTCPeerConnection,现在我正尝试将它们分成两个单独的页面并连接它们。但是,在编写代码并交换报价和答案之后,我注意到
我正在尝试实现纯语音 WebRTC 应用程序。我在 Chrome Version 29.0.1547.0 dev 上运行它。我的应用使用 Socket.IO 作为信号机制。 peerConnectio
我正在尝试使用 webRTC 连接两个对等点。我能够正确显示本地和远程视频,但是只要远程视频出现,候选对象就会变为 null 并且在控制台上它会记录以下错误消息。 TypeError: Failed
我使用网络 Rtc 和网络套接字创建了一个简单的视频通话应用程序。但是当我运行代码时,出现了以下错误。 DOMException [InvalidStateError: "setRemoteDescr
我是一名优秀的程序员,十分优秀!