Cómo implementar CameraStream con WebRTC

1. Antes de comenzar

La característica CameraStream pertenece a los dispositivos que tienen la capacidad de transmitir feeds de video a pantallas inteligentes, dispositivos Chromecast y smartphones. El protocolo WebRTC ahora es compatible con la característica CameraStream, lo que significa que puedes reducir en gran medida la latencia de inicio y transmisión de una cámara a una pantalla Google Nest.

Dispositivos de cámara transmitiendo a una pantalla Google Nest

Requisitos previos

Qué aprenderás

  • Cómo implementar un servicio de nube para casas inteligentes
  • Cómo conectar tu servicio a Asistente de Google
  • Cómo transmitir a una pantalla Google Nest con el protocolo WebRTC

Requisitos

  • Un navegador web, como Google Chrome
  • Un dispositivo iOS o Android con la app de Google Home
  • Node.js (versión 10.16 o una posterior)
  • Plan Blaze (pago por uso) para Firebase.
  • Un dispositivo de cámara web integrado o externo que sea compatible con la resolución Full HD
  • Una pantalla Google Nest.

2. Comenzar

Instala Firebase CLI

Firebase CLI te permite entregar tus apps web de forma local y, luego, implementarlas en Firebase Hosting.

Para instalar Firebase CLI, sigue estos pasos:

  1. En la terminal, descarga y, luego, instala Firebase CLI:
$ npm install -g firebase-tools
  1. Verifica que la CLI se haya instalado de forma correcta:
$ firebase --version
  1. Autoriza Firebase CLI con tu Cuenta de Google:
$ firebase login

Cómo crear y configurar un proyecto de Actions

  1. Ve a la Consola de Actions y, luego, haz clic en Proyecto nuevo.
  2. En el cuadro de texto Nombre del proyecto, ingresa un nombre para el proyecto y, luego, haz clic en Crear proyecto.

El diálogo Nuevo proyecto en la Consola de Actions

  1. En la página What kind of Action do you want to build?, haz clic en Smart home > Startbuilding. El proyecto se abrirá en la Consola de Actions.

La pestaña Descripción general de la Consola de Actions

  1. Haz clic en Develop > Invocation.
  2. En el cuadro de texto Nombre visible, ingresa un nombre para la acción y, luego, haz clic en Guardar. Este nombre aparecerá en la app de Google Home más tarde, cuando haya un dispositivo para configurar. Para este codelab, ingresamos WebRTC Codelab como nombre visible, pero puedes usar uno diferente.

Panel Invocación en la Consola de Actions

  1. Haz clic en Acciones.
  2. En el cuadro de texto URL de entrega, ingresa una URL de marcador de posición, como https://example.com.

Ejecuta la app cliente de CameraStream

El código fuente de este codelab incluye un cliente WebRTC que establece, negocia y administra la sesión de WebRTC entre la cámara web y la pantalla de casa inteligente de Google.

Para ejecutar la app cliente de WebRTC de CameraStream, realiza una de las siguientes acciones:

  • Haz clic en el siguiente botón para descargar el código fuente en tu máquina de desarrollo:

Descargar código fuente

  • Clona este repositorio de GitHub:
$ git clone https://github.com/google-home/smarthome-camerastream-webrtc.git

El código incluye los siguientes directorios:

  • El directorio camerastream-start, que contiene el código de partida en el que realizas la compilación
  • El directorio camerastream-done, que contiene el código de la solución del codelab terminado

El directorio camerastream-start contiene los siguientes subdirectorios:

  • El subdirectorio de public, que contiene una IU de frontend para controlar y supervisar fácilmente el estado de tu dispositivo de cámara.
  • El subdirectorio de functions, que contiene un servicio en la nube completamente implementado que administra la cámara con Cloud Functions para Firebase y Realtime Database.

El código de partida contiene comentarios TODO que indican dónde debes agregar o cambiar el código, como en el siguiente ejemplo:

// TODO: Implement full SYNC response.

Cómo conectarse a Firebase

  1. Navega al directorio camerastream-start y configura Firebase CLI con tu proyecto de acciones:
$ cd camerastream-start
$ firebase use PROJECT_ID
  1. En el directorio camerastream-start, navega a la carpeta functions y, luego, instala todas las dependencias necesarias:
$ cd functions
$ npm install
  1. Si ves el siguiente mensaje, ignóralo. Esta advertencia se debe a dependencias antiguas. Para obtener más información, consulta este problema de GitHub.
found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
  1. Inicializa un proyecto de Firebase:
$ firebase init
  1. Selecciona Functions y Hosting. Esto inicializa las APIs y las funciones necesarias para tu proyecto.
? 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. Configura Cloud Functions con los archivos predeterminados y asegúrate de no reemplazar los archivos index.js y package.json existentes en la muestra del proyecto:
? 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. Configura Hosting con el directorio public en el código del proyecto y usa el archivo 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. Mensajes de protocolo de descripción de sesión (SDP) de Exchange

El intercambio de mensajes SDP es un paso importante en el establecimiento de una transmisión de WebRTC. El SDP es un protocolo basado en texto que describe las características de una sesión multimedia. Se usa en WebRTC para negociar los parámetros de una conexión entre pares, como los códecs utilizados, las direcciones IP de los participantes y los puertos usados para el transporte de medios.

Si quieres usar Realtime Database como host para intercambiar mensajes SDP entre tu cámara web y la app cliente de CameraStream de la casa inteligente, sigue estos pasos:

  1. En Firebase console, haz clic en Compilación > Realtime Database > Crear base de datos.

La página Realtime Database en Firebase console

  1. En el menú desplegable Ubicación de Realtime Database, selecciona una ubicación adecuada para alojar la base de datos.

El menú desplegable Ubicación de Realtime Database en el diálogo Configurar base de datos

  1. Selecciona Comenzar en modo de prueba y, luego, haz clic en Habilitar. Cuando la base de datos en tiempo real está habilitada, necesitas poder hacer referencia a ella desde la app cliente de CameraStream.
  1. En Firebase console, selecciona 513f2be95dcd7896.png Configuración del proyecto > Configuración del proyecto > e584a9026e2b407f.pngAgregar Firebase a tu app web para iniciar el flujo de trabajo de configuración.
  2. Si ya agregaste una app a tu proyecto de Firebase, haz clic en Agregar app para que se muestren las opciones de plataforma.
  3. Ingresa un sobrenombre para la app, como My web app, y haz clic en Registrar app.
  4. En la sección Add Firebase SDK, selecciona Use <script> tag.
  5. Copia los valores del objeto firebasebaseConfig y pégalos en el archivo camaerastream-start/public/webrtc_generator.js.
const firebaseConfig = {
  apiKey: "XXXXX",
  authDomain: "XXXXX",
  projectId: "XXXXX",
  storageBucket: "XXXXX",
  messagingSenderId: "XXXXX",
  appId: "XXXXX",
  measurementId: "XXXXX"
};
  1. Haz clic en Ir a la consola para completar el proceso. Verás la app web recién creada en la página Configuración del proyecto.

4. Cómo crear una cámara WebRTC

Ahora que configuraste tu Acción, tu servicio de nube necesita controlar los siguientes intents:

  • Un intent SYNC que se produce cuando Asistente desea saber qué dispositivos conectó el usuario Este se envía a tu servicio cuando el usuario vincula una cuenta. Deberías responder con una carga útil JSON de los dispositivos del usuario y sus capacidades.
  • Un intent EXECUTE/QUERY que se produce cuando Asistente quiere controlar un dispositivo en nombre de un usuario Deberías responder con una carga útil JSON con el estado de ejecución de cada dispositivo solicitado.

En esta sección, actualizarás las funciones que implementaste antes para controlar estos intents.

Actualiza la respuesta SYNC

  1. Navega al archivo functions/index.js. Contiene el código para responder a las solicitudes de Asistente.
  2. Edita el intent SYNC para mostrar los metadatos y las funciones del 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
        },
      }],
    },
  };
});

Cómo controlar el intent EXECUTE

El intent EXECUTE procesa comandos para actualizar el estado del dispositivo. La respuesta muestra el estado de cada comando (por ejemplo, SUCCESS, ERROR o PENDING) y el estado del dispositivo nuevo.

  • A fin de controlar un intent EXECUTE, edita el intent EXECUTE para que muestre el extremo signaling del proyecto de Firebase en el archivo 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],
    },
  };

Controla el uso compartido de recursos entre dominios (CORS)

  • Para controlar CORS debido al uso del método POST para enviar el SDP, agrega la URL de Firebase Hosting al array allowlist en el archivo 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 obtener más información sobre CORS, consulta Uso compartido de recursos entre dominios (CORS).

Controla la terminación de transmisión

  • Para controlar la finalización de la transmisión de WebRTC, agrega la URL de la función “indicación” de Firebase al archivo 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();

Realiza la implementación en Firebase

  • Para realizar la implementación en Firebase, implementa la entrega en la nube actualizada con Firebase CLI:
$ firebase deploy

Este comando implementa una app web y varias funciones de Cloud Functions para Firebase:

...

✔ Deploy complete!

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

Habilitar vinculación de cuentas

Para habilitar la vinculación de cuentas después de implementar tu proyecto, sigue estos pasos:

  1. En la Consola de Actions, selecciona Desarrollar > Vinculación de cuentas.
  2. En la sección Información del cliente de OAuth, ingresa la siguiente información en los cuadros de texto correspondientes:

ID de cliente

ABC123

Secreto de cliente

DEF456

URL de autorización

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

URL del token

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

La página de vinculación de cuentas en la Consola de Actions

  1. Haz clic en Save > Test.

5. Prueba la cámara virtual de WebRTC

  1. Navega a la URL de Hosting que viste cuando implementaste tu proyecto de Firebase. Verás la siguiente interfaz, que es la app cliente de CameraStream:

La interfaz de la app cliente de CameraStream

  1. En el panel Resolución de video local, selecciona el video que desees.
  2. Otorga permiso a la app cliente de CameraStream para acceder a tu cámara web y micrófono. Aparecerá un feed de video de tu cámara web en el cliente.
  1. En la app de Google Home, presiona Agregar > Funciona con Google.

La página Configura un dispositivo en la app de Google Home

  1. Busca la acción que creaste y selecciónala.

La Acción de casa inteligente en la app de Google Home

  1. Anota el código alfanumérico único de cinco caracteres porque lo necesitarás más adelante.

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

  1. Presiona Volver. Se agregará la cámara WebRTC a tu estructura en la app de Google Home.

Cómo iniciar una transmisión de WebRTC

  1. En la página web de la app cliente de CameraStream, ingresa el código alfanumérico de la última sección en el cuadro de texto Valor del token de vinculación de cuenta y, luego, haz clic en Enviar.

Cuadro de texto del valor del token de vinculación de cuenta

  1. Para iniciar una sesión de WebRTC desde la pantalla inteligente de Google, realiza una de las siguientes acciones:
  • Di "Hey Google, transmite la cámara de WebRTC".
  • En la pantalla inteligente de Google, presiona Control de la casa > Cámara > Cámara WebRTC.

En la app cliente de CameraStream de la casa inteligente de Google, ves que el SPD de oferta y el SDP de respuesta se generaron e intercambiaron correctamente. La imagen de la cámara web se transmite a la pantalla inteligente de Google con WebRTC.

6. Felicitaciones

¡Felicitaciones! Aprendiste a transmitir desde tu cámara web a una pantalla Google Nest con el protocolo WebRTC.

Más información