Service OTT¶
Diffuse des flux via des protocoles basés sur HTTP — HLS (sur MPEG-TS), MPEG-DASH et Low-Latency HLS (sur CMAF — MP4 fragmenté, depuis la version 1.13), ainsi que MPEG-TS over HTTP. HTTPS (SSL) et HTTP/3 (QUIC) sont pris en charge. La diffusion s’active dans l’onglet OTT des paramètres Stream.
Les URL de connexion ont le format :
http://host:port/http/stream/login/password — autorisation par login et mot de passe
http://host:port/http/stream/login — autorisation par login (token)
http://host:port/http/stream/ — autorisation par IP
host et port se définissent dans les paramètres de http server.
stream — ID du stream. Ne pas confondre avec le numéro d’ordre dans la liste des streams. L”ID est affiché en haut de la page de statistiques du stream et dans la colonne ID de la liste des streams ; il est défini à la création du stream et ne change jamais.
De même pour HLS, DASH et Low-Latency HLS (les deux derniers — uniquement en OTT/HLS/LL-HLS/LL-Dash, voir ci-dessous) :
Sur la page de statistiques du flux s’affichent les URL des protocoles connectés (sous forme de modèle) et leur statut. L’accès non autorisé est interdit ; les clients doivent être déclarés dans Peers.
Pour HLS et DASH, des paramètres supplémentaires sont disponibles dans l’URL (optionnels) :
[URL]?a=1&s=40&m=40&v=5&h3=1
a : 1 — chemin absolu dans la playlist, 0 — chemin relatif (par défaut).
s : durée de la playlist dynamique (s), 40 s par défaut.
m : durée minimale de la playlist dynamique (s), 40 s par défaut. Taille maximale de la playlist dynamique 60 s. Si la taille actuelle du buffer de chunks est inférieure à la taille minimale demandée dans la requête, une erreur 404 est retournée. Cela garantit que HLS démarre avec un buffer de chunks rempli côté serveur.
v : la version du protocole HLS émise dans la playlist. Par défaut, la valeur dépend du mode HLS (voir ci-dessous) : OTT/HLS et OTT/HLS/LL-HLS/LL-Dash — 6, Peering/HLS — 3. Une valeur explicite dans l’URL remplace la valeur par défaut. Changer de version peut être nécessaire pour la compatibilité avec un client HLS particulier.
h3 : opt-in à HTTP/3 (QUIC) pour cette session OTT. Force le serveur à émettre un en-tête
Alt-Svcdans la réponse, après quoi un lecteur / navigateur compatible bascule sur QUIC. Voir la section HTTP/3 (QUIC) ci-dessous.
Pour la compatibilité avec certains clients HLS, on peut ajouter le nom de fichier index.m3u8 à l’URL, par ex. http://host:port/hls/stream/login/password/index.m3u8.
Le mode de diffusion est défini par le paramètre de flux OTT HLS (onglet OTT) : Peering/HLS, OTT/HLS ou OTT/HLS/LL-HLS/LL-Dash.
Peering/HLS — un mode avec découpage simple en segments (chunks). Recommandé pour le peering (la distribution) des flux. Seul HLS sur MPEG-TS (/hls) est diffusé. Par défaut, la playlist est servie en EXT-X-VERSION:3 pour la compatibilité avec les clients pairs.
OTT/HLS — un mode avec un découpage des segments optimisé pour un démarrage rapide des lecteurs en diffusion OTT. Dans ce mode, la charge CPU est plus élevée ; il est recommandé pour la diffusion. HLS sur MPEG-TS (/hls) est diffusé. Par défaut, la playlist est servie en EXT-X-VERSION:6 avec EXT-X-INDEPENDENT-SEGMENTS et l’attribut CHARACTERISTICS dans EXT-X-MEDIA TYPE=SUBTITLES (Apple HLS, hls.js, Safari, dash.js/Shaka). Si un client particulier a besoin d’une valeur antérieure, définissez-la via le paramètre de requête ?v= (voir la liste des paramètres ci-dessus).
OTT/HLS/LL-HLS/LL-Dash — un mode de diffusion sur CMAF (MP4 fragmenté, fMP4 ; depuis la version 1.13). Le flux produit des segments fMP4 (.m4s + un init.mp4 commun, mimeType="video/mp4"), au-dessus desquels sont diffusés :
MPEG-DASH sur
/dash— désormais sur CMAF, et non sur MPEG-TS ;Low-Latency HLS sur
/llhls(voir Low-Latency HLS ci-dessous) ;avec le paramètre de flux Enable TS Chunk activé (par défaut true) — en plus, du HLS legacy sur MPEG-TS (
/hls), comme en OTT/HLS ; avec false, seuls les segments fMP4 sont diffusés, ce qui économise le disque et le CPU.
La playlist HLS en OTT/HLS/LL-HLS/LL-Dash est elle aussi EXT-X-VERSION:6 par défaut.
Note
MPEG-DASH et Low-Latency HLS ne sont disponibles qu’en OTT/HLS/LL-HLS/LL-Dash. En OTT/HLS et Peering/HLS, seul HLS sur MPEG-TS est diffusé.
SSL (HTTPS) peut être activé sur le serveur HTTP via ses paramètres.
Chunk Min Interval et Chunk Max Interval
En mode OTT, le flux est analysé pour PAT/PMT/SPS/PPS/IFrame et les chunks sont découpés selon le critère de démarrage rapide des lecteurs. L’analyse commence à min interval, et si pour une raison quelconque les données ne sont pas trouvées, le chunk est forcément découpé à max interval.
GOP-aligned segments
En OTT/HLS, le segmenteur aligne les limites des chunks sur les points d’accès aléatoire et distingue IDR d’une I-frame ordinaire. Si la source diffuse en closed-GOP (IDR présent), chaque segment TS .ts commence à coup sûr par SPS / PPS / IDR (pour HEVC — également VPS) — un véritable point d’entrée à partir duquel le lecteur ouvre le flux. Si la source est en open-GOP / sans IDR, la limite est l’I-frame la plus proche (comportement antérieur). Le segmenteur retire la « queue » du GOP précédent — les slices P / B — de la fenêtre comprise entre le PAT en tête et le premier SPS du chunk. Cela :
élimine la trame noire initiale au démarrage d’une session VOD (
?t=/?epg=) dans hls.js, Safari et VLC : le décodeur MSE reçoit l’ensemble d’en-tête correct d’unités NAL dès le premier segment et démarre immédiatement ;aligne la sortie sur HLS RFC 8216 §3 (« Each Media Segment MUST contain a SPS and a PPS that decode its first Access Unit ») ;
rend correcte la déclaration EXT-X-INDEPENDENT-SEGMENTS dans une playlist EXT-X-VERSION:6.
Contrôle via le paramètre par flux gop-aligned-segment (par défaut true). Ne s’applique qu’en HLS = OTT/HLS : en Peering/HLS et pour les flux MPTS, le comportement est inchangé. Le PSI (PAT / PMT) et l’audio sont préservés en intégralité ; le seul effet secondaire est un saut d’une seule image du continuity_counter sur la PID vidéo à la frontière entre deux chunks adjacents, ce qui constitue une decode boundary légitime pour HLS / DASH MSE.
Lors de l’alignement sur les points d’entrée, la durée réelle du chunk peut être arrondie au-dessus de Chunk Min Interval. Par conséquent, dans la playlist live, la valeur EXT-X-TARGETDURATION reflète la durée de segment réelle maximale (section 4.3.3.1 de RFC 8216) plutôt que le minimum configuré. Cela maintient le manifeste conforme à la norme : hls.js et les lecteurs compatibles ne réduisent pas l’intervalle de rafraîchissement de la playlist et n’émettent pas de faux bufferStalledError.
Low-Latency HLS (/llhls)
En OTT/HLS/LL-HLS/LL-Dash, en plus de /dash, un endpoint Low-Latency HLS distinct est disponible — diffusion à latence réduite sur les mêmes segments fMP4 CMAF :
La playlist média est découpée en segments partiels (parts, directives #EXT-X-PART) : le lecteur démarre la lecture sans attendre que le segment complet soit prêt. Sont utilisés le rechargement bloquant de la playlist (le serveur retient la requête jusqu’à ce que le part suivant soit prêt) et l’indice de préchargement #EXT-X-PRELOAD-HINT.
La durée cible d’un part est définie par le paramètre de flux Part Target Duration (ms ; par défaut 500, plage 100–5000). La valeur est appliquée à la volée, sans redémarrer le flux, et doit être inférieure à Chunk Min Interval.
HLS / DASH / LL-HLS Adaptive Multistream
HLS Adaptive Multistream est pris en charge depuis la version 1.10, DASH Adaptive Multistream depuis la version 1.12 (depuis la version 1.13 — sur CMAF), et Low-Latency HLS Adaptive depuis la version 1.13.
Pour les flux adaptatifs, une playlist distincte est configurée. Pour cela :
Activer la diffusion OTT sur les flux qui feront partie de la playlist adaptative : OTT/HLS — pour le HLS adaptatif sur MPEG-TS ; OTT/HLS/LL-HLS/LL-Dash — pour les DASH / Low-Latency HLS adaptatifs sur CMAF.
Une section des flux adaptatifs apparaît dans le menu principal. Il faut y ajouter un flux et y indiquer tous les flux qui doivent figurer dans cette playlist.
Les flux peuvent avoir un paramètre de débit. Par défaut, il vaut 0 — le débit est repris de la valeur mesurée ; sinon, il peut être défini explicitement.
Pour les playlists adaptatives, l’URL diffère :
Des restrictions d’accès aux flux adaptatifs peuvent être imposées aux pairs (clients), comme aux flux ordinaires. L’autorisation d’un flux adaptatif englobe l’autorisation de tous les flux qu’il contient.
HTTP/3 (QUIC)¶
Depuis la version 1.13.1.438, Perfect Streamer intègre un serveur HTTP/3 pour la diffusion OTT de HLS, MPEG-DASH et Low-Latency HLS sur QUIC (RFC 9000 + RFC 9114). La pile est ngtcp2 (QUIC v1) + nghttp3 (HTTP/3 frame layer) ; l’infrastructure TLS réutilise le même certificat que le listener HTTPS.
QUIC ne sert que les routes OTT :
/— redirection racine,/hls/...,/dash/...et/llhls/...— master playlists / MPD,/h<sessID>/...— URL par session (media playlists, segments, VTT),/http/<stream>/...— MPEG-TS brut sur HTTP.
Low-Latency HLS et DASH sont diffusés sur QUIC de façon incrémentale (chunked) : les parts sont envoyées au client au fur et à mesure, sans attendre le segment complet.
Les chemins administratifs (/data, /config, /xmltv, /db/, /login, /logout, /restart) renvoient 404 sur QUIC — l’API d’administration reste sur HTTPS / HTTP-TCP. Il s’agit d’une restriction délibérée visant à réduire la surface d’attaque du listener QUIC.
Activation¶
Les paramètres QUIC se trouvent dans la section Configuration / HTTP server (nœud /config/http-server) :
HTTP/3 Enable (
http3-enable) — drapeau global activant le listener QUIC. Valeur par défaut : off. L’activation ouvre un socket UDP surhttp3-port; la désactivation le ferme.HTTP/3 Port (
http3-port) — port UDP du listener QUIC. Valeur par défaut : 43984. QUIC fonctionne sur UDP et HTTPS sur TCP ; les ports peuvent coïncider ou différer, sans conflit entre eux.HTTP/3 0-RTT Enable (
http3-zero-rtt-enable) — autorise le handshake 0-RTT (RFC 9001 §4.6.1) lors de la reprise de connexion d’un même client. Réduit la latence de démarrage ; le risque de rejeu doit être pris en compte pour les requêtes non idempotentes (sans danger pour une charge OTT en lecture seule). Valeur par défaut : on.
Les modifications de configuration sont appliquées à chaud, sans redémarrage du service.
Le certificat et la clé sont repris du listener HTTPS — il n’existe pas de configuration de certificat distincte pour HTTP/3. Si HTTPS n’est pas configuré (ssl-enable=false), l’activation de HTTP/3 ne donne rien — le handshake n’aboutira pas.
Le paramètre ?h3 — opt-in par session¶
Un navigateur ne se connecte pas directement à un endpoint HTTP/3 — il passe d’abord par HTTPS/TCP, reçoit dans la réponse l’en-tête Alt-Svc: h3=":<port>"; ma=86400 (RFC 7838), et seules les requêtes suivantes vers cet origin sont basculées sur QUIC.
Dans Perfect Streamer, l’émission de Alt-Svc est un opt-in par session OTT. Le serveur n’annonce pas QUIC à tous les clients sans distinction : le client doit explicitement demander HTTP/3 via le paramètre de requête ?h3 sur l’URL master HLS / DASH.
Valeur dans l’URL |
Valeur opt-in |
|
|---|---|---|
paramètre absent |
off (default) |
non |
|
on |
oui |
|
on |
oui |
|
explicit off |
non (comme en l’absence) |
Une fois que le client a obtenu l’URL de session /h<sess>/..., l’indicateur wantH3 est conservé dans la session — tous les rafraîchissements ultérieurs de media playlist, les GET de segments et de chunks VTT sous cette URL de session reçoivent également Alt-Svc, même si ?h3 est absent de la requête elle-même. Sans opt-in sur le master, aucun comportement sticky n’est instauré.
Gating Alt-Svc :
Le listener QUIC est activé globalement (
http3-enable=true) ; sinon l’annonce est supprimée même si?h3est défini.La requête n’est pas arrivée via QUIC — sur des requêtes déjà servies en H3,
Alt-Svcn’a aucun sens et n’est pas émis.Par session ou par URL
wantH3=true(voir le tableau ci-dessus).Les serveurs d’administration et EPG n’émettent jamais
Alt-Svc— ils ne disposent d’aucun listener QUIC.
Ce comportement est conforme à la RFC 7838 §3 — le serveur décide lui-même sur quelles réponses émettre Alt-Svc.
Scénario de bascule vers QUIC dans le navigateur¶
Déroulement typique (Chrome / Firefox / Safari) :
Le lecteur ouvre l’URL master avec un opt-in explicite :
https://stream.example.com:41982/hls/test1/login/password/index.m3u8?h3=1
La première requête passe par HTTPS/TCP. Dans la réponse, le serveur émet
Alt-Svc: h3=":43984"; ma=86400.Le navigateur mémorise l’association
stream.example.com:41982 → h3=":43984". Dans Chrome elle est visible sur la pagechrome://net-internals/#alt-svc; dans Firefox —about:networking#http3.Sur les requêtes ultérieures vers le même origin (rafraîchissement de playlist, GET de segments, VTT), le navigateur ouvre une connexion QUIC sur
udp/43984et poursuit en HTTP/3. Dans DevTools → Network, la colonne Protocol afficheh3pour ces requêtes.
Si la connexion QUIC ne peut être établie (port UDP bloqué par le pare-feu, certificat non approuvé par le système), le navigateur reste de manière transparente sur HTTPS/TCP — fonctionnellement, le flux continue à jouer sans interruption.
Comptabilisation des clients et supervision¶
L’adresse IP réelle d’un client QUIC dans la comptabilisation des pairs actifs (/data/http-clients, limites de connexions concurrentes, ACL par IP) correspond à l”adresse de pair effective de la connexion QUIC, et non au loopback du pont backend interne.
L’attribut ott-type dans /data/http-clients est composite, au format <PROTO>/<scheme> :
PROTO— protocole OTT :HLS,DASHouHTTP.scheme— le transport réseau effectif :http,httpsouquic.
Exemples : HLS/quic, DASH/https, HTTP/http. L’interface d’administration affiche à la fois le protocole OTT et le transport réseau de chaque client dans une même colonne.
Le délai d’expiration d’une session OTT est de 60 secondes, quel que soit le transport. Lorsque le client change de transport, le schéma n’est mis à jour que vers le haut selon la chaîne de priorité http → https → quic. Un repli parallèle vers une connexion moins sécurisée n’écrase pas le type courant — la comptabilisation conserve le transport le plus sécurisé observé.
Compatibilité des lecteurs¶
HTTP/3 pour l’OTT est pris en charge par :
iOS AVPlayer / Safari — nativement, via
Alt-Svc; 0-RTT est pris en charge.Chrome, Firefox, Edge, Brave — via
Alt-Svc; HLS est joué via hls.js, DASH via dash.js / Shaka, et le trafic du lecteur hérite de HTTP/3 par l’API fetch du navigateur.Android ExoPlayer — via le moteur QUIC Cronet (transport non utilisé par défaut, nécessite une configuration côté client).
VLC (libVLC) ne prend pas en charge HTTP/3 — sur ces clients le flux continue de fonctionner sur HTTPS/TCP, sans le bénéfice de QUIC.
Le gain réel de QUIC par rapport à HTTPS/TCP est surtout sensible sur les réseaux mobiles / Wi-Fi / les réseaux avec pertes :
pas de head-of-line blocking au niveau TCP — une perte dans un flux HTTP ne retarde pas les autres ;
handshake 0-RTT lors de la reprise de connexion d’un même client ;
débit ABR plus stable avec des pertes de paquets de 1 à 5 %.
Sur les réseaux gérés / les Wi-Fi d’entreprise, le gain reste habituellement modeste — 5 à 10 % sur la latence de démarrage et quasiment nul en régime établi. La charge CPU côté serveur est plus élevée pour QUIC que pour le TCP du noyau — c’est le coût d’une pile TLS + transport en espace utilisateur.
Modèle de mise en cache pour OTT HLS et DASH¶
Le serveur produit trois catégories de réponses qui diffèrent par leur durée de vie et leur aptitude à la mise en cache par les nœuds intermédiaires (reverse proxy, CDN, cache client).
1. Modèle de mise en cache¶
1.1. Ressources et en-têtes HTTP¶
Ressource |
URL |
Content-Type |
Cache-Control |
|---|---|---|---|
Segment TS (HLS) |
|
|
|
Segment fMP4 (DASH / LL-HLS) |
|
|
|
DASH MPD |
|
|
|
HLS master |
|
|
|
HLS media |
|
|
|
302 Redirect |
|
— |
|
Raw TS |
|
|
non défini ; non mis en cache |
1.2. Caractéristiques des segments¶
L’identifiant hexadécimal du segment dans l’URL (<keyHex> dans les chemins /h<sess>/<keyHex>.ts) est calculé comme un CRC64 sur l’instant de début du segment et l’ID du flux, et il est globalement unique. L’URL du segment adresse un contenu immuable — sur des requêtes répétées vers la même URL, un flux d’octets identique est renvoyé (tant que le segment reste dans la fenêtre glissante).
La directive immutable supprime la revalidation conditionnelle côté client (If-None-Match, If-Modified-Since). La valeur max-age=60 reste compatible avec un timeShiftBufferDepth=40s typique.
Les segments fMP4 CMAF (.m4s) et l”init.mp4 commun pour DASH / Low-Latency HLS sont adressés de manière analogue et mis en cache selon le même modèle (immutable, max-age=60). Les segments partiels (parts) de LL-HLS sont des requêtes byte-range dans le même .m4s, ils ne forment donc pas d’entrée de cache distincte.
1.3. Caractéristiques des manifestes¶
max-age=1 limite la limite supérieure d’obsolescence du contenu en cache à une seconde. Combiné à proxy_cache_lock on (nginx), les pics de requêtes vers le manifeste sont coalescés en une seule requête vers l’origine par seconde.
1.4. Variabilité du contenu¶
Avec absPath=0 (valeur par défaut, paramètre d’URL a absent), les manifestes HLS media et DASH MPD ne contiennent pas d’identifiant de session dans le corps. Le contenu du manifeste est identique entre les sessions appartenant à la même combinaison (stream, param). Cela permet au cache du reverse-proxy de réutiliser une seule entrée entre sessions lorsque la clé de cache est normalisée.
Avec absPath=1 (paramètre d’URL a=1), le corps du manifeste contient des URL absolues incluant le schéma, l’hôte et l’identifiant de session. Le contenu devient spécifique à la session ; la réutilisation du cache entre sessions n’est pas possible.
2. Comportement des clients¶
Client |
URL de rafraîchissement du manifeste |
Impact sur le nombre de sessions |
|---|---|---|
VLC 3.x HLS |
|
Une session par lecture |
VLC 3.x DASH |
|
Traité par session reuse (voir 3.3) |
ffmpeg 5.x HLS |
|
Une session par lecture |
ffmpeg 5.x DASH |
|
Traité par session reuse (voir 3.3) |
dash.js, hls.js |
|
Une session par lecture |
3. Mécanismes spéciaux¶
3.1. Redirection HTTP 302 pour DASH¶
Une requête de la forme /dash/<stream>/<login>/<pass>/index.mpd renvoie une réponse 302 Found avec l’en-tête Location: /h<sess>/index.mpd. Le corps de la réponse est vide. L’authentification et l’allocation de la session ont lieu pendant le traitement de la redirection.
Les clients qui prennent en charge le caching de redirection accèdent directement à l’URL de session dans les requêtes suivantes. Les clients qui ne le prennent pas en charge réémettent la requête de redirection. Le coût du retraitement de la redirection se limite à la vérification d’authentification et aux opérations de session reuse.
3.2. Session reuse pour DASH¶
Lors du traitement d’une requête /dash/.../index.mpd du même login vers le même flux (avec le même indicateur adaptive), le serveur trouve une session DASH déjà existante et renvoie à nouveau son identifiant. Aucune nouvelle session n’est créée ; aucun slot du quota de connexions simultanées n’est consommé.
Applicable uniquement à DASH. Pour HLS, aucun mécanisme de reuse distinct n’est nécessaire : les clients HLS rafraîchissent la media playlist via l’URL de session et ne créent pas de nouvelle session à chaque rafraîchissement.
3.3. Réutilisation des segments entre sessions¶
Le chemin /h<sess>/<keyHex>.ts est indépendant de <sess> lors de la résolution de <keyHex> en contenu : <keyHex> identifie de manière globalement unique un segment TS au sein d’un flux. Nginx avec une clé de cache normalisée (retirant le préfixe /h<sess>/) sert toute requête pour le même <keyHex> depuis une seule entrée de cache, quels que soient les clients qui l’ont émise.
Il en va de même pour les segments fMP4 CMAF (.m4s) et init.mp4 : leur contenu est immuable et adressé au sein du flux, de sorte que la normalisation de la cache key produit la même déduplication inter-sessions dans le cache.
4. Paramètres de requête¶
Paramètre |
Valeur par défaut |
Impact |
|---|---|---|
|
|
|
|
|
|
|
|
Longueur minimale de la fenêtre pour émettre le manifeste |
|
|
|
|
non défini (off) |
opt-in à HTTP/3 (QUIC) — force le serveur à émettre |
La modification d’un paramètre via la query string met à jour les valeurs stockées dans la session lors de sa prochaine réouverture.
5. Caractéristiques de charge¶
La charge sur l’origine évolue avec le nombre de streams distincts visionnés simultanément. L’augmentation du nombre de clients regardant le même stream n’augmente pas le nombre de requêtes vers l’origine en présence d’un cache reverse-proxy avec clé de cache normalisée.
Scénario |
Fréquence des requêtes origin (réf.) |
|---|---|
1 client par flux X |
MPD: 0.4 req/s, segment: 0.2 req/s |
N clients sur un même flux X (cache activé) |
MPD: 1 req/s, segment: 0.2 req/s |
N clients ffmpeg en mode replay sur un même flux |
MPD : 1 req/s (avec |
N clients sur N flux distincts |
MPD: 0.4·N req/s, segment: 0.2·N req/s |
6. Nginx comme reverse proxy avec cache¶
6.1. Configuration de base¶
proxy_cache_path /var/cache/nginx/pss_segments
levels=1:2 keys_zone=pss_segments:100m
max_size=20g inactive=30m use_temp_path=off;
proxy_cache_path /var/cache/nginx/pss_manifests
levels=1:2 keys_zone=pss_manifests:10m
max_size=256m inactive=5m use_temp_path=off;
upstream pss_backend {
server 127.0.0.1:41972;
keepalive 64;
}
map $uri $pss_cache_key {
~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$ "stream:$tail";
default $uri;
}
server {
listen 80;
server_name stream.example.com;
location ~* "^/h[0-9a-f]{16}(/[0-9]+)?/([0-9a-f]+\.(ts|m4s)|init\.mp4)$" {
proxy_cache pss_segments;
proxy_cache_key $pss_cache_key;
proxy_cache_valid 200 60s;
proxy_cache_valid 404 403 0s;
proxy_cache_lock on;
proxy_cache_use_stale updating error timeout;
proxy_cache_revalidate on;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://pss_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering on;
}
location ~* "(^/h[0-9a-f]{16}(/[0-9]+)?/index\.(m3u8|mpd)$|^/(hls|dash)/.*\.(m3u8|mpd)$)" {
proxy_cache pss_manifests;
proxy_cache_key $pss_cache_key;
proxy_cache_valid 200 1s;
proxy_cache_valid 404 403 0s;
proxy_cache_lock on;
proxy_cache_lock_timeout 2s;
proxy_cache_use_stale updating;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://pss_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
location / {
proxy_pass http://pss_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_buffering off;
proxy_read_timeout 3600s;
}
}
6.2. Rôle des directives¶
Directive |
Objectif |
|---|---|
|
Sérialise l’exécution des requêtes upstream lors de cache miss simultanés sur la même clé |
|
Renvoie la copie périmée aux requêtes parallèles pendant le rafraîchissement du cache |
|
Utilise |
|
Interdit la mise en cache des erreurs d’autorisation et 404 |
|
Maintient un pool de connexions persistantes vers l’origin |
|
Pour les segments ; active la mise en buffer de la réponse dans nginx |
|
Pour la section |
6.3. Calcul de max_size du cache de segments¶
Valeur indicative : bitrate × timeShiftBufferDepth × distinct_streams × 2
Exemple : 10 flux × 8 Mbps × 40 s × 2 ≈ 800 Mo. Un facteur de sécurité de 10× est recommandé pour absorber la variabilité du bitrate.
6.4. Terminaison TLS¶
Le serveur Perfect Streamer accepte les connexions sur les ports HTTP et HTTPS. En cas de terminaison TLS sur nginx, l’upstream utilise le port HTTP. Le transfert des en-têtes X-Forwarded-Proto et X-Forwarded-Host est obligatoire pour la formation correcte des URL absolues lorsque absPath=1.
server {
listen 443 ssl http2;
server_name stream.example.com;
ssl_certificate /etc/letsencrypt/live/stream.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location ... {
proxy_pass http://pss_backend;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $host;
# + caching directives from 6.1
}
}
server {
listen 80;
server_name stream.example.com;
return 301 https://$host$request_uri;
}
En HTTPS entre nginx et l’origin, on applique proxy_ssl_verify et proxy_ssl_trusted_certificate. Pour les connexions loopback, le chiffrement est superflu.
6.5. Multi-host¶
Lorsque plusieurs server_name sont servis par un même processus nginx, $host est ajouté à la cache key pour isoler les contenus :
map $uri $pss_cache_key {
~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$ "$host:stream:$tail";
default "$host:$uri";
}
La taille de keys_zone se calcule à 8000 clés/Mo. Pour des installations multi-hôtes avec des milliers de flux, il est recommandé keys_zone=...:300m ou plus.
7. Mise en cache côté client¶
Cache-Control: immutable est honoré par les navigateurs Chrome/Firefox/Safari. Le cache client renvoie le segment sans requête conditionnelle lors d’un nouvel accès (y compris seek arrière dans le buffer du lecteur).
Les Service Workers peuvent appliquer une stratégie cache-first basée sur le contenu de Cache-Control. Les lecteurs DASH (dash.js, Shaka) utilisent MSE via SourceBuffer ; un segment placé dans le buffer reste disponible sans nouvelle requête HTTP jusqu’à ce qu’il sorte de la fenêtre.
Pour les requêtes inter-domaines, l’en-tête Access-Control-Allow-Origin: * permet le caching dans les shared caches sans Vary: Origin. Le passage de l’ACAO à un Origin spécifique nécessite Vary: Origin, ce qui réduit l’efficacité du shared cache.
8. Distribution via CDN¶
Perfect Streamer est compatible avec les CDN en mode pull-from-origin (Cloudflare, Akamai, Fastly, BunnyCDN, Amazon CloudFront).
Origin shield. Il est recommandé de placer un ou plusieurs nœuds shield entre l’edge du CDN et l’origin afin de réduire le taux de requêtes vers l’origin lorsque les clients sont répartis globalement.
Purge. Les segments adressés par contenu n’ont pas besoin de purge. Lors d’un changement de métadonnées du flux (codec, résolution), les manifestes se rafraîchissent dans la fenêtre max-age=1 sans purge explicite.
Cache warming. En cas de pic de charge attendu sur un flux donné, on peut préchauffer le CDN depuis plusieurs points géographiques avant le début de la diffusion.
Géo-distribution. Les segments (max-age=60) conviennent bien au caching géographiquement distribué. Les manifestes (max-age=1) tolèrent jusqu’à une seconde de retard de livraison — acceptable pour du live non low-latency.
9. Surveillance¶
9.1. X-Cache-Status¶
Ajouter add_header X-Cache-Status $upstream_cache_status; dans chaque location avec cache. Valeurs :
Valeur |
Description |
|---|---|
|
Réponse depuis le cache |
|
Absent du cache ; récupéré depuis l’origin et stocké |
|
Expiré, rafraîchi |
|
Copie stale renvoyée à une requête parallèle pendant le rafraîchissement |
|
|
|
L’origin a renvoyé 304 Not Modified |
|
|
9.2. Format des logs d’accès¶
log_format pss_cache '$remote_addr $status $request_method "$request" '
'$body_bytes_sent rt=$request_time ut=$upstream_response_time '
'cache=$upstream_cache_status key=$pss_cache_key';
server {
access_log /var/log/nginx/pss.log pss_cache;
}
9.3. Métriques¶
Le module nginx-vts exporte les métriques par zone au format Prometheus
GET /status/format/prometheus
Seuils recommandés pour les alertes :
Métrique |
Seuil |
Cause possible |
|---|---|---|
Segment HIT rate |
< 90 % sur 5 minutes |
Normalisation de la cache key cassée ; |
Manifest MISS rate |
> 50 % sur 1 minute |
|
Upstream response time p95 |
> 500 ms sur 1 minute |
Surcharge de l’origin |
Cache zone fill |
> 90 % sur 10 minutes |
Approche de |
10. Diagnostic¶
Symptôme |
Cause probable |
Solution |
|---|---|---|
Taux HIT segment faible |
|
Vérifier les en-têtes et le regex de la directive |
404 sur les segments sortis de la fenêtre |
404 mis en cache pour un segment sorti de la fenêtre glissante |
Ajouter |
Délai de démarrage de lecture 2–5 s |
|
Réduire à 1–2 s ; activer |
Le manifeste ne se rafraîchit pas |
|
Définir explicitement |
Augmentation de TIME_WAIT côté upstream |
|
Ajouter |
403 sur |
Le client résout les URL relatives par rapport à l’URL avant redirection |
Le serveur émet |
Lags, rebuffering fréquents chez les clients distants |
Throughput TCP effectif faible à cause du slow start et de l’idle restart sur de longs RTT (300 ms et plus) |
Réglage de la pile réseau Linux sur l’origin : voir 10.1 |
10.1. Réglage TCP de l’origin pour les clients high-RTT¶
Le problème se manifeste sur les clients ayant un grand RTT jusqu’à l’origin (par exemple 300 ms et plus), lorsque le bitrate du flux est proche de la capacité du canal. Symptômes côté lecteur (VLC, ffmpeg, dash.js) — rebuffering fréquents, warnings du type ES_OUT_SET_PCR called too late (augmentation de pts_delay), buffer deadlock prevented, ruptures de flux. Côté serveur le client paraît normal, il n’y a pas d’erreurs, et le throughput sur /data/stream/... correspond au flux d’entrée.
Cause :
TCP slow start. Chaque nouvelle connexion TCP démarre avec un congestion window d’environ 14 Ko et l’augmente sur plusieurs RTT. À 300 ms de RTT, atteindre la fenêtre complète prend 2 à 3 secondes. Pendant ce temps, un segment HLS/DASH d’une durée de 5 s (4-6 Mo) se télécharge sensiblement plus lentement qu’en temps réel.
TCP idle restart. Entre deux requêtes de segments, un client HLS en pull-model fait une pause de 4 à 5 s. Par défaut, après une telle pause, le noyau Linux remet le congestion window de la connexion à l’initial cwnd (comportement
net.ipv4.tcp_slow_start_after_idle=1). En conséquence, au GET suivant, la connexion keep-alive reprend la transmission depuis le slow start — même sur une session déjà chauffée.
Une aggravation supplémentaire — le congestion control CUBIC par défaut supporte mal les longs RTT et les pertes de paquets sur des segments intermédiaires du réseau.
Solution — deux paramètres sysctl sur l’origin :
# Keep congestion window across idle pauses inside keep-alive sessions.
sysctl -w net.ipv4.tcp_slow_start_after_idle=0
# Use BBR instead of CUBIC: better behaviour on long-RTT paths
# with mild packet loss; paces sending instead of bursting.
modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr
Pour une application persistante :
cat > /etc/sysctl.d/99-pss-net.conf <<EOF
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl --system
L’effet principal vient du premier paramètre (tcp_slow_start_after_idle=0). Il élimine directement le slow start répété entre les requêtes de segments au sein d’une même connexion keep-alive. Le second (BBR) apporte une robustesse supplémentaire et s’applique à toutes les nouvelles connexions.
Le réglage ne nécessite pas de redémarrer Perfect Streamer et s’applique à toutes les nouvelles connexions TCP immédiatement après sysctl -w. Les connexions existantes conservent le congestion control avec lequel elles ont été établies.
11. Sécurité¶
11.1. Session URL¶
Une URL au format /h<sess>/... joue le rôle de jeton de session — pas besoin de réauthentification. La durée de vie est bornée par l’idle timeout (valeur 30 s). En l’absence d’activité, la session est supprimée par la tâche cleaner.
Exigences :
HTTPS pour tous les chemins OTT (
/hls/,/dash/,/h<sess>/) en productionL’identifiant de session dans l’en-tête
Locationdu 302 n’est pas mis en cache (no-cache, no-store)
11.2. Rate limiting¶
limit_req_zone $binary_remote_addr zone=dash_top:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=hls_top:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=llhls_top:10m rate=5r/s;
server {
location /dash/ {
limit_req zone=dash_top burst=20 nodelay;
proxy_pass http://pss_backend;
}
location /hls/ {
limit_req zone=hls_top burst=20 nodelay;
proxy_pass http://pss_backend;
}
location /llhls/ {
limit_req zone=llhls_top burst=20 nodelay;
proxy_pass http://pss_backend;
}
}
Les URL de session (/h<sess>/) ne nécessitent pas de rate limiting — le traitement est peu coûteux, les réponses sont mises en cache.
11.3. Mise en cache des réponses d’erreur¶
proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;
Interdit la mise en cache des redirections (sess unique dans Location) et des réponses d’erreur d’autorisation ou de ressource absente.
11.4. Restriction de l’accès réseau à l’origin¶
Le port 41972 (41982 pour HTTPS) doit être fermé au trafic externe. Configurations acceptables :
Lier Perfect Streamer à
127.0.0.1(si nginx est colocalisé)Règle de pare-feu :
iptables -A INPUT -p tcp --dport 41972 ! -s 10.0.0.0/8 -j DROP
12. Intégration middleware¶
12.1. Modèle prefix-login¶
Perfect Streamer peut déléguer l’identification utilisateur à un middleware/système de facturation via le mécanisme prefix-login. Un connecteur externe vers le système de facturation n’est pas inclus dans la version actuelle.
Configuration de l’utilisateur embedded :
{
"id": 9,
"login": "sub",
"password": "xxx",
"is-prefix": true,
"max-conn-http-hls": 1,
"accept-stream": [ ... ]
}
Avec is-prefix: true, le serveur accepte les URL dont le login suit <prefix><billing_user_id>
/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8
12.2. Format des statistiques¶
<clients>
<client login-id="-1974387287" login="sub" match-login="sub42"
sess-id="11331..." ott-type="dash" stream-id="10000" .../>
<client login-id="-2147031294" login="sub" match-login="sub43"
sess-id="11132..." ott-type="dash" stream-id="10000" .../>
</clients>
Le champ login-id contient le hash du login URL. login est la valeur configurée. match-login est le login URL utilisé par le client.
12.3. Limitations du prefix-login¶
Mot de passe partagé. Tous les abonnés du pool prefix utilisent une même valeur de mot de passe. Sa compromission donne accès à tout
<prefix><string>.Granularité ACL.
accept-streams’applique à tout le pool prefix ; pas d’ACL par abonné sans facturation externe.Rotation du mot de passe. Le changement du mot de passe déconnecte tous les abonnés actifs. Un remplacement progressif nécessite l’utilisation temporaire de deux prefix-logins.
13. Sous-titres WebVTT¶
La source des sous-titres est DVB Teletext / DVB Subtitling depuis le MPEG-TS d’entrée. Les pistes de sous-titres Teletext doivent être présentes dans les sections Media Information ou Original Media Information. La section Analyzer permet également de vérifier que les paquets des PID correspondants sont actifs.
Pour OTT HLS/DASH, le mode OTT doit être activé (en Peering/HLS, les sous-titres WebVTT ne sont pas disponibles). Dans la section Output # OTT, le compteur de chunks OTT WebVTT buffer chunk count doit devenir non nul.
Pour diagnostiquer les sous-titres, activer Analyze et Trace sur le stream. Au démarrage du flux, le journal du stream doit afficher :
Start Teletext subtitle decoder
[ttxsubdec] ttx: pid=331 magazine=8 page=0x88 lang=***
Le journal contient ensuite le texte décodé des sous-titres.
13.1. URL des segments VTT¶
Schéma |
URL |
Contenu |
|---|---|---|
HLS master |
|
|
HLS subtitle playlist |
|
liste |
Segment VTT HLS |
|
VTT avec X-TIMESTAMP-MAP de type HLS |
DASH MPD AdaptationSet |
dans |
|
Segment VTT DASH |
|
VTT avec X-TIMESTAMP-MAP de type DASH |
<keyHex> est un CRC64 hex de 16 caractères calculé sur l’instant de début du segment, l’ID du flux et le PID de la piste de sous-titres. <seq> est le numéro d’ordre décimal d’un chunk du flux de sous-titres (la numérotation des sous-titres est indépendante de celle des chunks TS).