WebRTC - Satellite-im/Core-PWA GitHub Wiki

The WebRTC functionality makes it possible to create a peer-to-peer connection between 2 or more users and allow them to share data and streams across this data channel. The current implementation uses web torrent trackers for signaling, that way we don't have to run our own server.

Architecture

Wire

A Wire represents a connection between 2 peers within a specific channel. It is used as an abstraction for peers that automatically connect to each other using web torrent trackers for signaling. The Wire entity handles a series of message types that can be exchanged between peers and provides a mechanism for identifying peers. For the web torrent signaling, it uses the P2PT library. To better understand how it works, here is the description from the P2PT repo:

WebRTC is how browsers can communicate to other browsers peer to peer (P2P). WebTorrent makes use of WebRTC for sharing Torrents on the web.

But, to establish P2P connections, a signaling server is needed. Signaling servers can be made in any way. But, you'll have to host it yourself. In WebTorrent, it's the WebSocket trackers that are the signaling servers. What if we use those trackers to establish P2P connections for our apps ?! That is what P2PT does! :)

How do we find peers for torrents to download? We use a magnet link. That magnet link has a unique identifier for our torrent called the Info Hash. This ID will be unique for all torrents.

Similarly, to build our apps, we use an identifier. This identifier is converted to a valid Info Hash and sent to our WebTorrent trackers who will give us a list of web peers. These web peers would be the other users also using our app :

const p2pt = new P2PT(trackersAnnounceURLs, 'appId')

The idea is to use an ECDH shared secret as appId. That way only the 2 parties involved can compute the secret and connect each other. Once the connection between 2 peers happens, an identification mechanism that makes use of a signed message exchange ensure that only the desired peer can keep the connection open.

The Wire emits the following events:

ERROR: (data: { peerId: string; error: Error }) => void // Whenever an error occurs
TRACKER_CONNECT: (data: { tracker: string }) => void // The library connected to a web torrent tracker
CONNECT: (data: { peerId: string }) => void // A new peer is connected
DATA: (data: { peerId: string; data: any }) => void // Data from the connected peer is received in the right format
RAW_DATA: (data: { peerId: string; data: any }) => void // Data from the connected peer is received in the wrong format
CLOSE: (data: { peerId: string }) => void // The connection with the peer has been closed
IDENTIFICATION: (data: { peerId: string }) => void // An identification message has been received
SIGNAL: (data: { peerId: string; data: SignalData }) => void // A signal message has been received
REFUSE: (data: { peerId: string }) => void // A refuse message has been received
TYPING_STATE: (data: {
  state: KeyboardStates.TYPING | KeyboardStates.NOT_TYPING
  peerId: string
}) => void // A typing state message has been received

Call

It's a utility class that manages the audio/video call between 2 peers. It uses a wire as a communication bus for signaling. It creates a new peer instance that is specific to the current call.