mding5692
mding5692

Reputation: 806

WebRTC on AWS EC2 with TURN server on AWS EC2 on 2 different networks, error: ICE failed, add a STUN server

Currently I have a videochat web app using WebRTC and written in Reactjs deployed on an AWS EC2 Instance. The videochat works with two users on two different computers on a local network or the same internet network and we can easily talk and see each other.

However when I try to videochat with another user who is on a different network, the videochat stops working and I got an error message in my Chrome browser console like this:

Uncaught (in promise) DOMException: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate

and the other user gets:

ICE failed, add a STUN server and see about:webrtc for more details

I believe the issue is with the TURN server, however I have set up the TURN server using COTURN (https://github.com/coturn/coturn) on an AWS EC2 instance and it seems to work when I test it on https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ with the same credentials when I try to see for relays.

I deployed the TURN server using instructions from this stackoverflow post: How to create stun turn server instance using AWS EC2

I have also allowed inbound port access for UDP and TCP for a large range of ports on AWS security groups.

Some relevant code, this one processes the responses I get back from a WebRTC signalling server:

/**
     * Parse a broadcast message and reply back with
     * the appropriate details
     */
    receiveBroadcast(packetObject) {
        try {
            var payload = JSON.parse(packetObject.Payload)
        } catch (err) {
            var payload = packetObject.Payload
        }

        if (payload.Type == 'Ice Offer') {
            // Set remote descriptions and construct an ICE answer
            var icePacket = new this.rtcSessionDescription({
                type: payload.IcePacket.type,
                sdp: payload.IcePacket.sdp,
            })

            this.peerConnection.setRemoteDescription(icePacket, function () {
                this.peerConnection.createAnswer(this.onCreateAnswerSuccess.bind(this), this.onCreateSessionDescriptionError)
            }.bind(this), this.onSetSessionDescriptionError)


        } else if (payload.Type == 'Ice Answer') {
            // Set the remote description
            var icePacket = new this.rtcSessionDescription({
                type: payload.IcePacket.type,
                sdp: payload.IcePacket.sdp,
            })

            this.peerConnection.setRemoteDescription(icePacket, function () {
                this.onSetRemoteSuccess()
            }.bind(this), this.onSetSessionDescriptionError)
        } else if (payload.Type == 'Ice Candidate') {

            console.log('ICE payload :')
            console.log(payload)

            // Add the candidate to the list of ICE candidates
            var candidate = new this.rtcIceCandidate({
                sdpMLineIndex: payload.sdpMLineIndex,
                sdpMid: payload.sdpMid,
                candidate: payload.candidate,
            })
            this.peerConnection.addIceCandidate(candidate)
        }
    }

Its mainly the last line that is not working.

I set up console.logs to see what the process looks like:

Local stream set
bundle.js:1 Video Set
bundle.js:1 setRemoteDescription complete
bundle.js:1 ICE payload :
bundle.js:1 {Type: "Ice Candidate", sdpMLineIndex: 0, candidate: "candidate:0 1 UDP 2122252543 xxx.xxx.x.xx 57253 typ host", sdpMid: "0"}
bundle.js:1 ICE payload :
bundle.js:1 {Type: "Ice Candidate", sdpMLineIndex: 0, candidate: "candidate:1 1 UDP 2122187007 xx.xxx.x.xx 53622 typ host", sdpMid: "0"}
bundle.js:1 ICE payload :
bundle.js:1 {Type: "Ice Candidate", sdpMLineIndex: 0, candidate: "candidate:2 1 TCP 2105524479 xxx.xxx.x.xx 9 typ host tcptype active", sdpMid: "0"}
bundle.js:1 ICE payload :
bundle.js:1 {Type: "Ice Candidate", sdpMLineIndex: 0, candidate: "candidate:3 1 TCP 2105458943 xx.xxx.x.xx 9 typ host tcptype active", sdpMid: "0"}
bundle.js:1 ICE payload :
bundle.js:1 {Type: "Ice Candidate", sdpMLineIndex: 0, candidate: "", sdpMid: "0"}

Upvotes: 1

Views: 3857

Answers (1)

mding5692
mding5692

Reputation: 806

Figured it out, it was a stupid mistake, the config JSON I was using for specifying the ICE servers had an extra layer and WebRTC just couldn't process it. However the WebRTC error messages are pretty much unusable and not very informational.

So for any future people stuck on debugging WebRTC, these are the steps I figured out and resources I used so that other people can better debug their problems.

1) Use Chrome
2) Open up in new tab chrome://webrtc-internals/
3) Open up your videochat app in another tab and observe whats happening in chrome://webrtc-internals/
4) Make sure not to close the tab with the videochat app, if you do chrome://webrtc-internals will refresh
5) Open up a working videochat app like https://morning-escarpment-67980.herokuapp.com/ which is an app built from this github repo: https://github.com/nguymin4/react-videocall
6) Compare the differences between yours and the successful video chat app's chrome://webrtc-internals
7) Use this resource to help understand error messages and more details: https://blog.codeship.com/webrtc-issues-and-how-to-debug-them/

Hopefully this helps.

Upvotes: 2

Related Questions