【问题标题】:Not able to add remote ice candidate in webrtc无法在 webrtc 中添加远程冰候选
【发布时间】:2014-04-27 15:54:00
【问题描述】:

我正在尝试建立 p2p 音频/视频连接 b/w 2 对等方。对等点 P1 向对等点 P2 发送要约。拿到offer后,P2会-

{
    pc = new RTCPeerConnection(ice);
    pc.setRemoteDescription(new RTCSessionDescription(msg.offer),
            onSetRemoteDescriptionSuccess, onSetSessionDescriptionError);                    

    function onSetRemoteDescriptionSuccess() {
        console.log('onSetRemoteDescriptionSuccess called');                                 
    }                                                                                        

    function onSetSessionDescriptionError() {
        console.log('onSetSessionDescriptionError called');                                  
    }                                                                                        

    pc.onicecandidate = function(evt) {                                                      
        if (evt.candidate) {
            console.log('got local icecandidate', evt.candidate);                            
            send_ice_candicate(evt.candidate.sdpMLineIndex,                                  
                      evt.candidate.sdpMid,
                      evt.candidate.candidate                                                
                      );                                                                     
        }                                                                                    
    }                                                                                        

    pc.onaddstream = function (evt) {
        var remote_video = document.getElementById('remote_video');                          
        remote_video.src = window.URL.createObjectURL(evt.stream);                           
    }                                                                                        

    navigator.getUserMedia({ "audio": true, "video": true },                                 
            gotStream, logError);
} 

function gotStream(stream) {                                                                     
    pc.addStream(stream);                                                                        

    var local_video = document.getElementById('local_video');                                    
    local_video.src = window.URL.createObjectURL(stream);                                        

    pc.createAnswer(function(answer) {
        pc.setLocalDescription(answer);
        console.log('creating answer', answer.sdp)                                           
        signalingChannel.send(answer.sdp);                                                 
        });
    got_ice_candidate(remote_ice_candidate);                                                     
}                                     

remote_ice_candidate 是在 offer 之前收到的,因此被缓冲了,我试图在答案准备好并且其他先决条件完成后添加。

但我在尝试添加远程候选冰时仍然遇到错误。

P2 上的对等连接对象看起来像-

RTCPeerConnection {ondatachannel: null, oniceconnectionstatechange: null, onremovestream: null, onaddstream: function, onsignalingstatechange: null…}
iceConnectionState: "new"
iceGatheringState: "gathering"
localDescription: RTCSessionDescription
sdp: "v=0
↵o=- 5043546633484176483 2 IN IP4 127.0.0.1
↵s=-
↵t=0 0
↵a=group:BUNDLE audio video
↵a=msid-semantic: WMS irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk
↵m=audio 10990 RTP/SAVPF 111 103 104 0 8 106 105 13 126
↵c=IN IP4 122.171.69.180
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=candidate:3022624816 1 udp 2122260223 192.168.1.4 50063 typ host generation 0
↵a=candidate:4205470912 1 tcp 1518280447 192.168.1.4 0 typ host generation 0
↵a=candidate:494278629 1 udp 1686052607 122.171.69.180 10990 typ srflx raddr 192.168.1.4 rport 50063 generation 0
↵a=ice-ufrag:1ZCyumc5I0T8mbFJ
↵a=ice-pwd:+JUisFsiKa8ezPXDIuzu99tv
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:active
↵a=mid:audio
↵a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
↵a=sendrecv
↵a=rtcp-mux
↵a=rtpmap:111 opus/48000/2
↵a=fmtp:111 minptime=10
↵a=rtpmap:103 ISAC/16000
↵a=rtpmap:104 ISAC/32000
↵a=rtpmap:0 PCMU/8000
↵a=rtpmap:8 PCMA/8000
↵a=rtpmap:106 CN/32000
↵a=rtpmap:105 CN/16000
↵a=rtpmap:13 CN/8000
↵a=rtpmap:126 telephone-event/8000
↵a=maxptime:60
↵a=ssrc:2173896727 cname:PZV2reyyZuw6KufJ
↵a=ssrc:2173896727 msid:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk fb1b496d-ffa9-43cd-940a-7c68df86d3b3
↵a=ssrc:2173896727 mslabel:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk
↵a=ssrc:2173896727 label:fb1b496d-ffa9-43cd-940a-7c68df86d3b3
↵m=video 10990 RTP/SAVPF 100 116 117
↵c=IN IP4 122.171.69.180
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=candidate:3022624816 1 udp 2122260223 192.168.1.4 50063 typ host generation 0
↵a=candidate:4205470912 1 tcp 1518280447 192.168.1.4 0 typ host generation 0
↵a=candidate:494278629 1 udp 1686052607 122.171.69.180 10990 typ srflx raddr 192.168.1.4 rport 50063 generation 0
↵a=ice-ufrag:1ZCyumc5I0T8mbFJ
↵a=ice-pwd:+JUisFsiKa8ezPXDIuzu99tv
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:active
↵a=mid:video
↵a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
↵a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
↵a=sendrecv
↵a=rtcp-mux
↵a=rtpmap:100 VP8/90000
↵a=rtcp-fb:100 ccm fir
↵a=rtcp-fb:100 nack
↵a=rtcp-fb:100 nack pli
↵a=rtcp-fb:100 goog-remb
↵a=rtpmap:116 red/90000
↵a=rtpmap:117 ulpfec/90000
↵a=ssrc:2118221653 cname:PZV2reyyZuw6KufJ
↵a=ssrc:2118221653 msid:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk a735b317-1752-40fa-96df-511c0febb55e
↵a=ssrc:2118221653 mslabel:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk
↵a=ssrc:2118221653 label:a735b317-1752-40fa-96df-511c0febb55e
↵"
type: "answer"
__proto__: RTCSessionDescription
onaddstream: function (evt) {
arguments: null
caller: null
length: 1
name: ""
prototype: Object
__proto__: function Empty() {}
<function scope>
ondatachannel: null
onicecandidate: function (evt) {
oniceconnectionstatechange: null
onnegotiationneeded: null
onremovestream: null
onsignalingstatechange: null
remoteDescription: RTCSessionDescription
sdp: "v=0
↵o=- 8847796014807563532 2 IN IP4 127.0.0.1
↵s=-
↵t=0 0
↵a=group:BUNDLE audio video
↵a=msid-semantic: WMS na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK
↵m=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126
↵c=IN IP4 0.0.0.0
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=ice-ufrag:mfL29tarMKRBN9F/
↵a=ice-pwd:/my1DZo1Yjne4BrcQGKN1o3I
↵a=ice-options:google-ice
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:actpass
↵a=mid:audio
↵a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
↵a=sendrecv
↵a=rtcp-mux
↵a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:ggGTdSmkygu0aVidv2M6kO25w5DX/OknOXFnRBYK
↵a=rtpmap:111 opus/48000/2
↵a=fmtp:111 minptime=10
↵a=rtpmap:103 ISAC/16000
↵a=rtpmap:104 ISAC/32000
↵a=rtpmap:0 PCMU/8000
↵a=rtpmap:8 PCMA/8000
↵a=rtpmap:106 CN/32000
↵a=rtpmap:105 CN/16000
↵a=rtpmap:13 CN/8000
↵a=rtpmap:126 telephone-event/8000
↵a=maxptime:60
↵a=ssrc:702054304 cname:++QJWJ3eyXhSOSgH
↵a=ssrc:702054304 msid:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK 054d6450-034f-48ca-85dc-3a843c7f7554
↵a=ssrc:702054304 mslabel:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK
↵a=ssrc:702054304 label:054d6450-034f-48ca-85dc-3a843c7f7554
↵m=video 1 RTP/SAVPF 100 116 117
↵c=IN IP4 0.0.0.0
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=ice-ufrag:mfL29tarMKRBN9F/
↵a=ice-pwd:/my1DZo1Yjne4BrcQGKN1o3I
↵a=ice-options:google-ice
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:actpass
↵a=mid:video
↵a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
↵a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
↵a=sendrecv
↵a=rtcp-mux
↵a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:ggGTdSmkygu0aVidv2M6kO25w5DX/OknOXFnRBYK
↵a=rtpmap:100 VP8/90000
↵a=rtcp-fb:100 ccm fir
↵a=rtcp-fb:100 nack
↵a=rtcp-fb:100 nack pli
↵a=rtcp-fb:100 goog-remb
↵a=rtpmap:116 red/90000
↵a=rtpmap:117 ulpfec/90000
↵a=ssrc:846853801 cname:++QJWJ3eyXhSOSgH
↵a=ssrc:846853801 msid:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK c0dde33c-f422-4774-9f7b-65cec136e107
↵a=ssrc:846853801 mslabel:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK
↵a=ssrc:846853801 label:c0dde33c-f422-4774-9f7b-65cec136e107
↵"
type: "offer"
__proto__: RTCSessionDescription
signalingState: "stable"
__proto__: RTCPeerConnection    

我得到的错误是

Failed to add Ice Candidate: Error processing ICE candidate      

【问题讨论】:

  • 能否包含您用于添加 Ice Candidate 的代码?它是您要添加的候选人数组吗?您能否将您尝试添加为候选对象的对象的打印输出包括在内?这是在 Chrome 还是 Firefox 中?
  • 在我的情况下,错误是相同的,但是由于“无法设置远程报价 sdp:在错误状态下调用:STATE_SENTOFFER”而发生此错误。问题出在我的代码中,报价是从双方创建的。

标签: javascript web webrtc


【解决方案1】:

我不知道你从哪里获得 remote_ice_candidate 对象。但是要正确处理冰消息,您应该有这样的东西:

首先: 在 ice 候选事件中,您应该将其发送给其他对等方。例如:

pc.onicecandidate = function (event) {
    if (!event || !event.candidate) return;
    socket.emit("iceCandidate", event.candidate); //send ice candidate through your signaling server to other peer
};

然后: 我们还应该监听来自信令服务器的“iceCandidate”消息,并将 ice 候选添加到 RTCPeerConnection,例如:

socket.on("iceCandidate", function(iceCandidate){
  pc.addIceCandidate(new RTCIceCandidate(iceCandidate));
});

仅此而已。 根据我的观察,交换冰消息是在提供/回答通信之后开始的,所以在那之前你不应该准备好冰候选对象。 当然,此代码仅适用于 chrome。

【讨论】:

  • liosedhel 是正确的,ICE 消息应该出现在 Offer-Answer 交换之后。此外,候选人不需要参加 SDP,您的时间最好花在实施涓涓冰上。
  • ICE 候选人在设置本地描述 setLocalDescription() 后开始聚集,这可能与 Offer-Answer 交换无关。甚至在收到答案之前就会生成候选人
  • @UnahD 那么该怎么办,如果候选人开始生成,即使你还没有设置 remotesdp,我是不是明白了 remotesdp 应该在 addIceCandidate() 调用之前设置
  • @MuhammadUmer 是(远程描述应该在 addIceCandidate() 调用之前设置)。这种同步必须在客户端完成
  • 我明白了,那么在设置 remoteDescription 之前不发送或添加 ICE 候选人的好策略是什么。我想到的一种方法是创建offer,不设置localDescription,等待答案,当得到答案时将本地和远程描述结合在一起。
【解决方案2】:

这是对 cme​​ts 的回复,询问如何确保仅在设置远程描述后才添加候选冰:

let candidates = [];
let remoteDescriptionSet = false;

function wsMessage(ev) {
  if (!ev || !ev.data) return;
  const json = JSON.parse(ev.data);
  if (!json) return;
  if (json.type === 'answer') {
    pc.setRemoteDescription(json)
    .then(() => {
      remoteDescriptionSet = true;
      console.log('remote description set');
      return Promise.all(candidates.map(c => pc.addIceCandidate(c)));
    })
    .then(() => {
      console.log('all stored candidates added');
      candidates.length = 0;
    })
    .catch(err => console.error(err));
  }
  else if (json.type === 'ice') {
    if (remoteDescriptionSet) {
      pc.addIceCandidate(json.ice)
      .then(() => console.log(`adding remote ice candidate: ${json.ice.candidate}`))
      .catch(err => console.error(err));
    }
    else {
      candidates.push(json.ice);
      console.log(`storing remote ice candidate: ${json.ice.candidate}`);
    }
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多