WebRTC onicecandidate:我的ICE候选人只有sdpMid =音频而不是视频

Sun*_*nny 6 webrtc

使用的浏览器是Chrome ...我有调用者和接收者代码来生成SDP和ICE候选者.我得到调用者代码以生成具有sdpMid = video的正确SDP和ICE候选者但是对于接收器,我得到仅针对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
Run Code Online (Sandbox Code Playgroud)

这是为相应的getUserMedia生成的,如下所示:

 navigator.getUserMedia({ audio: true, video: { width: 1280, height: 720 } },...
Run Code Online (Sandbox Code Playgroud)

ICE候选生成代码是:

pc.onicecandidate = function (event) {
   console.log("Generated Icecandidate:" );
   console.log(event);
   ...
 };
Run Code Online (Sandbox Code Playgroud)

在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"
Run Code Online (Sandbox Code Playgroud)

不用说,我无法显示远程视频.我在本地网络上尝试这个,所以甚至不需要STUN.

我想知道,为什么我没有为sdpMid =视频获得任何ICE候选人.此外,在生成的四个ICE候选者中,三个ICE候选者具有sdpMLineIndex:0并且一个ICE候选者具有候选属性为null!

更新1:我得到了上一期的答案...候选财产为空."注意:RTCPeerConnection.onicecandidate将使用空候选属性调用一次,以表示涓流ICE事件的结束." 这在这里解释.

在来电方面,我获得了超过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
Run Code Online (Sandbox Code Playgroud)

如果我在获取用户媒体之后插入代码来生成商品(就像我在调用者代码中那样),生成的ICE候选者也包含用于视频的代码.当然,这仅仅是为了测试之后的其余代码炸弹,正如预期的那样.

jib*_*jib 8

(从评论中可以看出,你正在缓存ICE候选人.不要这样做.我也怀疑时间问题可能是一些候选人失去的原因.)

Trickle ICE的重点是涓流候选人,也就是说,一旦候选人出现,就立即发送候选人.

使用WebRTC,您的应用程序负责对等体之间的信令,这对时间敏感.所以:

  1. 发送pc.localDescription不迟于setLocalDescription成功回调.
  2. 期望pc.onicecandidate在回调后立即开始射击.发送它们.

双方都是如此(提供和回答).你想在电线上看到的是:

offer, candidate, candidate, candidate
Run Code Online (Sandbox Code Playgroud)

和另一种方式:

answer, candidate, candidate, candidate
Run Code Online (Sandbox Code Playgroud)

什么不该做:

  • 不要缓存ICE候选人.
  • 不要等到你有回答,这只是浪费时间.
  • setRemoteDescription当出于任何原因在接收端出现要约时,不要延迟通话,否则它不会准备好接收候选人.

更新2:

你的sdp说a=recvonly而不是a=sendrecv,这意味着收件人只能接收,而不会发送任何回报.两件事之一可能导致这种情况:

  1. 调用者设置了offerToReceiveVideo:false和/或的createOffer选项offerToReceiveAudio:false.
  2. 接收者未及时致电pc.addStream(之前)pc.setLocalDescription.

如果在getUserMedia收到要约之间有竞争,则第二种情况可能发生.

更新3:

如果所有其他方法都失败了,请与工作代码进 我之前在其他答案中分享了一个交叉表演示,但它只发送了视频,没有收到任何.

是该演示的修改版本,仅从远程摄像头接收视频.像往常一样,在同一浏览器中的两个选项卡中打开它.

请注意,在Firefox中,在您点击之后Call,您必须在允许访问相机之前对其他选项卡进行物理聚焦.