I am trying to establish a p2p audio/video connection b/w 2 peers. Peer P1 sends an offer to peer P2. On getting offer, P2 does-
{
pc = new RTCPeerConnection(ice);
pc.setRemoteDescription(new RTCSessionDescription(msg.offer),
onSetRemoteDescriptionSuccess, onSetSessionDescriptionError);
function onSetRemoteDescriptionSuccess() {
console.log('onSetRemoteDescriptionSuccess called');
}
function onSetSessionDescriptionError() {
console.log('onSetSessionDescriptionError called');
}
pc.onicecandidate = function(evt) {
if (evt.candidate) {
console.log('got local icecandidate', evt.candidate);
send_ice_candicate(evt.candidate.sdpMLineIndex,
evt.candidate.sdpMid,
evt.candidate.candidate
);
}
}
pc.onaddstream = function (evt) {
var remote_video = document.getElementById('remote_video');
remote_video.src = window.URL.createObjectURL(evt.stream);
}
navigator.getUserMedia({ "audio": true, "video": true },
gotStream, logError);
}
function gotStream(stream) {
pc.addStream(stream);
var local_video = document.getElementById('local_video');
local_video.src = window.URL.createObjectURL(stream);
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer);
console.log('creating answer', answer.sdp)
signalingChannel.send(answer.sdp);
});
got_ice_candidate(remote_ice_candidate);
}
remote_ice_candidate is something which was received before offer and hence is buffered and I am trying to add after the answer is ready and other pre-requisites are done.
But still I am getting error while trying to add remote ice candidate.
Peer connection object on P2 looks like-
RTCPeerConnection {ondatachannel: null, oniceconnectionstatechange: null, onremovestream: null, onaddstream: function, onsignalingstatechange: null…}
iceConnectionState: "new"
iceGatheringState: "gathering"
localDescription: RTCSessionDescription
sdp: "v=0
↵o=- 5043546633484176483 2 IN IP4 127.0.0.1
↵s=-
↵t=0 0
↵a=group:BUNDLE audio video
↵a=msid-semantic: WMS irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk
↵m=audio 10990 RTP/SAVPF 111 103 104 0 8 106 105 13 126
↵c=IN IP4 122.171.69.180
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=candidate:3022624816 1 udp 2122260223 192.168.1.4 50063 typ host generation 0
↵a=candidate:4205470912 1 tcp 1518280447 192.168.1.4 0 typ host generation 0
↵a=candidate:494278629 1 udp 1686052607 122.171.69.180 10990 typ srflx raddr 192.168.1.4 rport 50063 generation 0
↵a=ice-ufrag:1ZCyumc5I0T8mbFJ
↵a=ice-pwd:+JUisFsiKa8ezPXDIuzu99tv
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:active
↵a=mid:audio
↵a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
↵a=sendrecv
↵a=rtcp-mux
↵a=rtpmap:111 opus/48000/2
↵a=fmtp:111 minptime=10
↵a=rtpmap:103 ISAC/16000
↵a=rtpmap:104 ISAC/32000
↵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:2173896727 cname:PZV2reyyZuw6KufJ
↵a=ssrc:2173896727 msid:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk fb1b496d-ffa9-43cd-940a-7c68df86d3b3
↵a=ssrc:2173896727 mslabel:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk
↵a=ssrc:2173896727 label:fb1b496d-ffa9-43cd-940a-7c68df86d3b3
↵m=video 10990 RTP/SAVPF 100 116 117
↵c=IN IP4 122.171.69.180
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=candidate:3022624816 1 udp 2122260223 192.168.1.4 50063 typ host generation 0
↵a=candidate:4205470912 1 tcp 1518280447 192.168.1.4 0 typ host generation 0
↵a=candidate:494278629 1 udp 1686052607 122.171.69.180 10990 typ srflx raddr 192.168.1.4 rport 50063 generation 0
↵a=ice-ufrag:1ZCyumc5I0T8mbFJ
↵a=ice-pwd:+JUisFsiKa8ezPXDIuzu99tv
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵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=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=rtpmap:116 red/90000
↵a=rtpmap:117 ulpfec/90000
↵a=ssrc:2118221653 cname:PZV2reyyZuw6KufJ
↵a=ssrc:2118221653 msid:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk a735b317-1752-40fa-96df-511c0febb55e
↵a=ssrc:2118221653 mslabel:irIWtGZ87WFi8P6XH94I85sUsKYcu775glZk
↵a=ssrc:2118221653 label:a735b317-1752-40fa-96df-511c0febb55e
↵"
type: "answer"
__proto__: RTCSessionDescription
onaddstream: function (evt) {
arguments: null
caller: null
length: 1
name: ""
prototype: Object
__proto__: function Empty() {}
<function scope>
ondatachannel: null
onicecandidate: function (evt) {
oniceconnectionstatechange: null
onnegotiationneeded: null
onremovestream: null
onsignalingstatechange: null
remoteDescription: RTCSessionDescription
sdp: "v=0
↵o=- 8847796014807563532 2 IN IP4 127.0.0.1
↵s=-
↵t=0 0
↵a=group:BUNDLE audio video
↵a=msid-semantic: WMS na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK
↵m=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126
↵c=IN IP4 0.0.0.0
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=ice-ufrag:mfL29tarMKRBN9F/
↵a=ice-pwd:/my1DZo1Yjne4BrcQGKN1o3I
↵a=ice-options:google-ice
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:actpass
↵a=mid:audio
↵a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
↵a=sendrecv
↵a=rtcp-mux
↵a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:ggGTdSmkygu0aVidv2M6kO25w5DX/OknOXFnRBYK
↵a=rtpmap:111 opus/48000/2
↵a=fmtp:111 minptime=10
↵a=rtpmap:103 ISAC/16000
↵a=rtpmap:104 ISAC/32000
↵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:702054304 cname:++QJWJ3eyXhSOSgH
↵a=ssrc:702054304 msid:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK 054d6450-034f-48ca-85dc-3a843c7f7554
↵a=ssrc:702054304 mslabel:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK
↵a=ssrc:702054304 label:054d6450-034f-48ca-85dc-3a843c7f7554
↵m=video 1 RTP/SAVPF 100 116 117
↵c=IN IP4 0.0.0.0
↵a=rtcp:1 IN IP4 0.0.0.0
↵a=ice-ufrag:mfL29tarMKRBN9F/
↵a=ice-pwd:/my1DZo1Yjne4BrcQGKN1o3I
↵a=ice-options:google-ice
↵a=fingerprint:sha-256 BE:16:E6:7B:C8:18:E6:B9:50:D9:31:F3:24:85:3B:63:26:BA:EA:6B:5D:F4:4E:0E:29:47:16:C0:1D:9D:B7:F3
↵a=setup:actpass
↵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=sendrecv
↵a=rtcp-mux
↵a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:ggGTdSmkygu0aVidv2M6kO25w5DX/OknOXFnRBYK
↵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=rtpmap:116 red/90000
↵a=rtpmap:117 ulpfec/90000
↵a=ssrc:846853801 cname:++QJWJ3eyXhSOSgH
↵a=ssrc:846853801 msid:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK c0dde33c-f422-4774-9f7b-65cec136e107
↵a=ssrc:846853801 mslabel:na7tuNpnYZpmg56IJULDdF8oMUG8V5ndTjkK
↵a=ssrc:846853801 label:c0dde33c-f422-4774-9f7b-65cec136e107
↵"
type: "offer"
__proto__: RTCSessionDescription
signalingState: "stable"
__proto__: RTCPeerConnection
The error that I get is
Failed to add Ice Candidate: Error processing ICE candidate
The RTCIceCandidate interface—part of the WebRTC API—represents a candidate Interactive Connectivity Establishment (ICE) configuration which may be used to establish an RTCPeerConnection . An ICE candidate describes the protocols and routing needed for WebRTC to be able to communicate with a remote device.
Trickle ICE is an optimization of the ICE specification for NAT traversal. The main bottleneck in ICE is the time it takes to start initiating connectivity checks – it requires collecting all ICE candidates in advance, which in turn means interacting with external servers (STUN and TURN servers).
This is a reply to comments asking how to ensure ice candidates are only added after the remote description is set:
let candidates = [];
let remoteDescriptionSet = false;
function wsMessage(ev) {
if (!ev || !ev.data) return;
const json = JSON.parse(ev.data);
if (!json) return;
if (json.type === 'answer') {
pc.setRemoteDescription(json)
.then(() => {
remoteDescriptionSet = true;
console.log('remote description set');
return Promise.all(candidates.map(c => pc.addIceCandidate(c)));
})
.then(() => {
console.log('all stored candidates added');
candidates.length = 0;
})
.catch(err => console.error(err));
}
else if (json.type === 'ice') {
if (remoteDescriptionSet) {
pc.addIceCandidate(json.ice)
.then(() => console.log(`adding remote ice candidate: ${json.ice.candidate}`))
.catch(err => console.error(err));
}
else {
candidates.push(json.ice);
console.log(`storing remote ice candidate: ${json.ice.candidate}`);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With