Saúdo todos os leitores de Habr. Este ano, tive a oportunidade de escrever um módulo de comunicação por vídeo para um portal de treinamento para telefonar via comunicação por vídeo diretamente no site do professor e do aluno. Não foi necessário resolver uma tarefa tão precoce. Após uma breve pesquisa, descobri que existem duas maneiras: Flash e
WebRTC . O WebRTC, em sua forma pura, acabou sendo complicado e, em geral, é natural, pois a tarefa da comunicação por vídeo não é simples. Mas então me deparei com o
PeerJS , que é um invólucro para o WebRTC. Neste artigo, mostrarei como organizar rapidamente o discador do navegador.
Para repetir o exemplo, será necessário o acesso à sua página de teste através do protocolo https (já que a página solicitará acesso à câmera e ao microfone, e sem um protocolo seguro, o navegador simplesmente apresentará um erro)
O layout inicial terá a seguinte aparência:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Peer</title> <script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script> </head> <body> <p><h3> ID: </h3><span id=myid ></span></p> <input id=otherPeerId type=text placeholder="otherPeerId" > <button onclick="callToNode(document.getElementById('otherPeerId').value)"></button> <br> <video id=myVideo muted="muted" width="400px" height="auto" ></video> <div id=callinfo ></div> <video id=remVideo width="400px" height="auto" ></video> </body>
Na seção principal, conectamos o PeerJS remotamente. Também é possível baixar o script e conectá-lo localmente.
input id = otherPeerId - projetado para entrar no banquete daquele a quem ligaremos (você pode tomá-lo como índice ou como número de telefone).
Duas tags de vídeo foram projetadas para exibir seu próprio vídeo e para o vídeo do interlocutor, respectivamente.
Agora, um pouco sobre a tecnologia WebRTC e como a chamada é feita. O WebRTC faz uma chamada de cliente para cliente diretamente, sem o envolvimento do servidor, portanto, na primeira etapa, os navegadores devem se encontrar. Para fazer isso, um WebRTC clássico requer um servidor de sinal, ou seja, um servidor que informa a um navegador os parâmetros de outro navegador e, no WebRTC, você mesmo deve organizar esse servidor. No entanto, os desenvolvedores do PeerJS fornecem seu próprio servidor de sinal. Tudo o que você precisa fazer é passar o peerID para o interlocutor em potencial, ou seja, o índice exclusivo recebido no sistema PeerJS. Em um rascunho de trabalho, organizei-o assim:
- Depois de carregar a página, um objeto Peer é criado
- Seu peerID é gravado no banco de dados mysql
- Quando o botão Ligar é pressionado, o peerID do interlocutor é retirado do banco de dados e usado para estabelecer uma conexão
No caso de teste atual, inseriremos o peerID do interlocutor no campo de texto otherPeerId
Então, vamos começar a escrever código.1. Crie o objeto de mesmo nível principal
var peer = new Peer();
2. Na abertura do banquete, receberemos o cobiçado peerID, que deve ser transferido para o parceiro para que ele possa entrar em contato conosco
peer.on('open', function(peerID) { document.getElementById('myid').innerHTML=peerID; });
3. Para receber uma chamada, desligamos o manipulador do evento de chamada
var peercall; peer.on('call', function(call) {
Com uma chamada recebida, obtemos um objeto de
chamada , que salvamos na variável global
peercall . Também no bloco de informações, uma notificação sobre uma chamada recebida e 2 botões será exibida: Aceitar e Rejeitar
4. Escrevemos uma função para o botão
Aceitar function callanswer() { navigator.mediaDevices.getUserMedia ({ audio: true, video: true }).then(function(mediaStream) { var video = document.getElementById('myVideo'); peercall.answer(mediaStream);
navigator.mediaDevices.getUserMedia - solicita acesso à câmera e ao microfone. Nos dados do objeto que é passado para esse método
{audio: true, video: true}, você pode solicitar acesso apenas à câmera ou ao microfone. Comentários adicionais foram adicionados diretamente ao código.
setTimeout foi adicionado empiricamente: o vídeo do parceiro não começou a ser reproduzido, mas funcionou com um tempo limite.
5. A função de discagem pelo botão
Ligar function callToNode(peerId) {
Como no parágrafo anterior, solicitamos seu fluxo de mídia. Depois de chamarmos a função de chamada do objeto de mesmo nível, que nos retornará o objeto de chamada, salve-o em peercall. Processamos o evento de fluxo para descobrir o que eles responderam e colocamos o fluxo de entrada no objeto de vídeo correspondente
Isso é tudo, mas ...
Se os dois chamadores estiverem atrás da NAT, a chamada não será atendida. (Por quê? Leia aqui
habr.com/en/company/yandex/blog/419951 )
Para superar esse obstáculo, é necessário especificar o servidor TURN ao criar o objeto de mesmo nível (a questão de onde obtê-lo não era a mais fácil. Tivemos que criar nosso próprio: VPS no Ubuntu 16.04. Instalação com o comando
apt install coturn
)
Então a criação da festa será mais ou menos assim:
var callOptions={'iceServers': [ {url: 'stun:95.xxx.xx.x9:3479', username: "user", credential: "xxxxxxxxxx"}, { url: "turn:95.xxx.xx.x9:3478", username: "user", credential: "xxxxxxxx"}] }; peer= new Peer({config: callOptions});
Finalmente, todo o código:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Peer</title> <script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script> </head> <body> <p><h3> ID: </h3><span id=myid ></span></p> <input id=otherPeerId type=text placeholder="otherPeerId" > <button onclick="callToNode(document.getElementById('otherPeerId').value)"></button> <br> <video id=myVideo muted="muted" width="400px" height="auto" ></video> <div id=callinfo ></div> <video id=remVideo width="400px" height="auto" ></video> <script> var callOptions={'iceServers': [ {url: 'stun:95.xxx.xx.x9:3479', username: "user", credential: "xxxxxxxxxx"}, { url: "turn:95.xxx.xx.x9:3478", username: "user", credential: "xxxxxxxx"}] }; peer= new Peer({config: callOptions}); peer.on('open', function(peerID) { document.getElementById('myid').innerHTML=peerID; }); var peercall; peer.on('call', function(call) { </script> </body>
Esta solução foi testada com sucesso no Windows7 e Ubuntu 18.04 no Chrome, Opera, Firefox. O Chrome também funciona no Android e MacOS, mas não no iPhone e iPad.