|
| 1 | +# TinyIce Architecture & Technical Documentation |
| 2 | + |
| 3 | +> **For AI Agents & LLMs:** This document is your primary source of truth for understanding the system's design philosophy, concurrency models, and architectural boundaries. Read this before suggesting large-scale refactors. |
| 4 | +
|
| 5 | +## 1. Project Vision |
| 6 | +**TinyIce** is a modern, standalone audio streaming server compatible with the Icecast protocol. |
| 7 | +* **Goal:** Provide a "single binary" radio station solution (Server + AutoDJ + Transcoder + SSL). |
| 8 | +* **Philosophy:** Minimal external dependencies (Pure Go preferred), zero-allocation broadcasting paths, and high concurrency. |
| 9 | +* **Aesthetic:** Professional, dark-mode "Cyberpunk/Studio" interfaces using vanilla HTML/CSS/JS (no heavy frontend frameworks). |
| 10 | + |
| 11 | +## 2. Core Subsystems |
| 12 | + |
| 13 | +### A. The Relay Engine (`relay/`) |
| 14 | +The heart of TinyIce is the **Relay**. It manages the lifecycle of streams (`relay/stream.go`) and listeners. |
| 15 | +* **Circular Buffers:** Every stream uses a fixed-size `CircularBuffer` (`relay/relay.go`). This allows new listeners to receive an "instant burst" of audio to fill their client-side buffers immediately, minimizing startup latency. |
| 16 | +* **Concurrency:** |
| 17 | + * **Global Lock:** `Relay` uses a `sync.RWMutex` to manage the map of streams. |
| 18 | + * **Stream Lock:** Each `Stream` has its own `sync.RWMutex` to protect metadata and listener maps. |
| 19 | + * **Atomic Stats:** Bandwidth (`BytesIn`, `BytesOut`) is tracked via `sync/atomic` for performance. |
| 20 | + |
| 21 | +### B. AutoDJ & Streamer (`relay/streamer.go`) |
| 22 | +The **Streamer** is an internal audio source that behaves like an external source client. |
| 23 | +* **Decoding:** Uses `hajimehoshi/go-mp3` for decoding. |
| 24 | +* **Encoding:** Uses a custom native implementation (`relay/transcode.go`) to re-encode audio into chunks suitable for streaming (MP3/Opus). |
| 25 | +* **Pacing:** Crucial. The streamer must manually pace itself (sleep) to match the playback duration of the audio frames, otherwise, it would flood the buffer. |
| 26 | +* **Metadata:** ID3 tags are extracted using `bogem/id3v2` (pure Go) in a non-blocking background goroutine (`fetchTitleAndCache`) to prevent UI stalls. |
| 27 | + |
| 28 | +### C. Networking & Security (`server/socket_*.go`) |
| 29 | +* **Dual Stack:** Binds to both IPv4 and IPv6. |
| 30 | +* **Hot Swap (`SO_REUSEPORT`):** Allows a new process to bind to the *same* port while the old one is still running. The old process hands off duties and shuts down gracefully (`server/server.go` -> `HotSwap()`). |
| 31 | +* **TCP Banning:** We implement a `BannedListener` wrapper that drops connections from banned IPs at the `Accept()` level, before any TLS or HTTP overhead is incurred. |
| 32 | + |
| 33 | +### D. Web Interface (`server/templates/`) |
| 34 | +* **Technology:** Server-Side Rendered (SSR) Go templates + Vanilla JS. |
| 35 | +* **Real-time:** Uses **Server-Sent Events (SSE)** (`/admin/events`) to push JSON state updates (listeners, current song, VU meters) to the frontend. |
| 36 | +* **Studio UI:** A specific focus on "app-like" behavior using AJAX forms (`submitForm`) to avoid full page reloads during broadcast operations. |
| 37 | +* **Go Live Studio:** Enables direct browser-to-server streaming using WebAudio API. |
| 38 | + * **WebRTC Mode:** Uses `pion/webrtc` for ultra-low latency Opus streaming. |
| 39 | + * **HTTP Fallback:** Uses `MediaRecorder` to stream chunks via POST requests. |
| 40 | + |
| 41 | +## 3. Directory Structure |
| 42 | + |
| 43 | +```text |
| 44 | +tinyice/ |
| 45 | +├── main.go # Entry point. Flags, config loading, and Updater initialization. |
| 46 | +├── config/ # JSON configuration struct and defaults. |
| 47 | +├── relay/ # AUDIO CORE. |
| 48 | +│ ├── relay.go # CircularBuffer and Stream structs. |
| 49 | +│ ├── streamer.go # AutoDJ logic (playlist, queue, playback loop). |
| 50 | +│ ├── transcode.go # Native MP3/Opus encoding logic. |
| 51 | +│ ├── mpd.go # Minimal implementation of MPD protocol. |
| 52 | +│ ├── webrtc.go # WebRTC PeerConnection and Source management. |
| 53 | +│ └── client.go # Logic for pulling external relay streams. |
| 54 | +├── server/ # HTTP/TCP LAYER. |
| 55 | +│ ├── server.go # Routes, handlers, auth, middleware. |
| 56 | +│ ├── socket_*.go # OS-specific socket syscalls (SO_REUSEPORT). |
| 57 | +│ └── templates/ # HTML/CSS/JS assets. |
| 58 | +└── updater/ # Self-update mechanism (GitHub Releases). |
| 59 | +``` |
| 60 | + |
| 61 | +## 4. Key Data Flows |
| 62 | + |
| 63 | +### A. AutoDJ Playback |
| 64 | +1. `StreamerManager` selects a file from `Playlist` or `Queue`. |
| 65 | +2. File is decoded to PCM. |
| 66 | +3. Transcoder (`EncodeMP3`/`EncodeOpus`) converts PCM to streaming chunks. |
| 67 | +4. Chunks are written to the `Stream.Buffer`. |
| 68 | +5. `Stream.Broadcast` signals all waiting Listener goroutines via channels. |
| 69 | + |
| 70 | +### B. WebRTC Source (Go Live) |
| 71 | +1. Browser captures microphone via `getUserMedia`. |
| 72 | +2. Opus packets are sent via WebRTC `TrackRemote`. |
| 73 | +3. `WebRTCManager` receives RTP packets and uses `oggwriter` to mux them into Ogg pages. |
| 74 | +4. The resulting Ogg data is written directly to the `Stream.Buffer` for distribution. |
| 75 | + |
| 76 | +### C. Listener Connection |
| 77 | +1. `handleListener` (`server/server.go`) accepts HTTP request. |
| 78 | +2. `Stream.Subscribe` registers the listener and returns a buffer offset (rewound by `burst_size`). |
| 79 | +3. The listener loop reads from the `CircularBuffer` starting at that offset. |
| 80 | +4. Loop waits on a signal channel for new data to arrive. |
| 81 | + |
| 82 | +## 5. Future Roadmap & Missing Features |
| 83 | + |
| 84 | +If you are an AI agent looking to contribute, focus on these areas: |
| 85 | + |
| 86 | +### High Priority (functionality) |
| 87 | +1. **Scheduler:** The AutoDJ needs a time-based scheduler (e.g., "Play 'Jazz' playlist every Friday at 8 PM"). |
| 88 | +2. **Jingles/Sweepers:** A mechanism to inject short audio files (station IDs) between tracks or every $N$ songs. |
| 89 | +3. **Live Mic Injection:** Integrate `pion/webrtc` more deeply to allow "Go Live" directly from the browser (WebRTC -> Opus -> Internal Buffer mix). |
| 90 | +4. **S3/MinIO Support:** Allow the AutoDJ to stream files directly from object storage instead of the local filesystem (cloud-native scaling). |
| 91 | + |
| 92 | +### Medium Priority (UX/Polish) |
| 93 | +1. **Visualizer:** A server-side or client-side FFT visualizer in the Studio. |
| 94 | +2. **Request System:** A public-facing widget where listeners can request songs from the library (with rate limiting). |
| 95 | +3. **OIDC/OAuth:** Support for logging in via GitHub/Google/OIDC instead of just Basic Auth/Cookies. |
| 96 | + |
| 97 | +### Architecture Improvements |
| 98 | +1. **HLS/DASH Support:** Currently only supports progressive HTTP (Icecast). Adding HLS would improve mobile compatibility. |
| 99 | +2. **Clustering:** Allow multiple TinyIce nodes to share state/streams (Relay-chaining is already supported, but shared state is not). |
0 commit comments