Finalmente instalei algumas câmeras de vigilância na casa nova. Além do aspecto dissuasório, está me proporcionando tarimba numa área que desconheço completamente: vídeo digital. E como entusiasta de código aberto e do UNIX way of life, estou tentando evitar o caminho fácil de comprar um DVR ou contratar um serviço na nuvem.
Minha câmera padrão é a Intelbras VIP 1230. É uma câmera IP PoE, leve, relativamente barata, pode ficar no tempo, grande-angular (90º de visão), possui iluminador IR para até 30m de visão noturna. É um produto de visível qualidade, de uma empresa que conheço mais ou menos de perto. Se dinheiro desse em árvores, padronizaria na VIP 3230.
Parece que essa VIP 1230 realmente roda um Linux embarcado. A interface Web funciona muito bem, parece ser muito estável. Múltiplos clientes podem conectar-se à câmera, com um limite global de banda de 24Mbps. Há a opção de stream secundária de baixa resolução.
Talvez experimente com algum modelo da HikVision no futuro, que tende a custar mais barato. Ou quem sabe até com aqueles módulos ESP32-CAM.
A grana está curta para arrumar hardware especializado? Isso não impede de começar a brincadeira. Os módulos ESP32-CAM custam 5 doletas no AliExpress, e este projeto implementa o RTSP nesse microcontrolador. Existem apps que transformam aquele seu celular velho jogado na gaveta numa câmera RTSP. (Lembrando que a maioria dos celulares são resistentes à água, e a qualidade da câmera provavelmente é muito superior a uma câmera de vigilância tradicional, então pode ser uma solução até superior em alguns aspectos.)
Uma vez que não comprei NVR, e minha solução caseira não estava pronta, pretendia usar num primeiro momento o app da Intelbras que dá acesso remoto às câmeras (ISIC Lite), de forma semelhante ao app AMT Mobile que dá acesso remoto à central de alarme, que já uso faz tempo e funciona bem.
Infelizmente, parece que pelo fato da Intelbras Cloud ter sido desativada, o ISIC Lite também não funciona mais; já falhou no processo de criação de conta.
Então o jeito foi correr um pouco com o segundo estágio, que é publicar as streams de vídeo na Web, para que sejam acessíveis de qualquer lugar. Isso também deu mais trabalho do que o esperado, e é a motivação principal deste texto.
Quem possui câmeras de vigilância em casa, acredito que deseja as seguintes funcionalidades:
Cada um desses desejos tem desafios técnicos não-triviais. O grande problema de lidar com vídeo, principalmente vídeo 24x7, é que tudo é superlativo.
Uma única câmera com bitrate de 1Mbps gera 300GB de dados por mês. Dez câmeras, 3000GB. Transmitir e armazenar isso tudo exige muita rede e muito disco. Qualquer processamento (transcoding, detecção de movimento) exige muita CPU. Detecção "inteligente" de eventos vai exigir uma ou mais GPUs (que estão custando os olhos da cara graças aos mineradores de criptomoedas).
Um DVR resolve alguns desses problemas, e simplifica outros (e.g. o acesso de fora é apenas para o DVR, não para cada câmera). Para quem não quer se incomodar, DVR é a solução. Eu não comprei um DVR porque quero fuçar (***).
Outra solução simples, aparentemente melhor que um DVR local, é um serviço de nuvem. Mas, além das soluções ofertadas não serem exatamente de graça (US$ 12/câmera/mês, em média), ainda resta a problemática do upload de filmagem. Dez câmeras a 1Mbps significa um upload contínuo de 10Mbps, que saturaria qualquer Internet residencial (*).
A questão da rede fica exacerbada se seu provedor usa CGNAT e não oferece IPv6. Uma vez que a câmera é um servidor RTSP, vai dar trabalho estabelecer a conexão com um serviço externo.
Pelo mesmo motivo, é ilusão achar que serviços tipo ISIC Lite da Intelbras seriam gratuitos para sempre. Outros fabricantes oferecem coisa semelhante, porém com franquia minúscula. O simples playback da câmera na nuvem significa download e upload de enormes quantidades de dados, e quem usa AWS sabe que isto não sai de graça.
Este é um nicho em que a computação de nuvem falhou em cumprir suas promessas. A expectativa é fazer livestream de todas as câmeras no YouTube, gerar compactos usando a inteligência artificial do ChatGPT, o AWS RedShift armazenando tudo para sempre, e tudo isso aí custando uns poucos centavos por mês. A realidade é ter acesso às câmeras unicamente através de um app proprietário, que não funciona.
A solução é trazer de volta o bom e velho servidor de rede local, rebatizado como "servidor de borda" ou edge server.
Por último, mas não menos importante, é que a nuvem depende totalmente de uma Internet funcionando. Entre Murphy e Maquiavel, é certo que ela vai falhar quando você mais precisar. Mesmo usando a nuvem, é essencial haver um dispositivo de borda (como é um DVR) na rede local.
Mas chega dessa conversa, daqui para frente é tudo tecnologia aberta e software livre.
Se a ideia é assistir a stream a partir de qualquer aparelho (computador, celular, tablet, smart TV, etc.) a solução mais versátil é publicar a stream como uma página Web. É uma solução universal, que não exige instalar app. A desvantagem é ter de configurar um servidor Web — o que não é difícil nem incomum para o leitor que já chegou até aqui.
Uma página Web não pode consumir uma stream RTSP diretamente. Antigamente, a solução era usar um plug-in Flash ou ActiveX. Como estamos na era HTML5, existem soluções nativas em duas vertentes principais: transmitir a stream via HTTP, ou usar o WebRTC.
Num primeiro momento, optei pelo streaming via HTTP, que é mais fácil de realizar e funciona em praticamente qualquer situação, mesmo em redes com firewalls restritivos e proxies transparentes. Se YouTube funciona, streaming HTTP também funciona. Mas ele tem maior latência, e exige alguma espécie de conversor RTSP–HTTP do lado servidor.
A solução aberta mais conhecida, mais fácil de usar, e que realmente funciona, é o MediaMTX. Ele embute o conversor RTSP e um servidor Web, e serve uma página prontinha para reproduzir a stream de vídeo no seu browser. Se tudo que você quer é publicar uma stream na Web, o MediaMTX resolve sozinho.
Quem for mais caprichoso vai procurar escondê-lo atrás de um proxy reverso como o NGINX — inclusive porque configurar HTTPS no NGINX é bem mais fácil. O proxy reverso também permite rodar o MediaMTX num computador separado, ou mesmo numa VPN privada.
Minhas câmeras estão (ou não estão) conectadas à Internet via CGNAT. O único jeito de ter acesso a elas é via VPN. Num primeiro momento, o MediaMTX rodava na nuvem, mesma máquina que o NGINX, obtendo as streams RTSP através da VPN.
Por questões que vou abordar mais adiante, o MediaMTX foi movido para um servidor de borda, na mesma rede que as câmeras, e o proxy reverso faz a ponte através da VPN. Antes, vou detalhar um pouco sobre como ele funciona.
Há dois métodos de streaming HTTP: Media Source Extensions (MSE) e HTTP Live Streaming (HLS).
O MSE é conceitualmente simples: é uma API Javascript que permite alimentar <video> e <audio> programaticamente. É o método mais antigo e funciona em quase todos os browsers, com a notória exceção do iPhone.
Um elemento <video> espera ser alimentado com uma stream H.264 (ou outro codec suportado). E de onde o Javascript vai obter essa stream? Isso o MSE não especifica. O site (ou seja, você) tem de inventar algum protocolo para transmitir a mídia H.264 sobre HTTP, de forma segmentada (HTTP nem sempre funciona bem com transmissão contínua, então não se pode contar com ela).
Note que <video> não aceita uma stream RTSP; ele espera H.264 puro. É preciso extrair a mídia do encapsulamento RTSP antes de transmiti-la para a página Web. Por isso precisamos do conversor RTSP–HTTP (que o MediaMTX embute, felizmente).
Já o HLS foi proposto pela Apple, obviamente funciona no iPhone, e é o mais utilizado hoje em dia. A especificação abrange comportamentos de cliente e de servidor. No código HTML, não poderia ser mais simples: basta apontar o src do <video> para uma URL de extensão .m3u8.
O formato m3u8 é uma playlist que contém a lista de segmentos de mídia obteníveis via HTTP. É aqui que a mágica acontece. Para um filme, a playlist pode ser um arquivo estático. Para TV ao vivo ou uma câmera de vigilância, a playlist tem de ser gerada e atualizada dinamicamente.
Os segmentos de mídia HLS têm uma forma predefinida. Eles devem encapsular a stream H.264 em MPEG-TS ou MP4, então o conversor RTSP–HTTP tem um pouco mais de trabalho a fazer. Analogamente ao playlist, os segmentos podem ser arquivos estáticos (distribuídos por CDN e tudo mais) para um filme, enquanto para programação ao vivo os novos segmentos têm de ser gerados dinamicamente. (Os segmentos passados de uma stream ao vivo poderiam ser armazenados e adicionados à playlist se o site deseja oferecer rewind.)
Existem bibliotecas Javascript que implementam suporte a reprodução de mídia m3u8 em browsers que suportam apenas MSE. Isso permite a um site oferecer apenas HLS do lado servidor, e ainda cobrir 100% da clientela. É exatamente o que o MediaMTX faz.
Na primeira tentativa de usar HLS e o MediaMTX, levei 15 minutos para fazer funcionar nos computadores e no celular Android, e mais 3 horas para fazer funcionar no iPhone.
A primeira questão é que nem toda combinação de browser+plataforma suporta o codec H.265, então tive de mudar as câmeras para H.264. É realmente uma pena, pois o H.265 tem bitrate muito mais baixo para a mesma qualidade. (Se não fosse possível mudar na câmera, teria de fazer transcoding, e aí, haja CPU.) Mas isso vai se resolver com o tempo, conforme o suporte a H.265 torna-se universal.
O segundo problema foi uma certa dificuldade para iniciar o playback no iPhone. Demandava duas, três tentativas até rodar, suspeitei até de problema na câmera. Mas era uma conjunção de características do HLS, da configuração do MediaMTX, e das minhas câmeras:
A solução rápida foi desligar a "compressão inteligente" das câmeras e configurar o I-frame para um a cada 5 quadros. Infelizmente, isto aumentou *muito* o bitrate da câmera. Mesmo diminuindo a resolução de 2MP apra 1MP e o frame rate para 5 FPS, o bitrate ainda ficou em torno de 2.3Mbps. Tudo isso só para fazer funcionar no iPhone...
A solução definitiva foi mover o MediaMTX da nuvem para o servidor de borda, na mesma LAN que as câmeras. Assim, ele pode obter as streams RTSP de todas as câmeras continuamente, haja ou não alguém assistindo. Os segmentos HLS mais recentes estão sempre no buffer, para entrega imediata quando algum cliente conectar.
Mesmo com o servidor de borda, existe um conflito entre taxa de I-frame e atraso de visualização. Com um I-frame a cada 3 segundos, o atraso HLS é de 3 segmentos ou 9 segundos. Habilitando a "compressão inteligente", o atraso podia passar de 60 segundos, então preferi usar uma taxa fixa de I-frame, que mantém o bitrate em níveis civilizados e o atraso num patamar aceitável.
Numa câmera de vigilância, um atraso exagerado entre geração e exibição é muito prejudicial à experiência do usuário. Muita coisa pode acontecer em 10 segundos. Se o vídeo for usado para instruir alguém à distância, qualquer atraso de 1 segundo já faz a interlocução virar uma conversa de surdos. Usar WebRTC elimina completamente esse problema. No WebRTC, a taxa de I-frame só influencia o início da exibição, pois o decoding começa quando o primeiro I-frame é recebido. Depois disso, é tudo em tempo real.
Grande dilema: qual a configuração ideal para a câmera? Por gosto, adotaríamos a máxima qualidade possível. Mas precisamos limitar bitrate por conta de streaming e armazenamento. E precisamos limitar resolução e FPS se houver análise automatizada. Num primeiro momento, vamos nos concentrar no problema do bitrate.
A primeira decisão é entre usar CBR (bitrate fixo) ou VBR (bitrate variável). Muitos pensam que o CBR garante qualidade e bitrate ao mesmo tempo, mas isso é impossível. O CBR garante o bitrate variando a qualidade. Se o bitrate escolhido for muito baixo, a qualidade cai assim que acontece algo interessante na frente da câmera.
Por outro lado, o VBR garante a qualidade variando o bitrate. A medida de qualidade pode ser expressa em bitrate médio, bitrate máximo, ou por um simples número. Nas minhas câmeras, é um valor de 1 a 6, que faz variar o bitrate médio por um fator de 10.
Dada uma mesma qualidade subjetiva, o VBR entrega um bitrate médio muito menor que o CBR, embora o bitrate instantâneo possa ser até três vezes maior que a média. Em resumo, o VBR é melhor e deve ser sua primeira escolha. O único motivo para usar CBR é por compatibilidade com algum equipamento velho que só suporta CBR.
No caso de uso de câmera de vigilância, o principal "vilão" de banda é o I-frame. O bitrate é quase que linearmente proporcional à taxa de I-frames. Aumentar a taxa de I-frame de, digamos, 1:15 para 1:5 triplicará o bitrate VBR, mantidos iguais os outros parâmetros. Já no caso do CBR, aumentar a taxa de I-frame sem aumentar o bitrate causará uma severa perda de qualidade.
Como vimos antes, o I-frame tem impacto na latência. Do ponto de vista de quem consome a stream, quanto mais I-frames melhor, então é uma verdadeira escolha de Sofia. O recurso de "compressão inteligente", que nada mais é do que produzir o mínimo possível de I-frames, não combina com streaming ao vivo. É preciso escolher a taxa manualmente.
No momento, uso uma taxa de I-frame de 1:15, que dá um I-frame a cada 3 segundos em 5 FPS, que é uma tentativa de balancear todos os prós e contras.
A relação entre bitrate e resolução é complexa; ela pode ir de sublinear até superlinear, a depender dos outros parâmetros.
Exemplo: com VBR nível 4, 5 FPS e I-frame 1:15, o bitrate estático é 170kbps para 1MP e 233kbps para 2MP (aumento sublinear). Se a taxa de I-frame for 1:5, os bitrates são 336kbps e 688kbps (aumento linear). Se também subirmos o VBR para nível 6, a relação torna-se superlinear (810kbps x 2048kbps).
Para níveis "civilizados" de I-frame e qualidade VBR, a relação tende a ser sublinear.
A relação entre bitrate e FPS é definitivamente sublinear, tanto pela eficiência do codec H.264/5 quanto pelo caso de uso. Exemplo: com VBR nível 4, 1MP, um I-frame a cada 5s, o bitrate a 5 FPS é 120kbps. Aumentando para 20 FPS, o bitrate aumenta para 180kbps — apenas 50% mais bitrate para o quádruplo de FPS.
Porém, resolução e FPS têm grande impacto no pós-processamento (transcoding, detecção de movimentos e geração de compactos). O custo de CPU do pós-processamento é linearmente proporcional ao produto resolução x FPS, não interessa o bitrate. Revisitaremos o assunto mais adiante, mas esteja avisado.
Como dito antes, H.265 é um compressor muito mais eficiente que H.264, mas infelizmente o suporte H.265 ainda não é universal nos browsers. O ganho é maior para vídeos de maior qualidade, variando de 25% menos bitrate para VBR 4, até menos 40% com VBR 6.
Considerando um vídeo H.264 de 1MP, 5 FPS e taxa I-frame 1:15, no olhômetro me parece que 256kbps é insuficiente (muitos artefatos quando há mudanças na cena), 512kbps é passável, e 768kbps é bom. Se quiser garantir, vá de 1024kbps. Para essa mesma configuração, o VBR apresenta taxas de 120 a 840kbps (média de 10 minutos), dependendo do dinamismo da cena, então usar CBR realmente nivela o bitrate por cima.
Com base nisso, é possível extrapolar para outras configurações. Por exemplo, um vídeo de 10 FPS, taxa I-frame 1:30 e 2MP pediria 1500-2048kbps, considerando que dobrar a resolução quase dobra o bitrate, mas um aumento de FPS tem impacto de apenas 25%.
Estávamos contentes com o HLS, não tínhamos intenção de lidar com WebRTC no curto prazo, porém quando estávamos dentro de casa, ficou estranho assistir às câmeras de segurança com 10 segundos de atraso. Poderíamos usar a interface Web da própria câmera, mas não é ideal.
Sucede que, graças ao MediaMTX, é muito fácil servir streaming WebRTC em paralelo com o HLS. Basta ativar na configuração. O servidor de borda já estava na rede local, então usar WebRTC dentro de casa não esbarraria nos tradicionais problemas com NAT. Vídeo com zero latência, com esforço zero!
Eu quis caprichar e usei um NGINX local para esconder o número de porta não-padrão. O proxy reverso deve ser corretamente configurado para lidar com WebSockets, utilizados na sinalização do WebRTC. Muitos outros produtos também usam WebSockets, você pode e.g. adotar a configuração de proxy reverso para o Grafana como exemplo (foi o que eu fiz).
Na rede local, tudo é fácil, não tem NAT nem firewall. Fazer isso funcionar na Internet é mais complicado, e principalmente mais custoso.
Daqui para frente vou supor que o servidor MediaMTX roda num computador "escondido" atrás de um roteador NAT. A propósito, AWS também funciona desse jeito: a instância EC2 tem IP frio, e só pode receber conexões entrantes se o firewall e o "Elastic IP" estiverem configurados.
A forma mais simples de publicar seu conteúdo WebRTC é adquirir um "IP quente" fixo, e configurar o NAT para repassar conexões entrantes ao computador MediaMTX. Fazendo desse jeito, você não precisa (imediatamente) de um servidor TURN, pode se virar apenas com o STUN público do Google. Exemplo de configuração do MediaMTX:
webrtcICEServers: [stun:stun.l.google.com:19302] webrtcICEHostNAT1To1IPs: [IPv4 quente, IPv6 quente se tiver] webrtcICEUDPMuxAddress: :8885 webrtcICETCPMuxAddress: :8885
No exemplo acima, as conexões entrantes 8885 TCP e UDP têm de ser direcionadas do roteador NAT para o computador rodando o MediaMTX.
Se você não pode obter um IP fixo, ou não pode configurar o roteador NAT para aceitar conexões entrantes, o jeito é rodar um servidor TURN, ou contratar este serviço de terceiros. A configuração do MediaMTX ficaria algo como
webrtcICEServers: [turn:usuario:senha:nome:porta] webrtcICEHostNAT1To1IPs: [] webrtcICEUDPMuxAddress: :8885 webrtcICETCPMuxAddress: :8885
Um site profissional teria ambas as soluções ativadas: IPs fixos (IPv4 e IPv6) e TURN, para ter 100% de garantia que a conexão vai acontecer.
...E ainda assim pode acontecer do WebRTC não funcionar, se o cliente estiver numa rede com firewall muito restritivo (tipo WiFi de café ou hotel, que praticamente só permite acesso à Web, com proxy transparente e o escambau). A modalidade HLS ainda funcionaria nesta situação, então é interessante continuar a oferecer HLS como plano B.
A priori, gravar streams RTSP é simples. Basta um script rodando ffmpeg. Uma vez que as câmeras podem servir RTSP a vários clientes ao mesmo tempo, o gravador pode ser um computador separado do MediaMTX. Pode haver dois gravadores, ou mesmo três, depende de quanta redundância de gravação você deseja. Se não envolver transcoding, a gravação via ffmpeg gasta pouca CPU, até um Raspberry Zero dá conta de um punhado de câmeras.
Este script tenta usar o ffmpeg para gravar streams de forma robusta. O ffmpeg pode quebrar ou pode travar durante a gravação. É raro, mas acontece, e o script lida com estas situações.
O formato MP4 armazena metadados no início *e* no final do arquivo. Se o ffmpeg for interompido, mesmo voluntariamente (por Ctrl-C) o resultado é um arquivo corrompido. Por isso, MP4 não é adequado para gravar streaming. Os formatos MKV e WebM, que são aparentados, são resistentes a interrupções. Nós utilizamos o MKV. A página do projetinho tem mais informações.
Para largar um PC ou Raspberry gravando vídeo 24x7, é preciso administrar o espaço em disco apagando gravações antigas. Aqui está outro script que faz isso (**).
A outra questão é que, se você for gravar 10 câmeras em 2 computadores, mais a eventual stream ao vivo, você tem 60Mbps de tráfego total vindo das câmeras (assumindo um bitstream de 2Mbps). Isso é um bocado de banda, perigosamente próximo de 100Mbps que é o limite de componentes como switches PoE. Também não confio muito em colocar muitos clientes pendurados na câmera, essas coisas de IoT sempre incomodam fora do caso de uso "baunilha".
Porém o MediaMTX novamente salva o dia: ele também serve como repetidor RTSP, então ele pode redistribuir a stream da câmera para outros clientes RTSP (além de tomar conta do HLS e do WebRTC). Isto é particularmente útil se o computador que roda o MediaMTX também faz gravação: faz todo o sentido não fazer duas conexões para a mesma câmera a partir da mesma máquina. No caso de gravadores secundários ou terciários, pode ou não fazer sentido usar o MediaMTX como "proxy RTSP"; o ideal é pelo menos um correr independente para não parar caso o MediaMTX pare.
O padrão de fato para câmeras de segurança é servir protocolo RTSP, então vale a pena entendê-lo pelo menos superficialmente.
Quem já teve o desprazer de mexer com RTP, H.323 ou SIP/SDP, sabe quão complicado é fazer VoIP e mídia funcionar, principalmente através de NAT. O pessoal que elabora esses padrões tenta açambarcar todas as situações possíveis, e cria monstros.
A bem da verdade, quando esses protocolos foram criados, na virada do milênio, o paradigma era outro. Imaginávamos a Internet do futuro com rádio e TV por multicast, e telefonia peer-to-peer sem nenhum embaraço. Ninguém imaginou que em 2023 a realidade seria CGNAT ubíquo, IPv6 ainda patinando, e 99% da atenção dos usuários focada em 3 ou 4 apps.
No caso do RTP, nada menos que três protocolos têm de trabalhar em conjunto: RTP, RCTP, e RTSP. O RTP carrega a mídia em si, os demais fazem a sinalização. O RCTP faz sincronismo e controle de QoS. O RTSP é o "controle remoto". Imagine fazer tudo isso passar por firewalls e NATs, por diferentes portas TCP e UDP.
Sucede que o RTSP pode trafegar via TCP, e tem o recurso de multiplexar pacotes dos outros dois protocolos. Isso veio a calhar numa Internet cheia de NATs e firewalls. Podemos resolver tudo com uma única conexão TCP. O pragmatismo transformou essa modalidade num padrão de fato.
Um servidor RTSP também pode fazer papel de proxy ou distribuidor. O RTSP embutido no MediaMTX pode receber uma stream (e.g. do ffmpeg) numa certa URL, e repassá-la para diversos outros clientes que requisitam a stream na mesma URL.
A mídia H.264, ou de qualquer outro codec, está encapsulada em pacotes RTP que são multiplexados pelo RTSP. Então, para obter a mídia de verdade (que vai para o decodificador), é preciso "desempacotá-la", coisa que o MediaMTX faz para servir a stream via HLS ou WebRTC.
Para quem tiver interesse, vamos descrever brevemente como o WebRTC funciona, para entender os desafios:
A seqüência não é muito diferente de uma ligação VoIP SIP, com o SIP fazendo o papel de sinalização.
O grande problema do SDP é que ele transmite endereços IP à contraparte. Além de não ser muito católico (a camada de aplicação nunca deveria tomar conhecimento de detalhes da camada de rede), também cria problemas na presença de NAT, porque as interfaces de rede geralmente têm IPs frios. Contornar esse problema deixou muita gente louca no início do milênio, tentando fazer seu telefone SIP funcionar atrás de um roteador NAT.
Para solucionar o caso de forma mais simples e amigável, foram criados os protocolos STUN, TURN e ICE, cujo suporte foi sendo incorporado a produtos VoIP.
O STUN é essencialmente um método para o computador descobrir seu próprio endereço IP público, o que pode ser suficiente para viabilizar a conexão peer-to-peer, dependendo da conexão de rede e do tipo de roteador NAT que há pelo caminho. Mas não atende 100% dos casos.
O TURN adiciona ao STUN a capacidade de atuar como "refletor" ou transmissor intermediário. Isto garante que a conexão pode acontecer mesmo nos casos em que o STUN não resolve, com todo tipo de roteador NAT e CGNAT no caminho, e até mesmo se uma parte é apenas-IPv4 e a outra seja apenas-IPv6.
Porém, operar um servidor TURN tem custo de banda, então cada serviço de streaming tem de providenciar o seu. O software mais comumente utilizado é o coturn. Outra opção é contratar um serviço TURN de nuvem como o Twilio. Adotar o TURN quando o STUN daria conta é jogar dinheiro fora.
O ICE é uma consolidação das técnicas acima, e usa STUN e TURN para identificar endereços-candidatos para comunicação. Os candidatos são ordenados por prioridade. Por exemplo, um candidato LAN ou STUN é mais desejável que um candidato TURN, o protocolo UDP é mais desejável que TCP, IPv6 é mais desejável que IPv4, e assim por diante.
Agora, o pulo do gato: o ICE testa cada possível combinação de candidatos locais e remotos, enviando consultas STUN para cada candidato (não mais para o servidor STUN). Se a consulta obtém resposta, signfica que aquela combinação é boa para tráfego peer-to-peer. Se um lado tem 3 candidatos e o outro lado tem 2, cada lado tem 6 pares para testar, o que resulta em 12 testes no total. As combinações boas são coletadas, e a mais desejável para ambos os lados é eleita como canal de mídia.
O ICE quase sempre acha o melhor caminho, detectando inclusive se as partes estão na mesma LAN ou na mesma VPN. Uma vez que o WebRTC açambarca o ICE, WebRTC simplesmente funciona, do ponto de vista do usuário.
Do ponto de vista do dono do site, ele precisa estudar os recursos de rede disponíveis e decidir corretamente pelo serviço STUN ou TURN. Mas uma coisa é certa: um site com capacidades de streaming sempre vai ter custo substancial de operação.
Se quiser, dê uma olhada na Parte 2 desta aventura.
(*) Aqui estou vestindo o boné do provedor de Internet. Uma conexão GPON compartilha 1.25Gbps de upload entre até 128 clientes, o que dá 10Mbps garantidos por cabeça. Se todo mundo na sua vizinhança resolver colocar as câmeras na nuvem, é o que você vai ter.
(**) Se reclamar que abuso de scripts em vez de usar uma linguagem de verdade, chamarei o Toti e o Verde para te pegar.
(***) Eu acho que o DVR é a solução ideal para um ambiente controlado e vigiado. Já numa residência, ninguém fica vigiando quando se está dentro de casa; e o DVR e o cofre são as primeiras coisas que o ladrão vai procurar. Isto não invalida o DVR, apenas significa que precisamos de algo mais, como um segundo DVR escondido ou gravação na nuvem.