Serviço OTT¶
Entrega fluxos por protocolos baseados em HTTP — HLS (sobre MPEG-TS), MPEG-DASH e Low-Latency HLS (sobre CMAF — MP4 fragmentado, desde a versão 1.13), bem como MPEG-TS over HTTP. São suportados HTTPS (SSL) e HTTP/3 (QUIC). A entrega é ativada na aba OTT das configurações de Stream.
As URLs de conexão têm o formato:
http://host:port/http/stream/login/password — autorização por login e senha
http://host:port/http/stream/login — autorização por login (token)
http://host:port/http/stream/ — autorização por IP
host e port são definidos nas configurações do http server.
stream — ID do stream. Não confundir com o número de ordem na lista de streams. O ID é exibido no topo da página de estatísticas do stream e na coluna ID da lista de streams; é definido na criação do stream e nunca muda.
De forma análoga para HLS, DASH e Low-Latency HLS (os dois últimos — apenas em OTT/HLS/LL-HLS/LL-Dash, veja abaixo):
Na página de estatísticas do stream são exibidas as URLs dos protocolos conectados (como template) e seu status atual. O acesso não autorizado é proibido; os clientes devem estar registrados em Peers.
Para HLS e DASH estão disponíveis parâmetros adicionais na URL (opcionais):
[URL]?a=1&s=40&m=40&v=5&h3=1
a: 1 — caminho absoluto na playlist, 0 — caminho relativo (padrão).
s: duração da playlist dinâmica (s), 40 s por padrão.
m: duração mínima da playlist dinâmica (s), 40 s por padrão. Tamanho máximo da playlist dinâmica 60 s. Se o tamanho atual do buffer de chunks for menor que o tamanho mínimo solicitado na requisição, é retornado um erro 404. Assim, o HLS arranca com um buffer de chunks cheio no servidor.
v: a versão do protocolo HLS emitida na playlist. Por padrão, o valor depende do modo HLS (veja abaixo): OTT/HLS e OTT/HLS/LL-HLS/LL-Dash — 6, Peering/HLS — 3. Um valor explícito na URL substitui o padrão. Trocar a versão pode ser necessário para compatibilidade com um cliente HLS específico.
h3: opt-in para HTTP/3 (QUIC) nesta sessão OTT. Faz com que o servidor emita um cabeçalho
Alt-Svcna resposta, após o que um leitor / browser compatível passa para QUIC. Ver a secção HTTP/3 (QUIC) abaixo.
Para compatibilidade com alguns clientes HLS é possível adicionar o nome de arquivo index.m3u8 à URL, ex.: http://host:port/hls/stream/login/password/index.m3u8.
O modo de entrega é definido pela configuração de stream OTT HLS (aba OTT): Peering/HLS, OTT/HLS ou OTT/HLS/LL-HLS/LL-Dash.
Peering/HLS — um modo com divisão simples em segmentos (chunks). Recomendado para o peering (distribuição) de fluxos. É entregue apenas HLS sobre MPEG-TS (/hls). Por padrão, a playlist é servida como EXT-X-VERSION:3 para compatibilidade com clientes peer.
OTT/HLS — um modo com divisão de segmentos otimizada para um início rápido dos players na transmissão OTT. Nesse modo, a carga de CPU é maior; é recomendado para transmissão. É entregue HLS sobre MPEG-TS (/hls). Por padrão, a playlist é servida como EXT-X-VERSION:6 com EXT-X-INDEPENDENT-SEGMENTS e o atributo CHARACTERISTICS em EXT-X-MEDIA TYPE=SUBTITLES (Apple HLS, hls.js, Safari, dash.js/Shaka). Se um cliente específico precisar de um valor anterior, defina-o pelo parâmetro de consulta ?v= (veja a lista de parâmetros acima).
OTT/HLS/LL-HLS/LL-Dash — um modo de entrega sobre CMAF (MP4 fragmentado, fMP4; desde a versão 1.13). O stream gera segmentos fMP4 (.m4s + um init.mp4 comum, mimeType="video/mp4"), sobre os quais são entregues:
MPEG-DASH em
/dash— agora sobre CMAF, e não sobre MPEG-TS;Low-Latency HLS em
/llhls(veja Low-Latency HLS abaixo);com a configuração de stream Enable TS Chunk ativada (padrão true) — adicionalmente HLS legacy sobre MPEG-TS (
/hls), como no OTT/HLS; com false, são entregues apenas segmentos fMP4, o que economiza disco e CPU.
A playlist HLS no OTT/HLS/LL-HLS/LL-Dash também é EXT-X-VERSION:6 por padrão.
Nota
MPEG-DASH e Low-Latency HLS estão disponíveis apenas no OTT/HLS/LL-HLS/LL-Dash. No OTT/HLS e no Peering/HLS, é entregue exclusivamente HLS sobre MPEG-TS.
É possível habilitar SSL (HTTPS) no servidor HTTP nas configurações do servidor.
Chunk Min Interval e Chunk Max Interval
No modo OTT, o fluxo é analisado para PAT/PMT/SPS/PPS/IFrame e os chunks são fatiados segundo o critério de arranque rápido dos reprodutores. A análise começa em min interval e, se por algum motivo os dados não forem encontrados, o chunk é fatiado à força em max interval.
GOP-aligned segments
No OTT/HLS, o segmentador alinha as fronteiras dos chunks aos pontos de acesso aleatório e distingue entre IDR e um I-frame comum. Se a fonte transmite com closed-GOP (com IDR), cada segmento TS .ts começa garantidamente com SPS / PPS / IDR (para HEVC — também VPS) — um verdadeiro ponto de entrada a partir do qual o player abre o fluxo. Se a fonte for open-GOP / sem IDR, a fronteira é o I-frame mais próximo (o comportamento anterior). O segmentador remove a «cauda» do GOP anterior — os slices P / B — da janela entre o PAT inicial e o primeiro SPS do chunk. Isso:
elimina o quadro preto inicial no começo da sessão VOD (
?t=/?epg=) em hls.js, Safari e VLC: o decodificador MSE recebe o conjunto correto de unidades NAL de cabeçalho já no primeiro segmento e inicia imediatamente;alinha a saída com HLS RFC 8216 §3 («Each Media Segment MUST contain a SPS and a PPS that decode its first Access Unit»);
torna correta a declaração EXT-X-INDEPENDENT-SEGMENTS em uma playlist EXT-X-VERSION:6.
Controlado pela configuração por stream gop-aligned-segment (padrão true). Aplica-se apenas quando HLS = OTT/HLS: em Peering/HLS e para streams MPTS o comportamento não muda. O PSI (PAT / PMT) e o áudio são preservados integralmente; o único efeito colateral é um salto de um quadro do continuity_counter na PID de vídeo na fronteira entre dois chunks vizinhos, o que constitui um decode boundary legítimo para HLS / DASH MSE.
Ao alinhar aos pontos de entrada, a duração real do chunk pode ser arredondada para cima além de Chunk Min Interval. Por isso, na playlist live o valor EXT-X-TARGETDURATION reflete a duração de segmento real máxima (seção 4.3.3.1 de RFC 8216) em vez do mínimo configurado. Isso mantém o manifesto dentro do padrão: hls.js e os players compatíveis não reduzem o intervalo de atualização da playlist nem emitem bufferStalledError falsos.
Low-Latency HLS (/llhls)
No OTT/HLS/LL-HLS/LL-Dash, além de /dash há um endpoint Low-Latency HLS separado — entrega de baixa latência sobre os mesmos segmentos fMP4 de CMAF:
A playlist de mídia é dividida em segmentos parciais (parts, diretivas #EXT-X-PART): o player inicia a reprodução sem esperar o segmento completo ficar pronto. São aplicados o recarregamento bloqueante da playlist (o servidor retém a requisição até o próximo part ficar pronto) e a dica de pré-carregamento #EXT-X-PRELOAD-HINT.
A duração-alvo de um part é definida pela configuração de stream Part Target Duration (ms; padrão 500, faixa 100–5000). O valor é aplicado em tempo real, sem reiniciar o fluxo, e deve ser menor que Chunk Min Interval.
HLS / DASH / LL-HLS Adaptive Multistream
HLS Adaptive Multistream é suportado desde a versão 1.10, DASH Adaptive Multistream desde a versão 1.12 (desde a versão 1.13 — sobre CMAF), e Low-Latency HLS Adaptive desde a versão 1.13.
Para os fluxos adaptativos, configura-se uma playlist separada. Para isso:
Ativar a entrega OTT nos fluxos que farão parte da playlist adaptativa: OTT/HLS — para HLS adaptativo sobre MPEG-TS; OTT/HLS/LL-HLS/LL-Dash — para DASH / Low-Latency HLS adaptativos sobre CMAF.
No menu principal aparecerá uma seção de fluxos adaptativos. Nela é preciso adicionar um fluxo e indicar todos os fluxos que devem entrar nesta playlist.
Os fluxos podem ter um parâmetro de bitrate definido. Por padrão, é 0 — o bitrate é obtido do valor medido; caso contrário, pode ser definido explicitamente.
Para playlists adaptativas a URL é diferente:
Aos peers (clientes) pode-se impor restrições de acesso aos fluxos adaptativos, assim como aos comuns. A permissão para um fluxo adaptativo inclui a permissão para todos os fluxos que o compõem.
HTTP/3 (QUIC)¶
Desde a versão 1.13.1.438, o Perfect Streamer inclui um servidor HTTP/3 integrado para a entrega OTT de HLS, MPEG-DASH e Low-Latency HLS sobre QUIC (RFC 9000 + RFC 9114). A pilha é ngtcp2 (QUIC v1) + nghttp3 (HTTP/3 frame layer); a infraestrutura TLS reutiliza o mesmo certificado que o listener HTTPS.
O QUIC serve apenas rotas OTT:
/— redirecionamento raiz,/hls/...,/dash/...e/llhls/...— master playlists / MPD,/h<sessID>/...— URL por sessão (media playlists, segmentos, VTT),/http/<stream>/...— MPEG-TS bruto sobre HTTP.
Low-Latency HLS e DASH são entregues sobre QUIC de forma incremental (chunked): as parts são enviadas ao cliente à medida que ficam prontas, sem esperar o segmento completo.
Os caminhos administrativos (/data, /config, /xmltv, /db/, /login, /logout, /restart) devolvem 404 sobre QUIC — a API de administração permanece em HTTPS / HTTP-TCP. Trata-se de uma restrição deliberada para reduzir a superfície de ataque do listener QUIC.
Ativação¶
As definições de QUIC encontram-se na secção Configuration / HTTP server (nó /config/http-server):
HTTP/3 Enable (
http3-enable) — indicador global que ativa o listener QUIC. Valor por omissão: off. A ativação abre um socket UDP emhttp3-port; a desativação fecha-o.HTTP/3 Port (
http3-port) — porta UDP do listener QUIC. Valor por omissão: 43984. O QUIC opera sobre UDP e o HTTPS sobre TCP; as portas podem coincidir ou diferir, sem conflito entre si.HTTP/3 0-RTT Enable (
http3-zero-rtt-enable) — permite o handshake 0-RTT (RFC 9001 §4.6.1) em ligações retomadas do mesmo cliente. Reduz a latência de arranque; o risco de reprodução deve ser considerado para pedidos não idempotentes (é seguro para cargas OTT de apenas leitura). Valor por omissão: on.
As alterações de configuração são aplicadas a quente, sem reiniciar o serviço.
O certificado e a chave são obtidos do listener HTTPS — não existe configuração de certificado separada para HTTP/3. Se o HTTPS não estiver configurado (ssl-enable=false), a ativação do HTTP/3 não produz efeito — o handshake não será concluído.
O parâmetro ?h3 — opt-in por sessão¶
Um browser não liga diretamente a um endpoint HTTP/3 — acede primeiro via HTTPS/TCP, recebe na resposta o cabeçalho Alt-Svc: h3=":<port>"; ma=86400 (RFC 7838) e só os pedidos seguintes a esse origin são comutados para QUIC.
No Perfect Streamer, a emissão de Alt-Svc é opt-in por sessão OTT. O servidor não anuncia QUIC a todos os clientes indistintamente: o cliente deve solicitar HTTP/3 explicitamente através do parâmetro de consulta ?h3 no URL master HLS / DASH.
Valor no URL |
Valor opt-in |
|
|---|---|---|
parâmetro ausente |
off (default) |
não |
|
on |
sim |
|
on |
sim |
|
explicit off |
não (como se ausente) |
Depois de o cliente obter o URL de sessão /h<sess>/..., o indicador wantH3 fica armazenado na sessão — todas as atualizações posteriores de media playlist, GET de segmentos e GET de chunks VTT sob esse URL de sessão recebem também Alt-Svc, mesmo que ?h3 esteja ausente do pedido em si. Sem opt-in no master, não se estabelece comportamento sticky.
Filtragem de Alt-Svc:
O listener QUIC está globalmente ativado (
http3-enable=true); caso contrário o anúncio é suprimido mesmo com?h3definido.O pedido não chegou por QUIC — em pedidos já servidos sobre H3,
Alt-Svcnão faz sentido e não é emitido.Por sessão ou por URL
wantH3=true(ver a tabela acima).Os servidores de administração e EPG nunca emitem
Alt-Svc— não possuem listener QUIC.
Este comportamento está em conformidade com a RFC 7838 §3 — o próprio servidor decide em que respostas emite Alt-Svc.
Cenário de comutação para QUIC no browser¶
Fluxo típico (Chrome / Firefox / Safari):
O leitor abre o URL master com opt-in explícito:
https://stream.example.com:41982/hls/test1/login/password/index.m3u8?h3=1
O primeiro pedido vai por HTTPS/TCP. Na resposta o servidor emite
Alt-Svc: h3=":43984"; ma=86400.O browser memoriza o mapeamento
stream.example.com:41982 → h3=":43984". No Chrome pode ser visto na páginachrome://net-internals/#alt-svc; no Firefox —about:networking#http3.Nos pedidos seguintes ao mesmo origin (atualização da playlist, GET de segmentos, VTT) o browser abre uma ligação QUIC em
udp/43984e prossegue sobre HTTP/3. Em DevTools → Network a coluna Protocol desses pedidos passa ah3.
Se a ligação QUIC não puder ser estabelecida (porta UDP bloqueada pela firewall, certificado não confiável no sistema), o browser permanece de forma transparente em HTTPS/TCP — funcionalmente o fluxo continua a reproduzir sem interrupção.
Contabilização de clientes e monitorização¶
O endereço IP real de um cliente QUIC na contabilização de pares ativos (/data/http-clients, limites de ligações concorrentes, ACL por IP) é o endereço de peer real da ligação QUIC, não o loopback da ponte de backend interna.
O atributo ott-type em /data/http-clients é composto, com o formato <PROTO>/<scheme>:
PROTO— protocolo OTT:HLS,DASHouHTTP.scheme— o transporte de rede efetivo:http,httpsouquic.
Exemplos: HLS/quic, DASH/https, HTTP/http. A interface de administração mostra tanto o protocolo OTT como o transporte de rede de cada cliente numa única coluna.
O tempo-limite de uma sessão OTT é de 60 segundos, independentemente do transporte. Quando o cliente alterna entre transportes, o esquema apenas é atualizado para cima segundo a cadeia de prioridade http → https → quic. Um retorno paralelo a uma ligação menos segura não sobrescreve o tipo atual — na contabilização permanece o transporte mais seguro observado.
Compatibilidade dos leitores¶
O HTTP/3 para OTT é suportado por:
iOS AVPlayer / Safari — nativamente, através de
Alt-Svc; com 0-RTT.Chrome, Firefox, Edge, Brave — através de
Alt-Svc; o HLS é reproduzido com hls.js e o DASH com dash.js / Shaka; o tráfego do leitor herda o HTTP/3 da fetch API do browser.Android ExoPlayer — através do motor QUIC Cronet (não é o transporte predefinido; requer configuração no cliente).
VLC (libVLC) não suporta HTTP/3 — nestes clientes o fluxo continua a funcionar sobre HTTPS/TCP, sem o benefício do QUIC.
O benefício real do QUIC face ao HTTPS/TCP é mais notório em redes móveis / Wi-Fi / redes com perdas:
ausência de head-of-line blocking ao nível do TCP — uma perda num fluxo HTTP não atrasa os restantes;
handshake 0-RTT em ligações retomadas do mesmo cliente;
taxa de bits ABR mais estável com perdas de pacotes de 1 a 5 %.
Em redes geridas / Wi-Fi corporativo, o ganho costuma ser modesto — de 5 a 10 % na latência de arranque e praticamente nulo em regime estacionário. A carga de CPU no servidor é maior com QUIC do que com o TCP do kernel — é o preço de uma pilha TLS + transporte em user space.
Modelo de cache para OTT HLS e DASH¶
O servidor produz respostas em três categorias, distintas pelo tempo de vida do conteúdo e pela adequação ao cache em nós intermediários (reverse proxy, CDN, cache do cliente).
1. Modelo de cache¶
1.1. Recursos e cabeçalhos HTTP¶
Recurso |
URL |
Content-Type |
Cache-Control |
|---|---|---|---|
Segmento TS (HLS) |
|
|
|
Segmento fMP4 (DASH / LL-HLS) |
|
|
|
DASH MPD |
|
|
|
HLS master |
|
|
|
HLS media |
|
|
|
302 Redirect |
|
— |
|
Raw TS |
|
|
não definido; não é cacheado |
1.2. Características dos segmentos¶
O identificador hexadecimal do segmento na URL (<keyHex> nos caminhos /h<sess>/<keyHex>.ts) é calculado como um CRC64 sobre o tempo de início do segmento e o ID do stream, e é globalmente único. A URL do segmento endereça conteúdo imutável — em requisições repetidas para a mesma URL é devolvido um fluxo de bytes idêntico (enquanto o segmento permanecer dentro da janela deslizante).
A diretiva immutable suprime a revalidação condicional pelo cliente (If-None-Match, If-Modified-Since). O valor max-age=60 é compatível com o típico timeShiftBufferDepth=40s.
Os segmentos fMP4 de CMAF (.m4s) e o init.mp4 comum para DASH / Low-Latency HLS são endereçados de forma análoga e armazenados em cache pelo mesmo modelo (immutable, max-age=60). Os segmentos parciais (parts) do LL-HLS são requisições byte-range dentro do mesmo .m4s, portanto não formam uma entrada de cache separada.
1.3. Características dos manifestos¶
max-age=1 limita o limite superior de obsolescência do conteúdo no cache em um segundo. Em conjunto com proxy_cache_lock on (nginx), picos de requisições ao manifesto coalescem em uma única requisição ao origin por segundo.
1.4. Variabilidade do conteúdo¶
Com absPath=0 (valor padrão; sem o parâmetro de URL a) os manifestos HLS media e DASH MPD não incluem identificador de sessão no corpo. O conteúdo do manifesto é idêntico entre sessões que pertencem à mesma combinação (stream, param). Isso permite que o cache do reverse-proxy reutilize uma única entrada entre sessões quando a chave de cache está normalizada.
Com absPath=1 (parâmetro de URL a=1) o corpo do manifesto contém URLs absolutas que incluem o esquema, o host e o identificador de sessão. O conteúdo torna-se específico da sessão; a reutilização de cache entre sessões não está disponível.
2. Comportamento dos clientes¶
Cliente |
URL de atualização do manifesto |
Impacto no número de sessões |
|---|---|---|
VLC 3.x HLS |
|
Uma sessão por reprodução |
VLC 3.x DASH |
|
Tratado por session reuse (ver 3.3) |
ffmpeg 5.x HLS |
|
Uma sessão por reprodução |
ffmpeg 5.x DASH |
|
Tratado por session reuse (ver 3.3) |
dash.js, hls.js |
|
Uma sessão por reprodução |
3. Mecanismos especializados¶
3.1. Redirect HTTP 302 para DASH¶
Uma requisição da forma /dash/<stream>/<login>/<pass>/index.mpd retorna a resposta 302 Found com o cabeçalho Location: /h<sess>/index.mpd. O corpo da resposta é vazio. A autenticação e a alocação da sessão acontecem na fase de processamento do redirecionamento.
Clientes que suportam cache de redirecionamento acessam diretamente a URL da sessão nas requisições subsequentes. Clientes que não suportam repetem a requisição de redirecionamento. O custo do reprocessamento do redirecionamento limita-se à verificação de autenticação e às operações de session reuse.
3.2. Session reuse para DASH¶
Ao processar uma requisição /dash/.../index.mpd do mesmo login para o mesmo stream (com o mesmo indicador adaptive), o servidor encontra uma sessão DASH já existente e devolve novamente o identificador dela. Nenhuma nova sessão é criada; nenhum slot do limite de conexões simultâneas é consumido.
Aplica-se apenas ao DASH. Para HLS não é necessário um mecanismo de reuse separado: os clientes HLS atualizam a media playlist via URL de sessão e não criam uma nova sessão a cada refresh.
3.3. Reutilização de segmentos entre sessões¶
O caminho /h<sess>/<keyHex>.ts não depende de <sess> ao resolver <keyHex> em conteúdo: <keyHex> identifica de forma globalmente única um segmento TS dentro de um stream. Nginx com uma chave de cache normalizada (que remove o prefixo /h<sess>/) atende cada requisição para o mesmo <keyHex> a partir de uma única entrada de cache, independentemente de quais clientes a emitiram.
O mesmo vale para os segmentos fMP4 de CMAF (.m4s) e init.mp4: seu conteúdo é imutável e endereçado dentro do stream, de modo que a normalização da cache key produz a mesma deduplicação entre sessões no cache.
4. Parâmetros da requisição¶
Parâmetro |
Valor padrão |
Impacto |
|---|---|---|
|
|
|
|
|
|
|
|
Comprimento mínimo da janela para emitir o manifesto |
|
|
|
|
ausente (off) |
opt-in para HTTP/3 (QUIC) — faz com que o servidor emita |
A alteração de um parâmetro via query string atualiza os valores armazenados na sessão na sua próxima reabertura.
5. Características de carga¶
A carga no origin escala com o número de streams distintos assistidos simultaneamente. O aumento do número de clientes assistindo o mesmo stream não aumenta o número de requisições ao origin quando há reverse-proxy cache com chave de cache normalizada.
Cenário |
Taxa de requisições ao origin (ref.) |
|---|---|
1 cliente por fluxo X |
MPD: 0.4 req/s, segment: 0.2 req/s |
N clientes em um mesmo fluxo X (cache ativo) |
MPD: 1 req/s, segment: 0.2 req/s |
N clientes ffmpeg em modo replay no mesmo fluxo |
MPD: 1 req/s (com |
N clientes em N fluxos distintos |
MPD: 0.4·N req/s, segment: 0.2·N req/s |
6. Nginx como reverse proxy com cache¶
6.1. Configuração 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. Função das diretivas¶
Diretiva |
Finalidade |
|---|---|
|
Serializa as requisições upstream em cache misses simultâneos para a mesma chave |
|
Devolve a cópia obsoleta às requisições paralelas durante a atualização do cache |
|
Usa |
|
Proíbe o cache de erros de autorização e 404 |
|
Mantém um pool de conexões persistentes ao origin |
|
Para segmentos; ativa o bufferização da resposta no nginx |
|
Para a seção |
6.3. Cálculo de max_size do cache de segmentos¶
Valor de referência: bitrate × timeShiftBufferDepth × distinct_streams × 2
Exemplo: 10 fluxos × 8 Mbps × 40 s × 2 ≈ 800 MB. Recomenda-se uma margem de 10× para absorver a variabilidade do bitrate.
6.4. Terminação TLS¶
O servidor do Perfect Streamer aceita conexões nas portas HTTP e HTTPS. Com terminação TLS no nginx, o upstream usa a porta HTTP. O encaminhamento dos cabeçalhos X-Forwarded-Proto e X-Forwarded-Host é obrigatório para a composição correta de URLs absolutas quando 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;
}
Para HTTPS entre nginx e origin aplicam-se proxy_ssl_verify e proxy_ssl_trusted_certificate. Em conexões loopback a criptografia é redundante.
6.5. Multi-host¶
Quando um único processo nginx atende vários server_name, $host é adicionado à cache key para isolar o conteúdo:
map $uri $pss_cache_key {
~^/h[0-9a-f]{16}(?<tail>/.+\.(ts|m3u8))$ "$host:stream:$tail";
default "$host:$uri";
}
O tamanho de keys_zone é dimensionado em 8000 chaves/MB. Para instalações multi-host com milhares de fluxos, recomenda-se keys_zone=...:300m ou mais.
7. Cache do cliente¶
Cache-Control: immutable é processado pelos navegadores Chrome/Firefox/Safari. O cache do cliente devolve o segmento sem requisição condicional em acessos repetidos (incluindo seek para trás dentro do buffer do player).
Service Workers podem aplicar a estratégia cache-first baseada no conteúdo de Cache-Control. Os players DASH (dash.js, Shaka) usam MSE através de SourceBuffer; o segmento colocado no buffer permanece disponível sem nova requisição HTTP até sair da janela deslizante.
Para requisições cross-domain, o cabeçalho Access-Control-Allow-Origin: * permite o cache em shared caches sem Vary: Origin. Ao trocar o valor ACAO para um Origin específico passa a ser necessário Vary: Origin, o que reduz a eficiência do shared cache.
8. Distribuição via CDN¶
Perfect Streamer é compatível com CDNs em modo pull-from-origin (Cloudflare, Akamai, Fastly, BunnyCDN, Amazon CloudFront).
Origin shield. Recomenda-se colocar um ou mais nós shield entre o edge do CDN e o origin para reduzir a taxa de requisições ao origin quando os clientes estão distribuídos globalmente.
Purge. Segmentos content-addressed não precisam de purge. Quando os metadados do stream mudam (codec, resolução), os manifestos atualizam dentro de max-age=1 sem purge explícito.
Cache warming. Em caso de pico esperado em um stream específico, é admissível pré-aquecer a CDN a partir de vários pontos geográficos antes do início da transmissão.
Geodistribuição. Os segmentos (max-age=60) são bem adequados para cache geograficamente distribuído. Os manifestos (max-age=1) toleram atraso de entrega de até um segundo — aceitável para live non-low-latency.
9. Monitoramento¶
9.1. X-Cache-Status¶
Adicionar add_header X-Cache-Status $upstream_cache_status; em cada location com cache. Valores:
Valor |
Descrição |
|---|---|
|
Resposta do cache |
|
Não estava em cache; obtido do origin e armazenado |
|
Expirado, atualizado |
|
Cópia stale entregue à requisição paralela durante a atualização |
|
|
|
Origin retornou 304 Not Modified |
|
|
9.2. Formato do access-log¶
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étricas¶
O módulo nginx-vts exporta métricas por zona no formato Prometheus:
GET /status/format/prometheus
Limites recomendados para alertas:
Métrica |
Limite |
Causa possível |
|---|---|---|
Segment HIT rate |
< 90 % em 5 minutos |
Normalização de cache key quebrada; |
Manifest MISS rate |
> 50 % em 1 minuto |
|
Upstream response time p95 |
> 500 ms em 1 minuto |
Sobrecarga do origin |
Cache zone fill |
> 90 % em 10 minutos |
Aproximação de |
10. Diagnóstico¶
Sintoma |
Causa provável |
Solução |
|---|---|---|
Taxa HIT de segmento baixa |
|
Verificar cabeçalhos e regex na diretiva |
404 em segmentos após sair da janela |
404 em cache para segmento que saiu da janela deslizante |
Adicionar |
Atraso do início da reprodução 2–5 s |
|
Reduzir para 1–2 s; ativar |
O manifesto não atualiza |
|
Definir explicitamente |
Crescimento de TIME_WAIT no upstream |
Falta |
Adicionar |
403 em |
O cliente resolve URLs relativas a partir da URL pré-redirect |
O servidor emite |
Lags, rebuffering frequente em clientes remotos |
Throughput TCP efetivo baixo devido a slow start e idle restart com RTTs grandes (300 ms e superiores) |
Ajuste da pilha de rede do Linux no origin: ver 10.1 |
10.1. Ajuste TCP do origin para clientes high-RTT¶
O problema se manifesta em clientes com RTT grande até o origin (por exemplo 300 ms ou mais) quando o bitrate do stream está próximo da capacidade do canal. Sintomas no reprodutor (VLC, ffmpeg, dash.js) — rebuffering frequente, warnings do tipo ES_OUT_SET_PCR called too late (aumento de pts_delay), buffer deadlock prevented, interrupções do stream. No servidor, enquanto isso, o cliente parece normal, não há erros, e o throughput em /data/stream/... corresponde ao stream de entrada.
Causa:
TCP slow start. Cada nova conexão TCP começa com um congestion window de cerca de 14 KB e o aumenta ao longo de vários RTT. Com um RTT de 300 ms, atingir a janela completa leva 2-3 segundos. Durante esse tempo, um segmento HLS/DASH com duração de 5 s (4-6 MB) é baixado visivelmente mais devagar do que em tempo real.
TCP idle restart. Entre solicitações de segmentos, um cliente HLS em pull-model faz uma pausa de 4-5 s. Por padrão, após tal pausa o kernel do Linux redefine o congestion window da conexão para o initial cwnd (comportamento
net.ipv4.tcp_slow_start_after_idle=1). Como resultado, no próximo GET a conexão keep-alive retoma a transmissão a partir do slow start — mesmo em uma sessão já aquecida.
Um agravante adicional — o congestion control CUBIC padrão lida mal com RTTs longos e perdas de pacotes em trechos intermediários da rede.
Solução — dois parâmetros sysctl no 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
Para aplicação persistente:
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
O principal efeito vem do primeiro parâmetro (tcp_slow_start_after_idle=0). Ele elimina diretamente o slow start repetido entre solicitações de segmentos dentro de uma mesma conexão keep-alive. O segundo (BBR) oferece robustez adicional e aplica-se a todas as novas conexões.
O ajuste não requer reinicialização do Perfect Streamer e aplica-se a todas as novas conexões TCP imediatamente após sysctl -w. As conexões existentes conservam o congestion control com o qual foram estabelecidas.
11. Segurança¶
11.1. Session URL¶
A URL no formato /h<sess>/... cumpre a função de token de sessão — não exige reautenticação. O tempo de vida é limitado pelo idle timeout (valor 30 s). Em caso de inatividade, a sessão é removida pela tarefa cleaner.
Requisitos:
HTTPS em todos os caminhos OTT (
/hls/,/dash/,/h<sess>/) em produçãoO Session ID no cabeçalho
Locationdo 302 não é cacheado (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;
}
}
URLs de sessão (/h<sess>/) não exigem rate limiting — o processamento é barato e as respostas são cacheadas.
11.3. Cache de respostas com erros¶
proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;
Proíbe o cache de redirecionamentos (sess único em Location) e de respostas de erro de autorização ou recurso ausente.
11.4. Restrição do acesso de rede ao origin¶
A porta 41972 (41982 para HTTPS) deve estar fechada ao tráfego externo. Configurações aceitáveis:
Bind do Perfect Streamer em
127.0.0.1(com nginx local)Regra de firewall:
iptables -A INPUT -p tcp --dport 41972 ! -s 10.0.0.0/8 -j DROP
12. Integração com middleware¶
12.1. Modelo prefix-login¶
O Perfect Streamer permite delegar a identificação de usuário a middleware/sistema de billing via o mecanismo prefix-login. Um conector externo ao sistema de billing não está incluído nesta versão.
Configuração do usuário embedded:
{
"id": 9,
"login": "sub",
"password": "xxx",
"is-prefix": true,
"max-conn-http-hls": 1,
"accept-stream": [ ... ]
}
Com is-prefix: true o servidor aceita URLs cujo login segue <prefix><billing_user_id>:
/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8
12.2. Formato das estatísticas¶
<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>
O campo login-id contém o hash do login URL. login é o valor configurado. match-login é o login URL usado pelo cliente.
12.3. Limitações do prefix-login¶
Senha compartilhada. Todos os assinantes do pool prefix usam um único valor de senha. O comprometimento da senha concede acesso a qualquer
<prefix><string>.Granularidade de ACL.
accept-streamaplica-se a todo o pool prefix; não há ACL por assinante sem billing externo.Rotação da senha. A alteração da senha desconecta todos os assinantes ativos. Uma substituição gradual requer o uso temporário de dois prefix-logins.
13. Legendas WebVTT¶
A fonte das legendas é DVB Teletext / DVB Subtitling do MPEG-TS de entrada. As faixas de legendas Teletext devem estar presentes nas seções Media Information ou Original Media Information. A seção Analyzer também permite verificar se os pacotes dos PIDs correspondentes estão ativos.
Para OTT HLS/DASH o modo OTT deve estar ativado (em Peering/HLS as legendas WebVTT não estão disponíveis). Na seção Output # OTT o contador de chunks OTT WebVTT buffer chunk count deve ficar diferente de zero.
Para diagnosticar as legendas, ativar Analyze e Trace no stream. Ao iniciar o fluxo, o log do stream deve exibir:
Start Teletext subtitle decoder
[ttxsubdec] ttx: pid=331 magazine=8 page=0x88 lang=***
Em seguida, o log registra o texto decodificado das legendas.
13.1. URL dos segmentos VTT¶
Esquema |
URL |
Conteúdo |
|---|---|---|
HLS master |
|
|
HLS subtitle playlist |
|
lista |
Segmento VTT HLS |
|
VTT com X-TIMESTAMP-MAP estilo HLS |
DASH MPD AdaptationSet |
em |
|
Segmento VTT DASH |
|
VTT com X-TIMESTAMP-MAP estilo DASH |
<keyHex> é um CRC64 hex de 16 caracteres calculado a partir do tempo de início do segmento, do ID do stream e do PID da faixa de legendas. <seq> é o número decimal sequencial de um chunk do stream de legendas (a numeração das legendas não está relacionada com a dos chunks TS).