yc_
cd ../projects
Live 2026 Solo — media servers, signalling, infra

HubStream

A globally distributed WebRTC SFU — mesh routing between regional media servers, so latency tracks the nearest edge instead of the host.

Topology

SFU + inter-server mesh

Media stack

mediasoup

Deployment

Multi-region, Terraform

Fan-out cost

1 uplink per publisher

Why an SFU, and why distributed

A full-mesh WebRTC call makes every participant encode and upload a stream for every other participant. It is lovely at three people and unusable at ten. An SFU fixes the fan-out: each client publishes once, and the server forwards the stream to everyone else — no transcoding, no re-encoding, just routing.

That solves the bandwidth shape but not geography. A single-region SFU means a participant in Taipei and a participant in Frankfurt both pay a round trip to whichever region happens to host the room. So HubStream runs media servers in several regions and routes between them: each participant connects to their nearest server, and the servers forward between themselves over a pipe.

Topology diagram — mesh vs. single SFU vs. distributed SFU

Three small panels in one SVG; the fan-out arrows tell the whole story

Architecture

  • Media plane: mediasoup workers, one router per room shard, PipeTransports linking routers across regions
  • Signalling: WebSocket service handling join, transport negotiation, and producer/consumer lifecycle
  • Client: Next.js app driving getUserMedia, device negotiation, and adaptive layer selection
  • Infra: Docker images deployed per region, provisioned via Terraform on AWS

End-to-end flow — join, negotiate, publish, consume

Sequence diagram, or a screen capture of two clients connecting

The parts that were actually hard

Signalling state is the real complexity of a conferencing system. A room is a graph of producers and consumers that changes on every join, leave, mute, reconnect and network flap, and every one of those transitions has to leave both ends agreeing on what exists. Most of the debugging time went here, not into the media path.

Cross-region piping adds a second failure surface: a participant's stream now traverses two servers, so a stall has to be attributed to the publisher's uplink, the inter-region pipe, or the subscriber's downlink. That attribution question is what pushed the observability work that became the next project.

Short clip — multi-party call running across regions

Screen capture with the stats overlay visible

The 2026 rebuild

The original build predated the SFU work — it was a mesh prototype. The rebuild replaced the media path wholesale with mediasoup, split signalling out of the app server, and moved deployment to Terraform so a new region is a variable rather than an afternoon.

What I would do next

  • Simulcast layer selection driven by measured downlink rather than a fixed ladder
  • Room sharding across routers on a single host to use more than one core per room
  • Automated region failover when an inter-server pipe degrades

Stack

MediasoupWebRTCNext.jsNode.jsDockerTerraformAWS