Javascript WebRTC onicecandidate:我得到的ICE候选人sdpMid=仅音频,不用于视频

Javascript WebRTC onicecandidate:我得到的ICE候选人sdpMid=仅音频,不用于视频,javascript,webrtc,Javascript,Webrtc,使用的浏览器是Chrome。。。我有调用方和接收方代码来生成SDP和ICE候选。 我获取调用方代码,以生成正确的SDP和ICE候选,sdpMid=video,但对于接收器,我仅为sdpMid=audio生成ICE候选 更新:以下是更改后接收方的localSessionDescription SDP,建议如下: v=0 o=- 7912682607537349212 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE audio video a=ms

使用的浏览器是Chrome。。。我有调用方和接收方代码来生成SDP和ICE候选。 我获取调用方代码,以生成正确的SDP和ICE候选,sdpMid=video,但对于接收器,我仅为sdpMid=audio生成ICE候选

更新以下是更改后接收方的localSessionDescription SDP,建议如下:

 v=0
 o=- 7912682607537349212 2 IN IP4 127.0.0.1
 s=-
 t=0 0
 a=group:BUNDLE audio video
 a=msid-semantic: WMS 9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
 m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126
 c=IN IP4 0.0.0.0
 a=rtcp:9 IN IP4 0.0.0.0
 a=ice-ufrag:0D1hLEwxnqReQosQ
 a=ice-pwd:Nsc4EAtefrfgzTetHjJA5lsg
 a=fingerprint:sha-256 6C:85:D8:33:D8:C6:CB:CE:D4:8E:B4:7A:C2:F5:2F:D0:67:04:25:B2:74:F9:C6:3A:2E:96:E6:56:E7:27:B0:F8
 a=setup:active
 a=mid:audio
 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
 a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
 a=sendrecv
 a=rtcp-mux
 a=rtpmap:111 opus/48000/2
 a=fmtp:111 minptime=10; useinbandfec=1
 a=rtpmap:103 ISAC/16000
 a=rtpmap:104 ISAC/32000
 a=rtpmap:9 G722/8000
 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:2958641119 cname:Iu8s16HLxglPDg9k
 a=ssrc:2958641119 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd bb63739b-cca2-4aa5-90a6-cf4bbaa199af
 a=ssrc:2958641119 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
 a=ssrc:2958641119 label:bb63739b-cca2-4aa5-90a6-cf4bbaa199af
 m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96
 c=IN IP4 0.0.0.0
 a=rtcp:9 IN IP4 0.0.0.0
 a=ice-ufrag:0D1hLEwxnqReQosQ
 a=ice-pwd:Nsc4EAtefrfgzTetHjJA5lsg
 a=fingerprint:sha-256 6C:85:D8:33:D8:C6:CB:CE:D4:8E:B4:7A:C2:F5:2F:D0:67:04:25:B2:74:F9:C6:3A:2E:96:E6:56:E7:27:B0:F8
 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=extmap:4 urn:3gpp:video-orientation
 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=rtcp-fb:100 transport-cc
 a=rtpmap:101 VP9/90000
 a=rtcp-fb:101 ccm fir
 a=rtcp-fb:101 nack
 a=rtcp-fb:101 nack pli
 a=rtcp-fb:101 goog-remb
 a=rtcp-fb:101 transport-cc
 a=rtpmap:116 red/90000
 a=rtpmap:117 ulpfec/90000
 a=rtpmap:96 rtx/90000
 a=fmtp:96 apt=100
 a=ssrc-group:FID 3143004909 4248148453
 a=ssrc:3143004909 cname:Iu8s16HLxglPDg9k
 a=ssrc:3143004909 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd 778ef702-e7fc-47ea-bb3a-477e0b4262ba
 a=ssrc:3143004909 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
 a=ssrc:3143004909 label:778ef702-e7fc-47ea-bb3a-477e0b4262ba
 a=ssrc:4248148453 cname:Iu8s16HLxglPDg9k
 a=ssrc:4248148453 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd 778ef702-e7fc-47ea-bb3a-477e0b4262ba
 a=ssrc:4248148453 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
 a=ssrc:4248148453 label:778ef702-e7fc-47ea-bb3a-477e0b4262ba
这是为相应的getUserMedia生成的,如中所示:

 navigator.getUserMedia({ audio: true, video: { width: 1280, height: 720 } },...
ICE候选生成代码为:

pc.onicecandidate = function (event) {
   console.log("Generated Icecandidate:" );
   console.log(event);
   ...
 };
在console.log上,我看到了ICE候选项,如下所示:

RTCIceCandidate
candidate: "candidate:211156821 1 udp 2122260223 192.168.1.5 41811 typ host generation 0 ufrag kV5Snl0LQhJlYujt"
sdpMLineIndex:0
sdpMid:"audio"
不用说,我无法显示远程视频。我在一个本地网络上尝试这个,所以实际上甚至不需要晕眩

我想知道,为什么我没有得到sdpMid=video的ICE候选人。另外,在生成的四个ICE候选者中,三个ICE候选者的sdpMLineIndex为0,一个ICE候选者的候选者属性为null

更新1:我得到了上一期的答案。。。候选属性为Null。“注意:RTCPeerConnection.onicecandidate将使用空的候选属性调用一次,以发出涓流冰事件结束的信号。”对此进行了解释

在主叫方,我得到了10多位ICE候选人,有些有音频,有些有视频

我哪里做错了

更新2: 以下是不生成视频ICE候选的接收器部分的代码。我剥离了身份验证和其他部分,只关注相关部分。我删除了ICE候选者的缓存,并按原样发送:

$(document).ready(function () {

  var socket = io.connect();
  var pc = new RTCPeerConnection ({
    "iceServers": [{"url": "stun:stun.l.google.com:19302"}]
  });

  pc.onicecandidate = function (event) {
    socket.emit('candidateFromReceiver',event.candidate);
    console.log("Candidate Generated:");
    console.log(event.candidate);
  }; 

  pc.onaddstream = function(ev) {
    stream = ev.stream;        
    var video = $('#vid2'); 
    video.attr('src', URL.createObjectURL(stream));
    video.onloadedmetadata = function(e) {
      video.play();
    }
  };

  socket.on('connect',function() { console.log("Socket connected"); });
  socket.on('candidateFromCaller', function (data) {
      pc.addIceCandidate(new RTCIceCandidate(data));
  });

  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
                       navigator.mozGetUserMedia;
  if (navigator.getUserMedia) {
    navigator.getUserMedia({ audio: true, video: { width: 1280, height: 720 } },
      function(stream) {
         var video = $('#vid1'); 
         video.attr('src', URL.createObjectURL(stream));
         video.onloadedmetadata = function(e) {
           video.play();
         }
     pc.addStream(stream);
      },error);

    socket.on('sdpOffer', function(data) {
      var sdpOffer = new RTCSessionDescription(data.sdpOffer);
      pc.setRemoteDescription(sdpOffer, function() {
        pc.createAnswer(function(sdpAnswer) {
          localSessionDescription = new RTCSessionDescription(sdpAnswer);
          pc.setLocalDescription(localSessionDescription, function() {
            socket.emit('sdpAnswer',localSessionDescription);
          },error);
        }, error);
      },error);
    });
  }

  function error(err) {
    console.log("ERROR!!!!");
    console.log(err);
  }

}); // End of document.ready function
如果我在获得用户媒体后插入代码生成报价(正如我在呼叫者代码中所做的那样),生成的ICE候选者也包括视频。当然,正如预期的那样,这只是为了测试之后的代码炸弹

(从评论中可以看出,您正在缓存ICE候选人。不要这样做。我还怀疑时间问题可能是某些候选人流失的原因。)

涓流冰的全部意义在于涓流候选人,也就是说,一旦候选人有空,就立即派遣他们

使用WebRTC,您的应用程序负责对等方之间的信令,这是时间敏感的。因此:

  • setLocalDescription
    成功回调之前发送
    pc.localDescription
  • 希望
    pc.onicecandidate
    在回调后立即启动。发送它们
  • 这对双方都是正确的(提供和回答)。您希望在导线上看到的是:

    offer, candidate, candidate, candidate
    
    另一方面:

    answer, candidate, candidate, candidate
    
    不要做什么:

    • 不要缓存ICE候选人
    • 不要等到你得到答复,那只会浪费时间
    • 当接收端出于任何原因收到录用通知时,不要延迟呼叫
      setRemoteDescription
      ,否则将无法接收候选人
    更新2:

     v=0
     o=- 7912682607537349212 2 IN IP4 127.0.0.1
     s=-
     t=0 0
     a=group:BUNDLE audio video
     a=msid-semantic: WMS 9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126
     c=IN IP4 0.0.0.0
     a=rtcp:9 IN IP4 0.0.0.0
     a=ice-ufrag:0D1hLEwxnqReQosQ
     a=ice-pwd:Nsc4EAtefrfgzTetHjJA5lsg
     a=fingerprint:sha-256 6C:85:D8:33:D8:C6:CB:CE:D4:8E:B4:7A:C2:F5:2F:D0:67:04:25:B2:74:F9:C6:3A:2E:96:E6:56:E7:27:B0:F8
     a=setup:active
     a=mid:audio
     a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
     a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
     a=sendrecv
     a=rtcp-mux
     a=rtpmap:111 opus/48000/2
     a=fmtp:111 minptime=10; useinbandfec=1
     a=rtpmap:103 ISAC/16000
     a=rtpmap:104 ISAC/32000
     a=rtpmap:9 G722/8000
     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:2958641119 cname:Iu8s16HLxglPDg9k
     a=ssrc:2958641119 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd bb63739b-cca2-4aa5-90a6-cf4bbaa199af
     a=ssrc:2958641119 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     a=ssrc:2958641119 label:bb63739b-cca2-4aa5-90a6-cf4bbaa199af
     m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96
     c=IN IP4 0.0.0.0
     a=rtcp:9 IN IP4 0.0.0.0
     a=ice-ufrag:0D1hLEwxnqReQosQ
     a=ice-pwd:Nsc4EAtefrfgzTetHjJA5lsg
     a=fingerprint:sha-256 6C:85:D8:33:D8:C6:CB:CE:D4:8E:B4:7A:C2:F5:2F:D0:67:04:25:B2:74:F9:C6:3A:2E:96:E6:56:E7:27:B0:F8
     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=extmap:4 urn:3gpp:video-orientation
     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=rtcp-fb:100 transport-cc
     a=rtpmap:101 VP9/90000
     a=rtcp-fb:101 ccm fir
     a=rtcp-fb:101 nack
     a=rtcp-fb:101 nack pli
     a=rtcp-fb:101 goog-remb
     a=rtcp-fb:101 transport-cc
     a=rtpmap:116 red/90000
     a=rtpmap:117 ulpfec/90000
     a=rtpmap:96 rtx/90000
     a=fmtp:96 apt=100
     a=ssrc-group:FID 3143004909 4248148453
     a=ssrc:3143004909 cname:Iu8s16HLxglPDg9k
     a=ssrc:3143004909 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd 778ef702-e7fc-47ea-bb3a-477e0b4262ba
     a=ssrc:3143004909 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     a=ssrc:3143004909 label:778ef702-e7fc-47ea-bb3a-477e0b4262ba
     a=ssrc:4248148453 cname:Iu8s16HLxglPDg9k
     a=ssrc:4248148453 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd 778ef702-e7fc-47ea-bb3a-477e0b4262ba
     a=ssrc:4248148453 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     a=ssrc:4248148453 label:778ef702-e7fc-47ea-bb3a-477e0b4262ba
    
    您的sdp显示的是
    a=recvonly
    ,而不是
    a=sendrecv
    ,这意味着接收方只能接收,而不发送任何回报。以下两种情况中的一种会导致这种情况:

  • 调用方设置createOffer选项,如
    offerToReceiveVideo:false
    和/或
    offerToReceiveAudio:false
  • 接收方未及时调用(之前)
    pc.setLocalDescription
  • 如果
    getUserMedia
    与收到报价之间存在竞争,则可能发生第二种情况

    更新3:

     v=0
     o=- 7912682607537349212 2 IN IP4 127.0.0.1
     s=-
     t=0 0
     a=group:BUNDLE audio video
     a=msid-semantic: WMS 9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126
     c=IN IP4 0.0.0.0
     a=rtcp:9 IN IP4 0.0.0.0
     a=ice-ufrag:0D1hLEwxnqReQosQ
     a=ice-pwd:Nsc4EAtefrfgzTetHjJA5lsg
     a=fingerprint:sha-256 6C:85:D8:33:D8:C6:CB:CE:D4:8E:B4:7A:C2:F5:2F:D0:67:04:25:B2:74:F9:C6:3A:2E:96:E6:56:E7:27:B0:F8
     a=setup:active
     a=mid:audio
     a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
     a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
     a=sendrecv
     a=rtcp-mux
     a=rtpmap:111 opus/48000/2
     a=fmtp:111 minptime=10; useinbandfec=1
     a=rtpmap:103 ISAC/16000
     a=rtpmap:104 ISAC/32000
     a=rtpmap:9 G722/8000
     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:2958641119 cname:Iu8s16HLxglPDg9k
     a=ssrc:2958641119 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd bb63739b-cca2-4aa5-90a6-cf4bbaa199af
     a=ssrc:2958641119 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     a=ssrc:2958641119 label:bb63739b-cca2-4aa5-90a6-cf4bbaa199af
     m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96
     c=IN IP4 0.0.0.0
     a=rtcp:9 IN IP4 0.0.0.0
     a=ice-ufrag:0D1hLEwxnqReQosQ
     a=ice-pwd:Nsc4EAtefrfgzTetHjJA5lsg
     a=fingerprint:sha-256 6C:85:D8:33:D8:C6:CB:CE:D4:8E:B4:7A:C2:F5:2F:D0:67:04:25:B2:74:F9:C6:3A:2E:96:E6:56:E7:27:B0:F8
     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=extmap:4 urn:3gpp:video-orientation
     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=rtcp-fb:100 transport-cc
     a=rtpmap:101 VP9/90000
     a=rtcp-fb:101 ccm fir
     a=rtcp-fb:101 nack
     a=rtcp-fb:101 nack pli
     a=rtcp-fb:101 goog-remb
     a=rtcp-fb:101 transport-cc
     a=rtpmap:116 red/90000
     a=rtpmap:117 ulpfec/90000
     a=rtpmap:96 rtx/90000
     a=fmtp:96 apt=100
     a=ssrc-group:FID 3143004909 4248148453
     a=ssrc:3143004909 cname:Iu8s16HLxglPDg9k
     a=ssrc:3143004909 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd 778ef702-e7fc-47ea-bb3a-477e0b4262ba
     a=ssrc:3143004909 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     a=ssrc:3143004909 label:778ef702-e7fc-47ea-bb3a-477e0b4262ba
     a=ssrc:4248148453 cname:Iu8s16HLxglPDg9k
     a=ssrc:4248148453 msid:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd 778ef702-e7fc-47ea-bb3a-477e0b4262ba
     a=ssrc:4248148453 mslabel:9f0MAtEwYGWY3pdBDI8ZtTu4dVu92R6IpEFd
     a=ssrc:4248148453 label:778ef702-e7fc-47ea-bb3a-477e0b4262ba
    
    如果所有其他操作都失败,请与工作代码进行比较。我以前在其他答案中分享过一个交叉标签演示,但它只发送了视频,没有收到任何视频

    这是一个只从远程摄像机接收视频的系统。像往常一样,在同一浏览器的两个选项卡中打开它


    请注意,在Firefox中,在您点击调用后,您必须在另一个选项卡允许访问摄像头之前对其进行物理聚焦。

    我可以通过设置:

    rtcConfiguration.bundlePolicy = "max-compat"
    

    请参阅:

    您正在处理的是所谓的bundeling。报价人和应答人同意将所有冰上运输捆绑成一个冰上运输。因此,对于第一个m形截面,您只能得到一个ICE候选

    报价人仍在为视频m部分提供所有这些ICE候选者,因为它不知道回答者是否同意使用捆绑包

    正如AlexD在他的回答中指出的,你可以通过“捆绑政策”影响发盘方的这种行为。例如,“maxBundle”作为策略将导致报价人假设应答人将理解捆绑,因此仅为单个传输创建ICE候选


    但是,只要报价人提供捆绑包,应答人就会使用它,如果它支持的话。

    很难说有什么问题,因为您没有发布任何代码来查看。您发布的sdp(答案)似乎有音频和视频的
    m=
    行,所以这看起来不错。你试过切换呼叫者和接受者吗?@jib切换呼叫者和接受者机器没有帮助。代码太长,无法发送。摘要:两个SDP都有m=音频和m=视频线路。在CALLER&RECEIVER中,我将ICE候选对象存储在一个数组中。此代码仅在创建PeerConnection之后。在CALLER中,在收到应答SDP后,我设置remoteDescription并将数组发送给接收器。在RECEIVER中,在收到offer SDP后,我设置remoteDescription并将数组发送给调用者。我怀疑这一顺序有问题。我在读RFC5245。如果你能提供一些指针,那将很有帮助。thnx整个数组的事情似乎是可疑的。你为什么这么做?涓涓冰的全部意义在于涓涓细流,也就是说,一旦候选人有空,就立即派出他们。不要缓存它们。在来电端,等待回复只会浪费大量时间。相反,在接收器端,我怀疑a