为了账号安全,请及时绑定邮箱和手机立即绑定

WebRTC卡在连接状态

WebRTC卡在连接状态

人到中年有点甜 2022-09-02 16:06:20
我已经成功地传达了从A到B的WebRTC连接的报价,答案和冰候选人。此时,连接卡在状态。启动器(A)似乎在一段时间后超时或什么,并切换到状态,而它的远程(B)则永久停留在状态。"connecting""failed""connecting"任何帮助将不胜感激。创建对等节点(A 和 B):let peer = new RTCPeerConnection({    iceServers: [        {            urls: [                "stun:stun1.l.google.com:19302",                "stun:stun2.l.google.com:19302",            ],        },        {            urls: [                "stun:global.stun.twilio.com:3478?transport=udp",            ],        },    ],    iceCandidatePoolSize: 10,});创建报价 (A):peer.onnegotiationneeded = async () => {    offer = await peer.createOffer();    await peer.setLocalDescription(offer);};收集冰候选者(A):peer.onicecandidate = (evt) => {    if (evt.candidate) {        iceCandidates.push(evt.candidate);    } else {        // send offer and iceCandidates to B through signaling server        // this part is working perfectly    }};创建答案并填充候选冰 (B):await peer.setRemoteDescription(offer);let answer = await this._peer.createAnswer();await peer.setLocalDescription(answer);// send answer back to A through signaling serverfor (let candidate of sigData.iceCandidates) {    await peer.addIceCandidate(candidate);}从 B 到信令服务器 (A) 的应答:await peer.setRemoteDescription(answer);检测连接状态更改(A 和 B):peer.onconnectionstatechange = () => {    console.log("state changed")    console.log(peer.connectionState);}另请注意,有两次成功连接,但我还没有看到它再次工作。编辑:我忘了提到我也在创建一个数据通道(没有这个事件似乎不会调用)。这将在构造并附加任何事件处理程序后立即调用。onicecandidateRTCPeerConnectionlet channel = peer.createDataChannel("...", {    id: ...,    ordered: true,});编辑2:正如@jib建议的那样,我现在也在收集B中的冰候选者,并把他们送回A进行添加。但是,完全相同的问题仍然存在。编辑3:它似乎连接时,我第一次硬重新加载A的网页和B的网页.连接再次停止工作,直到我再做一次硬重新加载。有没有人知道为什么会这样?至少我应该能够暂时继续开发,直到我能弄清楚这个问题。编辑4:我删除了我正在使用的构造函数,并将构造函数留空。不知何故,它现在更可靠了。但是我还没有在iOS Safari上获得成功的连接!iceServersRTCPeerConnection
查看完整描述

2 回答

?
POPMUISE

TA贡献1765条经验 获得超5个赞

在两个浏览器窗口中打开它,然后点击其中一个窗口中的按钮。这是代码:Connect


const pc = new RTCPeerConnection();


call.onclick = async () => {

  const stream = await navigator.mediaDevices.getUserMedia({video:true,audio:true})

  video.srcObject = stream;

  for (const track of stream.getTracks()) {

    pc.addTrack(track, stream);

  }

};


pc.ontrack = ({streams}) => video.srcObject = streams[0];

pc.oniceconnectionstatechange = () => console.log(pc.iceConnectionState);

pc.onicecandidate = ({candidate}) => sc.send({candidate});

pc.onnegotiationneeded = async () => {

  await pc.setLocalDescription(await pc.createOffer());

  sc.send({sdp: pc.localDescription});

}


const sc = new localSocket(); // localStorage signaling hack

sc.onmessage = async ({data: {sdp, candidate}}) => {

  if (sdp) {

    await pc.setRemoteDescription(sdp);

    if (sdp.type == "offer") {

      await pc.setLocalDescription(await pc.createAnswer());

      sc.send({sdp: pc.localDescription});

    }

  } else if (candidate) await pc.addIceCandidate(candidate);

}

这是A和B的相同来源,用您喜欢的信令通道(例如websocket)替换黑客攻击。localSocket


不要缓存ICE候选者,因为这违背了涓流ICE的目的。它可能在本地看起来很快,但在实际网络中ICE可能需要时间。


事实上,如果您延迟发送报价/答案,直到收集了所有本地候选人,则发送候选人是没有意义的,因为候选人已经嵌入到提议/答案()中。pc.localDescription


查看完整回答
反对 回复 2022-09-02
?
幕布斯6054654

TA贡献1876条经验 获得超7个赞

最后!几周后,我已经弄清楚了这个问题,这个问题在我的问题中包含的代码中并不明显,但对于遇到类似问题的人来说,它可能仍然有用。

我以为在活动结束后,冰上收集正在完成,并且提供了报价/答案。onnegotiationneeded

由于这个不正确的假设,我在这个阶段与冰候选人一起发出报价/答案的信号,但是非常频繁地(根据我的经验,总是在iOS Safari中)此时尚未创建报价/答案。

我通过创建两个承诺来解决这个问题:a)完成冰候选收集,以及b)创建报价/答案。我使用了两个承诺,当它们都完成时,我通过信令服务器同时发送了冰候选者和提供/答案。Promise.all

这是可行的,但是当然在未来,我应该通过发送零碎的东西来“涓涓细流”这些信息,而不是等待一切完全完成。但是我将来会担心这一点,因为目前我正在使用HTTP请求,而且这太麻烦了。

编辑:我的连接仍然总是卡住,所以我创建了一个新问题。但是,如果没有本地连接,则现在100%完全可靠:)iceServersiceServers


查看完整回答
反对 回复 2022-09-02
  • 2 回答
  • 0 关注
  • 394 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号