使用 WebRTC 实现 CameraStream

1. 准备工作

CameraStream trait 适用于能够将视频画面流式传输到智能显示屏、Chromecast 设备和智能手机的设备。CameraStream trait 现在支持 WebRTC 协议,这意味着您可以大幅缩短从摄像头设备到 Google Nest 显示屏设备的启动和流式传输延迟时间。

摄像头设备流式传输到 Google Nest 显示屏设备

前提条件

学习内容

  • 如何部署智能家居云服务。
  • 如何将您的服务关联到 Google 助理。
  • 如何使用 WebRTC 协议向 Google Nest 显示屏设备流式传输。

所需条件

  • 网络浏览器,例如 Google Chrome
  • 安装了 Google Home 应用的 iOS 或 Android 设备。
  • Node.js 10.16 或更高版本。
  • Firebase 的 Blaze(按需付费)方案。
  • 支持全高清分辨率的内置或外接摄像头设备。
  • Google Nest 显示屏设备。

2. 开始

安装 Firebase CLI

借助 Firebase CLI,您可以在本地提供 Web 应用,并将其部署到 Firebase Hosting。

如需安装 Firebase CLI,请按以下步骤操作:

  1. 在终端中,下载并安装 Firebase CLI:
$ npm install -g firebase-tools
  1. 验证 CLI 是否已正确安装:
$ firebase --version
  1. 使用您的 Google 账号授权 Firebase CLI:
$ firebase login

创建项目

  1. 前往 Google Home 开发者控制台
  2. 点击 Create Project,输入项目名称,然后点击 Create Project

为项目命名

运行 CameraStream 客户端应用

此 Codelab 的源代码包含一个 WebRTC 客户端,用于在网络摄像头和 Google 智能家居显示屏设备之间建立、协商和管理 WebRTC 会话。

如需运行 CameraStream WebRTC 客户端应用,请执行以下任一操作:

  • 点击以下按钮将源代码下载到您的开发机器:

  • 克隆以下 GitHub 代码库:
    $ git clone https://github.com/google-home/smarthome-camerastream-webrtc.git
    

该代码包含以下目录:

  • camerastream-start 目录,其中包含您要构建的起始代码。
  • camerastream-done 目录,其中包含已完成 Codelab 的解决方案代码。

camerastream-start 目录包含以下子目录:

  • public 子目录,其中包含一个前端界面,可轻松控制和监控摄像头设备的状态。
  • functions 子目录,其中包含一种已全面实现的云服务,可使用 Cloud Functions for Firebase 和 Realtime Database 来管理摄像头。

入门级代码包含 TODO 注释,用于指明您需要在哪些位置添加或更改代码,如以下示例所示:

// TODO: Implement full SYNC response.

创建 Firebase 项目

  1. 前往 Firebase
  2. 点击创建项目,然后输入项目名称。
  3. 选中同意复选框,然后点击继续。如果没有协议复选框,您可以跳过此步骤。
    创建 Firebase 项目
  4. 创建 Firebase 项目后,找到项目 ID。前往项目概览,然后依次点击“设置”图标 > 项目设置
    打开项目设置
  5. 您的项目会列在常规标签页下。
    常规项目设置

连接到 Firebase

  1. 前往 camerastream-start 目录,然后使用您的 Actions 项目设置 Firebase CLI:
$ cd camerastream-start
$ firebase use <firebase-project-id>
  1. camerastream-start 目录中,前往 functions 文件夹,然后安装所有必要的依赖项:
$ cd functions
$ npm install
  1. 如果您看到以下消息,请忽略它。此警告是由于较旧的依赖项而发出的。如需了解详情,请参阅此 GitHub 问题
found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
  1. 初始化 Firebase 项目:
$ firebase init
  1. 依次选择 FunctionsHosting。这会初始化项目的必要 API 和功能。
? 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. 使用默认文件配置 Cloud Functions,并确保不覆盖项目示例中的现有 index.jspackage.json 文件:
? 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. 使用项目代码中的 public 目录配置 Hosting,并使用现有的 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. 交换会话描述协议 (SDP) 消息

交换 SDP 消息是建立 WebRTC 流的重要步骤。SDP 是一种基于文本的协议,用于描述多媒体会话的特性。它在 WebRTC 中用于协商点对点连接的参数,例如所用编解码器、参与者的 IP 地址以及用于媒体传输的端口。

如需使用 Realtime Database 作为主机在摄像头和智能家居 CameraStream 客户端应用之间交换 SDP 消息,请按以下步骤操作:

  1. Firebase 控制台中,依次点击构建 > Realtime Database > 创建数据库

Firebase 控制台中的 Realtime Database 页面

  1. Realtime Database 位置下拉菜单中,选择一个合适的位置来托管您的数据库。

“设置数据库”对话框中的 Realtime Database 位置下拉菜单

  1. 选择以测试模式开始,然后点击启用。启用 Realtime Database 后,您需要能够从 CameraStream 客户端应用引用它。
  1. 在 Firebase 控制台中,依次选择 513f2be95dcd7896.png Project settings > Project settings > e584a9026e2b407f.pngAdd Firebase to your Web App,以启动设置工作流。
  2. 如果您已向 Firebase 项目添加了应用,请点击添加应用以显示平台选项。
  3. 为应用输入别名(例如 My web app),然后点击注册应用
  4. 添加 Firebase SDK 部分中,选择使用 <script> 标记
  5. 复制 firebasebaseConfig 对象中的值,然后将其粘贴到 camaerastream-start/public/webrtc_generator.js 文件中。
const firebaseConfig = {
  apiKey: "XXXXX",
  authDomain: "XXXXX",
  projectId: "XXXXX",
  storageBucket: "XXXXX",
  messagingSenderId: "XXXXX",
  appId: "XXXXX",
  measurementId: "XXXXX"
};
  1. 点击继续前往控制台完成此流程。您会在项目设置页面上看到新创建的 Web 应用。

4. 创建 WebRTC 摄像头

现在,您已配置 Action,您的云服务需要处理以下 intent:

  • 当 Google 助理想要了解用户关联了哪些设备时,就会发生 SYNC intent。当用户关联账号时,系统会向您的服务发送此 intent。您应该在响应时提供用户设备及其功能的 JSON 载荷。
  • 当 Google 助理想要代表用户控制设备时,就会发生 EXECUTE/QUERY intent。您应该在响应时提供 JSON 载荷,其中包含所请求的每台设备的执行状态。

在本部分中,您将更新之前部署的用于处理这些 intent 的函数。

更新 SYNC 响应

  1. 找到 functions/index.js 文件。其中包含用于响应来自 Google 助理的请求的代码。
  2. 修改 SYNC intent 以返回设备的元数据和功能:

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
      },
    }],
  },
};
});
  1. 代码中未定义 USER_ID。在 const _ = require('underscore'); 下方添加以下内容:
// Hardcoded user ID
const USER_ID = '123';

处理 EXECUTE intent

EXECUTE intent 可处理用于更新设备状态的命令。响应会返回每个命令的状态(例如 SUCCESSERRORPENDING)以及新的设备状态。

如需处理 EXECUTE intent,请修改 EXECUTE intent,以便在 functions/index.js 文件中返回 Firebase 项目的 signaling 端点:

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],
    },
  };
});

处理跨源资源共享 (CORS)

如需处理因使用 POST 方法发送 SDP 而导致的 CORS 问题,请将 Firebase Hosting 网址添加到 functions/index.js 文件中的 allowlist 数组:

index.js

'use strict';
.....

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

如需详细了解 CORS,请参阅跨域资源共享 (CORS)

处理数据流终止

如需处理 WebRTC 流终止,请将 Firebase“信号”函数网址添加到 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();

部署到 Firebase

如需部署到 Firebase,请使用 Firebase CLI 部署更新后的云执行方式:

$ firebase deploy

此命令会部署一个 Web 应用以及几个 Cloud Functions for Firebase

...

✔ Deploy complete!

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

配置您的开发者控制台项目

  1. 前往开发者控制台
  2. 点击 Create Project,输入项目名称,然后点击 Create Project

为项目命名

选择云到云集成

在 Play 管理中心的项目首页上,选择云到云下的添加云到云集成

添加云到云集成

  1. 输入集成名称,然后在设备类型下方选择摄像头。当有设备需要设置时,此名称会显示在 Google Home 应用中。对于此 Codelab,我们输入了 WebRTC Codelab 作为显示名称,但您可以使用其他名称。

添加显示名称

  1. 应用品牌信息下,为应用图标上传一个大小为 144 x 144 像素且名为 .pngpng 文件。

添加应用图标

启用账号关联

如需在项目部署后启用账号关联,请按以下步骤操作:

  1. 前往 Developer Console 并打开项目。
  2. 云到云部分下,依次点击开发 > 相应集成旁边的修改
  3. 设置和配置页面中,找到账号关联部分,然后在相应的文本框中输入以下信息:

客户 ID

ABC123

客户端密钥

DEF456

授权网址

https://us-central1-
.cloudfunctions.net/fakeauth

令牌网址

https://us-central1-
.cloudfunctions.net/faketoken

更新账号关联网址

  1. 依次点击保存 > 测试

5. 测试虚拟 WebRTC 摄像头

  1. 前往您在部署 Firebase 项目时看到的 Hosting 网址。您会看到以下界面,即 CameraStream 客户端应用:

CameraStream 客户端应用界面

  1. 本地视频分辨率面板中,选择所需的视频。
  2. 向 CameraStream 客户端应用授予使用摄像头和麦克风的权限。客户端上会显示来自网络摄像头的视频画面。
  1. 在 Google Home 应用中,依次点按添加 > 支持 Google

Google Home 应用中的“设置设备”页面

  1. 搜索您创建的操作,然后选择该操作。

Google Home 应用中的智能家居 Action

  1. 记下这个由 5 个字母数字组成的唯一代码,因为您稍后需要用到它。

唯一的五位数字母数字代码

  1. 点按返回。WebRTC 摄像头会添加到 Google Home 应用中的结构中。

启动 WebRTC 流式传输

  1. 在 CameraStream 客户端应用的网页上,在 Account linking token value(账号关联令牌值)文本框中输入上一部分中的字母数字代码,然后点击 Submit(提交)。

“账号关联令牌值”文本框

  1. 如需从 Google 智能显示屏设备启动 WebRTC 会话,请执行以下任一操作:
  • “Hey Google,流式传输 WebRTC 摄像头。”
  • 在 Google 智能显示屏设备上,依次点按住宅控制 > 摄像头 > WebRTC 摄像头

在 Google 智能家居 CameraStream 客户端应用中,您会看到 Offer SPD 和 Answer SDP 已成功生成并交换。网络摄像头的图片会通过 WebRTC 流式传输到 Google 智能显示屏设备。

6. 恭喜

恭喜!您了解了如何使用 WebRTC 协议将视频从摄像头流式传输到 Google Nest 显示屏设备。

了解详情