OTT service¶
Outputs streams over HTTP-based protocols — HLS, MPEG-DASH (since version 1.12) and MPEG-TS over HTTP. HTTPS (SSL) is supported. The output is enabled on the OTT tab of the Stream settings.
URLs for connections have format:
http://host:port/http/stream/login/password - login/password authorization
http://host:port/http/stream/login - login authorization (token)
http://host:port/http/stream/ - IP authorization
host and port - set in http server settings.
stream - stream ID. Not to be confused with the sequence number in streams list. ID is shown in stream stats page header and in streams list ID column, ID is set at stream creation and never changes.
Likewise for HLS and DASH:
Output URL templates and working status are shown on stream stats page. Unauthorized access is denied, all clients should be registered in Peers.
Additional parameters are available in the URL for HLS and DASH (optional):
[URL]?a=1&s=40&m=40&v=5&h3=1
a: 1 — absolute path in the playlist, 0 — relative path (default).
s - dynamic play list duration (sec), default 40 sec.
m: minimum dynamic-playlist duration (sec), 40 sec by default. The maximum dynamic-playlist size is 60 sec. If the current chunk-buffer size is less than the minimum size requested, an HTTP 404 is returned. This is done so that HLS starts with a filled chunk buffer on the server.
v: version of the HLS protocol declared in the playlist. By default the value depends on the HLS mode (see below): OTT mode — 6, Peer mode — 3. An explicit value in the URL overrides the default. A version change may be required for compatibility with a specific HLS client.
h3: opt-in to HTTP/3 (QUIC) for this OTT session. Causes the server to emit an
Alt-Svcheader in the response, after which a compatible player / browser switches to QUIC. See section HTTP/3 (QUIC) below.
File name index.m3u8 could be added to URL for some players support, for example: http://host:port/hls/stream/login/password/index.m3u8.
There are two modes of operation of the HLS server — Peer mode and OTT mode.
Peer mode — a mode with simple segment (chunk) slicing. Recommended for peering (distribution) of streams. By default the playlist is delivered as EXT-X-VERSION:3 for compatibility with peer clients.
OTT mode — a mode with segment slicing optimised for fast player start-up under OTT broadcasting. CPU load is higher in this mode, recommended for broadcasting. By default the playlist is delivered as EXT-X-VERSION:6 with EXT-X-INDEPENDENT-SEGMENTS and a CHARACTERISTICS attribute on EXT-X-MEDIA TYPE=SUBTITLES (Apple HLS, hls.js, Safari, dash.js/Shaka). If a particular client needs an earlier value — set it via the ?v= query parameter (see the parameter list above).
SSL (HTTPS) can be enabled for HTTP server, this is done in the server settings.
Chunk Min Interval and Chunk Max Interval
In OTT mode the stream is analysed for PAT/PMT/SPS/PPS/IFrame and chunks are sliced according to the fast-start criterion for players. The analysis starts from min interval, and if for any reason the data is not found, the chunk is forcibly sliced at max interval.
GOP-aligned segments
Since version 1.13.1.438, in OTT mode every .ts TS segment is guaranteed to start with SPS / PPS / IDR (for HEVC — also VPS). The segmenter cuts out the “tail” of the previous GOP — P / B slices — from the window between the leading PAT and the chunk’s first SPS. This:
eliminates the initial black frame at VOD session start (
?t=/?epg=) in hls.js, Safari and VLC: the MSE decoder receives the correct header set of NAL units already in the first segment and starts immediately;brings the output into compliance with HLS RFC 8216 §3 (“Each Media Segment MUST contain a SPS and a PPS that decode its first Access Unit”);
makes the EXT-X-INDEPENDENT-SEGMENTS declaration in an EXT-X-VERSION:6 playlist accurate.
Controlled by the per-stream gop-aligned-segment setting (default true). Applies only when HLS = OTT mode: in Peer mode and for MPTS streams the behaviour is unchanged. PSI (PAT / PMT) and audio are preserved in full; the only side effect is a one-frame continuity_counter break on the video PID at the boundary between two adjacent chunks, which is a legitimate decode boundary for HLS / DASH MSE.
HLS Adaptive Multistream
Since version 1.10 HLS Adaptive Multistream is supported, and since version 1.12 DASH Adaptive Multistream as well.
HLS playlist should be configured for each adaptive stream. To do it:
Enable HLS with OTT mode for each stream you going to use in adaptive streams.
Streams Adaptive menu item will available in main menu. There you should add adaptive stream and select all streams you need for current adaptive stream playlist.
Streams can have a bitrate parameter set. By default it is 0, which means the bitrate is taken from the measured value. Otherwise it can be set explicitly.
Adaptive stream URL is differ:
Peer (client) can have access list where adaptive streams are also available.Permission for an adaptive stream includes permissions for all streams that are included in it.
HTTP/3 (QUIC)¶
As of version 1.13.1.438, Perfect Streamer ships a built-in HTTP/3 server for OTT delivery of HLS and MPEG-DASH over QUIC (RFC 9000 + RFC 9114). The stack is ngtcp2 (QUIC v1) + nghttp3 (HTTP/3 frame layer); the TLS infrastructure reuses the same certificate as the HTTPS listener.
QUIC serves OTT routes only:
/— root redirect,/hls/...and/dash/...— master playlists / MPD,/h<sessID>/...— per-session URL (media playlists, segments, VTT),/http/<stream>/...— raw MPEG-TS over HTTP.
Administrative paths (/data, /config, /xmltv, /db/, /login, /logout, /restart) return 404 over QUIC — the admin API stays on HTTPS / HTTP-TCP. This is a deliberate restriction that reduces the attack surface of the QUIC listener.
Enabling¶
The QUIC settings reside in the Configuration / HTTP server section (node /config/http-server):
HTTP/3 Enable (
http3-enable) — global flag that enables the QUIC listener. Default is off. Enabling opens a UDP socket onhttp3-port; disabling closes it.HTTP/3 Port (
http3-port) — UDP port of the QUIC listener. Default is 43984. QUIC runs on UDP and HTTPS on TCP; the ports may coincide or differ — there is no conflict between them.HTTP/3 0-RTT Enable (
http3-zero-rtt-enable) — allows the 0-RTT handshake (RFC 9001 §4.6.1) on resumed connections from the same client. Reduces start-up latency; the replay risk must be considered for non-idempotent requests (it is safe for read-only OTT workloads). Default is on.
Configuration changes are applied hot, without restarting the service.
The certificate and key are taken from the HTTPS listener — there is no separate certificate setting for HTTP/3. If HTTPS is not configured (ssl-enable=false), enabling HTTP/3 yields nothing — the handshake will not complete.
The ?h3 parameter — per-session opt-in¶
A browser does not connect to an HTTP/3 endpoint directly — it first reaches HTTPS/TCP, receives the Alt-Svc: h3=":<port>"; ma=86400 header in the response (RFC 7838), and only subsequent requests to that origin are switched to QUIC.
In Perfect Streamer, Alt-Svc emission is opt-in per OTT session. The server does not advertise QUIC to every client indiscriminately: the client must explicitly request HTTP/3 via the ?h3 query parameter on the master HLS / DASH URL.
Value in URL |
Opt-in value |
|
|---|---|---|
parameter absent |
off (default) |
no |
|
on |
yes |
|
on |
yes |
|
explicit off |
no (as when absent) |
Once the client has obtained the session URL /h<sess>/..., the wantH3 flag is stored in the session — all subsequent media-playlist refreshes, segment GETs and VTT-chunk GETs under that session URL also receive Alt-Svc, even if ?h3 is absent from the individual request. Without opt-in on the master, no sticky behaviour is established.
Alt-Svc gating:
The QUIC listener is globally enabled (
http3-enable=true); otherwise the advertisement is suppressed even when?h3is set.The request did not arrive over QUIC — on requests already served over H3,
Alt-Svcis meaningless and is not emitted.Per-session or per-URL
wantH3=true(see the table above).The admin and EPG servers never emit
Alt-Svc— they have no QUIC listener.
This behaviour is consistent with RFC 7838 §3 — the server itself decides on which responses to emit Alt-Svc.
QUIC switch-over scenario in the browser¶
Typical flow (Chrome / Firefox / Safari):
The player opens the master URL with explicit opt-in:
https://stream.example.com:41982/hls/test1/login/password/index.m3u8?h3=1
The first request goes over HTTPS/TCP. In the response the server emits
Alt-Svc: h3=":43984"; ma=86400.The browser caches the mapping
stream.example.com:41982 → h3=":43984". In Chrome it can be inspected on thechrome://net-internals/#alt-svcpage; in Firefox —about:networking#http3.On subsequent requests to the same origin (playlist refresh, segment GETs, VTT) the browser opens a QUIC connection on
udp/43984and continues over HTTP/3. In DevTools → Network the Protocol column for these requests becomesh3.
If the QUIC connection cannot be established (UDP port blocked by firewall, certificate not trusted by the system), the browser transparently remains on HTTPS/TCP — functionally the stream keeps playing without interruption.
Client accounting and monitoring¶
The real IP address of a QUIC client in the active-peer accounting (/data/http-clients, concurrent-connection limits, IP-based ACLs) is the actual peer address of the QUIC connection, not the loopback of the internal backend bridge.
The ott-type attribute in /data/http-clients is composite, with the format <PROTO>/<scheme>:
PROTO— OTT protocol:HLS,DASHorHTTP.scheme— the actual network transport:http,httpsorquic.
Examples: HLS/quic, DASH/https, HTTP/http. The admin UI shows both the OTT protocol and the network transport of each client in a single column.
The OTT session timeout is 60 seconds, regardless of the transport. When a client switches between transports, the scheme is only upgraded along the priority chain http → https → quic. A concurrent fallback to a less secure connection does not overwrite the current type — the most secure transport seen is retained in the accounting.
Player compatibility¶
HTTP/3 for OTT is supported by:
iOS AVPlayer / Safari — natively, via
Alt-Svc; 0-RTT is supported.Chrome, Firefox, Edge, Brave — via
Alt-Svc; HLS is played through hls.js, DASH through dash.js / Shaka, and the player traffic inherits HTTP/3 from the browser fetch API.Android ExoPlayer — via the Cronet QUIC engine (not the default transport; requires client-side configuration).
VLC (libVLC) does not support HTTP/3 — on these clients the stream continues to work over HTTPS/TCP, without the benefit of QUIC.
The real-world benefit of QUIC vs HTTPS/TCP is most noticeable on mobile networks / Wi-Fi / lossy networks:
no head-of-line blocking at the TCP layer — a loss in one HTTP stream does not delay the others;
0-RTT handshake on resumed connections from the same client;
more stable ABR bitrate at packet losses of 1–5 %.
On managed networks / corporate Wi-Fi the benefit is usually modest — 5–10 % on startup latency and close to zero in steady state. CPU load on the server is higher for QUIC than for kernel TCP — this is the price of user-space TLS plus transport.
Caching model for OTT HLS and DASH¶
The server emits responses of three categories that differ in content lifetime and suitability for caching by intermediate nodes (reverse proxy, CDN, client cache).
1. Caching model¶
1.1. Resources and HTTP headers¶
Resource |
URL |
Content-Type |
Cache-Control |
|---|---|---|---|
TS segment |
|
|
|
DASH MPD |
|
|
|
HLS master |
|
|
|
HLS media |
|
|
|
302 Redirect |
|
— |
|
Raw TS |
|
|
not set; not cached |
1.2. TS segment characteristics¶
The hexadecimal segment identifier in the URL (<keyHex> in paths /h<sess>/<keyHex>.ts) is computed as a CRC64 over the segment start time and the stream ID, and is globally unique. The segment URL addresses immutable content — repeated requests for the same URL return an identical byte stream (as long as the segment stays within the sliding window).
The immutable directive suppresses conditional revalidation by the client (If-None-Match, If-Modified-Since). The max-age=60 value is compatible with a typical timeShiftBufferDepth=40s.
1.3. Manifest characteristics¶
max-age=1 caps the upper bound of cached-content staleness at one second. Combined with proxy_cache_lock on (nginx) it collapses bursts of manifest requests into a single origin request per second.
1.4. Content variance¶
With absPath=0 (the default, no a URL parameter) the HLS media and DASH MPD manifests do not embed a session identifier in the body. The manifest content is identical across sessions belonging to the same (stream, param) combination. This lets a reverse-proxy cache reuse a single entry across sessions when the cache key is normalised.
With absPath=1 (URL parameter a=1) the manifest body contains absolute URLs that include the scheme, host, and session identifier. The content becomes session-specific; cross-session cache reuse is not available.
2. Client behaviour¶
Client |
Manifest refresh URL |
Effect on session count |
|---|---|---|
VLC 3.x HLS |
|
One session per playback |
VLC 3.x DASH |
|
Handled by session reuse (see 3.3) |
ffmpeg 5.x HLS |
|
One session per playback |
ffmpeg 5.x DASH |
|
Handled by session reuse (see 3.3) |
dash.js, hls.js |
|
One session per playback |
3. Specialised mechanisms¶
3.1. HTTP 302 redirect for DASH¶
A /dash/<stream>/<login>/<pass>/index.mpd request returns 302 Found with a Location: /h<sess>/index.mpd header. The body is empty. Authentication and session allocation happen during the redirect.
Clients that cache the redirect address the session URL directly in subsequent requests. Clients that do not, re-issue the redirect request. The cost of repeat redirect handling is limited to auth check and session-reuse operations.
3.2. Session reuse for DASH¶
When processing a /dash/.../index.mpd request from the same login to the same stream (with the same adaptive flag), the server finds an existing DASH session and returns its identifier again. No new session is created; a slot in the concurrent-connections limit is not consumed.
Applies to DASH only. HLS does not require a separate reuse mechanism: HLS clients refresh the media playlist via the session URL and do not create a new session on each refresh.
3.3. Cross-session segment reuse¶
The path /h<sess>/<keyHex>.ts does not depend on <sess> when resolving <keyHex> to content: <keyHex> uniquely identifies a TS segment within a stream globally. Nginx with a normalised cache key (stripping the /h<sess>/ prefix) serves every request for the same <keyHex> from a single cache entry, regardless of which clients issued them.
4. Request parameters¶
Parameter |
Default value |
Effect |
|---|---|---|
|
|
|
|
|
|
|
|
Minimum window length for manifest emission |
|
|
|
|
absent (off) |
opt-in to HTTP/3 (QUIC) — causes the server to emit |
Changing a parameter via query string updates the values stored in the session on its next re-opening.
5. Load characteristics¶
Origin load scales with the number of distinct streams being watched concurrently. Increasing the number of clients watching the same stream does not increase origin requests when a reverse-proxy cache with a normalised cache key is in place.
Scenario |
Origin request rate (ref.) |
|---|---|
1 client per stream X |
MPD: 0.4 req/s, segment: 0.2 req/s |
N clients on one stream X (cache enabled) |
MPD: 1 req/s, segment: 0.2 req/s |
N ffmpeg clients in replay mode on one stream |
MPD: 1 req/s (with |
N clients on N distinct streams |
MPD: 0.4·N req/s, segment: 0.2·N req/s |
6. Nginx as a caching reverse proxy¶
6.1. Basic configuration¶
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. Directive purposes¶
Directive |
Purpose |
|---|---|
|
Serialises upstream requests when concurrent cache misses target the same key |
|
Returns the stale copy to concurrent requests while the cache is being refreshed |
|
Uses |
|
Disables caching of authorisation errors and 404 |
|
Maintains a pool of persistent connections to origin |
|
For segments; enables response buffering in nginx |
|
For the |
6.3. Computing segment cache max_size¶
Rough value: bitrate × timeShiftBufferDepth × distinct_streams × 2
Example: 10 streams × 8 Mbps × 40s × 2 ≈ 800 MB. A 10x headroom is recommended to absorb bitrate variance.
6.4. TLS termination¶
The Perfect Streamer server accepts connections on HTTP and HTTPS ports. With TLS termination at nginx the upstream uses the HTTP port. Forwarding X-Forwarded-Proto and X-Forwarded-Host headers is required for correct absolute URL composition when 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;
}
For HTTPS between nginx and origin, proxy_ssl_verify and proxy_ssl_trusted_certificate directives apply. Encryption is redundant for loopback connections.
6.5. Multi-host¶
When serving multiple server_name from a single nginx process, $host is added to the cache key to isolate content:
map $uri $pss_cache_key {
~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$ "$host:stream:$tail";
default "$host:$uri";
}
keys_zone size is sized at 8000 keys per MB. For multi-host installations with thousands of streams, keys_zone=...:300m or higher is recommended.
7. Client-side caching¶
Cache-Control: immutable is honoured by Chrome/Firefox/Safari. The client cache returns the segment without a conditional request on re-access (including backward seek within the player buffer).
Service Workers can apply a cache-first strategy based on Cache-Control content. DASH players (dash.js, Shaka) use MSE through SourceBuffer; a segment placed in the buffer remains available without a repeat HTTP request until it slides out of the window.
For cross-domain requests the Access-Control-Allow-Origin: * header allows caching in shared caches without Vary: Origin. Switching ACAO to a specific Origin requires Vary: Origin, which reduces shared-cache efficiency.
8. Distribution via CDN¶
Perfect Streamer is compatible with pull-from-origin CDNs (Cloudflare, Akamai, Fastly, BunnyCDN, Amazon CloudFront).
Origin shield. Placing one or more shield nodes between CDN edge and origin is recommended to reduce origin request rate when clients are globally distributed.
Purge. Content-addressed segments require no purge. When stream metadata changes (codec, resolution), manifests refresh within max-age=1 without an explicit purge.
Cache warming. When a specific stream is expected to spike, the CDN may be warmed from several geographic points before broadcast start.
Geo-distribution. Segments (max-age=60) are well suited for geographically distributed caching. Manifests (max-age=1) tolerate up to one-second delivery delay — acceptable for non-low-latency live.
9. Monitoring¶
9.1. X-Cache-Status¶
Add add_header X-Cache-Status $upstream_cache_status; in every cached location. Values:
Value |
Description |
|---|---|
|
Response from cache |
|
Not in cache; fetched from origin and stored |
|
Expired, refreshed |
|
Stale copy returned to a concurrent request during refresh |
|
|
|
Origin returned 304 Not Modified |
|
|
9.2. Access-log format¶
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. Metrics¶
The nginx-vts module exports per-zone metrics in Prometheus format:
GET /status/format/prometheus
Recommended alert thresholds:
Metric |
Threshold |
Possible cause |
|---|---|---|
Segment HIT rate |
< 90% over 5 minutes |
Cache-key normalisation broken; |
Manifest MISS rate |
> 50% over 1 minute |
|
Upstream response time p95 |
> 500 ms over 1 minute |
Origin overload |
Cache zone fill |
> 90% over 10 minutes |
Approaching |
10. Diagnostics¶
Symptom |
Likely cause |
Resolution |
|---|---|---|
Low segment HIT rate |
|
Inspect headers and the regex in the |
404 on segments after they leave the sliding window |
Cached 404 for a segment that fell out of the sliding window |
Add |
Playback start delay of 2–5 s |
|
Lower to 1–2 s; enable |
Manifest does not refresh |
|
Set |
Growing TIME_WAIT on upstream |
|
Add |
403 on |
Client resolves relative URLs against the pre-redirect URL |
Server emits |
Lags, frequent rebuffering for remote clients |
Low effective TCP throughput due to slow start and idle restart at large RTTs (300 ms and above) |
Tuning of the Linux network stack on the origin: see 10.1 |
10.1. TCP tuning of the origin for high-RTT clients¶
The problem appears on clients with a large RTT to the origin (e.g. 300 ms and above) when the stream bitrate is close to the channel capacity. Player symptoms (VLC, ffmpeg, dash.js) — frequent rebuffering, warnings such as ES_OUT_SET_PCR called too late (with pts_delay increasing), buffer deadlock prevented, stream interruptions. On the server side the client looks normal, there are no errors, and the throughput on /data/stream/... matches the input stream.
Cause:
TCP slow start. Every new TCP connection starts with a congestion window of about 14 KB and grows it over several RTTs. At an RTT of 300 ms, reaching the full window takes 2-3 seconds. During that time, an HLS/DASH segment lasting 5 s (4-6 MB) downloads noticeably slower than real time.
TCP idle restart. Between segment requests, an HLS pull-model client pauses for 4-5 s. By default, after such a pause the Linux kernel resets the connection’s congestion window back to the initial cwnd (the
net.ipv4.tcp_slow_start_after_idle=1behaviour). As a result, on the next GET the keep-alive connection restarts transmission from slow start anew — even on an already warmed-up session.
An additional aggravation — the default CUBIC congestion control copes poorly with long RTTs and packet loss on intermediate network segments.
Solution — two sysctl parameters on the 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
For persistent application:
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
The main effect comes from the first parameter (tcp_slow_start_after_idle=0). It directly eliminates repeated slow start between segment requests within the same keep-alive connection. The second (BBR) provides additional robustness and applies to all new connections.
The tuning does not require a Perfect Streamer restart and applies to all new TCP connections immediately after sysctl -w. Existing connections retain the congestion control with which they were established.
11. Security¶
11.1. Session URL¶
A URL of the form /h<sess>/... acts as the session token — no repeat authentication is required. Lifetime is bounded by an idle timeout (30 s). On inactivity the session is removed by the cleaner task.
Requirements:
HTTPS on every OTT path (
/hls/,/dash/,/h<sess>/) in productionSession ID in the
Locationheader of 302 is not cached (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;
}
}
Session URLs (/h<sess>/) do not require rate limiting — handling is cheap and responses are cached.
11.3. Caching of error responses¶
proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;
Disables caching of redirects (unique sess in Location) and of authorisation/missing-resource error responses.
11.4. Restricting network access to origin¶
Port 41972 (41982 for HTTPS) must be closed to external traffic. Acceptable configurations:
Bind Perfect Streamer to
127.0.0.1(when nginx is co-located)Firewall rule:
iptables -A INPUT -p tcp --dport 41972 ! -s 10.0.0.0/8 -j DROP
12. Middleware integration¶
12.1. Prefix-login model¶
Perfect Streamer supports delegating user identification to a middleware/billing system via the prefix-login mechanism. An external connector to the billing system is not included in the current release.
Embedded-user configuration:
{
"id": 9,
"login": "sub",
"password": "xxx",
"is-prefix": true,
"max-conn-http-hls": 1,
"accept-stream": [ ... ]
}
With is-prefix: true the server accepts URLs whose login follows <prefix><billing_user_id>:
/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8
12.2. Statistics format¶
<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>
The login-id field holds the hash of the URL login. The login field is the configured value. The match-login field is the URL login used by the client.
12.3. Prefix-login limitations¶
Shared password. All subscribers of a prefix pool use a single password value. Compromising the password grants access to any
<prefix><string>.ACL granularity.
accept-streamapplies to the whole prefix pool. Per-subscriber ACL is not available without external billing.Password rotation. Changing the password disconnects all active subscribers. A gradual rollover requires temporarily using two prefix logins.
13. WebVTT subtitles¶
The subtitle source is DVB Teletext / DVB Subtitling from the input MPEG-TS. Teletext subtitle tracks must be present in the Media Information or Original Media Information sections. The Analyzer section can also be used to verify that packets of the corresponding PIDs are active.
For OTT HLS/DASH the OTT mode must be enabled (in Peer mode WebVTT subtitles are not available). The chunk counter OTT WebVTT buffer chunk count in the Output # OTT section must become non-zero.
To diagnose subtitles, enable Analyze and Trace on the stream. At stream start the stream log should contain:
Start Teletext subtitle decoder
[ttxsubdec] ttx: pid=331 magazine=8 page=0x88 lang=***
Subsequent log entries contain the decoded subtitle text.
13.1. VTT segment URLs¶
Scheme |
URL |
Content |
|---|---|---|
HLS master |
|
|
HLS subtitle playlist |
|
list of |
HLS VTT segment |
|
VTT with HLS-flavoured X-TIMESTAMP-MAP |
DASH MPD AdaptationSet |
inside |
|
DASH VTT segment |
|
VTT with DASH-flavoured X-TIMESTAMP-MAP |
<keyHex> is a 16-character hex CRC64 of the segment start time, stream ID, and subtitle-track PID. <seq> is the decimal sequence number of a subtitle-stream chunk (subtitle numbering is unrelated to TS-chunk numbering).