简体   繁体   English

为什么 WebRTC 只有在第二次报价后才建立连接?

[英]Why does WebRTC set up a connection only after second offer?

I want to set up a WebRTC datachannel and send some text.我想设置一个 WebRTC 数据通道并发送一些文本。 Therefore I create a RTCPeerConnection object with an "onicecandidate" and "ondatachannel" handler.因此,我创建了一个带有“oniceccandidate”和“ondatachannel”处理程序的 RTCPeerConnection object。 (I keep "configuration" for RTCPeerConnection empty because connection is between localhost only.) (我将 RTCPeerConnection 的“配置”保留为空,因为连接仅在本地主机之间。)

var configuration = {}; 
myConnection = new RTCPeerConnection(configuration);
  
myConnection.onicecandidate = function (event) {
    if (event.candidate) { 
        send({ 
            type: "candidate", 
            candidate: event.candidate 
        }); 
    } 
};

myConnection.ondatachannel = function (event) {
    dataChannel = event.channel;
    dataChannel.onerror = function (error) { 
        console.log("Error:", error); 
    };
                
    dataChannel.onmessage = function (event) { 
        console.log("RTC message:", event.data); 
    };  
};

Then I'm sending an offer from A to B.然后我从 A 向 B 发送报价。

offer = await myConnection.createOffer();
await myConnection.setLocalDescription(offer);
send({type: "offer", offer: offer});

Receiver B then sends an answer.接收器 B 然后发送一个答案。

async function onOffer(offer, name) { 
    myConnection.setRemoteDescription(new RTCSessionDescription(offer));

    answer = await myConnection.createAnswer();
    await myConnection.setLocalDescription(answer);
    send({type: "answer", answer: answer});
}

Which A sets as remote description and opens up the datachannel.其中A设置为远程描述并打开数据通道。

function onAnswer(answer) { 
    myConnection.setRemoteDescription(new RTCSessionDescription(answer));
    openDataChannel();
}

function openDataChannel() { 
    var dataChannelOptions = { 
        reliable:true 
    }; 
    
    dataChannel = myConnection.createDataChannel("myDataChannel", dataChannelOptions);
        
    dataChannel.onerror = function (error) { 
        console.log("Error:", error); 
    };
        
    dataChannel.onmessage = function (event) { 
        console.log("RTC message:", event.data); 
    };  
}

There is also a function which handles the received candidates on both sides.还有一个 function 处理双方收到的候选人。

function onCandidate(candidate) { 
    myConnection.addIceCandidate(new RTCIceCandidate(candidate));
}

After A sends the first offer, it receives an answer but the "iceGatheringState" and "iceConnectionState" of the RTCPeerConnection stays "new". A 发送第一个 offer 后,它收到了一个答复,但 RTCPeerConnection 的“iceGatheringState”和“iceConnectionState”保持“new”。 No "onicecandidate" events are triggered.不会触发“onicecandidate”事件。 After A calls createOffer() again, the offer looks "bigger" (contains more values).在 A 再次调用 createOffer() 之后,报价看起来“更大”(包含更多值)。 After setting the second offer to local description "onicecandicate" events are fired on both sides.将第二个提议设置为本地描述后,双方都会触发“onicecandicate”事件。 But the datachannel only establishes after A sends the second offer to B.但数据通道只有在 A 向 B 发送第二个 offer 后才建立。

I know this is the same question but the answer doesn't seem to fit because I have an "onicecandidate" handler.我知道是同一个问题,但答案似乎不合适,因为我有一个“oniceccandidate”处理程序。 I also read about trickle ice but still don't know what the issue is.我也读到了涓流冰,但仍然不知道问题是什么。

You must call myConnection.createDataChannel at least once before negotiating, to have the connection negotiate the use of datachannels.在协商之前,您必须至少调用一次myConnection.createDataChannel ,以使连接协商数据通道的使用。 They're not included by default.默认情况下不包括它们。

There's no media and no datachannel before then, nothing to negotiate.在那之前没有媒体,也没有数据通道,没有什么可协商的。 This makes your first negotiation redundant, a no-op, which is why the state never leave "new" .这使您的第一次协商变得多余,无操作,这就是 state 永远不会离开"new"的原因。

Once you've done this, there's no need to do it again, as all subsequent datachannels are multiplexed over the same sctp transport.完成此操作后,无需再次执行此操作,因为所有后续数据通道都通过同一个 sctp 传输多路复用。

To have negotiation only happen when needed, consider setting up:要仅在需要时进行协商,请考虑设置:

pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    send({type: "offer", offer: pc.localDescription});
  } catch (e) {
    console.error(e);
  }
};

Then negotiation will be triggered automatically when you call pc.createDataChannel the first time (but not the subsequent times).然后,当您第一次调用pc.createDataChannel时(但不是随后的时间),将自动触发协商。

But beware of glare if you do this on both ends, or use the perfect negotiation pattern.但是,如果您在两端都这样做,或者使用完美的谈判模式,请注意眩光。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM