Van server naar client

Hoe het gedemoduleerde geluid, het spectrum, de S-meter en alle knoppen tussen de ThetisLink-server en jouw client heen en weer reizen — een uitleg in gewone taal. Met plaatjes.

Nederlands  ·  English

Het grote idee

De server staat thuis, vlak naast de radio en Thetis. De client (op je laptop, pc of Android-telefoon) kan overal staan — in de woonkamer, op kantoor, aan de andere kant van de wereld. Tussen die twee loopt één dunne netwerkverbinding. Daarover moet alles: het geluid van de ontvanger, het spectrum- en watervalbeeld, de signaalsterkte, én elke knop die je indrukt.

De grote uitdaging is vertraging (latency). Als je de zendknop indrukt of aan de afstemknop draait, moet dat nu gebeuren — niet een halve seconde later. Daarom is heel ThetisLink gebouwd rond één principe:

Ontwerpprioriteit. Latency > bandbreedte > features. Zo min mogelijk vertraging in de audio en de zendknop staat bovenaan. Alles wat onnodig vertraging toevoegt — extra buffers, wachtrijen, bevestigingen heen en weer — wordt vermeden.

RadioANAN / Yaesu Thetisvia TCI TL2-serverWindows-pc netwerkUDP · poort 4580 client — laptop/pc client — Android jijkoptelefoon
Figuur 1 — De keten. De radio en Thetis maken het geluid en het spectrum; de TL2-server pakt dat in en stuurt het over het netwerk; de client speelt het af en stuurt jouw bedieningen terug.

Dit document gaat over het rechterstuk: de TL2-server → het netwerk → de client. Hoe het geluid ontstaat (de demodulatie, de FFT-channelizer) staat in het zusterdocument “Hoe een VRX werkt”.

Inhoud

1. Twee soorten verkeer

Alles wat over de lijn gaat valt in twee groepen, en die hebben heel verschillende eisen:

Beide groepen reizen over dezelfde verbinding, maar de manier waarop bepaalt of het systeem snel en soepel aanvoelt. Dat brengt ons bij de belangrijkste keuze.

2. Waarom UDP en geen TCP

Er zijn twee manieren om data over internet te sturen. Een vergelijking met de post helpt:

Voor live audio is dat tweede precies wat je wilt. Een verloren pakketje van 20 ms hoor je hooguit als een minuscuul klikje; daar wachten zou veel erger zijn. ThetisLink gebruikt daarom UDP — voor álle verkeer, audio én opdrachten.

Maar opdrachten mogen toch niet verloren gaan? Klopt. Daarvoor is een ander trucje: de server stuurt voortdurend de actuele stand terug (de frequentie, de mode…). Zie je na een druk op de knop de waarde niet veranderen, dan stuurt de client hem desnoods opnieuw. Geen trage bevestiging per pakket; wel zekerheid via de teruggemelde stand.

In ThetisLink. Eén UDP-socket op poort 4580 draagt alles: audio, spectrum, S-meter, instellingen en de zendknop. Geen aparte TCP-verbinding. De server vergroot wel zijn UDP-buffers, want de standaard van Windows is te klein voor de grote spectrum-pakketten.

3. De server vinden (auto-discovery)

Voordat er iets kan reizen, moet de client weten waar de server staat. Dat kan op twee manieren:

In ThetisLink. Auto-discovery gebruikt de standaard mDNS (service-type _thetislink._udp); de server zet zijn versie en een vriendelijke naam in de aankondiging. Buiten het lokale netwerk: handmatig adres en poort 4580.

4. Eén pakket, één envelop

Omdat alles over dezelfde socket reist, moet de ontvanger van elk pakketje meteen kunnen zien wat het is. Daarom begint elk pakket met een korte, vaste kop van 4 bytes — als het adres op een envelop:

0xAAherkenteken versieprotocol = 3 typeaudio? spectrum?… vlaggenPTT, breedband… inhoudde rest van het pakket — 4 bytes kop —
Figuur 2 — Elke envelop opent met een herkenteken, het protocolnummer, het type (audio, spectrum, frequentie, S-meter, …) en een paar losse vlaggen. Daarna volgt de inhoud die bij dat type hoort.

Het type is de kern: daaraan ziet de ontvanger of dit een stukje RX1-audio is, een spectrumrij, een nieuwe frequentie, een S-meterstand of een druk op de zendknop. Zo kan één socket tientallen verschillende soorten berichten door elkaar dragen zonder dat ze verward raken.

Analogie. Eén brievenbus, maar elke brief heeft linksboven een duidelijk label: “GELUID”, “BEELD”, “KNOP”. De postsorteerder hoeft de brief niet eens te openen om te weten waar hij heen moet.

5. Audio: Opus over UDP

Het gedemoduleerde geluid (uit de VRX-keten, of rechtstreeks van Thetis of een Yaesu) is een stroom audiomonsters. Die ongecomprimeerd versturen zou onnodig veel bandbreedte kosten. Daarom wordt het eerst gecomprimeerd met de Opus-codec — een moderne, zeer efficiënte audiocompressie die speciaal goed is in lage vertraging.

Het geluid wordt in hapjes van 20 ms geknipt; elk hapje wordt apart als Opus-blokje gecodeerd en in één UDP-pakket gestopt. Naast de Opus-bytes zelf zitten in dat pakket twee belangrijke getallen:

kop volgnummerseq tijdstempeltimestamp lengteopus-len Opus-gecomprimeerd geluid~20 ms audio
Figuur 3 — Een audiopakket: de standaardkop, een volgnummer, een tijdstempel, de lengte, en daarna het Opus-blokje met ongeveer 20 ms geluid. (Voor een VRX-kanaal zit er ook nog een klein kanaalnummer bij, zodat VRX1 en VRX2 uit elkaar te houden zijn.)

Smal of breed — dezelfde keuze als in de VRX-keten

Net als bij de iFFT-keuze (zie het VRX-document) kan de audio smalband of breedband zijn:

Welke van de twee bepaalt de client met één schakelaar; de server codeert daarop. (Op de TX-kant — als je zelf zendt — wordt altijd breedband gebruikt voor de beste microfoonkwaliteit.)

In ThetisLink. Opus, 20 ms-frames. Voor de gewone Thetis-RX is de codec op spraak afgesteld (met foutcorrectie/FEC en stilte-onderdrukking/DTX, zodat een verloren pakketje deels herstelbaar is en stilte bijna geen data kost). Voor de VRX-kanalen staat de stilte-onderdrukking juist uit (en geen FEC) — dat is continue ontvangst, geen telefoongesprek, en je wilt ook de ruis tussendoor horen. De Yaesu-audio heeft een eigen afstelling per smal- of breedband.

6. Veel geluidsstromen over één lijn

ThetisLink kan meer dan één ding tegelijk laten horen: de hoofdontvanger (RX1), de tweede ontvanger (RX2/VFO-B), de virtuele ontvangers VRX1 en VRX2, en het geluid van een aangesloten Yaesu-radio. Al die stromen reizen door dezelfde socket. Hoe blijven ze uit elkaar?

Heel simpel: elk soort stroom heeft zijn eigen pakkettype (en elk een eigen volgnummer-teller). De client ziet aan het type-label meteen in welk audiokanaal een pakketje thuishoort en stuurt het naar de juiste afspeel-buffer.

RX1 RX2 VRX1 / VRX2 Yaesu één socketpoort 4580 buffer RX1 buffer RX2 buffer VRX1/2 buffer Yaesu type-label houdt ze uit elkaar
Figuur 4 — Alle audiokanalen gaan door dezelfde socket en worden aan de ontvangstkant op hun type-label weer uit elkaar gehaald, elk naar zijn eigen afspeel-buffer.

Daarnaast bestaat er een “gebundelde” variant die meerdere kanalen in één pakket stopt met hetzelfde volgnummer en tijdstempel — handig als kanalen exact gelijk moeten lopen (bijvoorbeeld een stereo links/rechts-beeld).

7. De jitter-buffer

Pakketjes reizen niet allemaal even snel over het netwerk. De één doet er 8 ms over, de volgende 21 ms, soms komt er één vóór zijn voorganger aan. Die wisselende vertraging heet jitter. Zou je elk pakketje meteen afspelen zodra het binnenkomt, dan klonk het hakkelig en door elkaar.

De oplossing is een kleine jitter-buffer aan de clientkant: een wachtkamertje van een handvol pakketjes. Binnenkomende pakketten worden daar op volgnummer op de juiste plek gelegd; het afspelen loopt er met een vaste, rustige tik doorheen. Zo wordt een hobbelige aankomst een vloeiende weergave.

aankomst — onregelmatig, soms verwisseld 1 2 4 3 5? jitter-buffer — sorteert op volgnummer weergave — gelijkmatig, op volgorde 1 2 3 4 ~5 5 mist → kort opgevuld zo klein mogelijk gehouden — elke extra plek is extra vertraging
Figuur 5 — Pakketten komen ongelijk en soms verwisseld binnen (4 vóór 3). De buffer sorteert ze op volgnummer en geeft ze gelijkmatig door. Mist er één, dan vult de codec dat gaatje kort op in plaats van te stoppen.

Hier zit precies de afweging uit het begin: een diepere buffer is gladder maar trager; een ondiepe buffer is sneller maar gevoeliger voor uitval. ThetisLink houdt de buffer daarom zo klein mogelijk en past de diepte automatisch aan: meet hij weinig jitter, dan krimpt de buffer (minder vertraging); wordt het netwerk grillig, dan groeit hij net genoeg om haperingen te voorkomen.

In ThetisLink. De buffer meet de jitter continu (een voortschrijdend gemiddelde, met een snelle reactie op pieken) en mikt op de kleinste diepte die nog vloeiend speelt — doorgaans maar een paar frames, dus enkele tientallen milliseconden. Een verloren pakketje vult Opus kort op door het gat te overbruggen (PLC); op de spraak-RX, waar FEC aanstaat, kan een deel zelfs écht hersteld worden. Raakt de buffer toch leeg, dan wordt heel even gepauzeerd en bijgevuld in plaats van te gaan stotteren.

8. Het spectrum over de lijn

Het spectrum- en watervalbeeld is een rij bins (zie het VRX-document): per bin een waarde die zegt hoeveel energie daar zit. Zo'n rij kan groot zijn — duizenden tot tienduizenden bins. Die elke keer volledig en op volle precisie sturen zou veel bandbreedte kosten, dus hier speelt de tweede prioriteit: bandbreedte.

Twee knoppen houden dat in toom:

In elk spectrumpakket zitten naast de bins ook de middenfrequentie, de breedte (span) en een referentieniveau, zodat de client het beeld op de juiste plek en schaal kan tekenen. En net als bij audio heeft elke bron — RX1, RX2, VRX1, VRX2 — zijn eigen pakkettype.

In ThetisLink. Het zoomen en pannen gebeurt grotendeels op de server: de client vraagt “ik wil dít stukje, op deze resolutie”, en de server stuurt alleen dat uitgesneden stuk in plaats van altijd het hele brede beeld. Dat scheelt fors in data zonder dat je detail inlevert waar je naar kijkt.

9. De S-meter

De signaalsterkte komt langs drie verschillende wegen binnen, afhankelijk van de bron:

De schaal (de vertrouwde S-units: S9 = −73 dBm, elke S-unit 6 dB) wordt altijd in de client getekend. De server levert het rauwe getal; de client maakt er de naald van.

In ThetisLink. Wie de waarde berekent verschilt dus per bron, maar het tekenen van de S-meter is overal in de client gelijk — zo ziet elke meter er hetzelfde uit.

10. Instellingen en knoppen

Draai je aan de afstemknop of kies je een mode, dan stuurt de client een klein opdracht-pakketje: meestal niet meer dan een identificatie (“dit is het volume”, “dit is de mode”, “dit is de filterbreedte”) plus een waarde. Frequentie en mode hebben zelfs hun eigen pakkettype. Dat is alles — een paar bytes, meteen verstuurd.

Zoals in hoofdstuk 2 al bleek: er komt geen aparte bevestiging terug. In plaats daarvan meldt de server voortdurend de actuele stand terug. Die teruggemelde waarde is je bevestiging: zie je de frequentie meeveranderen, dan is de opdracht aangekomen. Zo blijft de client altijd in sync met wat de radio écht doet, ook als iemand aan de radio zelf draait.

Vraagt de client bij verbinden de hele stand op? Nee. Er is geen grote “geef-mij-alles”-uitwisseling. De server zendt zijn toestand toch al doorlopend uit, dus binnen een seconde na verbinden heeft de client vanzelf de frequentie, mode, S-meter, spectrum en apparaatstatus binnen.
In ThetisLink. Opdrachten zijn “afvuren-en-vergeten” (één id + waarde). De teruggemelde stand dient als bevestiging; klopt die na een druk niet, dan kan de client het zonder ophef opnieuw sturen.

11. De zendknop (PTT)

De zendknop is het meest tijdkritische signaal van allemaal — hier telt elke milliseconde. Daarom is er geen apart, traag knopbericht. In plaats daarvan zet de client een vlag in de TX-audiopakketten: zodra je de knop indrukt, dragen je uitgaande audiopakketjes het PTT-vlaggetje, en de server schakelt de radio naar zenden. Het indrukken en je spraak reizen zo in één en dezelfde stroom mee — niets dat op elkaar hoeft te wachten.

Omdat meerdere clients tegelijk verbonden kunnen zijn, bewaakt de server dat er maar één tegelijk zendt. Wil een tweede client zenden terwijl de eerste al bezig is, dan krijgt die een kort “geweigerd”-bericht terug in plaats van dat ze door elkaar gaan praten.

Veiligheid: de zender blijft niet ongewild aan staan

Bij remote bediening is dit cruciaal: een zender die per ongeluk blijft “hangen” (blijft zenden) is gevaarlijk — voor je apparatuur, voor de band en voor je vergunning. Daarom is de zendknop bewust geen aan/uit-grendel, maar een vlag die de client zo'n 50× per seconde opnieuw meestuurt en bevestigt. De zender blijft dus alléén aan zolang die stroom van “PTT-aan”-pakketjes blijft binnenkomen.

Valt de verbinding weg terwijl je zendt — wifi hapert, de laptop valt in slaap, de app crasht — dan stopt die stroom vanzelf, en grijpen twee onafhankelijke vangnetten in:

Het ergste wat een netwerkstoring dus kan doen, is je zender binnen een fractie van een seconde tot hooguit twee seconden terugzetten naar ontvangst — nooit eindeloos laten doorzenden. Dat is het klassieke dodemansknop-principe (dead-man's switch).

In ThetisLink. Voor de Thetis-zender is PTT een vlag in de TX-audiopakketten, geen losse handshake. De server regelt de exclusiviteit (één zender tegelijk) en meldt een botsing met een PTT-geweigerd-bericht; tijdens zenden wisselt ook de S-meter van ontvangst-sterkte (dBm) naar uitgangsvermogen (watt). Twee veiligheidstimers vangen een wegvallende verbinding op: na ~500 ms zonder pakketten, of ~2 s zonder heartbeat, valt TX automatisch terug naar RX (met alarm). Voor een aangesloten Yaesu-radio loopt de zendknop niet via de audiovlag maar als losse opdracht, die de server als CAT-commando naar het toestel stuurt.

12. Verbinden en beveiligen

Bij het verbinden wisselen client en server eerst kort uit wat ze allebei kunnen. De client vertelt welke mogelijkheden hij ondersteunt (breedband-audio, spectrum, een tweede ontvanger…), de server antwoordt met de doorsnede: alleen wat ze allebei aankunnen wordt gebruikt. Zo zet een nieuwere kant zijn extra's vanzelf uit tegenover een oudere — binnen dezelfde protocolversie. Een heel andere protocolversie wordt wél geweigerd; server en clients moeten dan samen worden bijgewerkt.

Staat de server open op internet, dan kun je een wachtwoord instellen. Het wachtwoord zelf gaat nooit over de lijn: de server stuurt een willekeurige “uitdaging”, de client beantwoordt die met een berekend antwoord op basis van het wachtwoord (HMAC), en optioneel komt er nog een tijdscode (TOTP, zoals een authenticator-app) overheen.

In ThetisLink. De mogelijkheden-uitwisseling loopt mee in het hartslag-bericht (heartbeat) dat de verbinding ook levend houdt. Authenticatie is optioneel en alleen nodig als de server van buiten bereikbaar is.

13. Het latency-budget

Tel je alles bij elkaar op, dan zie je waar de vertraging tussen “geluid bij de radio” en “geluid in je koptelefoon” vandaan komt:

Opus-frame~20 ms netwerk (heen)afhankelijk van afstand jitter-bufferpaar frames, zo klein mogelijk afspelengeluidskaart het netwerk-deel kun je niet wegnemen; al het andere wordt zo klein mogelijk gehouden
Figuur 6 — De vaste brokjes (één Opus-frame, de jitter-buffer, het afspelen) zijn elk maar enkele tientallen milliseconden. De netwerkreis zelf is het enige stuk dat ThetisLink niet in de hand heeft — daarom is al het overige zo strak mogelijk gehouden.

Dit is het netwerk- en codecbudget, vanaf het moment dat de audio klaarstaat om te verzenden. Voor VRX-audio komt daar vóór de Opus-codering nog de channelizer-blokvertraging bij (~16 ms, zie het VRX-document); voor de Yaesu-radio's spelen de USB-CODEC en CAT mee.

Dit is waarom de keuzes in dit document zijn zoals ze zijn: UDP in plaats van TCP, korte Opus-frames, een minimale adaptieve buffer, opdrachten zonder trage bevestiging, en de PTT-vlag mee in de audiostroom. Stuk voor stuk dezelfde regel: haal de vertraging weg die je kúnt weghalen.

Tot slot — alles samen

De server pakt het geluid (gecomprimeerd met Opus, in hapjes van 20 ms), het spectrum (bins, compact gecodeerd) en de S-meter in genummerde pakketjes, en stuurt die over één UDP-verbinding op poort 4580 naar de client. Jouw bedieningen reizen als kleine opdracht-pakketjes terug; de server meldt de stand voortdurend, zodat client en radio in sync blijven. Een minimale jitter-buffer maakt van de hobbelige aankomst weer vloeiend geluid, en overal staat hetzelfde voorop: zo min mogelijk vertraging.

Samen met het zusterdocument “Hoe een VRX werkt” heb je daarmee de hele keten te pakken: van radiogolf, via demodulatie, tot het geluid en beeld op je scherm — waar je ook bent.