gpt4 book ai didi

javascript - 参数为 null 的 addIceCandidate 导致错误

转载 作者:行者123 更新时间:2023-11-29 23:00:26 27 4
gpt4 key购买 nike

我正在尝试学习 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”。但我不明白为什么我此时会看到我看到的错误。

我尝试过的:

  1. 我曾尝试编写一个检查,如果 candidate 为空,则跳过 addIceCandidate。
  2. 将所有连接逻辑放在更少的按钮中以减少函数调用之间的延迟
  3. 将 adapter-latest.js 添加到每个页面

结果:

  1. 发起者连接状态为“失败”,接收者连接状态为"new"。无法流式传输到接收者页面。
  2. 同样的错误被抛出
  3. 错误消失了,但连接仍然失败

启动器.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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com