有没有办法以编程方式获取有关WebRTC中使用的连接类型的信息?
例如在我的应用程序中,我使用本地连接以及STUN和TURN。如果候选人的类型是主机或中继,我可以从ICE候选人那里收集,在服务器上我可以看到是否通过STUN(连接启动)或TURN(连接期间稳定流)尝试连接。
到目前为止,我找不到一种方法来访问浏览器中最终使用的连接类型的信息。有候选人,浏览器停止收集,然后有一个工作连接。透过这些事件我无法找到任何信息。
我知道Chrome在peerconnection上支持getStats(),这允许我访问chrome:// webrtc-internals中的大部分信息,但是我也没有在那里找到这些信息。
有没有办法从javascript访问这些信息?
非常感谢。
答案 0 :(得分:3)
我花了很长时间才能正确解决这个问题,因此希望这对某人有所帮助。
您现在可以从RTCPeerConnection
获取选定的候选对,而无需使用统计信息API:
const pair = rtcConnection.sctp.transport.iceTransport.getSelectedCandidatePair();
console.log(pair.remote.type);
在撰写本文时(2020年10月2日),这仅适用于Chromium。 您仍然可以将stats api用于其他浏览器。 另请注意,jib在下面的评论中说,只有在有数据通道的情况下,这才起作用。
根据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”是有效的。