简体   繁体   English

WebRTC 从不触发 IceCandidate

[英]WebRTC never fires onIceCandidate

I started developing with WebRTC, but that thing never gives me ICE candidates.我从 WebRTC 开始开发,但那个东西从来没有给我 ICE 候选人。 I set up everything, I'm exchanging the descriptions and stuff, I also made a super-ugly function narrow down there to make sure everything runs correctly, one after another.我设置了所有内容,我正在交换描述和内容,我还制作了一个超级丑陋的 function 以确保一切正常运行,一个接一个。 Signaling state is stable for both, onError is never fired (as expected), but onIceCandidate also (not as expected), and when I want to send a random, empty MediaStream object pc1.addStream(new webkitMediaStream());信号 state 对于两者都是稳定的,永远不会触发onError (如预期的那样),但 onIceCandidate 也会(如预期的那样),当我想发送随机的空 MediaStream object pc1.addStream(new webkitMediaStream()); , it always fires onNegotiationNeeded . , 它总是触发onNegotiationNeeded

Does anyone have an idea what the heck is wrong with my code?有谁知道我的代码到底出了什么问题? I spent hours of browsing Stack Overflow, HTML5 Rocks, and W3C docs, but I don't understand that.我花了几个小时浏览 Stack Overflow、HTML5 Rocks 和 W3C 文档,但我不明白。 Here is my entire code:这是我的整个代码:

var config={
  'iceServers':[{
    'url':'stun:stun.l.google.com:19302'
  },{
    'url':'stun:stun1.l.google.com:19302'
  },{
    'url':'stun:stun2.l.google.com:19302'
  },{
    'url':'stun:stun3.l.google.com:19302'
  },{
    'url':'stun:stun4.l.google.com:19302'
  }]
};
var pc1=new webkitRTCPeerConnection(config);
var pc2=new webkitRTCPeerConnection(config);

var onError=function(error)
{
  console.error(error);
}

pc1.onicecandidate=function()
{
  console.log('PC1 onIceCandidate (finally) fired!');
}
pc2.onicecandidate=function()
{
  console.log('PC2 onIceCandidate (finally) fired!');
}

pc1.oniceconnectionstatechange=function()
{
  console.log('PC1 oniceconnectionstatechange fired!');
}
pc2.oniceconnectionstatechange=function()
{
  console.log('PC2 oniceconnectionstatechange fired!');
}
pc1.onnegotiationneeded=function()
{
  console.log('PC1 onnegotiationneeded fired!');
}
pc2.onnegotiationneeded=function()
{
  console.log('PC2 onnegotiationneeded fired!');
}

pc1.createOffer(function(offer){
  pc1.setLocalDescription(offer,function(){
    pc2.setRemoteDescription(new RTCSessionDescription(offer),function(){
      pc2.createAnswer(function(answer){
        pc2.setLocalDescription(answer,function(){
          pc1.setRemoteDescription(new RTCSessionDescription(answer),new Function()/*I don't need you, bro*/,onError);
        },onError);
      },onError);
    },onError);
  },onError);
},onError);

BTW I'm developing with Google Chrome.顺便说一句,我正在使用 Google Chrome 进行开发。 I will make sure it also runs in Firefox, but right now the problem should be cross-browser.我会确保它也在 Firefox 中运行,但现在问题应该是跨浏览器的。 I want to make it to data channels before... (but I have nothing against a working solution with Firefox or cross-browser code)我想先进入数据通道...(但我不反对使用 Firefox 或跨浏览器代码的工作解决方案)

In Chrome 38 and earlier, OfferToReceiveAudio defaulted to true .在 Chrome 38 及更早版本中, OfferToReceiveAudio默认为true Starting from Chrome 39, OfferToReceiveAudio defaults to false, as announced by a WebRTC engineer at PSA: Behavior change to PeerConnection.createOffer constraint OfferToReceiveAudio (quoted below).从 Chrome 39 开始, OfferToReceiveAudio默认为 false,正如PSA的 WebRTC 工程师所宣布的那样:行为更改为 PeerConnection.createOffer 约束 OfferToReceiveAudio (引用如下)。
Because of this change, the SDP returned by createOffer does not contain any media, and therefore the ICE gathering process never starts.由于此更改, createOffer返回的 SDP 不包含任何媒体,因此 ICE 收集过程永远不会启动。 You can notice the consequences of this change by observing that the ICE events are never triggered, and the PeerConnection's iceGatheringState and iceConnectionState stay "new".您可以通过观察从未触发 ICE 事件并且 PeerConnection 的iceGatheringStateiceConnectionState保持“新”来注意到此更改的后果。

To make sure that the ICE gathering starts and complete, you have to add media to your offer, eg by setting OfferToReceiveAudio:true in the following constraints to your offer (either as a parameter of the PeerConnection constructor , or as a parameter to the peerConnection.createOffer method):为了确保 ICE 收集开始和完成,您必须向您的报价添加媒体,例如通过在您的报价的以下约束中设置OfferToReceiveAudio:true (作为PeerConnection构造函数的参数,或作为peerConnection.createOffer的参数) peerConnection.createOffer方法):

{
    mandatory: {
        OfferToReceiveAudio: true
    }
}

(other ways to get media in the SDP include setting OfferToReceiveVideo:true , or calling peerConnection.addStream with a media stream that you got from getUserMedia ) (在 SDP 中获取媒体的其他方法包括设置OfferToReceiveVideo:true ,或使用从getUserMedia获得的媒体流调用peerConnection.addStream


webrtc-discuss: PSA: Behavior change to PeerConnection.createOffer constraint OfferToReceiveAudio : webrtc-discuss: PSA: PeerConnection.createOffer 约束的行为改变 OfferToReceiveAudio :

I'm going to submit a change ( https://webrtc-codereview.appspot.com/16309004/ ) to change the behavior of RTCPeerConnection.createOffer.我将提交更改( https://webrtc-codereview.appspot.com/16309004/ )以更改 RTCPeerConnection.createOffer 的行为。 The change is expected to be included in Chrome M39.该更改预计将包含在 Chrome M39 中。

What's changed:改变了什么:

Currently if the OfferToReceiveAudio constraint is not specified in PeerConnection.createOffer, the resulted offer SDP will have an "m=audio" line even if there is no audio track attached to the PeerConnection.目前,如果在 PeerConnection.createOffer 中未指定 OfferToReceiveAudio 约束,则即使没有附加到 PeerConnection 的音频轨道,生成的商品 SDP 也将具有“m=audio”行。 In other words, OfferToReceiveAudio defaults to true.换句话说,OfferToReceiveAudio 默认为 true。

After my change, OfferToReceiveAudio no longer defaults to true.在我更改之后,OfferToReceiveAudio 不再默认为 true。 Whether the offer SDP has an "m=audio" line depends on if any audio track has been attached to the PeerConnection.报价 SDP 是否有“m=audio”线取决于是否有任何音轨附加到 PeerConnection。

What's not changed:什么没有改变:

The behavior of setting an explicit value for OfferToReceiveAudio remains the same, ie OfferToReceiveAudio:true will result in an "m=audio" line regardless of the existence of audio tracks;为 OfferToReceiveAudio 设置显式值的行为保持不变,即 OfferToReceiveAudio:true 将导致“m=audio”行,无论音轨是否存在; OfferToReceiveAudio:false will result in no "m=audio" line regardless of the existence of audio tracks, unless setLocalDescription has been called with an SDP containing an "m=audio" line, in which case the new offer SDP will mark the audio content inactive instead of removing the audio content. OfferToReceiveAudio:false 将导致没有“m=audio”行,无论是否存在音轨,除非使用包含“m=audio”行的 SDP 调用 setLocalDescription,在这种情况下,新的 offer SDP 将标记音频内容不活动而不是删除音频内容。

The above solution of Rob W from Jan 3 '15 worked for me at first but led to another problem. Rob W 于 2015 年 1 月 3 日的上述解决方案起初对我有用,但导致了另一个问题。
I included {'offerToReceiveAudio':true,'offerToReceiveVideo':true} in the createOffer and createAnswer calls and onIceCandidate was called as described.我在createOffercreateAnswer调用中包含了{'offerToReceiveAudio':true,'offerToReceiveVideo':true} ,并且按照描述调用了onIceCandidate
However, if I got it right, offerToReceive... means to only receive but not to send a stream.但是,如果我offerToReceive...对了, offerToReceive...意味着接收而不发送流。 I figured that out because of the a=recvonly in the sdp offer and the a=sendonly in the sdp answer.我想通了这一点,因为的a=recvonly的SDP提供和a=sendonly SDP应答。 As a result, only the caller could see the callees video but not vice versa.结果,只有呼叫者可以看到被呼叫者的视频,反之亦然。

As Rob states correctly:正如 Rob 正确指出的那样:

other ways to get media in the SDP include [...] calling peerConnection.addStream with a media stream that you got from getUserMedia在 SDP 中获取媒体的其他方法包括 [...] 使用从 getUserMedia 获得的媒体流调用 peerConnection.addStream

Adding the stream was what I had done already in the first place.添加流是我首先已经完成的。 However, my sending of the sdp happened before that adding because my logical flow was mixed up.但是,我的 sdp 发送发生在添加之前,因为我的逻辑流程混淆了。 Bringing that into the right order ( addStream -> sdp = getLocalDescription -> send(sdp) ) and removing the offerOptions did the trick for me.将其放入正确的顺序( addStream -> sdp = getLocalDescription -> send(sdp) )并删除 offerOptions 对我来说很有效。
Hope this helps anyone.希望这可以帮助任何人。

Solution in 2020 2020年解决方案

You have to do 2 things:你必须做两件事:

  • include offerToReceiveAudio and offerToReceiveVideo when create RTCPeerConnection包括offerToReceiveAudioofferToReceiveVideo创建时RTCPeerConnection
  • add addTrack添加添加addTrack

Sample code:示例代码:

const peerConnection= new RTCPeerConnection({
  configuration: {
    offerToReceiveAudio: true,
    offerToReceiveVideo: true
  },
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
})

localStream.getTracks().forEach(track => {
  peerConnection.addTrack(track, localStream)
})

const offer = await peerConnection.createOffer()
await peerConnection.setLocalDescription(offer)

peerConnection.onicecandidate = event => {
  if (event.candidate) {
    console.log('Ice candidate: ', event.candidate)

  }
}

... other codes

I found a solution.我找到了解决方案。 If you add this code after the config declaration:如果在配置声明之后添加此代码:

var mediaConstraints = {
  optional: [],
  mandatory: {
    OfferToReceiveAudio: true,
    OfferToReceiveVideo: true
  }
};

and modify the last line like this并像这样修改最后一行

},onError,mediaConstraints);

it just works.它只是有效。 Don't ask me why.不要问我为什么。

The doc page should be used as the reference: https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer文档页面应用作参考: https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer

const offerOptions = {
    offerToReceiveAudio: true,
    offerToReceiveVideo: true
}

myPeerConnection.createOffer ( offerOptions )

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

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