Releases: DatanoiseTV/tinyice
Releases · DatanoiseTV/tinyice
v2.6.3
v2.6.2
v2.6.2 - .deb + .rpm packages on every release Adds Debian + RPM packaging via nFPM. Per-arch packages (amd64, arm64) ship alongside the raw binaries on every tagged release. The package creates a tinyice system user, installs a hardened systemd unit, and MASKS the unit on install so it can't start accidentally before the operator configures it. No runtime / API changes.
v2.6.1 — chained Ogg-Opus + transcoder flap survival
Three-layer fix for the long-running auto-transcoder failure on robodj-style sources that rotate their Ogg logical stream between tracks. Pure Go end-to-end (no CGO introduced).
Fixed
- Chained Ogg-Opus decoder. Replaced
kazzmir/opus-go'sPacketReader(which pins the bitstream serial on first page and errors out on every new BOS) with a small pure-Go Ogg page reader that handles RFC 3533 §3 chained logical streams transparently. Each BOS resets the per-stream state (channels, preskip) and re-initialises the decoder; audio decoding is continuous across track-boundary rotations. - Codec swap to libopus-transpiled, lenient with real-world packets. Initial cut used
pion/opusfor the codec. Strict RFC 6716 validation rejected several real-world packets per minute (code-1 even-payload, ≤120 ms duration, VBR overrun, CBR divisibility) — each reject was a silent ~20 ms gap audible as a skip. Switched tokazzmir/opus-go's codec, which is libopus transpiled to pure Go viaccgo(no cgo) and matches reference-C tolerance.pion/opusdropped fromgo.mod. - Transcoded outputs survive source flaps.
HealthMonitor.checkskips auto-remove for streams flaggedIsTranscoded. A brief upstream disconnect (8-36 s is routine for robodj) no longer turns into an end-to-end outage with the player hitting 404 and giving up. - No stale audio burst on source-resume. New
Stream.FlushAtHeadbumps a per-stream flush generation, wakes every listener, and snapsMinListenerOffsetto the current buffer head. Listeners (existing and any auto-reconnecting subscribers) skip the stale buffered MP3 from before the gap and pick up at the live edge. - Stalled-pump watchdog kept as a safety net (extended 8 s → 30 s) — chain rotation no longer triggers it, so it only fires on a genuine decoder hang.
Upgrade notes
Drop-in. No config changes, no public API changes.
Full changelog: https://github.com/DatanoiseTV/tinyice/blob/v2.6.1/CHANGELOG.md
v2.6.0
v2.6.0 — transcoder leak fix + map rewrite
Fixed:
- Goroutine leak in transcoder retry loop. mirrorTranscodeMetadata
was spawned with the outer transcoder ctx instead of a per-
invocation child, so every source reconnect cycle leaked one
mirror goroutine + its references. Production accumulated
1052 leaked goroutines and 777 MB RSS over ~73 hours.
Fix: per-invocation context, defer-cancel.
- Transcoder auto-restart gap reduced from ~2 minutes to ~5 s.
The decoder hub pump's exit didn't close the orphaned PCM
fanout stream; subscribers stayed blocked until HealthMonitor
swept the stale entry after 2 minutes. Pump's defer now
RemoveStream's the PCM mount.
Changed:
- Dashboard + kiosk maps rewritten on MapLibre GL JS pointing
at openfreemap.org. The previous Leaflet + CARTO setup re-flew
the camera and re-created markers on every SSE tick — never
settled. New shared <LiveGeoMap> diffs markers in place and
only refits the camera when the set of cities changes.
v2.5.0
v2.5.0 — security release Patches a pre-auth stream-injection vulnerability in the WebRTC source-ingest endpoint plus adjacent auth-gap and stability fixes. See CHANGELOG.md. Security (CVE pending): Missing authentication on /webrtc/source-offer let any network-reachable user publish arbitrary audio/video to any mount, replacing the legitimate broadcast. Affected: >= 0.8.95, <= 2.4.1. Fixed: 8067d6b. CWE-306. CVSS 3.1: 7.4 High (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L). Operators upgrading from any 0.8.x / 0.9.x / 0.10.x / 0.11.x / 2.0.x – 2.4.x release should also rotate per-mount source passwords.
v2.4.1
v2.4.1 — fix listener handler stalling under load (WAL + async UA)
Recurring symptom: HTTPS goes unresponsive after burst listener
connects. Login UI hangs, /healthz times out, CLOSE_WAIT
accumulates. Journal showed /relay/history.go:126 INSERT INTO
user_agents serialising at >1 s each.
Root cause: synchronous RecordUA on the listener/source connect
hot path + SQLite default rollback-journal/full-fsync. Every
listener connect blocked the handler for the duration of a full-
file fsync; bursts queued behind the write lock; login (which
also touches the DB) waited behind them.
Fix:
- PRAGMA journal_mode=WAL + synchronous=NORMAL + busy_timeout=5000
on the history DB connection. Writers no longer fsync the
whole file; per-write latency drops ~200x.
- RecordUA now runs its INSERT in a fire-and-forget goroutine
so the listener / source handler returns immediately.
v2.4.0
v2.4.0 — live listener map (CartoDB / DB-IP), quarter/year/lifetime t…
v2.3.2
v2.3.2 — fix recurring HTTPS hang (per-write listener deadline, per-r…
v2.3.1
v2.3.1 — perf microoptimisations
Broadcast() Ogg page-magic scanner: byte-by-byte loop replaced with
bytes.IndexByte('O') skip-ahead. ~16x fewer comparisons for a typical
4-8 KiB Broadcast on an Opus mount.
mirrorTranscodeMetadata: tick 2 s → 5 s. RLock acquisitions on each
input cut by 2.5x; latency for catching a track-change is unchanged
in practice (the YP / dir.xiph.org directory polls minute-cadence).
No behaviour change.
v2.3.0
v2.3.0 — shared per-input decoder hub Each transcoder used to open its own PCMDecoder, so a single Opus source feeding three auto-mp3 outputs and one opus output ran four redundant decoders over the same input bytes. DecoderHub keeps one decoder per input mount. The first transcoder that wants the input triggers the pump goroutine: subscribe to input, open decoder, broadcast PCM into an internal Stream named <inputMount>/_pcm. Every subsequent transcoder for the same input attaches a SubscribeInternal to that PCM stream, wraps it in a readerDecoder shim (io.Reader + SampleRate()), and feeds its own encoder. Refcount-managed: the last transcoder release brings the pump down, so the next Acquire pays a fresh decoder warm-up but idle inputs do not hold one open. Empirical CPU on the 3-source / 10-encoder configuration: v2.2.0 baseline ~100 % v2.2.1 ~50 % v2.2.2 ~17 % v2.3.0 ~12 % This is a MINOR bump rather than PATCH because the internal relay/transcode contract changed (TranscoderManager now owns a DecoderHub; performTranscode no longer opens PCMDecoders directly). External API surface — config, HTTP routes, /admin/traffic, etc. — is unchanged.