猿问

WebRTC卡在连接状态

我已经成功地传达了从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 server


for (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);

}

另请注意,有两次成功连接,但我还没有看到它再次工作。


编辑:我忘了提到我也在创建一个数据通道(没有这个事件似乎不会调用)。这将在构造并附加任何事件处理程序后立即调用。onicecandidateRTCPeerConnection


let channel = peer.createDataChannel("...", {

    id: ...,

    ordered: true,

});

编辑2:正如@jib建议的那样,我现在也在收集B中的冰候选者,并把他们送回A进行添加。但是,完全相同的问题仍然存在。


编辑3:它似乎连接时,我第一次硬重新加载A的网页和B的网页.连接再次停止工作,直到我再做一次硬重新加载。有没有人知道为什么会这样?至少我应该能够暂时继续开发,直到我能弄清楚这个问题。


编辑4:我删除了我正在使用的构造函数,并将构造函数留空。不知何故,它现在更可靠了。但是我还没有在iOS Safari上获得成功的连接!iceServersRTCPeerConnection


人到中年有点甜
浏览 397回答 2
2回答

POPMUISE

在两个浏览器窗口中打开它,然后点击其中一个窗口中的按钮。这是代码:Connectconst 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 hacksc.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

幕布斯6054654

最后!几周后,我已经弄清楚了这个问题,这个问题在我的问题中包含的代码中并不明显,但对于遇到类似问题的人来说,它可能仍然有用。我以为在活动结束后,冰上收集正在完成,并且提供了报价/答案。onnegotiationneeded由于这个不正确的假设,我在这个阶段与冰候选人一起发出报价/答案的信号,但是非常频繁地(根据我的经验,总是在iOS Safari中)此时尚未创建报价/答案。我通过创建两个承诺来解决这个问题:a)完成冰候选收集,以及b)创建报价/答案。我使用了两个承诺,当它们都完成时,我通过信令服务器同时发送了冰候选者和提供/答案。Promise.all这是可行的,但是当然在未来,我应该通过发送零碎的东西来“涓涓细流”这些信息,而不是等待一切完全完成。但是我将来会担心这一点,因为目前我正在使用HTTP请求,而且这太麻烦了。编辑:我的连接仍然总是卡住,所以我创建了一个新问题。但是,如果没有本地连接,则现在100%完全可靠:)iceServersiceServers
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答