WebRTC:确定选定的ICE候选者

11

我有一个webrtc应用程序,假设有两个客户端(client1client2),有没有办法找出client1提供的ICE候选者被client2使用,反之亦然?因为每次找到这个信息,我都必须在两个客户端上使用wireshark,我认为读取sdp可能会有所帮助,但我错了,因为它会给出所有可能的候选项...

场景: client1的所有UDP端口都被阻塞(由我进行测试目的的阻塞)。 Client1的SDP:

...
a=rtcp:49407 IN IP4 <client1's IP>
a=candidate:3864409487 1 udp 2122194687 <client1's IP> 49407 typ host generation 0 // this would never work, since the udp ports are blocked...
a=candidate:3864409487 2 udp 2122194687 <client1's IP> 49407 typ host generation 0
a=candidate:2832583039 1 tcp 1518214911 <client1's IP> 0 typ host tcptype active generation 0
a=candidate:2832583039 2 tcp 1518214911 <client1's IP> 0 typ host tcptype active generation 0
a=candidate:973648460 1 udp 25042687 <TURN server IP> 64790 typ relay raddr <Proxy IP> rport 39963 generation 0
a=ice-ufrag:YSvrOiav8TglpCWD
...

3
请查看此帖子:https://groups.google.com/d/msg/discuss-webrtc/-VReEXf9RBM/h91i7CD-oJ8J - Guy S
3个回答

10

好的,以下内容摘自我的回答:

我编写并测试了下面的代码,在最新版本的Firefox和Chrome中都可以正常工作。 getConnectionDetails返回一个Promise对象,它会解析出连接细节:

function getConnectionDetails(peerConnection){


  var connectionDetails = {};   // the final result object.

  if(window.chrome){  // checking if chrome

    var reqFields = [   'googLocalAddress',
                        'googLocalCandidateType',   
                        'googRemoteAddress',
                        'googRemoteCandidateType'
                    ];
    return new Promise(function(resolve, reject){
      peerConnection.getStats(function(stats){
        var filtered = stats.result().filter(function(e){return e.id.indexOf('Conn-audio')==0 && e.stat('googActiveConnection')=='true'})[0];
        if(!filtered) return reject('Something is wrong...');
        reqFields.forEach(function(e){connectionDetails[e.replace('goog', '')] = filtered.stat(e)});
        resolve(connectionDetails);
      });
    });

  }else{  // assuming it is firefox
    return peerConnection.getStats(null).then(function(stats){
        var selectedCandidatePair = stats[Object.keys(stats).filter(function(key){return stats[key].selected})[0]]
          , localICE = stats[selectedCandidatePair.localCandidateId]
          , remoteICE = stats[selectedCandidatePair.remoteCandidateId];
        connectionDetails.LocalAddress = [localICE.ipAddress, localICE.portNumber].join(':');
        connectionDetails.RemoteAddress = [remoteICE.ipAddress, remoteICE.portNumber].join(':');
        connectionDetails.LocalCandidateType = localICE.candidateType;
        connectionDetails.RemoteCandidateType = remoteICE.candidateType;
        return connectionDetails;
    });

  }
}


//usage example:
getConnectionDetails(pc).then(console.log.bind(console));

我得到了prflx作为googRemoteCandidateTyperelay作为googLocalCandidateType。你知道prflx是什么意思吗? - Anand S
@anand需要检查一下,但我认为这是STUN ICE候选者。 - mido
1
prflx 意味着对等反射候选。请参阅此链接 - ceiling cat

4

这个问题非常古老,但以下内容在2021年仍然可靠!- 至少对我来说是这样的。

您可以使用RTCIceTransport.getSelectedCandidatePair()方法,该方法返回一个RTCIceCandidatePair对象(本地和远程冰候选对)。

例如:要获取用于从对等连接发送媒体的选定候选对。

peerConnection.getSenders().map(sender => {
    const kindOfTrack = sender.track?.kind;
    if (sender.transport) {
        const iceTransport = sender.transport.iceTransport;
        const logSelectedCandidate = (e) => {
            const selectedCandidatePair = iceTransport.getSelectedCandidatePair();
            console.log(`SELECTED ${kindOfTrack || 'unknown'} SENDER CANDIDATE PAIR`, selectedCandidatePair);
        };
        iceTransport.onselectedcandidatepairchange = logSelectedCandidate;
        logSelectedCandidate();
    } else {
        // retry at some time later
    }
});

上述方法同样适用于对等连接对象上接收到的媒体。 在这种情况下,请使用RTCPeerConnection.getReceivers()

1
这篇文章https://testrtc.com/find-webrtc-active-connection/也有一些很好的信息。 - Prince Odame

-1
在Chrome中我用了这个:
let pc1 = new RTCPeerConnection(cfg);
    
pc1.addEventListener('connectionstatechange', async (e) => {    
    if (pc1.connectionState === 'connected') {
        // Peers connected!
        let stats = await pc1.getStats();
        for (const value of stats.values()) {
            if(value.type=="local-candidate" || value.type=="remote-candidate")
                console.log(value);
        }
    }
})

1
为什么要负评? - Cesar Morillas
好的观点,我认为强制留下负面投票的解释是必要的 - 我唯一会质疑的是为什么使用“const value of stats.values()”?既然它在循环中,应该使用“var”或“let”,而不是“const”。 - user2677034
2
我使用const而不是let作为一种保护风格。请参见https://dev59.com/p1MH5IYBdhLWcg3wvyA4 - Cesar Morillas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接