UnityPeerJS - simple WebRTC support for Unity WebGL

The other day I became interested in how WebRTC works, for peer-to-peer networking in the browser, and with jonas’s WebSockets package as a guide I felt my way through the process of making a package for at least one popular WebRTC API - PeerJS. It was not very difficult, and kind of fun, and this is the result so far:

UnityPeerJS.unitypackage

The package includes the jslib, the interop C# layer, and a test MonoBehaviour that’s not quite self-sufficient - it needs something to connect to. With a few changes you could make it connect to an instance of itself; however I tested it by connecting to a vanilla PeerJS client running from a regular HTML page in the browser.

In a nutshell the C# API lets you identify yourself (pick a name), establish connections to other peers (so long as you already know their names), and send and receive byte[ ] data. Error handling is minimal, and resource cleanup almost entirely absent. So at the moment this is an experimental toy, not a stable library.

Feel free to use it for whatever you like, bearing in mind PeerJS’s licensing of course. I found jonas’s WebSockets unitypackage a great help, and maybe this can be similarly helpful for other people.

A couple of important things to note:

  • You can read about PeerJS here. A lot of the unitypackage API directly mirrors the upstream Javascript API.
  • I didn’t implement a C# wrapper, partly because of a distinct scarcity of C#-based WebRTC libraries. I did find one that might work. But for now, the only way to try this out is by doing WebGL builds - it won’t work in the editor.
  • WebRTC is a peer-to-peer system but the peers require a central server for matchmaking (referred to as a signalling server). PeerJS defaults to using their own servers for this, and my unitypackage doesn’t expose the configuration options for changing that.
  • NAT punchthrough is supported, to a degree. PeerJS defaults to using a STUN server hosted by google, with no TURN servers set up. Again, I don’t yet expose the configuration options you need for changing that. If you need to experiment you could just hack the jslib though, as a quick workaround.
  • WebRTC connections have optional settings like requiring packets to be delivered reliably, or in-order; PeerJS exposes some of this, but my unitypackage does not. Again, hack it in the jslib if you need it.

I am going to play with this some more, and maybe do another version without the PeerJS stuff, just using the browser’s WebRTC layer directly.

WebRTC itself is a bit of a shambles at the moment, especially if your interest is game networking, because it’s not really what WebRTC is for and nobody seems to care much about what games need. As far as I can make out, current WebRTC protocols are extremely inefficient (huge headers…) and nobody seems to realise how much of a problem that is for game traffic. There are also big problems with cross-browser support, but it works pretty well in Chrome and Firefox so kind of matches Unity’s WebGL portability right now.

2 Likes

Wow, just tried it, this is awesome!

I fixed a lot of bugs in the code, and made a chat client demo. You can download the updated unitypackage including the code and scene for the chat demo.

EDIT: There’s an odd bug in the chat client demo - it fails for Peer IDs of length 1, 5, 9, etc. I’m not sure why yet.

Socket.io not do the same?

No, Socket.IO doesn’t use WebRTC, it uses old fashioned long-polling, with a post-connection upgrade to WebSockets if they are available.

Nice, thanks for the example!

Assuming it is using SCTP for the data channel it adds 28 bytes to the header, is that correct? I like the idea of WebRTC, it seems like it has come a long way.

Also if the page I read can be believe STUN by itself for Googles GTalk app has about 92% success with only 8% of clients requiring TURN. That’s still a large number when you talk about Google scale but for a game I think I could deal without TURN…

I only read about this a little bit, but my understanding is that SCTP is tunnelled inside DTLS, which is tunnelled inside UDP. Compared to plain UDP, this is something like an extra 50 header bytes. It might be a temporary measure due to poor router-level support for SCTP or something like that, but still, the UDP header is only 8 bytes so even without it this is still a pretty fat header. I also wouldn’t hold your breath for router upgrades - IPv6 has been waiting for decades…

I would expect STUN to perform no better than any other modern NAT traversal technique. 92% is higher than I would have guessed, but they are the ones with the figures. :slight_smile:

TURN is probably not a good idea for a game. While reading up on WebRTC, I came across this company that rents TURN bandwidth. Check out the prices… Xirsys - TURN Server WebRTC NAT Traversal

So I think that like Unity’s relay server it’s neat that it is supported, but it’s not commercially viable for serious games. You’re better off requiring that people who want to host their own sessions have decent NAT set-ups.

Yep, TURN is essentially just a relay server so I would expect pricing is going to be similar to running a websocket server via some hosting service, ie. expensive. That’s the big draw of WebRTC to me, can I really justify paying for bandwidth for a game I might not even charge for? Probably not.

What’s worse is I looked at that provider and they make you authenticate your app with a TURN API key which in HTML5 would be easily snatched out of the source, so any user could copy your app and also use your TURN bandwidth…I can deal with the fact someone can rip my code in HTML5, that’s sort of a compliment, but racking up huge bills I’m on the hook for, different story.

Yes. I think I saw something about short-term passwords somewhere, where your web server arranges short-term keys on the TURN server for clients to use. Then it doesn’t matter so much if they are stolen. Maybe they can build that into their signalling server or something.

The components are all generic, but browsers do enforce some things like accurate Origin headers which may allow game-funded servers to filter out any cuckoo traffic. It would at least prevent some other game from just hijacking your servers.

So what is the difference between WebRTC and WebSockets? I’m familiar with the latter and I have my own server that supports we sockets already but not familiar with WebRTC.

Main thing is WebSockets you connect to a server, WebRTC allows peer to peer connections for things like video/audio streaming or data channels.

So what advantage does it have over, say a lan based setup or matchmaking server combo with direct tcp/ip or better yet UDP connections between peers? Does it provide any Nat traversal benefits? Is it a guaranteed delivery system like tcp/ip or more performance based but potentially lossy like UDP? I’m assuming it is tcp/ip based as I think you mentioned a requirement around packet delivery order.

Let me see if I can answer as non confusing as possible, it gets kind of hairy. If I fail check out this page it is pretty in depth: O'Reilly Media - Technology and Business Training

Why WebRTC instead of just normal direct tcp or udp between peers?
WebRTC can be initiated from a web browser specifically thus useful for HTML5. The only sockets that you can initiate from HTML5 apps are plain http, websockets(upgraded http), and WebRTC. Vanilla TCP and UDP is not an option from the browser unless you’re using plugins. You also cannot start a WebSocket listener in a browser, only outbound.

Does it provide any Nat traversal benefits?
It utilizes STUN and TURN for NAT traversal so you need to provide or use someone elses STUN server and also provide some sort of signalling server to do the matchmaking, but after the two peers are connected all data flows peer to peer. The bandwidth/servers required to get STUN information is provided for free by a number of providers, STUN basically just tells you your public ip address and port so you can inform the other peer who to connect to. TURN is a relay server like you would typically do with something like Photon for instance, shuttling data through a middleman server, but is optional for clients that can’t connect with plain STUN/ICE.

Is it a guaranteed delivery system like tcp/ip or more performance based but potentially lossy like UDP?
It is udp on the transport layer(makes NAT punchthrough much easier than tcp), encrypted with udp equivalent of TLS called “DTLS” and then a protocol called SCTP is tunneled over the DTLS connection(confused yet?). SCTP supports optional reliable/ordered delivery like tcp, but not required. There are a few WebRTC APIs of interest, audio/video/data, the one most games would be interested in is the DataChannel API, whereas VoiP would be more interested in the streaming media/audio stuff. The DataChannel stuff is pretty much the same as the normal websocket API(message based) and supports text or binary.

I have yet to do anything beyond proof of concept with it so gfoot or someone else may be able to provide more color. At the end of the day I find it really cool but unlikely to use it for any of my games since I find the security aspect of peer to peer just too difficult to protect against cheating, but it is something I will keep following.

4 Likes

Yep, for me it’s primarily a matter of using things that work in WebGL builds, where options are limited. On other platforms, unless your game has a very low traffic level, you’re better off with plain UDP, and maybe a lightweight layer like UdpKit.

TURN vs Photon Cloud is a complex comparison - although they both relay traffic through publicly-visible servers, I think they behave quite differently. Photon Cloud gives more functionality, and if that extra functionality suits your game then it should use less bandwidth that TURN in severe situations where peer-to-peer doesn’t work; the main disadvantage is that the bandwidth gets used even for peers who could in theory talk directly to each other.

1 Like

By the way, thanks for the link to that book - it is a great description of the protocols involved. Seeing the content of the SCTP header makes me angry though!

Sure no problem, actually it is a really great book in general, check out the section on tcp especially, can help tune a lot of things.

o… It’s only a simply chat, I hope at the video chat =). So, if I want a video chat at the WebGL project on Unity - what am I do -?

This was just to demonstrate using WebRTC to form a data connection. For video or audio chat you should probably use the browser’s direct support, which is quite mature these days. I’m not sure whether there’s a clean way to get the result into Unity (like using it as a texture in your scene).

hm… but I want that user from my game(on facebook or another web page) clicked on the button “video” and run a video chat from another player

I would like to make an online realtime game with WebRTC but I do not understand is there support for WebRTC when exporting to exe,android,os
Maybe you have ideas how to implement it (if possible =) )?

the fact that the player from the game in WebGL version could play the other versions of the game exe,android,os