Implementar 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 você pode reduzir muito a latência de inicialização e streaming de um dispositivo de câmera para um dispositivo de exibição Google Nest.

Dispositivos de câmera em streaming para um dispositivo de tela Google Nest

Pré-requisitos

Neste curso, você vai aprender a:

  • Como implantar um serviço de nuvem de casa inteligente.
  • Como conectar seu serviço ao Google Assistente.
  • Como fazer streaming para um dispositivo de 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 posterior
  • Plano Blaze (pagamento por utilização) para Firebase.
  • Um dispositivo de webcam externo ou integrado que seja compatível com resolução HD total.
  • Um dispositivo de tela Google Nest.

2. Começar

Instale a CLI do Firebase

A CLI do Firebase permite exibir 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 Firebase CLI:
$ 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, digite um nome e clique em Criar projeto.

A 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 > Começar 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 Nome de exibição, digite um nome para a ação e clique em Salvar. Esse nome aparecerá no app Google Home 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 de 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 exibição de casa inteligente do Google.

Para executar o aplicativo cliente CameraStream WebRTC, 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 os seguintes diretórios:

  • O diretório camerastream-start, que contém o código inicial sobre o qual você cria.
  • 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 IU de front-end para controlar e monitorar facilmente o estado do dispositivo da 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 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 você vir a mensagem a seguir, ignore-a. Esse aviso se deve a dependências mais antigas. Para mais informações, veja este problema no GitHub (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 Funções e Hospedagem. Isso inicializa as APIs e os recursos necessários para seu 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 certifique-se de não substituir os arquivos index.js e package.json existentes 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 existente:
? 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 de sessão do Exchange (SDP)

A troca de mensagens SDP é uma etapa importante no estabelecimento de um fluxo WebRTC. O SDP é um protocolo de 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.

Para usar o Realtime Database como um host para trocar mensagens SDP entre sua webcam e o app cliente de transmissão inteligente CameraStream, siga estas etapas:

  1. No Console do Firebase, clique em Build > Realtime Database > Create database.

A 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 de locais 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, você precisa referenciá-lo no app cliente do StreamStream.
  1. No Console do Firebase, selecione 513f2be95dcd7896.png Configurações do projeto > Configurações do projeto > e584a9026e2b407f.pngAdicionar 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 tag <script>.
  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. O app da Web recém-criado é exibido 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 as seguintes intents:

  • Uma intent SYNC que ocorre quando o Google Assistente quer saber a quais dispositivos o usuário está conectado. Ela é enviada ao seu serviço quando o usuário vincula uma conta. Você deve responder 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ê atualizará as funções implantadas anteriormente para processar essas intents.

Atualizar 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 o encerramento da transmissão

  • Para lidar com o encerramento da transmissão WebRTC, adicione o URL da função de "sinalização" do Firebase ao arquivo public/webrtc_generator.js:

webrtc_generator.js (em inglês)

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 atualizado da nuvem com a CLI do Firebase:
$ firebase deploy

Este comando implanta um app da Web e várias 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 da conta 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, insira 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

A página de vinculação de conta no Console do Actions

  1. Clique em Save > Test.

5. Testar a câmera WebRTC virtual

  1. Navegue até o URL do Hosting que você viu ao implantar o projeto do Firebase. Você verá a seguinte interface, que é o app cliente do StreamStream:

A interface do app do cliente 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 aparece no cliente.
  1. No app Google Home, toque em Adicionar > Compatível com o Google.

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

  1. Pesquise 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, pois você precisará dele mais tarde.

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

  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 aplicativo cliente CameraStream, insira o código alfanumérico da última seção na caixa de texto Valor do token de vinculação de contas e clique em Enviar.

Caixa de texto &quot;Valor do token de vinculação da conta&quot;

  1. Para iniciar uma sessão WebRTC do seu dispositivo Smart Display do Google, siga um destes procedimentos:
  • Diga "Ok Google, faça streaming da câmera WebRTC".
  • No dispositivo Smart Display do Google, toque em Automação residencial > Câmera > Câmera WebRTC.

No app cliente Smart Stream do Google Home, você vê que o SDP de oferta e o SDP de resposta foram gerados e trocados. A imagem da webcam é transmitida para o dispositivo de smart display do Google com WebRTC.

6. Parabéns

Parabéns! Você aprendeu a transmitir da webcam para um dispositivo de tela Google Nest com o protocolo WebRTC.

Saiba mais