Codelab do Firebase + WebRTC

1. Introdução

Neste codelab, você aprenderá a criar um aplicativo simples de chat por vídeo usando a API WebRTC no navegador e o Cloud Firestore para sinalização. A aplicativo é chamado FirebaseRTC e funciona como um exemplo simples que ensinará os conceitos básicos da criação de aplicativos compatíveis com WebRTC.

O que você vai aprender

  • Como iniciar uma videochamada em um aplicativo da Web usando WebRTC
  • Como sinalizar para a parte remota usando o Cloud Firestore

O que é necessário

Antes de iniciar este codelab, verifique se você instalou o seguinte:

  • npm que normalmente vem com Node.js - O Node LTS é recomendado

2. Criar e configurar um projeto do Firebase

Crie um projeto do Firebase

  1. No Console do Firebase, clique em Adicionar e nomeie-o de FirebaseRTC.

Lembre-se do ID do seu projeto do Firebase.

  1. Clique em "Criar projeto".

O aplicativo que você vai criar usa dois serviços do Firebase disponíveis na Web:

  • Cloud Firestore para salvar dados estruturados na nuvem e receber notificação quando os dados forem atualizados
  • Firebase Hosting para hospedar e exibir seus recursos estáticos

Neste codelab específico, você já configurou o Firebase Hosting no do projeto que você vai clonar. No entanto, vamos mostrar como a configuração e a ativação dos serviços usando o Console do Firebase.

Ativar o Cloud Firestore

O app usa o Cloud Firestore para salvar as mensagens e receber novas conversas e envio de mensagens.

Você precisará ativar o Cloud Firestore:

  1. Na seção "Desenvolver" do menu do Console do Firebase, clique em "Banco de dados".
  2. Clique em Criar banco de dados no painel do Cloud Firestore.
  3. Selecione a opção Iniciar no modo de teste e clique em "Ativar" depois de ler sobre as regras de segurança.

O modo de teste garante que você possa gravar livremente no banco de dados durante o desenvolvimento. Deixaremos nosso banco de dados mais seguro mais adiante neste codelab.

3. Fazer o download do exemplo de código

Clone o repositório do GitHub na linha de comando:

git clone https://github.com/webrtc/FirebaseRTC

O exemplo de código foi clonado no diretório FirebaseRTC. De agora em diante, verifique se a linha de comando é executada neste diretório:

cd FirebaseRTC

Importar o app inicial

Abra os arquivos em FirebaseRTC em seu editor e altere-os de acordo com as instruções abaixo. Esse diretório contém o código inicial do codelab, que consiste em um app WebRTC ainda não funcional. Faremos isso funcional ao longo deste codelab.

4. Instalar a interface de linha de comando do Firebase

A interface de linha de comando (CLI) do Firebase permite disponibilizar um app da Web localmente e implantar seu app da Web no Firebase Hosting.

  1. Execute o seguinte comando npm para instalar a CLI: sh npm -g install firebase-tools
.
  1. Execute o comando a seguir para verificar se a CLI foi instalada corretamente. comando: sh firebase --version

Verifique se a versão da CLI do Firebase é a v6.7.1 ou mais recente.

  1. Autorize a CLI do Firebase executando o seguinte comando: sh firebase login

Você definiu o modelo de app da Web para receber a configuração do seu app para o Firebase Hospedagem do diretório e dos arquivos locais do seu app. Mas, para fazer isso, você precisa associar o app ao projeto do Firebase.

  1. Execute o comando a seguir para associar o app ao projeto do Firebase: comando: sh firebase use --add

  2. Quando solicitado, selecione o ID do projeto e dê um alias.

Um alias será útil se você tiver vários ambientes (produção, preparo etc.). No entanto, neste codelab, vamos usar apenas o alias de default.

  1. Siga as instruções restantes na linha de comando.

5. Executar o servidor local

Você já pode começar a trabalhar no nosso app. Vamos executar o app localmente.

  1. Execute o seguinte comando da CLI do Firebase: sh firebase serve --only hosting

  2. Sua linha de comando vai exibir a seguinte resposta: hosting: Local server: http://localhost:5000

Estamos usando o emulador do Firebase Hosting para disponibilizar nosso app localmente. O app da Web deve estar agora disponível em http://localhost:5000.

  1. Abra o app em http://localhost:5000.

Você verá sua cópia do FirebaseRTC que foi conectado à sua projeto do Firebase.

O app se conectou automaticamente ao seu projeto do Firebase.

6. Criando um novo ambiente

Neste aplicativo, cada sessão de chat por vídeo é chamada de sala. Um usuário pode criar uma nova sala clicando em um botão no aplicativo. Isso gera um ID que o grupo remoto pode usar para entrar na mesma sala. O ID é usado como a chave no Cloud Firestore para cada sala.

Cada quarto vai conter o RTCSessionDescriptions da oferta e do bem como duas coleções separadas com candidatos ICE de cada partido.

Sua primeira tarefa é implementar o código que está faltando para criar um novo ambiente com a proposta inicial do autor da chamada. Abra public/app.js, encontre o comentário // Add code for creating a room here e adicione este código:

const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);

const roomWithOffer = {
    offer: {
        type: offer.type,
        sdp: offer.sdp
    }
}
const roomRef = await db.collection('rooms').add(roomWithOffer);
const roomId = roomRef.id;
document.querySelector('#currentRoom').innerText = `Current room is ${roomId} - You are the caller!`

A primeira linha cria um RTCSessionDescription que representa a oferta. do autor da chamada. Ela é definida como a descrição local e exibida para o novo objeto de sala no Cloud Firestore.

Em seguida, detectaremos alterações no banco de dados e detectaremos quando uma resposta o recebedor da chamada foi adicionado.

roomRef.onSnapshot(async snapshot -> {
    console.log('Got updated room:', snapshot.data());
    const data = snapshot.data();
    if (!peerConnection.currentRemoteDescription && data.answer) {
        console.log('Set remote description: ', data.answer);
        const answer = new RTCSessionDescription(data.answer)
        await peerConnection.setRemoteDescription(answer);
    }
});

Isso espera até que o recebedor da chamada grave o RTCSessionDescription para o atender e definir isso como a descrição remota no autor da chamada RTCPeerConnection.

7. Participando de uma sala

A próxima etapa é implementar a lógica para participar de uma sala existente. O usuário faz isso clicando no botão Participar da sala e inserindo o código da sala para participar. Sua tarefa aqui é implementar a criação do RTCSessionDescription para a resposta e atualizar a sala no banco de dados de maneira adequada.

const offer = roomSnapshot.data().offer;
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);

const roomWithAnswer = {
    answer: {
        type: answer.type,
        sdp: answer.sdp
    }
}
await roomRef.update(roomWithAnswer);

No código acima, começamos extraindo a oferta do autor da chamada e criando um RTCSessionDescription definido como a descrição remota. Em seguida, criamos definir a resposta como a descrição local e atualizar o banco de dados. A atualização do banco de dados acionará o callback onSnapshot no lado do autor da chamada, que define a descrição remota com base na resposta do recebedor da chamada. Isso conclui a troca dos objetos RTCSessionDescription entre as autor da chamada e o recebedor da chamada.

8. Coletar candidatos ICE

Antes que o autor da chamada e o recebedor da chamada possam se conectar, eles também precisam troca de candidatos ICE que informam ao WebRTC como se conectar ao terminal remoto. Sua próxima tarefa é implementar o código que detecta candidatos ICE e adiciona para uma coleção no banco de dados. Encontre a função collectIceCandidates e adicione o seguinte código:

async function collectIceCandidates(roomRef, peerConnection,
                                    localName, remoteName) {
    const candidatesCollection = roomRef.collection(localName);

    peerConnection.addEventListener('icecandidate', event -> {
        if (event.candidate) {
            const json = event.candidate.toJSON();
            candidatesCollection.add(json);
        }
    });

    roomRef.collection(remoteName).onSnapshot(snapshot -> {
        snapshot.docChanges().forEach(change -> {
            if (change.type === "added") {
                const candidate = new RTCIceCandidate(change.doc.data());
                peerConnection.addIceCandidate(candidate);
            }
        });
    })
}

Essa função faz duas coisas. Ele coleta candidatos ICE da API WebRTC e os adiciona ao banco de dados e detecta candidatos ICE adicionados pelo de peering e os adiciona à instância RTCPeerConnection. É importante quando detectar alterações no banco de dados para filtrar qualquer coisa que não seja uma novidade, já que, de outra forma, teríamos adicionado o mesmo conjunto de candidatos ICE várias vezes de novo.

9. Conclusão

Neste codelab, você aprendeu a implementar a sinalização para WebRTC usando o Cloud e como usá-lo para criar um chat por vídeo simples para o aplicativo.

Para saber mais, visite:

  1. Código-fonte do FirebaseRTC
  2. Amostras de WebRTC
  3. Cloud Firestore