如何获取有关WebRTC PeerConnection连接类型的信息?

时间:2014-12-01 14:29:26

标签: javascript browser webrtc

有没有办法以编程方式获取有关WebRTC中使用的连接类型的信息?

例如在我的应用程序中,我使用本地连接以及STUN和TURN。如果候选人的类型是主机或中继,我可以从ICE候选人那里收集,在服务器上我可以看到是否通过STUN(连接启动)或TURN(连接期间稳定流)尝试连接。

到目前为止,我找不到一种方法来访问浏览器中最终使用的连接类型的信息。有候选人,浏览器停止收集,然后有一个工作连接。透过这些事件我无法找到任何信息。

我知道Chrome在peerconnection上支持getStats(),这允许我访问chrome:// webrtc-internals中的大部分信息,但是我也没有在那里找到这些信息。

有没有办法从javascript访问这些信息?

非常感谢。

4 个答案:

答案 0 :(得分:3)

我花了很长时间才能正确解决这个问题,因此希望这对某人有所帮助。

新方法

您现在可以从RTCPeerConnection获取选定的候选对,而无需使用统计信息API:

const pair = rtcConnection.sctp.transport.iceTransport.getSelectedCandidatePair();
console.log(pair.remote.type);

在撰写本文时(2020年10月2日),这仅适用于Chromium。 您仍然可以将stats api用于其他浏览器。 另请注意,jib在下面的评论中说,只有在有数据通道的情况下,这才起作用。

对于不支持getSelectedCandidatePair()的浏览器

根据https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidatePairStats (在页面底部的selected属性中。

确定所选候选对的符合规范的方法是查找传输类型为stats的RTCTransportStats对象。该对象的selectedCandidatePairId属性指示指定的传输是否正在使用。

因此,尝试使用stat.nominated && stats.state == "succeeded"查找所选对不是正确的方法。

相反,您可以通过查看transport统计信息中的选定对来获得它。 Firefox不支持此功能,但幸运的是,Firefox候选对中有一个非标准的selected属性。

const stats = await rtcConnection.getStats();
if(stats){
    let selectedPairId = null;
    for(const [key, stat] of stats){
        if(stat.type == "transport"){
            selectedPairId = stat.selectedCandidatePairId;
            break;
        }
    }
    let candidatePair = stats.get(selectedPairId);
    if(!candidatePair){
        for(const [key, stat] of stats){
            if(stat.type == "candidate-pair" && stat.selected){
                candidatePair = stat;
                break;
            }
        }
    }

    if(candidatePair){
        for(const [key, stat] of stats){
            if(key == candidatePair.remoteCandidateId){
                return stat.candidateType;
            }
        }
    }
}

答案 1 :(得分:2)

根据目前在Firefox中实现的the specification,但在Chrome中没有,你确实可以从候选对的统计数据中找出活跃候选者,这些候选对包括:

dictionary RTCIceCandidatePairStats : RTCStats {
    DOMString                     transportId;
    DOMString                     localCandidateId;
    DOMString                     remoteCandidateId;
    RTCStatsIceCandidatePairState state;
    unsigned long long            priority;
    boolean                       nominated;
    boolean                       writable;
    boolean                       readable;
    unsigned long long            bytesSent;
    unsigned long long            bytesReceived;
    double                        roundTripTime;
    double                        availableOutgoingBitrate;
    double                        availableIncomingBitrate;
};

结合候选人的统计数据:

dictionary RTCIceCandidateAttributes : RTCStats {
    DOMString                ipAddress;
    long                     portNumber;
    DOMString                transport;
    RTCStatsIceCandidateType candidateType;
    long                     priority;
    DOMString                addressSourceUrl;
};

使用peerConnection.getStats()寻找既被提名又已成功的冰候选对:

pc.getStats(null))
.then(function(stats) {
  return Object.keys(stats).forEach(function(key) {
    if (stats[key].type == "candidatepair" &&
        stats[key].nominated && stats[key].state == "succeeded") {
      var remote = stats[stats[key].remoteCandidateId];
      console.log("Connected to: " + remote.ipAddress +":"+
                  remote.portNumber +" "+ remote.transport +
                  " "+ remote.candidateType);
    }
  });
})
.catch(function(e) { console.log(e.name); });

这可能会输出如下内容:

Connected to: 192.168.1.2:49190 udp host

您可以针对LAN range进行测试。相反,它返回的内容如下:

Connected to: 24.57.143.7:61102 udp relayed

然后你就有了TURN连接。

这里显示了jsfiddle(由于其他原因需要Firefox Developer Edition)。

答案 2 :(得分:2)

感谢@DavidP和一个more in-depth answer,我编写了下面的代码来获取ICE候选类型。

function getConnectionDetails(pc){
  pc.getStats(null)
  .then(function(stats) {
        stats.forEach(report => {
          if (report.type == "candidate-pair" 
              && report.nominated 
              && report.state == "succeeded")
          {
            console.log( "Local ICE:", report.localCandidateId)
            console.log( "Remote ICE:",report.remoteCandidateId)
            getCandidates(pc, report.localCandidateId, report.remoteCandidateId)
          }
      });
  })
  .catch(function(e) { console.log(e.name); });
};

function getCandidates(pc, localId, remoteId){
  //console.log("looking for candidates")
  pc.getStats(null)
  .then(function(stats) {
        stats.forEach(report => {
          if (report.id == localId) {
              console.log("Local: Type:", report.candidateType," IP:", report.ip)
          } else if (report.id == remoteId){
              console.log("Remote: Type:", report.candidateType," IP:", report.ip)
          }
      })
  })
  .catch(function(e) { console.log(e.name); });
}

我对WebRTC并不是特别熟悉,所以我不确定您是否同时需要远程和本地类型(只有在没有一方使用NAT的情况下,我才能想到)。

答案 3 :(得分:1)

jib从2015年3月开始的回答非常有帮助,但不适用于2019年3月的Firefox v65或Chrome v72(在Windows上)。需要两个更新:

1)现在,两个浏览器中的“ stats”值类型均为RTCStatsReport,它是一个没有键的可迭代对象。因此,使用forEach(report => {...})对其进行迭代,然后“ report”将是一个对象,其键的类型类似于jib为“ stats”显示的那些键。

2)“ candidatepair”不是report.type的有效值,但“ candidate-pair”是有效的。