Month: March 2021

WebRTC Signaling with Signal-Fire

WebRTC Signaling with Signal-Fire

WebRTC is a technology which allows individual peers to talk directly to each other. This requires a signaling server.

A WebRTC signaling server communicates between peers to set up peer-to-peer audio/video and/or data channels. This allows your clients to communicate directly with each other.

Years ago I developed signal-fire, a WebRTC signaling server built for node.js. There also was a browser client available which greatly reduced the burden of setting up peer connections. Lack of maintenance led to the module’s eventual demise and I recently officially retired it.

Luckily I had some inspiration for the new and improved version, and I got to work. The result was the Signal-Fire ecosystem, starting with Signal-Fire Server, a server that does exactly the same as its predecessor did, but better!

The Server

Signal-Fire Server is based on my other quite recent module Luce. Luce is a versatile WebSocket framework for node.js. An excellent pairing for my new project.

Command-Line Interface (CLI)

If you want to get started with Signal-Fire Server without too much hassle, and you’re content with the basic features (for now), you can use the CLI to start and manage Server workers.

Install the CLI globally:

> npm i -g @signal-fire/cli

To start a worker on port 3003:

> signal-fire start -p 3003

Starting the Server

The Server can be installed through npm:

> npm i @signal-fire/server

To manage client IDs the Server requires a registry. In the example below we use LocalRegistry, an in-memory store.

import { Server } from 'http'

import createApp from './index'
import { LocalRegistry } from '@lucets/registry'

const registry = new LocalRegistry()
const app = createApp(registry)
const server = new Server()

server.on('upgrade', app.onUpgrade())
server.listen(3003, () => {
  console.log('Server listening on port 3003')
})

Congratulations, you now have a basic server running!

The Client

Signal-Fire Client is the replacement of signal-fire-client, which has also been deprecated. The Client is also new and improved. The Client is designed for the browser and uses the native EventTarget.

The Client is meant to be used with browserify.

Install the client through npm:

> npm i @signal-fire/client

Connecting to the Server is exceedingly simple:

import connect from '@signal-fire/client'

const client = await connect('ws://localhost/socket')

Sessions

Sessions are requests and responses for setting up the peer connection. One peer creates a session, which its target can either accept or deny.

This example shows how to start a session:

import connect, { PeerConnection } from '@signal-fire/client'

async function run () {
  const client = await connect('ws://localhost:3003/socket')
  const session = await client.createSession('<target id>')

  session.addEventListener('accepted', (ev: CustomEvent<PeerConnection>) => {
    console.log('Session accepted!')

    const connection = ev.detail
    const stream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    })

    stream.getTracks().forEach(track => connection.addTrack(track, stream))
  })

  session.addEventListener('rejected', () => {
    console.log('Session rejected')
  })

  session.addEventListener('timed-out', () => {
    console.log('Session timed out')
  })
}

This example shows how to accept a session:

import connect, { IncomingSession } from '@signal-fire/client'

async function run () {
  const client = await connect('ws://localhost:3003/socket')

  client.addEventListener('session', (ev: CustomEvent<IncomingSession>) => {
    const session = ev.detail
    const connection = await session.accept()
  })
}

Next

The Signal-Fire Server and Client are projects I intent to keep maintaining, and using myself. If you’ve checked out either and found a bug, please open an issue on GitHub, or better yet, a pull request.

WebRTC signaling with Signal-Fire

WebRTC signaling with Signal-Fire

In 2016 I wrote signal-fire, a WebRTC signaling server built for node.js and client built for the browser. I had not maintained the module since then, which unsurprisingly resulted in the modules no longer working.

So recently I took it upon myself to start the projects from scratch. I wrote a capable and extensible WebRTC signaling server for node.js and accompanying client module for the browser. Together they form a strong first start towards using WebRTC in any framework.

Early versions are already available:

The Server

The Signal-Fire Server is the main component of the ecosystem. It provides a flexible Luce application. Luce is a versatile WebSocket framework which uses asynchronous hooks to extend functionality. I developed Luce as the spiritual successor to my now deprecated module Illustriws.

At its core the Server provides each client with a unique ID, which can then be used to process the signaling necessary to set up a WebRTC peer connection. The protocol is JSON-based and simple to work with. Methods of exchanging IDs falls outside the scope of the Server, although the versatility of Luce allows many possible strategies for creating and storing IDs.

The Command-Line Interface (CLI)

To make using Signal-Fire Server as easy as possible, I have developed a command-line interface (CLI). Using the interface one can start multiple app workers and manage their lifecycle. The interface is currently a work in progress, as are all Signal-Fire modules.

The Client

The Signal-Fire Client works in combination with the Server to provide an easy to use and (almost) complete WebRTC solution. The Client abstracts away the hassle of communicating with the Server, negotiating ICE candidates, and setting up peer connections and data channels.

The Client is designed to be used in the browser. The spec has somewhat stabilized since 2016, so it is my hope the new Signal-Fire modules will be a little more future-proof.

The Future

I would like to continue development of both the Luce and Signal-Fire ecosystems. Unfortunately I lack some basic skills, like unit testing and CI. I plan to rectify the situation and refactor where necessary to get reasonable test coverage.

I intent to develop a product which includes both ecosystems as a fundamental part of its architecture. This should help me get an idea of what is actually working and important, and focus development accordingly.

It’s my hope both ecosystems will see some usage. I have deprecated a couple of modules recently and resurrected some others (like Wormhole, my IPC module). The result has been Luce and Signal-Fire. I am curious to see if they will see any use.

Back From Beyond

Back From Beyond

This blog has not been updated in a long while. So I thought it would be time to do so. This is the grand reopening of the Art of Coding blog. Welcome, grab yourself a piece of cake, and enjoy. This post will contain a summary of what I’ve been working on recently.

I have been coding Luce, the spiritual successor to Illustriws and signal-fire (which I have both officially deprecated). Luce is a versatile WebSocket server framework built for node.js. Luce uses asynchronous hooks analogous to middleware functions in, for example, Koa. I have created the beginning of an ecosystem which I hope others can use as well.

I have also resurrected signal-fire, the WebRTC Signaling Server for node.js. I have rewritten the server and client from the ground up. Both are still works-in-progress. The WebRTC signaling server and client can be used to establish peer connections between individual peers, for the exchange of video and audio, or other data. Signal-Fire helps ease the pain of implementing them directly.

In order to track peers, I have made a Registry interface which others can extend to implement client registries with multiple back-ends. This way you can scale your messaging apps with east. Included is an in-memory registry, which can be used as a reference implementation. I have also made a Redis registry, which is currently a work-in-progress.

I have done some work with Redis Streams, and as such developed redis-streams-manager, a streams manager built around the EventEmitter interface. Stream entries are emitted by stream name.

My Inter-Process Communication (IPC) module Wormhole had aged a little, so I have rewritten it in TypeScript. Now it’s future-proof and ready to be used (again).

That’s it for today. Thanks for coming, hope to see you again!