Plataforma

Todo por dentro

Una capa de gestión sobre un SFU LiveKit: ingest multi-protocolo, WebRTC sub-segundo, HLS en vivo, grabación a tu propio S3, una API REST y un SDK drop-in. Acá está el panorama técnico completo — el mano a mano con Ant Media, todas las funciones, la API y el SDK.

Arquitectura

Entra una señal, salen miles

Seguí la señal de punta a punta: un dispositivo publica una vez, el origen la pasa por tu app y sus plugins, la replica a los nodos edge y la reparte a cada espectador en WebRTC sub-segundo o HLS.

Topología de StreamHub: un dispositivo de ingesta (cámara, teléfono o encoder) publica una única señal por RTMP, WHIP o SRT al nodo origen que corre StreamHub Core (SFU LiveKit, API REST, apps multi-tenant). Dentro del origen la señal pasa por una app tenant cuyos plugins — yolo, deface, scheduled-live, live-chat — la procesan y enriquecen. El origen luego replica la señal a los nodos edge del clúster, y cada edge la reparte a muchos espectadores a la vez por WebRTC sub-segundo y HLS.

Arquitectura de streaming de StreamHub Diagrama animado: un dispositivo de ingesta transmite al nodo origen, los plugins procesan la señal, el origen la replica a los nodos edge y los edges la reparten a muchos espectadores. RTMP · WHIP · SRT replicación WebRTC · HLS Dispositivo de ingesta Origen — StreamHub Core SFU LiveKit · API · apps app: cams App (tenant) PLUGINS yolo deface scheduled-live live-chat Nodos edge edge-01 edge-02 Espectadores
Ingesta

Una señal de entrada — RTMP, WHIP o SRT desde cualquier cámara, teléfono o encoder.

Proceso

La app y sus plugins enriquecen la señal: detección, enmascarado de privacidad, programación, chat.

Distribución

El origen replica a los nodos edge; cada espectador recibe WebRTC sub-segundo o HLS en vivo.

StreamHub vs Ant Media Enterprise

Todo lo que le pedís a Ant Media EE, open source y self-hosted

StreamHub cubre el feature-set de Ant Media Server Enterprise para streaming real — medido, no prometido — y suma las piezas que siempre nos faltaron: webhooks firmados, tenancy por app y un marketplace de plugins. Licencia AGPL, gratis mientras dura la beta, y tu media nunca sale de tu infra.

0.19s

de latencia WebRTC — p50 medido sobre 601 muestras en producción

$0

de licencia — open source (AGPL). Ant Media EE: ~USD 109/mes por instancia

1 línea

para instalar — curl | sudo bash en Ubuntu 24.04 / 26.04 LTS

Licencia y precio

StreamHub · Open source (AGPL). Sin licencia por instancia — gratis mientras dura la beta.

Ant Media EE · Propietario. ~USD 109/mes (~USD 1.068/año) por instancia.

Latencia WebRTC

StreamHub · 0.19s p50, medido end-to-end sobre 601 muestras en producción.

Ant Media EE · ~0.5s según su marketing. Ambos son sub-segundo de verdad.

Webhooks

StreamHub · Cada evento se postea firmado con HMAC-SHA256, verificable en tu backend.

Ant Media EE · Webhooks sin firma — confiás en quien llama.

Grabación → S3

StreamHub · MP4 a tu propio bucket por app + snapshots periódicos, VODs indexados con paginación y descarga presignada.

Ant Media EE · También graba MP4/WebM a S3 — acá hay paridad.

Multi-tenant

StreamHub · Cada app es un tenant real: rooms, S3, base de datos, tokens, cuotas, teams y roles aislados.

Ant Media EE · Las applications separan settings y streams.

SDK de migración

StreamHub · @streamhub/adaptor shimea el WebRTCAdaptor de Ant Media: mismos callbacks y métodos, sin reescribir.

Ant Media EE · Su propio SDK WebRTCAdaptor.

Plugins

StreamHub · Marketplace con verticales andando: detección YOLO, cockpit CCTV, radio, watermark, live chat.

Ant Media EE · SDK de plugins en Java — los construís vos.

Cluster e instalación

StreamHub · Origin + edge; un edge se suma con un comando y un token. Instalador one-liner idempotente, TLS incluido.

Ant Media EE · Cluster origin + edge (feature EE); instalación por script más setup de licencia.

Observabilidad

StreamHub · Prometheus /metrics nativo + Grafana, y logs con retención de 30 días directo en el panel.

Ant Media EE · Pipeline de monitoreo vía Kafka hacia Grafana.

Sin humo

Ant Media EE es un producto maduro y hoy sigue adelante en granularidad de configuración (~170 settings por app), SDKs móviles nativos y restream multi-destino — esto último está arriba de nuestro roadmap. Si eso es lo que te bloquea hoy, preferimos decírtelo ahora.

¿Venís de Ant Media?

Cambiás el import del SDK — tus callbacks siguen funcionando.

Funciones

Un media server completo, self-hosted

WebRTC, RTMP, WHIP, RTSP y HLS; grabación a tu S3; realtime, multi-tenant, webhooks firmados y un SDK WebRTC liviano. Sobre LiveKit, self-hosted.

Streaming

Ingest y salida multi-protocolo

Entrá por donde quieras, salí en WebRTC de baja latencia o en HLS embebible.

WebRTC de baja latencia

sub-segundo

Player WebRTC sobre LiveKit con latencia sub-segundo para "ver en vivo ahora" y videollamadas. Tokens de subscribe efímeros por room.

Ingest RTMP

RTMP · OBS

Push desde OBS/ffmpeg a rtmp://…:1935/live/<key>. Stream key + password opcional: StreamHub corta el push que no se validó antes.

WHIP

WebRTC-HTTP

Endpoint WHIP para publicar desde el navegador o encoders modernos por WebRTC, sin pasar por RTMP.

RTSP relay

RTSP pull

Tirá de una fuente remota (rtsp://camara/stream) y republicala en la room. Ideal para cámaras IP y NVRs.

HLS en vivo

video.js

Egress HLS segmentado servido en /hls/<app>/<room>/index.m3u8 (video.js, CORS abierto). ~6-15s, embebible en cualquier lado.

Grabación y salida

Grabá en tu propio S3, restreameá a donde quieras

La media es tuya: se sube a tu bucket. Las salidas van a YouTube, Twitch o tu CDN.

Grabación a TU S3

AWS · Wasabi · MinIO

Egress a MP4 y subida a tu propio bucket S3 (AWS, Wasabi, MinIO). Un bucket/prefijo por app; las claves nunca viven en el YAML.

VOD listo para reproducir

VOD

Cada grabación queda como VOD en tu S3 con snapshot, metadatos (duración/resolución/codec) y URL pública o presignada.

Split MP4 por partes

split N min

Cortá la grabación cada N minutos: cada parte es su propio MP4 = su propio VOD, indexado y con callback recording_part_ready.

Snapshots periódicos

JPEG cada Ns

Capturá un JPEG cada N segundos durante la grabación, subido a tu S3. También snapshots on-demand de cualquier room.

Broadcast webcam → RTMP

YouTube · Twitch

Reenviá una room a un RTMP/RTMPS externo (YouTube/Twitch/custom) con el widget Transmitir: webcam del navegador → restream.

Realtime

Interacción en vivo y eventos

Chat, reacciones y viewers sobre data-channels; webhooks firmados de todo lo que pasa.

Chat en vivo

data-channel

Chat sobre data-channels de LiveKit (con emojis). El backend puede inyectar mensajes y dispara el callback chat_message.

Reacciones

reactions

Reacciones animadas flotantes sobre el topic reaction: corazones y likes en tiempo real, con su callback reaction.

Contador de viewers

en vivo

Conteo de subscribers reales por stream en vivo, excluyendo publishers y participantes ocultos/QC. Exportado a Prometheus.

Webhooks firmados

HMAC-SHA256

StreamHub postea un JSON firmado (HMAC-SHA256) por CADA evento: room, participantes, ingress/egress, grabación, VOD y HLS.

Players embebibles

/play · /embed

Páginas públicas /play y /embed + snippet iframe. Players WebRTC y HLS sin auth, con panel de chat/reacciones/viewers incluido.

Escala

Multi-tenant, adaptativo y observable

Apps aisladas, transcoding adaptativo con GPU opcional y métricas Prometheus de todo.

Transcoding adaptativo

720 / 480 / 240

Ladder de renditions vía simulcast de LiveKit + ingress multi-layer para un player adaptativo por app, sin config extra.

GPU opcional

NVENC · VAAPI

Detección de GPU por nodo (NVIDIA nvidia-smi / VAAPI /dev/dri) y hwaccel auto/gpu/cpu por app. Nunca falla si no hay GPU.

Apps multi-tenant aisladas

apps

Cada "app" es un tenant: rooms/streams namespaced, su S3, sus VODs/DB, sus tokens y callbacks. Totalmente aisladas.

Teams, roles y cuotas

RBAC · quotas

Equipos aislados por tenant, roles/permisos y cuotas: apps, streams concurrentes, minutos de grabación y GB de egress al mes.

Observabilidad

Prometheus

Métricas Prometheus en /metrics (streams, viewers, VODs, uploads S3, callbacks, GPU…), health probe, stats y logs consultables.

Per-app SQLite

SQLite

Registro global streamhub.db + una vods.db por app. Sin base pesada que operar: SQLite por tenant y media en S3 por app.

Operaciones

Un backoffice que maneja toda la flota

Todo lo que antes hacías por SSH, ahora en el panel: tableros por app, logs, VODs, cluster, configuración del server y backups.

Tablero por app

stats · filtros

Cada app tiene su propio tablero: streams activos, viewers en vivo, ingress/egress y actividad de grabación, filtrable por tenant.

Gestión de logs

retención 30 días

Logs globales y por app con rotación a 30 días, consultables y paginados desde la API y el panel. Sin SSH.

Biblioteca de VODs + descarga

paginado · presigned

Listado paginado de VODs por app con snapshots y metadatos, más descarga en un click vía URLs S3 presignadas.

Gestor de cluster

origin + edge

Cada nodo con sus stats y su salud, directo en el dashboard. Un edge se suma al cluster con un token y un comando.

Panel de configuración del server

sin editar YAML

Configuración general del server desde el backoffice, estilo Ant Media: ajustá el server sin tocar archivos por SSH.

Backups + runbook

restore · rollback

Backups automáticos de las bases SQLite y la config por app, con un camino documentado de restore y rollback.

Devs

API, SDK drop-in y open source

Todo por API, todo self-hosteable. Sumás el SDK y empezás a publicar en pocas líneas.

SDK JS drop-in

@streamhub/adaptor

Un SDK JavaScript liviano: sumás @streamhub/adaptor (npm o un <script>) y StreamHubAdaptor te deja publicar y suscribirte por WebRTC en pocas líneas.

API REST

/api/v1

API bajo /api/v1 con envelope { data, error }. Apps, ingress, grabación, VODs, tokens, broadcast y HLS: todo por HTTP.

Auth + API tokens

JWT · sk_ tokens

Auth built-in (signup/login JWT, teams, superadmin) + API tokens sk_ para server-to-server. Bearer en todos los endpoints.

Radio / audio-only

audio-only

Rooms audio-only (voz estilo Discord) + modo radio: un locutor publica y los oyentes entran subscribe-only ocultos, con listen-token público.

Open source o hosted

self-host · hosted

Self-hosteable de punta a punta (Docker + LiveKit). En beta y gratis. ¿No querés operarlo? Lo hosteamos por vos.

Documentación

Docs y API

Un stack completo y self-hostable, documentado de punta a punta. Una API REST (global y por app), webhooks firmados, config por app, integraciones nativas y un deploy en un comando. Cada ruta vive detrás de un único dominio, con un explorador OpenAPI en vivo.

Funciones

Guías a fondo por función, de WebRTC a las cuotas.

  • WebRTC · ingest · HLS en vivo
  • Grabación → S3 · VOD
  • Transmisión · transcoding/GPU
  • Chat · reacciones · espectadores

API Global

Superficie REST de todo el server, protegida por tokens sk_.

  • GET /health · /stats
  • CRUD /apps
  • POST /tokens (emite sk_)
  • GET /logs
Abrir en Swagger →

API por app

Todo acotado a una única app tenant.

  • tokens · ingress · grabación
  • vods · streams · snapshots
  • HLS start/stop
  • config · capas de transcoding
Abrir en Swagger →

Webhooks y callbacks

Eventos entrantes de LiveKit y POST firmados salientes.

  • firma HMAC-SHA256
  • stream_started / _ended
  • vod_ready · recording_failed
  • chat_message · reaction

Referencia de config

El config.yaml por app, sin secretos.

  • recording · rtmp · webrtc
  • bucket S3 por app
  • bloque features
  • callbacks url + secret

Integraciones

Clientes nativos y de dispositivos, y el protocolo que habla cada uno.

  • Android (livekit-android)
  • iOS (LiveKitClient)
  • C++ (ffmpeg → RTMP)
  • ESP32-CAM → relay → RTMP

Self-hosting

Un curl | sudo bash — o docker compose up.

  • instalador one-liner (Ubuntu LTS)
  • join-cluster con un token
  • runbook · backups · rollback
  • Prometheus + Grafana

Arquitectura

Cómo está construido y hacia dónde va.

  • core mono-Node + LiveKit
  • modelo de datos SQLite por app
  • cluster origin + edge
  • WebRTC vs HLS/CDN

La API REST en cinco llamadas

Autenticá con un sk_ token. Los nombres de sala llevan el prefijo de la app (live + demolive-demo).

base · https://streamhub.digitalhub.com.ar/api/v1
# Scaffold an isolated tenant: config, per-app SQLite, S3 prefix, samples
curl -s -X POST https://streamhub.digitalhub.com.ar/api/v1/apps \
  -H "Authorization: Bearer $STREAMHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"live","displayName":"Live","roomPrefix":"live"}'
# One call returns the LiveKit token + wsUrl + play/embed URLs
curl -s -X POST https://streamhub.digitalhub.com.ar/api/v1/apps/live/tokens \
  -H "Authorization: Bearer $STREAMHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"room":"demo","identity":"viewer-1","canPublish":false,"ttl":"10m"}'
# → { "data": { "token": "<jwt>", "wsUrl": "wss://media.digitalhub.com.ar",
#              "room": "live-demo", "playUrl": "...", "embedUrl": "...", "iframe": "..." } }
# RTMP push endpoint (also: whip, or url for RTSP/HLS pull)
curl -s -X POST https://streamhub.digitalhub.com.ar/api/v1/apps/live/ingress \
  -H "Authorization: Bearer $STREAMHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inputType":"rtmp","room":"demo","enableTranscoding":true}'
# → { "data": { "ingressId": "IN_abc123", "streamKey": "sk-9f3c...", "roomName": "live-demo" } }

# then push with any RTMP encoder (OBS, ffmpeg, a drone...)
ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac \
  -f flv "rtmp://media.digitalhub.com.ar:1935/live/<streamKey>"
# Room-composite MP4 → the app's own bucket (AWS / Wasabi / MinIO) → VOD + snapshot
curl -s -X POST https://streamhub.digitalhub.com.ar/api/v1/apps/live/recording/start \
  -H "Authorization: Bearer $STREAMHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"roomName":"live-demo"}'
# → { "data": { "vodId": 12, "egressId": "EG_xyz789", "status": "recording" } }

# stop it (by VOD id or egress id); a vod_ready webhook fires when the upload finishes
curl -s -X POST https://streamhub.digitalhub.com.ar/api/v1/apps/live/recording/12/stop \
  -H "Authorization: Bearer $STREAMHUB_TOKEN"
# Start a live HLS egress for a stream (video.js-compatible, embeddable)
curl -s -X POST \
  https://streamhub.digitalhub.com.ar/api/v1/apps/live/streams/live-demo%2Fcamera-1/hls/start \
  -H "Authorization: Bearer $STREAMHUB_TOKEN"
# → { "data": { "playlistUrl":
#       "https://streamhub.digitalhub.com.ar/hls/live/live-demo/index.m3u8" } }

# the playlist itself needs no auth — point any HLS player at it
open https://streamhub.digitalhub.com.ar/hls/live/live-demo/index.m3u8
Webhooks firmados HMAC-SHA256
// Every callback is a signed POST. Verify the HMAC-SHA256 over the raw body.
import crypto from 'node:crypto';

app.post('/streamhub', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.header('X-StreamHub-Signature');                 // "sha256=<hex>"
  const expected =
    'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
  if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
    return res.status(401).end();

  const evt = JSON.parse(req.body.toString('utf8'));              // { event, app, data }
  switch (evt.event) {
    case 'stream_started':   /* a publisher/ingress went live */  break;
    case 'vod_ready':        /* recording uploaded to your S3 */  break;
    case 'recording_failed': /* upload failed, local file kept */ break;
  }
  res.status(200).end();
});
Self-host en un comando curl | sudo bash
# Open source — one command provisions a full node (Ubuntu 24.04/26.04 LTS):
curl -fsSL https://www.streamhub.studio/install.sh | sudo bash
# docker + LiveKit + ingress/egress + core + nginx/TLS + seeded API token. Idempotent.

# Prefer to wire the pieces yourself? (non-interactive install)
curl -fsSL https://www.streamhub.studio/install.sh | sudo bash -s -- \
  --non-interactive --domain media.example.com --email you@example.com
# then edit /opt/streamhub/.env  (LiveKit keys, per-app S3, PUBLIC_BASE_URL)

# Swagger / OpenAPI:  /api/v1/docs      Metrics:  /metrics      Health:  /api/v1/health

Esto es un recorrido, no el mapa completo — la referencia entera cubre arquitectura, operación, testing y cada variable de entorno. Exploralo en vivo en los docs OpenAPI, o leé los streamhub-docs en el repo.

streamhub-adaptor

Un SDK WebRTC liviano — publicá y suscribite en pocas líneas

@streamhub/adaptor es un SDK JavaScript liviano para publicar y suscribirte por WebRTC, construido sobre livekit-client. Habla el mismo idioma que el WebRTCAdaptor de Ant Media — mismos callbacks por string, mismos métodos — así que un front-end existente de Ant Media migra cambiando el import, no reescribiéndolo.

migrando desde Ant Media: cambiás un import
- import { WebRTCAdaptor } from "@antmedia/webrtc_adaptor";
+ import { StreamHubAdaptor } from "@streamhub/adaptor";

// Same callbacks, same methods — your Ant Media front-end keeps working.
const adaptor = new StreamHubAdaptor({ /* config below */ });
Instalar npm
npm install @streamhub/adaptor livekit-client
import { StreamHubAdaptor } from "@streamhub/adaptor";

const adaptor = new StreamHubAdaptor({
  // StreamHub mints the LiveKit token for you (prefer a pre-minted token + wsUrl in prod)
  streamhubApiUrl:   "https://streamhub.digitalhub.com.ar/api/v1",
  appName:           "live",
  streamhubApiToken: STREAMHUB_TOKEN,        // dev only — mint server-side for production
  mediaConstraints:  { video: true, audio: true },
  localVideoId:      "localVideo",           // <video id="localVideo"> preview element
  callback: (info, obj) => {
    if (info === "initialized")        adaptor.joinRoom("demo", "camera-1");
    else if (info === "joinedTheRoom") adaptor.publish(obj.streamId);   // send cam + mic
    else if (info === "publish_started") console.log("on air");
  },
  callbackError: (err, msg) => console.warn(err, msg),
});
import { StreamHubAdaptor } from "@streamhub/adaptor";

const viewer = new StreamHubAdaptor({
  streamhubApiUrl:   "https://streamhub.digitalhub.com.ar/api/v1",
  appName:           "live",
  streamhubApiToken: STREAMHUB_TOKEN,
  isPlayMode:        true,                    // subscribe-only: no camera / mic
  callback: (info, obj) => {
    if (info === "initialized")        viewer.joinRoom("demo", "viewer-1");
    else if (info === "joinedTheRoom") viewer.play(obj.ATTR_ROOM_NAME);
    else if (info === "newStreamAvailable") {
      const el = document.createElement("video");
      el.autoplay = el.playsInline = true;
      el.srcObject = new MediaStream([obj.track]);   // obj.track is a MediaStreamTrack
      document.getElementById("remote").append(el);
    }
  },
});
¿Sin build? Sumá una sola etiqueta IIFE · CDN
<!-- No build step? Drop in one script tag and you're ready. -->
<script src="https://streamhub.digitalhub.com.ar/sdk/streamhub-adaptor.global.js"></script>
<script>
  const viewer = new StreamHubAdaptor({ isPlayMode: true, /* ...config */ });
</script>
Reproductor embebible <iframe>
<!-- The mint call returns a ready-to-paste embed. Public player, no SDK needed. -->
<iframe
  src="https://streamhub.digitalhub.com.ar/embed/live/live-demo"
  width="640" height="360" frameborder="0"
  allow="autoplay; fullscreen; camera; microphone"
  allowfullscreen>
</iframe>

Drop-in del WebRTCAdaptor de Ant Media

mismos callbacks — initialized, publish_started, newStreamAvailable, data_received… — cambiás el import y tu código queda

Métodos

joinRoom, publish, play, sendData, switchVideoCameraCapture, enableStats…

Control de dispositivo y bitrate

cambiá cámara o micrófono al vuelo y ajustá el bitrate por emisor, en vivo

Canales de datos

chat y reacciones viajan por DataPackets de LiveKit; canPublishData va en cada token

LiveKit maneja simulcast y streaming adaptativo de forma nativa. Para producción, emití los tokens del lado del server y pasá token + wsUrl para que el token de administración nunca llegue al navegador.

¿Listo para levantarlo?

Instalá un nodo completo en Ubuntu LTS con un comando, o entrá a la app hosteada.