131 lines
5.8 KiB
Markdown
131 lines
5.8 KiB
Markdown
# Private stream testing
|
|
|
|
Lumi Stream Testing previews the real OBS output without publishing it to the
|
|
normal stream destination. Start it from the core **Stream testing** page in
|
|
Lumi Companion, then watch it at **Admin > Stream testing**.
|
|
|
|
## Architecture
|
|
|
|
- The existing paired-device WebSocket authenticates session creation, OBS
|
|
metrics, caption cues, stop requests, and server-ended notifications.
|
|
- The existing same-user OBS Bridge snapshots the complete current OBS service,
|
|
temporarily installs an expiring custom service, reports real output facts,
|
|
and restores the snapshot.
|
|
- Companion protects the minimum recovery record with Windows DPAPI and writes
|
|
it atomically before OBS is redirected. Normal stop, server failure, expiry,
|
|
Companion exit, WebSocket loss, and OBS restart all use that restore path.
|
|
- Core lazily starts a Lumi-managed MediaMTX process. MediaMTX accepts the
|
|
private RTMP(S) publisher and repackages the original source into low-latency
|
|
HLS without transcoding, scaling, a GPU requirement, or an adaptive ladder.
|
|
- The MediaMTX API, metrics, and HLS listeners bind only to loopback. The Admin
|
|
WebUI accesses HLS through an authenticated, no-store, same-origin streaming
|
|
proxy. RTSP, WebRTC, SRT, playback, pprof, and recording are disabled.
|
|
- Stable transcription captions are reused as a private WebVTT side channel.
|
|
No second transcription pipeline and no local speech inference are added.
|
|
|
|
Media segments stay in bounded MediaMTX memory and roll out of the short live
|
|
window. Lumi does not retain a raw stream recording or create temporary HLS
|
|
files. Session state, captions, and diagnostic facts disappear when the test
|
|
ends or Lumi restarts.
|
|
|
|
## Managed setup
|
|
|
|
No operating-system package installation, FFmpeg installation, or executable
|
|
path is required. Open **Admin > Stream testing** and choose **Install
|
|
MediaMTX**. Lumi then:
|
|
|
|
1. downloads the pinned official Windows x64 archive only after confirmation;
|
|
2. enforces download and extraction size limits;
|
|
3. verifies the exact SHA-256 checksum and archive layout;
|
|
4. probes the executable and exact expected version; and
|
|
5. atomically installs it while retaining the previous installation until the
|
|
replacement is known to be valid.
|
|
|
|
**Repair installation** repeats the same verified workflow. **Run health
|
|
check** starts MediaMTX with deny-by-default paths and tests its loopback API,
|
|
metrics, and HLS listeners; opening the page alone never downloads or starts a
|
|
runtime. `LUMI_MEDIAMTX_PATH` remains an advanced manual override for another
|
|
platform or operator-managed binary, but normal Windows installations do not
|
|
need it.
|
|
|
|
The managed release and checksum source are recorded in
|
|
`src/services/mediamtx-runtime-manifest.json`. MediaMTX's licence is retained in
|
|
the downloaded runtime and documented in
|
|
[`third-party/MediaMTX-MIT.txt`](third-party/MediaMTX-MIT.txt).
|
|
|
|
## Ingest network configuration
|
|
|
|
Lumi reuses the validated hostname from the Companion pairing record unless
|
|
`LUMI_STREAM_TEST_INGEST_HOST` overrides it. A session receives an exact
|
|
`lumi-test/<uuid>` path and high-entropy publisher credentials. Only that path
|
|
can be published, and the generated MediaMTX configuration contains SHA-256
|
|
credential hashes rather than plaintext credentials.
|
|
|
|
RTMPS is recommended for any public or routed network:
|
|
|
|
```text
|
|
LUMI_STREAM_TEST_TRANSPORT=rtmps
|
|
LUMI_STREAM_TEST_INGEST_PORT=19350
|
|
LUMI_STREAM_TEST_PUBLIC_PORT=19350
|
|
LUMI_STREAM_TEST_TLS_CERT=/absolute/path/to/fullchain.pem
|
|
LUMI_STREAM_TEST_TLS_KEY=/absolute/path/to/private-key.pem
|
|
```
|
|
|
|
The public port is the value given to OBS and can differ when a firewall or
|
|
port-forward maps it to the MediaMTX listener. Use the existing paired Lumi
|
|
hostname; no extra Stream Testing domain is required.
|
|
|
|
Unencrypted RTMP is allowed automatically only when the paired hostname
|
|
resolves entirely to loopback or private/LAN addresses:
|
|
|
|
```text
|
|
LUMI_STREAM_TEST_TRANSPORT=rtmp
|
|
```
|
|
|
|
`LUMI_STREAM_TEST_ALLOW_INSECURE_REMOTE=true` is an explicit dangerous override
|
|
for operators who understand that publisher credentials and media can cross
|
|
the network without transport encryption. It defaults to false. Restrict the
|
|
ingest port at the host firewall to the streaming network in either mode.
|
|
|
|
Optional session limits remain:
|
|
|
|
```text
|
|
LUMI_STREAM_TEST_MAX_MS=1800000
|
|
LUMI_STREAM_TEST_INACTIVITY_MS=45000
|
|
```
|
|
|
|
## Safety and recovery
|
|
|
|
Companion refuses to start while OBS is streaming or recording. During a test
|
|
its navigation status reads **PRIVATE TEST ACTIVE**. The DPAPI recovery file is
|
|
removed only after OBS confirms that the saved service type and complete
|
|
settings JSON were restored and saved.
|
|
|
|
If OBS was closed or unavailable during cleanup, open OBS and leave Companion
|
|
running. Automatic restoration resumes when the same-user bridge reconnects.
|
|
The **Repair restoration** action retries the same operation and does not create
|
|
a new session.
|
|
|
|
The receiver stops on maximum duration, lack of inbound media, process failure,
|
|
server shutdown, Companion disconnect, or administrator stop. OBS status
|
|
messages do not reset the media-inactivity clock. Only one session is allowed.
|
|
MediaMTX is reconfigured to a deny-by-default path set after every session.
|
|
|
|
## Diagnostics and verification
|
|
|
|
The Admin page reports real OBS bitrate, dropped frames, congestion, MediaMTX
|
|
path readiness, media tracks, inbound/outbound bytes, HLS viewers, discarded
|
|
frames, player latency, buffer health, stalls, errors, and caption delay.
|
|
Only an allowlist of MediaMTX API and metrics fields is exposed. Publisher
|
|
credentials are redacted from status, timeline entries, process logs, and
|
|
errors.
|
|
|
|
The runtime health check replaces the former transcoded synthetic test pattern.
|
|
Focused verification uses a fake MediaMTX process with real loopback API,
|
|
metrics, and HLS listeners:
|
|
|
|
```text
|
|
npm run verify:stream-testing
|
|
dotnet run --project companion/tests/Lumi.Companion.Core.Tests/Lumi.Companion.Core.Tests.csproj
|
|
```
|