javascriptwebsocketwebrtcsimple-peer

WebRTC (simple-peer) + STUN Without Extra Signaling?


I'm trying to use the simple-peer library to establish browser-to-browser WebRTC connections (data channels). It's my understanding (Maybe I have some misconception) that in order for two browsers to connect via WebRTC, they must exchange SDP data and perform NAT traversal. In order to do this, a STUN server can be implemented.

In the simple-peer library, they state that simple-peer does not implement a signaling protocol but it does provide a method of supplying STUN/ICE servers. Consider the following three HTML files from their mesh example:

peer1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Peer1</title>
</head>
<body>
<script src="../../js/simplepeer.min.js"></script>
<script>
    // These are peer1's connections to peer2 and peer3
    var peer2 = new SimplePeer({ initiator: true, config: {
            iceServers: [
                {urls: 'stun:stun.a-mm.tv:3478'}
            ]
        } })
    var peer3 = new SimplePeer({ initiator: true, config: {
            iceServers: [
                {urls: 'stun:stun.a-mm.tv:3478'}
            ]
        } })

    peer2.on('signal', data => {
        console.log(data)
    })

    peer2.on('connect', () => {
        peer2.send('hi peer2, this is peer1')
    })

    peer2.on('data', data => {
        console.log('got a message from peer2: ' + data)
    })

    peer3.on('signal', data => {
        console.log(data)
    })

    peer3.on('connect', () => {
        peer3.send('hi peer3, this is peer1')
    })

    peer3.on('data', data => {
        console.log('got a message from peer3: ' + data)
    })
</script>
</body>
</html>```

peer2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Peer2</title>
</head>
<body>
<script src="../../js/simplepeer.min.js"></script>
<script>
    // These are peer2's connections to peer1 and peer3
    var peer1 = new SimplePeer({
        config: {
            iceServers: [
                {urls: 'stun:stun.a-mm.tv:3478'}
            ]
        }
    })
    var peer3 = new SimplePeer({ initiator: true, config: {
            iceServers: [
                {urls: 'stun:stun.a-mm.tv:3478'}
            ]
        } })

    peer1.on('signal', data => {
        console.log(data)
    })

    peer1.on('connect', () => {
        peer1.send('hi peer1, this is peer2')
    })

    peer1.on('data', data => {
        console.log('got a message from peer1: ' + data)
    })

    peer3.on('signal', data => {
        console.log(data)
    })

    peer3.on('connect', () => {
        peer3.send('hi peer3, this is peer2')
    })

    peer3.on('data', data => {
        console.log('got a message from peer3: ' + data)
    })
</script>
</body>
</html>

peer3.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Peer3</title>
</head>
<body>
<script src="../../js/simplepeer.min.js"></script>
<script>
    // These are peer3's connections to peer1 and peer2
    var peer1 = new SimplePeer({
            config: {
                iceServers: [
                    {urls: 'stun:stun.a-mm.tv:3478'}
                ]
            }
        }
    )
    var peer2 = new SimplePeer({
        config: {
            iceServers: [
                {urls: 'stun:stun.a-mm.tv:3478'}
            ]
        }
    })

    peer1.on('signal', data => {
        console.log(data)
    })

    peer1.on('connect', () => {
        peer1.send('hi peer1, this is peer3')
    })

    peer1.on('data', data => {
        console.log('got a message from peer1: ' + data)
    })

    peer2.on('signal', data => {
        console.log(data)
    })

    peer2.on('connect', () => {
        peer2.send('hi peer2, this is peer3')
    })

    peer2.on('data', data => {
        console.log('got a message from peer2: ' + data)
    })
</script>
</body>
</html>

You can see that I've added two STUN servers there. Doesn't STUN exchange the necessary signaling data? However, in looking through their issues, they recommending using websockets to exchange such data. Am I then to assume that STUN is only so that each peer can first gather the SDP information and that websockets must then be used to exchange it? And that then, after that, the browsers can establish data channels with each-other?

Why did I think STUN handled this? It all seems a bit redundant to introduce websockets when STUN is already able to provide data to the clients. The goal of course is to drop all central server communications asap in favor of browser-to-browser data channels.

A good answer might answer these questions and modify the example.


Solution

  • It's my understanding (Maybe I have some misconception) that in order for two browsers to connect via WebRTC, they must exchange SDP data...

    Yes, this is correct.

    ... and perform NAT traversal.

    They must make a connection via ICE, which may involve NAT traversal, yes.

    In order to do this, a STUN server can be implemented.

    The only thing a STUN server does is try to figure out what the publicly accessible IP address is. A client behind NAT knows its own local addresses, but may not know its public IP address because it's on the other side of a router doing NAT. Therefore, some external server can reply back and tell it what IP address the client connected from.

    Doesn't STUN exchange the necessary signaling data?

    A STUN server does no signalling at all. None. The signalling is up to you, to be implemented through whatever method you choose.

    Am I then to assume that STUN is only so that each peer can first gather the SDP information...

    Mainly, for the ICE candidates (essentially, IP addresses and some other info). The SDP information is mainly made up of capabilities of the client. (Which codecs are supported and at what rates, etc.)

    ...and that websockets must then be used to exchange it?

    It doesn't have to be web sockets. Any bi-directional communication method can be used, but web sockets are commonly used.

    The goal of course is to drop all central server communications asap in favor of browser-to-browser data channels.

    Yes, unfortunately the current state of WebRTC fell way, way short of this. It would be fantastic if clients on the web could talk to each other... the basics of communication. Sadly, this isn't the case. Centralized servers are still needed to coordinate everything. Peer to peer connections are only made after the connection setup has occurred elsewhere.