Service OTT¶
Émet des flux via des protocoles HTTP — HLS, MPEG-DASH (depuis la version 1.12) et MPEG-TS over HTTP. HTTPS (SSL) est 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 manière similaire pour HLS et DASH :
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, des paramètres supplémentaires sont disponibles dans l’URL (optionnels) :
[URL]?a=1&s=40&m=40&v=5
a : 1 — chemins absolus dans la playlist (par défaut), 0 — chemins relatifs.
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 au minimum demandé, l’erreur 404 est renvoyée. Cela garantit que le HLS démarre depuis un buffer de chunks rempli sur le serveur.
v : version du protocole HLS annoncée dans la playlist. 5 par défaut ; un changement peut être nécessaire pour certains clients HLS.
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 serveur HLS dispose de deux modes — Peer mode et OTT mode.
Peer mode — mode avec découpage simple des segments (chunks). Recommandé pour le peering / la distribution.
OTT mode — mode avec un découpage des segments optimisé pour la diffusion OTT et un démarrage rapide des lecteurs. La charge CPU est plus élevée ; recommandé pour la diffusion.
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é sur 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 avec min interval ; si pour une raison quelconque les données ne sont pas trouvées, le chunk est forcément découpé selon max interval.
HLS Adaptive Multistream
Depuis la version 1.10, prise en charge de HLS Adaptive Multistream et, depuis 1.12, de DASH Adaptive Multistream
Pour les flux adaptatifs, on configure une playlist HLS dédiée. Pour ce faire :
Pour les flux à inclure dans la playlist adaptative, activez HLS avec OTT Mode.
Dans le menu principal apparaît la section des flux adaptatifs. Y ajouter un flux et y inscrire tous les flux à inclure dans la playlist.
On peut affecter aux flux un paramètre de bitrate. Par défaut 0 signifie que le bitrate mesuré est utilisé ; sinon, on peut le fixer 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.
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 |
|
|
|
DASH MPD |
|
|
|
HLS master |
|
|
|
HLS media |
|
|
|
302 Redirect |
|
— |
|
Raw TS |
|
|
non défini ; non mis en cache |
1.2. Caractéristiques des segments TS¶
L’identifiant keyID est formé comme CRC64(startTime || streamID) et est globalement unique. L’URL d’un segment adresse un contenu immuable — sur des requêtes répétées de 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.
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 (par défaut, sans paramètre d’URL « a »), les manifestes HLS media et DASH MPD ne contiennent pas l’identifiant de session dans leur corps. Le contenu du manifeste est identique entre sessions appartenant à une même combinaison (stream, param). Cela permet au cache reverse-proxy de réutiliser une entrée entre sessions avec normalisation de la clé de cache.
Avec absPath=1 (paramètre d’URL « a=1 »), le corps du manifeste contient des URL absolues incluant schéma, host et identifiant de session. Le contenu devient spécifique à la session — la réutilisation cross-session du cache n’est plus 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 de la requête /dash/.../index.mpd exécutée sous login-id L pour stream-id S et le drapeau adaptive=A, si _ottClientList contient déjà une session DASH avec les mêmes (L, S, A), son sessID est renvoyé. Aucune nouvelle session n’est créée, aucun slot maxConn n’est consommé.
Applicable uniquement à DASH. HLS n’a pas besoin d’un mécanisme de reuse distinct : les clients HLS rafraîchissent la media playlist via l’URL de session et ne déclenchent pas applyNewOTTSess à chaque rafraîchissement.
3.3. Réutilisation des segments entre sessions¶
Le chemin /h<sess>/<keyID>.ts est indépendant de sess lors de la résolution de keyID en contenu : keyID identifie de manière unique le segment dans la ChunkList enregistrée (voir _ottStreamList). Nginx avec une clé de cache normalisée (en supprimant le préfixe /h<sess>/) sert toutes les requêtes du même keyID depuis une unique entrée de cache.
4. Paramètres de requête¶
Paramètre |
Valeur par défaut |
Impact |
|---|---|---|
|
|
|
|
|
|
|
|
Longueur minimale de la fenêtre pour émettre le manifeste |
|
|
|
Modifier le paramètre via la query string met à jour les valeurs stockées dans la session lors du prochain appel à applyNewOTTSess.
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$" {
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;
# + директивы кеширования из 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 |
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;
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;
}
}
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 un même 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 déconnecte tous les abonnés actifs. Pour un remplacement progressif, deux prefix-logins sont temporairement nécessaires.
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 Peer mode, 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 l’hex 16 caractères de CRC64(startTime, streamID, pid). <seq> est le numéro décimal du chunk dans le subtitle storage (compteur distinct du video storage).