BuildWithMatija
Back to Builds
LabActiveClosed source

Sports Stream

Old phones, SRT ingest, OBS switching — without bonded cellular hardware or proprietary camera rigs.

  • Kotlin
  • Android Camera2
  • RootEncoder
  • MediaMTX
  • Docker
  • SRT
  • RTSP
  • HLS
  • Node.js
  • Express
  • React
  • Vite
  • TypeScript
  • pnpm
  • GitHub Actions
GitHub
Problem
Multi-camera sports coverage usually means expensive encoders, bonded LTE backpacks, or consumer apps that do not expose clean RTSP feeds for production switching in OBS.
Thesis
Consumer Android phones with hardware H.264 encoders can publish low-latency SRT over Wi-Fi or mobile data; MediaMTX can route those feeds as RTSP inputs for OBS, with a thin control layer for pairing and remote start/stop.
Validation
End-to-end path validated on a Hetzner VPS: Android S22 publishes SRT, MediaMTX routes to RTSP, OBS consumes cam feeds. Server deploys automatically via GitHub Actions. Pairing API, QR setup, dashboard, and remote camera control are implemented and running on the dev environment. Not publicly launched — no paying users or production event deployment yet.
Proof points
  • MediaMTX server on a Hetzner VPS with automated deploy on push to master
  • OBS confirmed connecting to RTSP feeds from MediaMTX
  • Stable SRT streaming from Samsung S22 after client-side adaptive bitrate tuning
  • Three-camera path model (cam1/cam2/cam3) with per-camera auth and recording
  • QR pairing and remote start/stop validated between dashboard and Android client
Audience
  • Indie sports broadcasters running OBS multi-cam setups
  • Developers exploring phone-as-encoder pipelines
  • Anyone replacing dedicated SRT camera hardware with spare Android devices

Executive summary

Sports Stream is a monorepo I built to answer a practical question: can spare Android phones replace dedicated SRT camera hardware for multi-cam OBS productions? The stack encodes video on-device, publishes over SRT to a self-hosted MediaMTX router, and exposes RTSP feeds that OBS pulls directly. A small Node API and React dashboard sit on top for QR pairing, connection strings, camera health, and remote start/stop.

It is not a product launch. It is a working technical system — server deployed, ingest validated, production client confirmed — that proves the phone-to-OBS path is viable without custom transcoding infrastructure.

The problem

Running three or more camera angles for a local sports stream typically forces a choice between expensive gear and fragile workarounds. Bonded cellular encoders and dedicated SRT cameras work, but they are overkill for community or semi-pro coverage. Phone apps can stream to YouTube or Facebook, but they do not give OBS clean, switchable RTSP inputs. DIY setups often reinvent routing, auth, and pairing on every event.

The failure mode I was targeting: a producer with OBS and a few Android phones still cannot get stable, independently switchable camera feeds without either proprietary hardware or a brittle chain of RTMP relays and screen captures.

The thesis

The bet was that the hard parts — hardware encoding, SRT transport, and protocol conversion — already exist in mature open components. Android phones handle H.264 via MediaCodec. MediaMTX handles SRT ingest and RTSP output without acting as a production switcher. OBS remains the switcher and overlay engine.

What needed building was the glue: credential distribution so phones are not hardcoded, a control plane for start/stop during a live event, and enough operational tooling to deploy and debug the server reliably. If that glue worked, the total system cost drops to a VPS and phones already in a drawer.

Validation

What exists today:

  • A pnpm monorepo with four apps: MediaMTX server (apps/server), Android camera client (apps/android-app), Express control API (apps/api), and React dashboard (apps/web).
  • MediaMTX running on a Hetzner VPS with separate dev and prod folder clones on the same machine.
  • GitHub Actions SSH deploy for apps/server/** changes — production MediaMTX updates on push to master without manual intervention.
  • Confirmed OBS connection to RTSP output (rtsp://obs:***@host:8554/cam1).
  • Android client streaming from a Samsung S22 over SRT with hardware H.264, after resolving audio sync, SRT latency, and Wi-Fi throughput issues documented in the repo's debug log.
  • Pairing flow: dashboard serves QR codes and JSON credentials; phone scans or enters config manually.
  • Remote control: dashboard sends start/stop commands; phone polls every 3 seconds and reports bitrate, battery, and thermal status.

What does not exist yet:

  • Public release, Play Store distribution, or paying users.
  • Documented use at a live sports event in production.
  • Fully automated deploy for the API and web dashboard (still manual git pull + tmux restart on the VPS).

What I built

MediaMTX server (apps/server)

  • Docker Compose deployment of MediaMTX 1.18.2
  • SRT ingest (UDP 8890), RTSP output (TCP 8554), HLS and WebRTC outputs
  • Per-camera publish auth (cam1/cam2/cam3) and OBS read credentials
  • Automatic segment recording to disk with 7-day retention
  • Shell scripts for up/down/logs/healthcheck/deploy
  • Separate dev and prod compose files with different port mappings on one VPS

Android camera app (apps/android-app)

  • Kotlin app using RootEncoder for Camera2 capture, MediaCodec H.264/H.265 encoding, and SRT publishing
  • Connection state machine: idle → connecting → streaming → error
  • Codec, resolution, and bitrate selectors; client-side adaptive bitrate when SRT congestion is detected
  • QR pairing via ZXing (PairActivity) with manual credential fallback
  • StatusReporter: polls API every 3s for remote start/stop, pushes bitrate/battery/thermal back
  • OLED power saver mode — black screen at 5% brightness with a pulsing live indicator to extend battery during long streams

Control API (apps/api)

  • Express + TypeScript on port 3000
  • GET /pair/:cam and GET /pair/:cam/qr.png for credential distribution
  • GET /connections — full SRT/RTSP/HLS/WebRTC URL reference for all cameras
  • POST /cameras/:id/command and status polling endpoints for remote control
  • Syncs live connection state from MediaMTX API every 10 seconds
  • Serves the production React build as static files

Web dashboard (apps/web)

  • React + Vite + shadcn/ui
  • Camera status cards with connection state, bitrate, battery, thermal
  • Connection strings panel with copyable SRT/RTSP/HLS URLs and QR links
  • Auto-refreshes every 5 seconds

Shared types (packages/shared)

  • TypeScript definitions for camera IDs, server config, and SRT/RTSP URL builders

CI/CD

  • .github/workflows/deploy-server.yml — SSH deploy via appleboy/ssh-action on server changes

Related services

  • Internal tools
  • AI systems & automation

Working through something similar?

If your company has a workflow, content system, or internal process that needs to become real software, this is the kind of work I can help with.

Get in touch
Build with Matija logo

Build with Matija

Modern websites, content systems, and AI workflows built for long-term growth.

Services

  • Headless CMS Websites
  • Next.js & Headless CMS Advisory
  • AI Systems & Automation
  • Website & Content Audit

Resources

  • Case Studies
  • How I Work
  • Blog
  • CMS Hub
  • E-commerce Hub
  • Dashboard

Headless CMS

  • Payload CMS Developer
  • CMS Migration
  • Payload vs Sanity
  • Payload vs WordPress
  • Payload vs Contentful

Get in Touch

Ready to modernize your stack? Let's talk about what you're building.

Book a discovery callContact me →
© 2026Build with Matija•All rights reserved•Privacy Policy•Terms of Service
BuildWithMatija
Get In Touch