【问题标题】:WebRTC never fires onIceCandidateWebRTC 从不触发 onIceCandidate
【发布时间】:2014-12-15 17:42:14
【问题描述】:

我开始使用 WebRTC 进行开发,但那东西从来没有给我 ICE 候选人。我设置了所有东西,我正在交换描述和东西,我还在那里缩小了一个超级丑陋的功能,以确保一切都正常运行,一个接一个。两者的信号状态都是稳定的,onError 永远不会被触发(如预期的那样),但 onIceCandidate 也会(不是预期的那样),当我想发送一个随机的空 MediaStream 对象pc1.addStream(new webkitMediaStream()); 时,它总是触发onNegotiationNeeded

有人知道我的代码到底有什么问题吗?我花了几个小时浏览 Stack Overflow、HTML5 Rocks 和 W3C 文档,但我不明白。这是我的完整代码:

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

顺便说一句,我正在使用 Google Chrome 进行开发。我会确保它也在 Firefox 中运行,但现在问题应该是跨浏览器。我想在此之前进入数据通道......(但我没有反对使用 Firefox 或跨浏览器代码的工作解决方案)

【问题讨论】:

  • OT;现在,当我看到这段代码时,我知道他们为什么发明了 JS 承诺……
  • 您可能想要post an actual answer(然后回滚您的编辑),而不是编辑您的问题的更新
  • 好的,谢谢,我不知道有可能……我这里有点新,通常我只看这个网站
  • 请注意,回调现在被视为遗留。 RTCPeerConnection supports promises 在所有浏览器中。
  • 我现在也会考虑大部分问题本身。不敢相信我写了这个。

标签: javascript webrtc


【解决方案1】:

在 Chrome 38 及更早版本中,OfferToReceiveAudio 默认为 true。从 Chrome 39 开始,OfferToReceiveAudio 默认为 false,正如 WebRTC 工程师在PSA: Behavior change to PeerConnection.createOffer constraint OfferToReceiveAudio 宣布的那样(引用如下)。
由于这种变化,createOffer 返回的 SDP 不包含任何媒体,因此 ICE 收集过程永远不会开始。通过观察从未触发过 ICE 事件,并且 PeerConnection 的 iceGatheringStateiceConnectionState 保持“新”状态,您可以注意到此更改的后果。

为确保 ICE 聚会开始并完成,您必须在报价中添加媒体,例如通过在以下约束中设置 OfferToReceiveAudio:true 您的报价(作为 PeerConnection constructor 的参数,或作为 peerConnection.createOffer 方法的参数):

{
    mandatory: {
        OfferToReceiveAudio: true
    }
}

(在 SDP 中获取媒体的其他方法包括设置 OfferToReceiveVideo:true,或使用从 getUserMedia 获得的媒体流调用 peerConnection.addStream


webrtc-讨论:PSA: Behavior change to PeerConnection.createOffer constraint OfferToReceiveAudio:

我将提交更改 (https://webrtc-codereview.appspot.com/16309004/) 以更改 RTCPeerConnection.createOffer 的行为。 预计该更改将包含在 Chrome M39 中。

发生了什么变化:

目前,如果没有在 PeerConnection.createOffer 中指定 OfferToReceiveAudio 约束,即使没有附加到 PeerConnection 的音轨,生成的报价 SDP 也会有一个“m=audio”行。换句话说,OfferToReceiveAudio 默认为 true。

更改后,OfferToReceiveAudio 不再默认为 true。报价 SDP 是否具有“m=audio”行取决于是否已将任何音轨附加到 PeerConnection。

没有改变的地方:

为 OfferToReceiveAudio 设置显式值的行为保持不变,即,无论是否存在音轨,OfferToReceiveAudio:true 都会导致“m=audio”行;无论是否存在音轨,OfferToReceiveAudio:false 都将导致没有“m=audio”行,除非已使用包含“m=audio”行的 SDP 调用了 setLocalDescription,在这种情况下,新的 offer SDP 将标记音频内容不活动而不是删除音频内容。

【讨论】:

  • 这似乎不再适用于 PeerConnection 构造函数,但适用于 peerConnection.createOffer 方法。 (铬 44)
  • 请注意,这个答案是outdated。正确的语法是{offerToReceiveAudio: true}(没有mandatory,小写o)。
  • 来自未来的你好……这非常有帮助,谢谢。我想提一下,offerToReceiveAudio 现在是旧版,据此:developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/… 我还没有找到另一种解决方法,但这让我的冰候选生成(我在做视频而不是音频)。
  • 花了 3 个小时试图找出为什么 onicecandidateerror oniceconnectionstatechange onicegatheringstatechange onicecandidate 没有被调用。我还看到它被标记为旧版,但这是让它在 Chrome 中工作的唯一方法。
  • 这个答案救了我的命
【解决方案2】:

2015 年 1 月 3 日 Rob W 的 above 解决方案起初对我有用,但导致了另一个问题。
我在createOffercreateAnswer 调用中加入了{'offerToReceiveAudio':true,'offerToReceiveVideo':true},并按照描述调用了onIceCandidate
但是,如果我没记错的话,offerToReceive... 表示 接收但不发送流。我发现这是因为 sdp 报价中的 a=recvonly 和 sdp 答案中的 a=sendonly 。因此,只有呼叫者可以看到被呼叫者的视频,反之则不行。

正如 Rob 所说的那样:

在 SDP 中获取媒体的其他方法包括 [...] 调用 peerConnection.addStream 并使用 您从 getUserMedia 获得的媒体流

添加流是我一开始就已经完成的事情。但是,我的 sdp 发送发生在添加之前,因为我的逻辑流程混淆了。将其放入正确的顺序 (addStream -> sdp = getLocalDescription -> send(sdp)) 并删除 offerOptions 对我来说是诀窍。
希望这对任何人都有帮助。

【讨论】:

    【解决方案3】:

    2020 年解决方案

    你必须做两件事:

    • 在创建RTCPeerConnection时包含offerToReceiveAudioofferToReceiveVideo
    • 添加addTrack

    示例代码:

    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
    

    【讨论】:

    • 这在 2021 年对我不起作用!我需要将配置显式添加到 createAnswer 方法(const answerDescription = await pc.createAnswer({offerToReceiveAudio: true, offerToReceiveVideo: true});)
    【解决方案4】:

    我找到了解决方案。如果在配置声明后添加此代码:

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

    并像这样修改最后一行

    },onError,mediaConstraints);
    

    它只是工作。不要问我为什么。

    【讨论】:

    • 魔术代码没有帮助,而且是糟糕的做法。总是问为什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    相关资源
    最近更新 更多