Implementar o CameraStream com WebRTC

1. Antes de começar

A característica CameraStream pertence a dispositivos com a capacidade de transmitir feeds de vídeo para smart displays, dispositivos Chromecast e smartphones. O protocolo WebRTC agora é compatível com a característica CameraStream, o que significa que é possível reduzir muito a latência de inicialização e streaming de um dispositivo de câmera para um dispositivo de tela Google Nest.

Dispositivos de câmera fazendo streaming para uma tela Google Nest

Pré-requisitos

O que você vai aprender

  • Como implantar um serviço de nuvem de casa inteligente.
  • Como conectar seu serviço ao Google Assistente.
  • Como fazer streaming para uma tela Google Nest com o protocolo WebRTC.

O que é necessário

  • Um navegador da Web, como o Google Chrome
  • Um dispositivo iOS ou Android com o app Google Home.
  • Node.js versão 10.16 ou mais recente
  • Plano Blaze (pagamento por uso) para o Firebase.
  • Um dispositivo webcam integrado ou externo compatível com resolução Full HD.
  • Uma tela Google Nest.

2. Primeiros passos

instalar a CLI do Firebase

A CLI do Firebase permite disponibilizar seus apps da Web localmente e implantá-los no Firebase Hosting.

Para instalar a CLI do Firebase, siga estas etapas:

  1. No seu terminal, faça o download e instale a CLI do Firebase:
$ npm install -g firebase-tools
  1. Verifique se a CLI foi instalada corretamente:
$ firebase --version
  1. Autorize a CLI do Firebase com sua Conta do Google:
$ firebase login

Criar e configurar um projeto do Actions

  1. Acesse o Console do Actions e clique em Novo projeto.
  2. Na caixa de texto Nome do projeto, insira o nome do projeto e clique em Criar projeto.

Caixa de diálogo "Novo projeto" no Console do Actions

  1. Na página Que tipo de ação você quer criar?, clique em Casa inteligente > Comece a criar. O projeto será aberto no Console do Actions.

Guia "Visão geral" no Console do Actions

  1. Clique em Desenvolver > Invocação.
  2. Na caixa de texto Display name, digite um nome para a ação e clique em Save. Esse nome vai aparecer no app Google Home mais tarde, quando houver um dispositivo para configurar. Neste codelab, inserimos WebRTC Codelab como o nome de exibição, mas é possível usar um nome diferente.

O painel "Invocação" no Console do Actions

  1. Clique em Ações.
  2. Na caixa de texto URL de fulfillment, insira um URL de marcador, como https://example.com.

Executar o app cliente do CameraStream

O código-fonte deste codelab inclui um cliente WebRTC que estabelece, negocia e gerencia a sessão WebRTC entre a webcam e o dispositivo de tela de casa inteligente do Google.

Para executar o app cliente WebRTC do CameraStream, siga um destes procedimentos:

  • Clique no botão a seguir para fazer o download do código-fonte para sua máquina de desenvolvimento:

  • Clone este repositório do GitHub:
$ git clone https://github.com/google-home/smarthome-camerastream-webrtc.git

O código contém estes diretórios:

  • O diretório camerastream-start, que contém o código inicial de base do build.
  • O diretório camerastream-done, que contém o código da solução do codelab concluído.

O diretório camerastream-start contém os seguintes subdiretórios:

  • O subdiretório public, que contém uma interface de front-end para controlar e monitorar facilmente o estado do dispositivo de câmera.
  • O subdiretório functions, que contém um serviço de nuvem totalmente implementado que gerencia a câmera com o Cloud Functions para Firebase e o Realtime Database.

O código inicial contém comentários TODO que indicam onde você precisa adicionar ou mudar o código, como no exemplo a seguir:

// TODO: Implement full SYNC response.

Conectar-se ao Firebase

  1. Navegue até o diretório camerastream-start e configure a CLI do Firebase com seu projeto do Actions:
$ cd camerastream-start
$ firebase use PROJECT_ID
  1. No diretório camerastream-start, navegue até a pasta functions e instale todas as dependências necessárias:
$ cd functions
$ npm install
  1. Se a mensagem a seguir aparecer, ignore-a. Esse aviso se deve a dependências mais antigas. Para saber mais, consulte este problema no GitHub (link em inglês).
found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
  1. Inicialize um projeto do Firebase:
$ firebase init
  1. Selecione Functions e Hosting. Isso inicializa as APIs e os recursos necessários para o projeto.
? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. 
❯◯ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◉ Functions: Configure a Cloud Functions directory and its files
 ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
 ◯ Hosting: Set up GitHub Action deploys
 ◯ Storage: Configure a security rules file for Cloud Storage
 ◯ Extensions: Set up an empty Extensions manifest
  1. Configure o Cloud Functions com os arquivos padrão e não substitua os arquivos index.js e package.json atuais na amostra do projeto:
? Would you like to initialize a new codebase, or overwrite an existing one?
Overwrite

? What language would you like to use to write Cloud Functions? 
JavaScript

? File functions/package.json already exists. Overwrite? 
No

? File functions/index.js already exists. Overwrite? 
No

? Do you want to install dependencies with npm now? 
Yes
  1. Configure o Hosting com o diretório public no código do projeto e use o arquivo index.html:
? What do you want to use as your public directory? 
public

? Configure as a single-page app (rewrite all urls to /index.html)? 
Yes

? Set up automatic builds and deploys with GitHub?
No

? File public/index.html already exists. Overwrite?
 No

3. Mensagens do protocolo de descrição da sessão (SDP, na sigla em inglês) do Exchange

A troca de mensagens SDP é uma etapa importante no estabelecimento de um fluxo WebRTC. SDP é um protocolo baseado em texto que descreve as características de uma sessão multimídia. Ele é usado no WebRTC para negociar os parâmetros de uma conexão ponto a ponto, como os codecs usados, os endereços IP dos participantes e as portas usadas para o transporte de mídia.

Se quiser usar o Realtime Database como host para trocar mensagens SDP entre a webcam e o app cliente de casa inteligente CameraStream, siga estas etapas:

  1. No Console do Firebase, clique em Build > Realtime Database > Criar banco de dados.

Página do Realtime Database no Console do Firebase

  1. No menu suspenso Local do Realtime Database, selecione um local apropriado para hospedar seu banco de dados.

Menu suspenso do local do Realtime Database na caixa de diálogo "Configurar banco de dados"

  1. Selecione Iniciar no modo de teste e clique em Ativar. Com o Realtime Database ativado, é necessário referenciá-lo no app cliente do CameraStream.
  1. No Console do Firebase, selecione 513f2be95dcd7896.png Configurações do projeto > Configurações do projeto > e584a9026e2b407f.pngAdicione o Firebase ao seu app da Web para iniciar o fluxo de trabalho de configuração.
  2. Se você já adicionou um app ao seu projeto do Firebase, clique em Adicionar app para exibir as opções da plataforma.
  3. Digite um apelido para o app, como My web app, e clique em Registrar app.
  4. Na seção Adicionar SDK do Firebase, selecione Usar <script> tag.
  5. Copie os valores do objeto firebasebaseConfig e cole-os no arquivo camaerastream-start/public/webrtc_generator.js.
const firebaseConfig = {
  apiKey: "XXXXX",
  authDomain: "XXXXX",
  projectId: "XXXXX",
  storageBucket: "XXXXX",
  messagingSenderId: "XXXXX",
  appId: "XXXXX",
  measurementId: "XXXXX"
};
  1. Clique em Continuar no console para concluir o processo. Você verá o app da Web recém-criado na página Configurações do projeto.

4. Criar uma câmera WebRTC

Agora que você configurou a ação, o serviço de nuvem precisa processar estas intents:

  • Uma intent SYNC que ocorre quando o Google Assistente quer saber a quais dispositivos o usuário conectou. Ela é enviada ao seu serviço quando o usuário vincula uma conta. Responda com um payload JSON dos dispositivos e recursos do usuário.
  • Uma intent EXECUTE/QUERY que ocorre quando o Google Assistente quer controlar um dispositivo em nome de um usuário. Você deve responder com um payload JSON com o status de execução de cada dispositivo solicitado.

Nesta seção, você vai atualizar as funções implantadas anteriormente para processar essas intents.

Atualize a resposta SYNC

  1. Navegue até o arquivo functions/index.js. Ele contém o código para responder a solicitações do Google Assistente.
  2. Edite a intent SYNC para retornar os metadados e os recursos do dispositivo:

index.js

app.onSync((body) => {
  return {
    requestId: body.requestId,
    payload: {
      agentUserId: USER_ID,
      devices: [{
        id: 'camera',
        type: 'action.devices.types.CAMERA',
        traits: [
          'action.devices.traits.OnOff',
          'action.devices.traits.CameraStream',
        ],
        name: {
          defaultNames: ['My WebRTC Camera],
          name: 'Camera',
          nicknames: ['Camera'],
        },
        deviceInfo: {
          manufacturer: 'Acme Co',
          model: 'acme-camera',
          hwVersion: '1.0',
          swVersion: '1.0.1',
        },
        willReportState: false,
        attributes: {
          cameraStreamSupportedProtocols:['webrtc'],
          cameraStreamNeedAuthToken: true, 
          cameraStreamSupportsPreview: true
        },
      }],
    },
  };
});

Processar a intent EXECUTE

A intent EXECUTE processa comandos para atualizar o estado do dispositivo. A resposta retorna o status de cada comando, como SUCCESS, ERROR ou PENDING, e o novo estado do dispositivo.

  • Para processar uma intent EXECUTE, edite a intent EXECUTE para retornar o endpoint signaling do projeto do Firebase no arquivo functions/index.js:

index.js

app.onExecute(async (body,headers) => {
  var array = headers.authorization.split(' ');
  var snapshot = await firebaseRef.ref('/userId/'+array[1]).once('value');
  var offerGenLocation = snapshot.val().type;
  const {requestId} = body;

  var result = {
    status: 'SUCCESS',
    states: {
      cameraStreamProtocol: 'webrtc',
      cameraStreamSignalingUrl:'https://us-central1-<project-id>.cloudfunctions.net/signaling?token='+array[1], // TODO: Add Firebase hosting URL
      cameraStreamIceServers: '',
      cameraStreamOffer:'',
      cameraStreamAuthToken:'',
    },
    ids: [ 
      'camera'
    ],
  };
  
  return {
    requestId: requestId,
    payload: {
      commands: [result],
    },
  };

Processar o compartilhamento de recursos entre origens (CORS)

  • Para processar o CORS devido ao uso do método POST para enviar o SDP, adicione o URL do Firebase Hosting à matriz allowlist no arquivo functions/index.js:

index.js

'use strict';

const functions = require('firebase-functions');
const {smarthome} = require('actions-on-google');
const {google} = require('googleapis');
const util = require('util');
const admin = require('firebase-admin');

var allowList = ['https:www.gstatic.com','https://<project-id>.web.app']; //TODO Add Firebase hosting URL.

Para mais informações sobre o CORS, consulte Compartilhamento de recursos entre origens (CORS).

Processar encerramento de stream

  • Para processar o encerramento do stream do WebRTC, adicione a "sinalização" do Firebase URL da função para o arquivo public/webrtc_generator.js:

webrtc_generator.js

terminateButton.onclick = function(){
  console.log('Terminating Stream!!')
  var signalingURL = 'https://us-central1-<project-id>.cloudfunctions.net/signaling'; //TODO Add Firebase hosting URL 
   var http = new XMLHttpRequest();

Implantar no Firebase

  • Para implantar no Firebase, implante o fulfillment da nuvem atualizado com a CLI do Firebase:
$ firebase deploy

Este comando implanta um app da Web e vários Cloud Functions para Firebase:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<project-id>/overview
Hosting URL: https://<project-id>.web.app

Ativar vinculação de contas

Para ativar a vinculação de contas após a implantação do projeto, siga estas etapas:

  1. No Console do Actions, selecione Desenvolver > Vinculação de contas.
  2. Na seção Informações do cliente OAuth, digite as seguintes informações nas caixas de texto correspondentes:

Client-ID

ABC123

Chave secreta do cliente

DEF456

URL de autorização

https://us-central1-{project-id}.cloudfunctions.net/fakeauth

URL do token

https://us-central1-{project-id}.cloudfunctions.net/faketoken

Página de vinculação de contas no Console do Actions

  1. Clique em Salvar > teste.

5. Testar a câmera virtual do WebRTC

  1. Navegue até o URL do Hosting que você viu quando implantou seu projeto do Firebase. Aparecerá a interface abaixo, que é o app cliente do CameraStream:

A interface do app cliente do CameraStream

  1. No painel Resolução de vídeo local, selecione o vídeo desejado.
  2. Conceda permissão ao app cliente CameraStream para acessar sua webcam e seu microfone. Um feed de vídeo da sua webcam será exibido no cliente.
  1. No app Google Home, toque em Adicionar > Funciona com o Google

Página &quot;Configurar um dispositivo&quot; no app Google Home

  1. Procure e selecione a ação que você criou.

A ação de casa inteligente no app Google Home

  1. Anote o código alfanumérico exclusivo de cinco caracteres, porque você precisará dele mais tarde.

O código alfanumérico único de cinco dígitos

  1. Toque em Voltar. A câmera WebRTC é adicionada à sua estrutura no app Google Home.

Iniciar um stream WebRTC

  1. Na página da Web do app cliente do CameraStream, insira o código alfanumérico da última seção na caixa de texto Valor do token de vinculação da conta e clique em Enviar.

Caixa de texto do valor do token de vinculação da conta

  1. Para iniciar uma sessão WebRTC no smart display do Google, siga um destes procedimentos:
  • Diga "Ok Google, fazer streaming da câmera WebRTC".
  • No dispositivo smart display do Google, toque em Automação residencial > Câmera > câmera WebRTC.

No app cliente CameraStream de casa inteligente do Google, o SDP de oferta e o SDP de resposta foram gerados e trocados corretamente. A imagem da webcam é transmitida para o dispositivo smart display do Google com WebRTC.

6. Parabéns

Parabéns! Você aprendeu a fazer streaming da webcam para uma tela Google Nest com o protocolo WebRTC.

Saiba mais