1. 准备工作
CameraStream
trait 适用于能够将视频画面流式传输到智能显示屏、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
创建项目
- 前往 Google Home 开发者控制台。
- 点击 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 项目
- 前往 Firebase。
- 点击创建项目,然后输入项目名称。
- 选中同意复选框,然后点击继续。如果没有协议复选框,您可以跳过此步骤。
- 创建 Firebase 项目后,找到项目 ID。前往项目概览,然后依次点击“设置”图标 > 项目设置。
- 您的项目会列在常规标签页下。
连接到 Firebase
- 前往
camerastream-start
目录,然后使用您的 Actions 项目设置 Firebase CLI:
$ cd camerastream-start $ firebase use <firebase-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 控制台中,依次选择 Project settings > Project settings > Add Firebase to your Web App,以启动设置工作流。
- 如果您已向 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
},
}],
},
};
});
- 代码中未定义
USER_ID
。在const _ = require('underscore');
下方添加以下内容:
// Hardcoded user ID
const USER_ID = '123';
处理 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';
.....
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
配置您的开发者控制台项目
- 前往开发者控制台。
- 点击 Create Project,输入项目名称,然后点击 Create Project。
选择云到云集成
在 Play 管理中心的项目首页上,选择云到云下的添加云到云集成。
- 输入集成名称,然后在设备类型下方选择摄像头。当有设备需要设置时,此名称会显示在 Google Home 应用中。对于此 Codelab,我们输入了 WebRTC Codelab 作为显示名称,但您可以使用其他名称。
- 在应用品牌信息下,为应用图标上传一个大小为 144 x 144 像素且名为
的.png png
文件。
启用账号关联
如需在项目部署后启用账号关联,请按以下步骤操作:
- 前往 Developer Console 并打开项目。
- 在云到云部分下,依次点击开发 > 相应集成旁边的修改。
- 在设置和配置页面中,找到账号关联部分,然后在相应的文本框中输入以下信息:
客户 ID |
|
客户端密钥 |
|
授权网址 |
|
令牌网址 |
|
- 依次点击保存 > 测试。
5. 测试虚拟 WebRTC 摄像头
- 前往您在部署 Firebase 项目时看到的 Hosting 网址。您会看到以下界面,即 CameraStream 客户端应用:
- 在本地视频分辨率面板中,选择所需的视频。
- 向 CameraStream 客户端应用授予使用摄像头和麦克风的权限。客户端上会显示来自网络摄像头的视频画面。
关联到智能家居 CameraStream
Action
- 在 Google Home 应用中,依次点按添加 > 支持 Google。
- 搜索您创建的操作,然后选择该操作。
- 记下这个由 5 个字母数字组成的唯一代码,因为您稍后需要用到它。
- 点按返回。WebRTC 摄像头会添加到 Google Home 应用中的结构中。
启动 WebRTC 流式传输
- 在 CameraStream 客户端应用的网页上,在 Account linking token value(账号关联令牌值)文本框中输入上一部分中的字母数字代码,然后点击 Submit(提交)。
- 如需从 Google 智能显示屏设备启动 WebRTC 会话,请执行以下任一操作:
- 说“Hey Google,流式传输 WebRTC 摄像头。”
- 在 Google 智能显示屏设备上,依次点按住宅控制 > 摄像头 > WebRTC 摄像头。
在 Google 智能家居 CameraStream 客户端应用中,您会看到 Offer SPD 和 Answer SDP 已成功生成并交换。网络摄像头的图片会通过 WebRTC 流式传输到 Google 智能显示屏设备。
6. 恭喜
恭喜!您了解了如何使用 WebRTC 协议将视频从摄像头流式传输到 Google Nest 显示屏设备。