Cómo implementar CameraStream con WebRTC

1. Antes de comenzar

La característica CameraStream pertenece a dispositivos con 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 un dispositivo de cámara a un dispositivo de pantalla Google Nest.

Dispositivos con 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 externo o integrado que admita resolución Full HD.
  • Una pantalla Google Nest.

2. Comenzar

Instala Firebase CLI

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

Para instalar Firebase CLI, sigue estos pasos:

  1. En tu 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.

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 > Comienza a compilar. 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 > Invocación:
  2. En el cuadro de texto Display name, ingresa un nombre para la acción y haz clic en Save. Este nombre aparecerá en la app de Google Home más adelante cuando haya un dispositivo para configurar. En este codelab, ingresamos WebRTC Codelab como el nombre visible, pero puedes usar uno diferente.

El panel Invocation de la Consola de Actions

  1. Haz clic en Acciones.
  2. En el cuadro de texto Fulfillment URL, 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 el dispositivo de 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 contiene los siguientes directorios:

  • El directorio camerastream-start, que contiene el código de partida en el que se basa 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 public, que contiene una IU de frontend para controlar y supervisar el estado del dispositivo de la cámara con facilidad.
  • El subdirectorio functions, que contiene un servicio de 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, luego, 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 más 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 existentes index.js y package.json 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 de intercambio (SDP)

El intercambio de mensajes del SDP es un paso importante en el establecimiento de una transmisión de WebRTC. 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 usados, las direcciones IP de los participantes y los puertos que se usan para el transporte de contenido multimedia.

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

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

La página de Realtime Database en Firebase console

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

Menú desplegable de la ubicación de Realtime Database en el cuadro de diálogo Configurar base de datos

  1. Selecciona Comenzar en modo de prueba y, luego, haz clic en Habilitar. Con Realtime Database habilitado, necesitas poder hacer referencia a él desde la app cliente de CameraStream.
  1. En Firebase console, selecciona 513f2be95dcd7896.png Configuración del proyecto > Configuración del proyecto > e584a9026e2b407f.pngAgrega 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, luego, haz clic en Registrar app.
  4. En la sección Agregar el SDK de Firebase, selecciona Usar <script>. etiqueta.
  5. Copia los valores del objeto firebasebaseConfig y, luego, 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 aplicación web que se acaba de crear en la página Configuración del proyecto.

4. Crear una cámara WebRTC

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

  • Un intent SYNC que se produce cuando Asistente quiere 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 las solicitudes del Asistente.
  2. Edita el intent SYNC para mostrar los metadatos y las capacidades 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.

  • Para controlar un intent EXECUTE, edita el intent EXECUTE para que se 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).

Cómo controlar la terminación de transmisión

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

Cómo implementar en Firebase

  • Para implementar en Firebase, implementa la entrega actualizada en la nube 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 Guardar > Probar

5. Probar la cámara virtual 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 Local Video Resolution, selecciona el video que desees.
  2. Otorga permiso a la app cliente de CameraStream para acceder a tu cámara web y micrófono. En el cliente aparecerá un feed de video de tu cámara web.
  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. Ten en cuenta 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. La cámara de WebRTC se agregará a tu estructura en la app de Google Home.

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 Account link token value y haz clic en Submit.

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

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

En la app cliente de CameraStream de casa inteligente de Google, verás que el SPD de oferta y el SDP de respuesta se generaron y se 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