1. 准备工作
CameraStream
特征属于能够将视频 Feed 流式传输到智能显示屏、Chromecast 设备和智能手机的设备。现在,CameraStream
trait 中支持 WebRTC 协议,这意味着,您可以大幅缩短从摄像头设备到 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,请按以下步骤操作:
- 在您的终端中,下载并安装 Firebase CLI:
$ npm install -g firebase-tools
- 验证 CLI 是否已正确安装:
$ firebase --version
- 使用您的 Google 帐号授权 Firebase CLI:
$ firebase login
创建和配置 Actions 项目
- 前往 Actions 控制台,然后点击 New project。
- 在项目名称文本框中,输入项目名称,然后点击创建项目。
- 在 What kind of Action do you want to build? 页面上,依次点击 Smart Home > Start building。该项目会在 Actions 控制台中打开。
- 点击开发 > 调用。
- 在 Display name 文本框中,输入 Action 的名称,然后点击 Save。待有设备可供设置后,Google Home 应用中就会显示此名称。在此 Codelab 中,我们输入了
WebRTC Codelab
作为显示名,但您可以使用其他名称。
- 点击操作。
- 在 Fulfillment 网址 文本框中,输入占位网址,例如
https://example.com
。
运行 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
- 进入
camerastream-start
目录,然后使用您的 Actions 项目设置 Firebase CLI:
$ cd camerastream-start $ firebase use PROJECT_ID
- 在
camerastream-start
目录中,导航到functions
文件夹,然后安装所有必要的依赖项:
$ cd functions $ npm install
- 如果您看到以下消息,请忽略它。此警告是因依赖项旧版所致。如需了解详情,请参阅此 GitHub 问题。
found 5 high severity vulnerabilities run `npm audit fix` to fix them, or `npm audit` for details
- 初始化 Firebase 项目:
$ firebase init
- 选择 Functions(函数)和 Hosting(托管)。这样会初始化您的项目所必需的 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
- 使用默认文件配置 Cloud Functions 函数,并确保不会覆盖项目示例中的现有
index.js
和package.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
- 使用项目代码中的
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 消息,请按以下步骤操作:
- 在 Firebase 控制台中,依次点击构建 > Realtime Database > 创建数据库。
- 在“Realtime Database 位置”下拉菜单中,选择要托管数据库的适当位置。
- 选择以测试模式开始,然后点击启用。启用 Realtime Database 后,您需要能够从 CameraStream 客户端应用引用该数据库。
- 在 Firebase 控制台中,依次选择 项目设置 > 项目设置 > 将 Firebase 添加到您的 Web 应用,以启动设置工作流。
- 如果您已向 Firebase 项目添加了应用,请点击添加应用以显示平台选项。
- 输入应用的别名,例如
My web app
,然后点击注册应用。 - 在添加 Firebase SDK 部分中,选择使用 <script> 标记。
- 复制
firebasebaseConfig
对象中的值,然后将其粘贴到camaerastream-start/public/webrtc_generator.js
文件中。
const firebaseConfig = {
apiKey: "XXXXX",
authDomain: "XXXXX",
projectId: "XXXXX",
storageBucket: "XXXXX",
messagingSenderId: "XXXXX",
appId: "XXXXX",
measurementId: "XXXXX"
};
- 点击前往控制台以完成此流程。您会在项目设置页面上看到新创建的 Web 应用。
4. 创建 WebRTC 摄像头
现在,您已配置 Action,您的云服务需要处理以下 intent:
- 当 Google 助理想要了解用户已连接哪些设备时发生的
SYNC
intent。当用户关联账号时,系统会向您的服务发送此 intent。您应使用用户设备及其功能的 JSON 载荷进行响应。 - 当 Google 助理想要代表用户控制设备时发生的
EXECUTE/QUERY
intent。您应该在响应时提供 JSON 载荷,其中包含所请求的每台设备的执行状态。
在本部分中,您将更新之前部署的用于处理这些 intent 的函数。
更新 SYNC
响应
- 找到
functions/index.js
文件。它包含响应来自 Google 助理的请求的代码。 - 修改
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
},
}],
},
};
});
处理 EXECUTE
intent
EXECUTE
intent 可处理用于更新设备状态的命令。响应会返回每个命令的状态(例如 SUCCESS
、ERROR
或 PENDING
)以及新的设备状态。
- 如需处理
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';
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.
如需详细了解 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
启用账号关联
如需在部署项目后启用帐号关联,请按以下步骤操作:
- 在 Actions 控制台中,依次选择 开发 > 账号关联。
- 在 OAuth 客户端信息部分的相应文本框中输入以下信息:
Client-ID |
|
客户端密钥 |
|
授权网址 |
|
令牌网址 |
|
- 依次点击保存 > 测试。
5. 测试虚拟 WebRTC 摄像头
- 前往您在部署 Firebase 项目时看到的 Hosting 网址。您会看到以下接口,即 CameraStream 客户端应用:
- 在 Local Video Resolution 面板中,选择所需的视频。
- 授权 CameraStream 客户端应用访问您的摄像头和麦克风。客户端上出现了摄像头拍摄的视频画面。
关联到智能家居 CameraStream
Action
- 在 Google Home 应用中,依次点按添加 > 与 Google 服务兼容。
- 搜索您创建的 Action,然后选择它。
- 请记下包含 5 个字符的唯一字母数字代码,因为稍后您会用到它。
- 点按返回。WebRTC 摄像头已添加到 Google Home 应用中的结构。
启动 WebRTC 流
- 在 CameraStream 客户端应用的网页上,在帐号关联令牌值文本框中输入上一部分中的字母数字代码,然后点击提交。
- 如需在 Google 智能显示屏设备上启动 WebRTC 会话,请执行以下操作之一:
- 说“Hey Google,流式传输 WebRTC 相机”。
- 在 Google 智能显示屏设备上,依次点按家居控制 > 摄像头 > WebRTC 摄像头。
在 Google 智能家居 CameraStream 客户端应用中,您可以看到“优惠 SPD 和应答 SDP”已成功生成并交换。通过 WebRTC 将摄像头拍摄的图片流式传输到 Google 智能显示屏设备。
6. 恭喜
恭喜!您已了解如何使用 WebRTC 协议从摄像头流式传输内容到 Google Nest 显示屏设备。