Files
tuner/plan.md
Scott Register 2e66b8c73d Add project plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 09:23:31 -08:00

13 KiB

Restreamer — Project Plan

Overview

Restreamer is a self-hosted, single-container streaming relay that presents a unified web video player to viewers. It supports two ingest sources:

  1. OBS/RTMP ingest — streamers push RTMP directly to the server (like Twitch/Owncast)
  2. IPTV relay — an admin selects a channel from an M3U playlist, and the server fetches the upstream HLS stream and rebroadcasts it to all viewers through a single connection to the provider

All viewers connect to the same output stream regardless of the source. The admin panel controls which source is active and, for IPTV mode, which channel is playing.

Deployment target: VM or LXC container on Proxmox, on rented bare-metal in a datacenter.


Architecture

┌──────────────────────────────────────────────────────────────┐
│  Docker Container (entrypoint: Go backend)                   │
│                                                              │
│  ┌──────────┐    RTMP     ┌───────────┐                     │
│  │ OBS/RTMP │────────────▶│ MediaMTX  │──── HLS/WebRTC ──┐  │
│  │ Streamer │             │ (video    │                   │  │
│  └──────────┘             │  engine)  │                   │  │
│                           └─────▲─────┘                   │  │
│                                 │ RTMP push               │  │
│  ┌──────────┐  pulls HLS ┌─────┴─────┐                   │  │
│  │ Upstream │◀────────────│  FFmpeg   │                   │  │
│  │ IPTV     │             │ (remux    │                   │  │
│  │ Provider │             │  relay)   │                   │  │
│  └──────────┘             └───────────┘                   │  │
│                             ▲       ▲                     │  │
│                  spawn/kill │       │ spawn/restart        │  │
│                    FFmpeg   │       │ MediaMTX             │  │
│                           ┌─┴───────┴──┐                  │  │
│                           │ Go Backend │                  │  │
│                           │ (API +     │                  │  │
│                           │  control)  │                  │  │
│                           └─────┬──────┘                  │  │
│                                 │ serves                  │  │
│                           ┌─────▼──────┐                  │  │
│                           │ React/Vite │                  │  │
│                           │ Frontend   │◀─────────────────┘  │
│                           │ (viewer +  │  (player fetches    │
│                           │  admin)    │   HLS stream)       │
│                           └────────────┘                     │
│                                                              │
└──────────────────────────────────────────────────────────────┘

Components

Component Role Technology
MediaMTX Video engine — RTMP ingest, HLS/LL-HLS/WebRTC output mediamtx binary
FFmpeg Pulls upstream IPTV HLS, remuxes and pushes RTMP into MediaMTX FFmpeg (no transcoding, copy codecs)
Go Backend REST API, M3U parsing, process management (MediaMTX + FFmpeg), admin logic, serves frontend Go (net/http, stdlib)
React Frontend Video player (hls.js), admin panel, source/channel selector React + Vite, hls.js
Process Manager Go backend manages MediaMTX and FFmpeg as child processes Built into Go backend (os/exec)

Ingest Paths

Path 1: OBS / RTMP Direct

OBS ──RTMP──▶ MediaMTX (rtmp://server:1935/live/stream)
                  │
                  ▼
            Viewers (HLS/WebRTC via MediaMTX)
  • OBS pushes to rtmp://<host>:1935/live/stream
  • MediaMTX receives and makes it available as HLS at http://<host>:8888/live/stream
  • The Go backend detects the stream is active (via MediaMTX API or webhook)
  • Frontend player connects to the HLS/WebRTC endpoint

Path 2: IPTV Relay

Admin selects channel ──▶ Go Backend parses M3U ──▶ spawns FFmpeg
                                                        │
IPTV Provider ◀──HLS pull──── FFmpeg ──RTMP push──▶ MediaMTX
                                                        │
                                                   Viewers (HLS/WebRTC)
  • Admin uploads or the container mounts an M3U playlist
  • Admin picks a channel from the parsed playlist in the web UI
  • Go backend spawns FFmpeg:
    ffmpeg -i <upstream_hls_url> -c copy -f flv rtmp://localhost:1935/live/stream
    
  • MediaMTX receives the RTMP push and serves it to all viewers
  • Only one upstream connection to the IPTV provider regardless of viewer count
  • When admin switches channels, Go backend kills the FFmpeg process and spawns a new one

Feature Scope

MVP (Phase 1)

  • Docker container with MediaMTX, FFmpeg, Go backend, React frontend
  • Go backend
    • REST API for admin operations
    • M3U playlist parser (EXTINF, group-title, tvg-logo, etc.)
    • Process manager for MediaMTX and FFmpeg (spawn, kill, monitor, restart)
    • Source switcher (OBS vs IPTV, and which IPTV channel)
    • Serves the built React frontend as static files
    • Basic health/status endpoint
  • React frontend
    • Video player page using hls.js
    • Admin panel (toggle source, browse/search IPTV channels, select channel)
    • Stream status indicator (live/offline, current source, viewer count if available)
  • MediaMTX configuration
    • RTMP ingest on port 1935
    • HLS output on port 8888
    • Preconfigured paths for the live/stream path
  • M3U playlist support
    • Parse standard M3U/M3U8 IPTV playlists
    • Extract channel name, group, logo URL, stream URL
    • Search/filter channels in admin UI
    • Playlist loaded via bind mount at /data/playlist.m3u

Phase 2 (Future)

  • Admin authentication (env var password, then optional user accounts)
  • Viewer authentication (optional shared password)
  • LL-HLS support via MediaMTX configuration
  • WebRTC playback option (MediaMTX supports this natively)
  • Playlist upload via admin UI (vs bind mount only)
  • Multiple concurrent IPTV channels (viewers choose which to watch)
  • EPG/guide data support (XMLTV)
  • Stream recording/DVR
  • Viewer count tracking
  • HTTPS/TLS termination (or document reverse proxy setup)
  • OBS stream key authentication

API Design (Go Backend)

Public Endpoints

Method Path Description
GET / Serves the React frontend
GET /api/status Current stream status (source, channel name, live/offline)

Admin Endpoints

Method Path Description
GET /api/admin/channels List all channels from the M3U playlist
GET /api/admin/channels?search=<q>&group=<g> Search/filter channels
GET /api/admin/groups List all channel groups from the playlist
POST /api/admin/source Set active source { "source": "iptv" | "obs" }
POST /api/admin/channel Select IPTV channel { "channel_id": "..." }
POST /api/admin/playlist/reload Re-parse the M3U playlist from disk
GET /api/admin/process/status Process status for MediaMTX and FFmpeg (running, pid, uptime, errors)

Directory Structure

restreamer/
├── plan.md                 # This file
├── Dockerfile              # Single all-in-one container
├── mediamtx.yml            # MediaMTX configuration
│
├── backend/                # Go backend
│   ├── go.mod
│   ├── go.sum
│   ├── main.go             # Entry point, HTTP server
│   ├── api/                # HTTP handlers
│   │   ├── admin.go        # Admin endpoints
│   │   ├── status.go       # Public status endpoint
│   │   └── middleware.go   # CORS, logging, (future: auth)
│   ├── m3u/                # M3U playlist parser
│   │   └── parser.go
│   ├── process/            # Child process management (FFmpeg + MediaMTX)
│   │   ├── ffmpeg.go       # FFmpeg spawn/kill/monitor
│   │   └── mediamtx.go     # MediaMTX spawn/monitor/restart
│   └── models/             # Shared types
│       └── types.go
│
├── frontend/               # React + Vite frontend
│   ├── package.json
│   ├── vite.config.ts
│   ├── index.html
│   ├── src/
│   │   ├── main.tsx
│   │   ├── App.tsx
│   │   ├── components/
│   │   │   ├── Player.tsx          # hls.js video player
│   │   │   ├── AdminPanel.tsx      # Admin controls
│   │   │   ├── ChannelList.tsx     # IPTV channel browser
│   │   │   └── StatusBar.tsx       # Stream status display
│   │   ├── api/
│   │   │   └── client.ts          # API client for Go backend
│   │   └── types/
│   │       └── index.ts
│   └── public/
│
└── data/                   # Runtime data (bind mount target)
    └── playlist.m3u        # IPTV playlist (mounted in)

Docker Setup

Single Container Strategy

  • Base image: ubuntu:24.04 or alpine:3.19
  • Installed: MediaMTX binary, FFmpeg, Go backend binary, built React static files
  • Entrypoint: The Go backend binary — it spawns MediaMTX as a child process and manages its lifecycle
  • The Go backend serves the React build output as static files (no separate web server needed)

Ports

Port Service Protocol
1935 MediaMTX RTMP ingest RTMP (TCP)
8080 Go backend (web UI + API) HTTP
8888 MediaMTX HLS output HTTP
8889 MediaMTX WebRTC (future) HTTP

Note: In production, ports 8080 and 8888 could be unified behind a reverse proxy. For MVP, they stay separate.

Volumes / Bind Mounts

Container Path Purpose
/data/playlist.m3u IPTV M3U playlist file

Environment Variables

Variable Default Description
RESTREAMER_PORT 8080 Go backend listen port
MEDIAMTX_RTMP_PORT 1935 RTMP ingest port
MEDIAMTX_HLS_PORT 8888 HLS output port
PLAYLIST_PATH /data/playlist.m3u Path to M3U playlist

Build & Run

Development

# Backend
cd backend && go run .

# Frontend
cd frontend && npm install && npm run dev

# MediaMTX (download binary and run locally)
./mediamtx mediamtx.yml

Docker

# Build
docker build -t restreamer .

# Run
docker run -d \
  --name restreamer \
  -p 1935:1935 \
  -p 8080:8080 \
  -p 8888:8888 \
  -v /path/to/playlist.m3u:/data/playlist.m3u:ro \
  restreamer

Key Design Decisions

  1. MediaMTX as the video engine — supports RTMP, HLS, LL-HLS, WebRTC, and RTSP. Modular enough to experiment with different delivery methods later without changing the rest of the stack.

  2. FFmpeg for IPTV relay (passthrough)ffmpeg -c copy remuxes without transcoding. Minimal CPU usage. The Go backend manages the FFmpeg lifecycle.

  3. Single stream path — both OBS and IPTV push to the same MediaMTX path (live/stream). Viewers always connect to one URL. Switching sources is seamless from the viewer's perspective.

  4. Go backend as the orchestrator and entrypoint — lightweight, single binary, manages both MediaMTX and FFmpeg as child processes, parses M3U, serves the API and static frontend. No external database needed (state is in-memory for MVP). No supervisord — the Go binary is the container entrypoint and owns the full process tree.

  5. React/Vite frontend embedded in Go binary — built at Docker build time, served as static files by the Go backend. Single port for the entire web experience.

  6. No transcoding — passthrough only. Keeps CPU usage low and simplifies the pipeline. Can be revisited in Phase 2.


Implementation Order

  1. Project scaffolding — Go module, React/Vite app, directory structure
  2. M3U parser — parse playlists, extract channels
  3. Process manager — spawn/kill/monitor child processes (MediaMTX + FFmpeg)
  4. Go API server — REST endpoints, serve static files
  5. MediaMTX config — configure for RTMP ingest + HLS output
  6. React frontend — player (hls.js), admin panel, channel list
  7. Dockerfile — multi-stage build, all-in-one container
  8. Integration testing — end-to-end with a test stream