diff --git a/docs/audio-ingest-rework.md b/docs/audio-ingest-rework.md index 6e4e6f5..0f0249a 100644 --- a/docs/audio-ingest-rework.md +++ b/docs/audio-ingest-rework.md @@ -11,6 +11,35 @@ Dieses Dokument beschreibt das Zielbild. Der aktuelle Ist-Stand in Phase 1 ist: ## Ziel `fm-rds-tx` soll mittelfristig mehrere Audio-Ingest-Pfade sauber unterstützen, ohne den bestehenden `ffmpeg`-Pfad kaputt zu machen. +## Einordnung des Phase-1-Ergebnisses +Mit Phase 1 wurde die Audio-Zuführung erstmals als eigenständiges Subsystem vor den bestehenden TX-/DSP-Pfad gezogen. +Die bestehende Sendekette bleibt weitgehend unangetastet; neue Ingest-Quellen laufen stattdessen über eine gemeinsame Runtime-Schicht, die Lifecycle, Formatwandlung und Basistelemetrie bündelt und weiterhin in den bestehenden `audio.StreamSource` einspeist. + +Konkret umfasst dieser Stand: +- gemeinsame Ingest-Runtime +- zentrale Source-Auswahl für `stdin`, `http-raw` und `icecast` +- Umstellung von `/audio/stream` auf den Ingest-Pfad +- Runtime-/Source-Stats im Control-Plane-Output +- Icecast-Adapter mit Reconnect-/Decoder-Policy +- Decoder-Layer mit explizitem Fallback-Pfad + +Wichtig ist die ehrliche Abgrenzung: +Die Decoder-Architektur ist vorhanden, aber native Decoder für `mp3`, `oggvorbis` und `aac` sind aktuell noch Platzhalter. Praktisch funktionsfähig ist der Icecast-Pfad derzeit vor allem über den expliziten `ffmpeg`-Fallback. Das ist für Phase 1 akzeptabel, weil die strukturelle Trennung jetzt sauber steht und spätere native Decoder nicht mehr die Runtime-Architektur verbiegen müssen. + +## Warum das ein sinnvoller Abschluss von Phase 1 ist +Phase 1 hatte nicht das Ziel, sämtliche Transport- und Codecvarianten produktionsreif abzuschliessen. Ziel war vielmehr, die bisher punktuellen Audio-Eingänge in ein gemeinsames, erweiterbares Modell zu überführen. Genau das ist erreicht: +- die TX-Schicht kennt keine Source-Familien mehr direkt +- HTTP- und CLI-Ingest hängen nicht mehr als Sonderfälle im Startcode +- Icecast ist als echter Source-Typ modelliert +- Decoder-Fallback ist explizit statt implizit +- die Control Plane kann Ingest-Zustand sichtbar machen + +## Nächster sinnvoller Schritt +Der nächste Block ist nicht noch mehr Runtime-Umbau, sondern gezielte inhaltliche Vervollständigung: +1. echte native Decoder für MP3 und Ogg/Vorbis +2. danach AAC/ADTS, sofern Bibliothekslage und Streaming-Verhalten sauber genug sind +3. erst danach zusätzliche Familien wie AoIP/SRT in die gemeinsame Runtime ziehen + Die strategische Richtung ist daher **nicht** „ffmpeg sofort ersetzen“, sondern: - bestehenden `ffmpeg`-Pfad als universellen Fallback behalten diff --git a/docs/config.plutosdr.json b/docs/config.plutosdr.json index 1cb9738..2a9939c 100644 --- a/docs/config.plutosdr.json +++ b/docs/config.plutosdr.json @@ -1,7 +1,7 @@ { "audio": { "inputPath": "", - "gain": 1.0, + "gain": 1, "toneLeftHz": 400, "toneRightHz": 2000, "toneAmplitude": 0.3 @@ -14,31 +14,89 @@ "pty": 0 }, "fm": { - "bs412Enabled": true, - "bs412ThresholdDBr": 0, - "frequencyMHz": 100.0, + "frequencyMHz": 102.8, "stereoEnabled": true, "pilotLevel": 0.09, "rdsInjection": 0.04, "preEmphasisTauUS": 50, - "outputDrive": 1.0, - "mpxGain": 1.0, + "outputDrive": 1, "compositeRateHz": 228000, "maxDeviationHz": 75000, "limiterEnabled": true, - "limiterCeiling": 1.0, - "fmModulationEnabled": true + "limiterCeiling": 1, + "fmModulationEnabled": true, + "mpxGain": 1, + "bs412Enabled": true, + "bs412ThresholdDBr": 0 }, "backend": { "kind": "pluto", "device": "usb:", - "driver": "", - "uri": "", - "deviceArgs": {}, "outputPath": "", "deviceSampleRateHz": 2280000 }, "control": { "listenAddress": "127.0.0.1:8088" + }, + "runtime": { + "frameQueueCapacity": 3 + }, + "ingest": { + "kind": "icecast", + "prebufferMs": 1500, + "stallTimeoutMs": 3000, + "reconnect": { + "enabled": true, + "initialBackoffMs": 1000, + "maxBackoffMs": 15000 + }, + "stdin": { + "sampleRateHz": 44100, + "channels": 2, + "format": "s16le" + }, + "httpRaw": { + "sampleRateHz": 44100, + "channels": 2, + "format": "s16le" + }, + "icecast": { + "url": "http://192.168.1.40:8000/stream", + "decoder": "native", + "radioText": { + "enabled": true, + "prefix": "", + "maxLen": 64, + "onlyOnChange": true + } + }, + "srt": { + "url": "", + "mode": "listener", + "sampleRateHz": 48000, + "channels": 2 + }, + "aes67": { + "sdpPath": "", + "sdp": "", + "discovery": { + "enabled": false, + "streamName": "", + "timeoutMs": 3000, + "interfaceName": "", + "sapGroup": "", + "sapPort": 0 + }, + "multicastGroup": "", + "port": 0, + "interfaceName": "", + "payloadType": 97, + "sampleRateHz": 48000, + "channels": 2, + "encoding": "L24", + "packetTimeMs": 1, + "jitterDepthPackets": 8, + "readBufferBytes": 1048576 + } } }