= CDN This documentation describes our Livestreaming CDN as of 2024. The File-CDN for media.ccc.de is described on [[software:voctoweb]]. == The Future of Streaming For redundancy and ease of use the CDN is managed by a distributed system built on consul. Damit ist es möglich redundante CDN-Master sowie redundante Ingest-Server zu betreiben und trotzdem ein Web-Backend mit allen relevanten Streaming-Infos bereitzustellen. Weiterhin könnte die Streaming-Webseite intelligent auf das Vorhandensein/Fehlen von Streams im CDN reagieren und zusätzliche Metadaten von Encodern verarbeiten. Ein weiterer Vorteil des angedachten Setups sind deutlich geringere Latenz durch den fehlenden Fanout, sowie deutlich schnellere Stream-Restarts durch aktive Benachrichtigung der Transcoder. === Übersicht {{drawio>diagram1.png}} ==== Repo Links * Stream-api, Upload-Proxy, Upload-Server: https://github.com/voc/stream-api * rtmp-auth daemon: https://github.com/voc/rtmp-auth * Transcoding-Script: https://github.com/voc/transcoding == Architecture The CDN-Cascade has 5 stages: Master-Encoder, Ingest, Transcoder, Master-Relays and finally Edge-Relays. {{:cdn_overview.png?1200|}} === 1. Master-Encoder The master stream encoding is created near the stage on the encoder PC running voctomix or on with other videoencoder for third party streams. The master encoding contains a 1080p25 video signal. Das Master-Encoding entsteht auf dem encoder-cube im Saal aus dem Ausgabesignal des Voctomix. Das Master-Encoding enthält den Mix als 1080p25 in h264 sowie die Slides als 1080p5 in h264 mit bis zu drei Audiospuren in AAC (Native, Translated, Translated-2). Wahlweise können die Übersetzerspuren sowie die Slide-Spur weggelassen werden. Alle Spuren werden in einem Matroska-Container verpackt. Das Master-Encoding wird von einem Script erzeugt, welches vom ansible aus folgendem Template erzeugt wird: https://github.com/voc/cm/blob/master/ansible/roles/encoder/templates/voctomix-scripts/streaming-sink-mkvonly.sh.j2 Das Master-Encoding wird auf den lokalen (= auf dem encoder-cube laufenden) Icedist (= Icecast zur internen Distribution) auf Port 7999 gepusht (http://encoderX.lan.c3voc.de:7999/sX). Der Icedist auf dem Master-Relay (z.B. ''live.ber.c3voc.de'') pullt diesen und bietet ihn seinerseits auf http://live.ber.c3voc.de:7999/sX an. ==== Debugging http://195.54.164.164:7999 (oder http://live.ber.c3voc.de:7999 im Inkognito-Modus damit einen der Browser nicht zu HTTPS zwingen will) ``` voc@live.ber:/etc/icecast2$ systemctl status icedist 2019-08-20 21:52:20 ● icedist.service - distribution Icecast Loaded: loaded (/etc/systemd/system/icedist.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-07-30 19:50:07 CEST; 3 weeks 0 days ago Main PID: 794 (icecast2) Tasks: 25 (limit: 4915) CGroup: /system.slice/icedist.service └─794 /usr/bin/icecast2 -c /etc/icecast2/icedist.xml sudo tail -f /var/log/icedist/error.log ``` === 1.5 Exkurs Stream-API Die "Stream-API" ist aktuell ein statisches JSON-File mit Pfaden und Transcoder-Zuordnungen für aktuelle Streams. Aktuelles Beispiel siehe https://live.ber.c3voc.de/stream_info.json (Zugang im Keepass unter stream-api). Das JSON wird periodisch auf dem Master Relay von einem Skript durch die Abfrage von Icedist/Icecast-Instanzen (lokal, ingest, etc.) erstellt. Damit enthält es alle Streams die aktuell oder kürzlich (bis zum timeout) auf dem icedist/icecast ankamen. Weiterhin wird anhand einer Config automatisiert ein (nicht-voller) Transcoder zum Stream zugeordnet. Jeder Transcoder hat in der Config eine "Kapazität" d.h. eine Maximalzahl von möglichen Streams anhand derer die Verteilung gewählt wird. === 2. Transcoder Das Transcoding läuft auf verschiedenen Transcodern. Aktuelle Zuordnung siehe ''event''-Inventory im ansible https://github.com/voc/cm/blob/master/ansible/event#L49 "alb". Jeder Transcoder pollt regelmäßig die Stream-Api und startet/stoppt entsprechende Systemd-Units der Form "transcode@sX.target". Abhängig von der Hardware starten diese entweder einzelne "transcode_h264@sX.service", "transcode_vpx@sX.service", etc. Units oder einen einzelnen "transcode_vaapi@sX.service". Die Pull/Push-Konfiguration jedes Streams wird aus der Stream-API entnommen und in ein File entsprechend "/opt/transcoder/config/sloop". Die Transcoding-Services verwenden dann diese Datei als EnvironmentFile. Die Quelle eines transkodierten Streams ist immer eine Icecast-URL der Form http://host:port/sX und das Ziel ist immer eine Icecast-URL der Form http://host2:port2/sX_format. (Beispiel: http://live.ber.c3voc.de:7999/s1 -> http://live.ber.c3voc.de:7999/s1_h264) Die transkodierten Formate sind dabei: h264, vpx (VP9), audio (MP3, Opus) und thumbnail (MJPEG mit 0.1Hz). Dementsprechend z.B.: * http://live.lan.c3voc.de:7999/sX_h264 * http://live.lan.c3voc.de:7999/sX_vpx * http://live.lan.c3voc.de:7999/sX_audio * http://live.lan.c3voc.de:7999/sX_thumbnail Die Scripte dazu werden vom ansible aus folgenden Templates erzeugt: https://github.com/voc/cm/tree/master/ansible/roles/transcoder/templates/transcoder Da jeder Format-Stream aus einem einzelnen ffmpeg-Prozess stammt und in einem Container landet sind die darin enthaltenen Videoströme Zeitsynchron zueinander. ==== Verwaltung Die Verteilung der Transcodings wird wie oben erwähnt über die Stream-API realisiert. Dadurch werden die Streams immer gleichmäßig verteilt und es gibt keine doppelten Zuweisungen. Die Maximalzahl der Streams pro Transcoder und eventuelle Stream-Bindungen an bestimmte Transcoder können über Variablen im ansible gesteuert werden. Um einen Überblick über die derzeit aktivierten Transcodings zu erhalten kann folgender Befehl verwendet werden: voc@tweety.int:~$ systemctl list-units 'trans*' 2018-01-23 0:22:42 UNIT LOAD ACTIVE SUB DESCRIPTION transcode_s1_audio.service loaded active running Transcoder audio Stream s1 transcode_s1_h264.service loaded active running Transcoder h264 Stream s1 transcode_s1_vpx.service loaded active running Transcoder vpx Stream s1 transcode_s2_audio.service loaded active running Transcoder audio Stream s2 … transcode_s1.target loaded active active All Transcoders of Stream s1 transcode_s2.target loaded active active All Transcoders of Stream s2 … Der Zustand des API-Clients ist gelegentlich sinnvoll abzufragen sudo journalctl -afu update_transcoding === 3. Fanout Die Format-Streams je Raum werden von der nächsten Stufe auf dem Master-Relay (''live.ber.c3voc.de'') in die finalen Streams in allen für Endnutzer angebotenen Kombinationen auseinander gemuxt (="fanout"). Dabei entstehen alle Kombinationen aus ''sX_[hd|sd|slides]_[native|translated|translated-2]'' in webm, hls und dash sowie ''sX_[native|translated|translated-2].[mp3|opus]'' und die Thumbnails. Die WebM- und die Audio-Streams werden gegen den Icecast auf http://live.ber.c3voc.de:8000/ gepusht, die HLS- und DASH-Streams werden vom nginx unter http://live.ber.c3voc.de/hls/ bzw. http://live.ber.c3voc.de/dash/ angeboten. Segmente im File-System: * /srv/nginx/dash/sX/[manifest.mpd|init_\d.webm|segment_\d_\d+.webm] * /srv/nginx/hls/[sX_native_[hd|sd|slides].m3u8] * /srv/nginx/hls/sX/[chunks_\d.m3u8|\d+-\d+_\d.ts] * /srv/nginx/thumbnail/sX/[poster.jpeg|thumb.jpeg] Die Scripte dazu werden vom ansible aus folgenden Templates erzeugt werden: https://github.com/voc/cm/tree/master/ansible/roles/relay/files/fanout. Um einen Überblick über die laufenden Fanout Skripte zu erhalten kann folgender Befehl verwendet werden: voc@live.ber:~$ systemctl list-units 'fanout*' Die Pull-Quelle und das Push-Ziel sowie der Pfad unter dem die HLS/DASH-Schnipsel und Playlisten abgelegt werden ist über Group-Vars konfigurierbar: https://github.com/voc/cm/blob/master/ansible/group_vars/relays#L5 Zu den Aufgaben der fanout-Scripte gehört auch das übermitteln des h264-Videostroms zu Youtube. Die Stream-Keys dazu kommen aus dem KeePass, die Scripte aus dem oben verlinkten Git-Repo. * Youtube ist derzeit deaktiviert und wird üblicherweise nur für den Congress aktiviert. Das Transcoding und Fanout reagiert dynamisch auf die Konfiguration des Streams der vom encoder-cube gesendet wird. Fehlt die Slides-Spur oder die Translation-Spuren wird diese nicht in den Master-Playlists und Dash-Manifestd für Adaptives streaming angeboten. Dadurch kann von Event zu Event entschieden werden, ob der Einsatz der Slide-Spur bzw. von Translations sinn ergibt. Siehe dazu [[voctomix:audiomapping|]] zu Details wie Translations de/aktiviert werden können. === 4. Transport- und Master-Relays Im Non-Congress Setup ist ''live.ber.c3voc.de'' das einzige (Non-Public) Transport-Relay. Die (Public) Edge-Relays ziehen ihre Daten von dort. === 5. Edge-Relays Die ganzjährigen Edge-Relay lauten: * ''live.bn.c3voc.de'' * ''live.alb.c3voc.de'' * ''live2.alb.c3voc.de'' * ''live.dus.c3voc.de'' * ''live.self.c3voc.de'' * ''live.fem.c3voc.de'' Diese pullen alle Icecast-Streams (Port :8000) – *nicht* die Icedist-Streams – von ''live.ber.c3voc.de''. Für die schlussendliche Auslieferung kommt ein nginx zum Einsatz, der abhängig von der URL Daten von einem der unterschiedlichen Backend proxied: * Für Anfragen zu einem WebM, MP3 oder Opus-Stream (z.B: http://live.x.c3voc.de/sX_native_hd.webm) agiert der nginx als Proxy zu seinem eigenen Icecast. Er übernimmt in dieser Rolle das Aggregieren auf die Ports 80/443 sowie das SSL-Handling (für 443). * Für Anfragen nach HLS oder DASH-Schnipseln, -Playlisten und -Manifests oder Thumbnails (z.B. http://live.x.c3voc.de/hls/sX_native_hd.m3u8) agiert der nginx als Proxy zum Master-Relay ''live.ber.c3voc.de'', von welcher er die angefragten Datein abholt und für einen genau festgelegten Zeitraum zwischenspeichert. Dieser Zeitraum muss dabei mit der Segmentlänge der Playlists abgestimmt sein, um eine fehlerfreie Wiedergabe zu ermöglichen. == Stream-URLs Die endgültigen Stream-URLs für einen Beispielstream sX sind dann wie folgt: MPEG-DASH (VPx Multi-Qualität + Multi-Lang) * http://cdn.c3voc.de/dash/sX/manifest.mpd HLS (h.264 Multi-Qualität + Multi-Lang) * http://cdn.c3voc.de/hls/sX/native_hd.m3u8 Moar HLS * http://cdn.c3voc.de/hls/sX/translated_hd.m3u8 (auch Multi-Lang, nur anderer Default) * http://cdn.c3voc.de/hls/sX/translated-2_hd.m3u8 * http://cdn.c3voc.de/hls/sX/native_sd.m3u8 (nur SD, aber trotzdem Multi-Lang) * http://cdn.c3voc.de/hls/sX/translated_sd.m3u8 * http://cdn.c3voc.de/hls/sX/translated-2_sd.m3u8 Legacy VPx-HD: * http://cdn.c3voc.de/sX_native_hd.webm * http://cdn.c3voc.de/sX_translated_hd.webm * http://cdn.c3voc.de/sX_translated-2_hd.webm Legacy VPx-SD: * http://cdn.c3voc.de/sX_native_sd.webm * http://cdn.c3voc.de/sX_translated_sd.webm * http://cdn.c3voc.de/sX_translated-2_sd.webm Legacy VPx-Slides: * http://cdn.c3voc.de/sX_native_slides.webm * http://cdn.c3voc.de/sX_translated_slides.webm * http://cdn.c3voc.de/sX_translated-2_slides.webm Audio-MP3: * http://cdn.c3voc.de/sX_native.mp3 * http://cdn.c3voc.de/sX_translated.mp3 * http://cdn.c3voc.de/sX_translated-2.mp3 Audio-Opus: * http://cdn.c3voc.de/sX_native.opus * http://cdn.c3voc.de/sX_translated.opus * http://cdn.c3voc.de/sX_translated-2.opus == Loadbalancer Neben den Transport- und Edge-Relays gibt es noch drei Loadbalancer: * ''lb.dus.c3voc.de'' * ''lb.alb.c3voc.de'' * ''lb.dort.c3voc.de'' Diese sind sowohl für die Domains ''streaming.media.ccc.de'' als auch für ''cdn.c3voc.de'' zuständig. Im DNS sind für beide Domains alle Server angegeben, so dass Clients per statistischem Round-Robin auf die Loadbalancer verteilt werden. === streaming.media.ccc.de Unter dieser Domain liefern beide LBs unabhängig von einander die [[:software:streamingwebsite|Streaming-Webseite]] aus. Die LBs sind dabei komplett unabhängig voneinander und haben auch je eine eigene Konfiguration. Es ist aufgabe des Website-Deployments die Konfiguration synchron zu halten. Durch dieses Setup kann bei Bedarf der jeweilige LB einfach aus der DNS-Rotation herausgenommen werden. === cdn.c3voc.de Die Domain ''cdn.c3voc.de'' wird auf beiden LBs von einem HAProxy bedient. Dieser sortiert eventuell zwischen DTAG und Lokalen Klienten und wählt auf dieser Basis einen des obenstehenden Relays aus. Im unterjährigen Betrieb gibt es keine Unterscheidung: Alle Anfragen werden unter den genannten Relays verteilt. Der HAProxy verteilt dabei ausschließlich per Redirect, er proxied (entgegen seines Namens) nicht. == RTMP Ingest Für Spezialanwendungen (z.B. Cam-Only Streaming im Fritz-Studio) existieren die RTMP-Endpunkte ''q1'' und ''q2'' auf ''ingest.c3voc.de''. Die Push-Targets lauten ''%%rtmp://ingest.c3voc.de/stream/q1%%'' bzw. ''q2''. Eine Systemd-Unit setzt diese dann auf Icecast-Ströme gleichen Namens um, von wo Transcoding und Fanout wie oben beschrieben automatisch ihren Weg nehmen. Achtung: Aufgrund der langen rtmp-Timeouts in ffmpeg kann es bis zu 40 Sekunden dauern, bis die Streams auftauchen und weitere 30 Sekunden, bis alle Formate zur Verfügung stehen. Keine Ungeduld. === Dynamische endpunkte mit rtmp-auth RTMP Endpunkte können unter https://ingest.c3voc.de/backend/ (passwort im keepass unter ansible/stream-api/htpasswd) erstellt werden. Nach dem Anlegen kann der Stream auf ingest gepusht werden. Die RTMP-Url für den endpunkt ''stream/qtest23'' mit auth token lautet z.B.: ''%%rtmp://ingest.c3voc.de/stream/qtest23?auth=token%%''