使用 WebRTC 實作 CameraStream

1. 事前準備

CameraStream 特徵屬於能夠串流播放影片動態饋給的裝置,包括智慧螢幕、Chromecast 裝置和智慧型手機。CameraStream 特徵現在支援 WebRTC 通訊協定,因此你可以大幅縮短從攝影機裝置到 Google Nest 螢幕裝置的啟動和串流延遲。

攝影機裝置正在串流至 Google Nest 螢幕裝置

必備條件

課程內容

  • 如何部署智慧型住宅雲端服務。
  • 如何將服務連結至 Google 助理。
  • 如何使用 WebRTC 通訊協定將內容串流至 Google Nest 螢幕裝置。

事前準備

  • 網路瀏覽器,例如 Google Chrome
  • 已安裝 Google Home 應用程式的 iOS 或 Android 裝置。
  • Node.js 10.16 或以上版本。
  • 適用於 Firebase 的 Blaze (即付即用) 方案。
  • 支援 Full HD 高畫質解析度的內建或外接網路攝影機裝置。
  • Google Nest 螢幕裝置。

2. 立即開始

安裝 Firebase CLI

Firebase CLI 可讓你在本機提供網頁應用程式,並部署至 Firebase 託管。

如要安裝 Firebase CLI,請按照下列步驟操作:

  1. 在終端機中下載並安裝 Firebase CLI:
$ npm install -g firebase-tools
  1. 確認 CLI 已正確安裝:
$ firebase --version
  1. 使用 Google 帳戶授權 Firebase CLI:
$ firebase login

建立及設定動作專案

  1. 前往動作控制台,然後按一下「新增專案」
  2. 在「專案名稱」文字方塊中,輸入專案名稱,然後按一下「建立專案」

Actions 主控台中的「New project」對話方塊

  1. 在「您想要建構哪一種動作?」頁面中,依序點選「智慧型住宅」 >「開始建構」。專案會在動作控制台中開啟。

Actions 控制台的「總覽」分頁

  1. 依序按一下「Develop」(開發) >「Invocation」(叫用)
  2. 在「顯示名稱」文字方塊中,輸入動作的名稱,然後按一下「儲存」。如果之後要設定裝置,這個名稱會出現在 Google Home 應用程式中。在本程式碼研究室中,我們輸入了 WebRTC Codelab 做為顯示名稱,但您可以使用不同的名稱。

Actions 控制台的「叫用」面板

  1. 按一下 [動作]
  2. 在「Fulfillment URL」(執行要求網址) 文字方塊中,輸入預留位置網址,例如 https://example.com

執行 CameraStream 用戶端應用程式

本程式碼研究室的原始碼包含用來建立、協商及管理網路攝影機和 Google 智慧住宅顯示裝置之間的 WebRTC 工作階段的 WebRTC 用戶端。

如要執行 CameraStream WebRTC 用戶端應用程式,請執行下列任一操作:

  • 點選下列按鈕,將原始碼下載至開發機器:

  • 複製這個 GitHub 存放區:
$ git clone https://github.com/google-home/smarthome-camerastream-webrtc.git

這個程式碼包含下列目錄:

  • camerastream-start 目錄,包含您要建構的範例程式碼。
  • camerastream-done 目錄,其中包含已完成程式碼研究室的解決方案程式碼。

camerastream-start 目錄包含下列子目錄:

  • public 子目錄內含前端 UI,可輕鬆控制及監控相機裝置的狀態。
  • functions 子目錄內含完全導入的雲端服務,可透過 Cloud Functions for Firebase 和即時資料庫管理相機。

範例程式碼包含 TODO 註解,用於指示需要新增或變更程式碼的位置,如以下範例所示:

// TODO: Implement full SYNC response.

連結至 Firebase

  1. 前往 camerastream-start 目錄,然後透過 Actions 專案設定 Firebase CLI:
$ cd camerastream-start
$ firebase use 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. 選取「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
  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 目錄設定「託管」,並使用現有的 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. Exchange 工作階段說明通訊協定 (SDP) 訊息

建立 WebRTC 串流時,交換 SDP 訊息是重要步驟。SDP 是一種文字型通訊協定,用於說明多媒體工作階段的特性。WebRTC 用於交涉點對點連線的參數,例如使用的轉碼器、參與者的 IP 位址,以及用於媒體傳輸的通訊埠。

如要將即時資料庫當做主機使用,以便在網路攝影機與智慧型住宅 CameraStream 用戶端應用程式之間交換 SDP 訊息,請按照下列步驟操作:

  1. Firebase 控制台,依序點選「Build」>「Realtime Database」>「Create database」

Firebase 控制台的「即時資料庫」頁面

  1. 在「Realtime Database location」(即時資料庫位置) 下拉式選單中,選取存放資料庫的適當位置。

「設定資料庫」對話方塊中的「即時資料庫位置」下拉式選單

  1. 選取「以測試模式啟動」,然後按一下「啟用」。啟用即時資料庫後,您必須能透過 CameraStream 用戶端應用程式參照該資料庫。
  1. 在 Firebase 控制台中,依序選取「專案設定」>「專案設定」513f2be95dcd7896.png 專案設定 >「專案設定」>e584a9026e2b407f.png將 Firebase 新增至網頁應用程式,啟動設定程序。
  2. 如果您已將應用程式加入 Firebase 專案,按一下「新增應用程式」即可顯示平台選項。
  3. 輸入應用程式暱稱 (例如 My web app),然後按一下「Register app」
  4. 在「Add Firebase SDK」部分,選取「Use <script> tag」
  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. 按一下「Continue to console」完成設定程序。「專案設定」頁面會顯示新建立的網頁應用程式。

4. 建立 WebRTC 攝影機

現在您已設定動作,您的雲端服務需要處理下列意圖:

  • 如果 Google 助理想瞭解使用者連結了哪些裝置,就會發生 SYNC 意圖。當使用者連結帳戶後,這個電子郵件會傳送至您的服務。您應運用使用者裝置及其功能的 JSON 酬載回應。
  • EXECUTE/QUERY 意圖。Google 助理想代表使用者控制裝置時,就會發生這個意圖。您應該透過 JSON 酬載回應,其中包含每個要求裝置的執行狀態。

在本節中,您將更新先前部署的函式來處理這些意圖。

更新 SYNC 回應

  1. 前往 functions/index.js 檔案。用於回應 Google 助理要求的程式碼。
  2. 編輯 SYNC 意圖,傳回裝置的中繼資料和功能:

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 意圖

EXECUTE 意圖會處理用於更新裝置狀態的指令。回應會傳回每個指令的狀態 (例如 SUCCESSERRORPENDING),以及新裝置狀態。

  • 如要處理 EXECUTE 意圖,請編輯 EXECUTE 意圖,在 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 託管網址新增至 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

這個指令會部署網頁應用程式和數個 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. 在「OAuth 用戶端資訊」部分的對應文字方塊中輸入下列資訊:

用戶端 ID

ABC123

用戶端密鑰

DEF456

授權網址

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

權杖網址

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

Actions 控制台的帳戶連結頁面

  1. 按一下「Save」(儲存) >「Test」(測試)

5. 測試虛擬 WebRTC 相機

  1. 前往您在部署 Firebase 專案時看到的託管網址。您會看到以下介面,也就是 CameraStream 用戶端應用程式:

CameraStream 用戶端應用程式介面

  1. 在「Local Video Resolution」面板中選取所需影片。
  2. 授權讓 CameraStream 用戶端應用程式存取網路攝影機和麥克風。用戶端出現來自網路攝影機的影片動態消息。
  1. 在 Google Home 應用程式中,依序輕觸「新增」>「與 Google 服務連結」

Google Home 應用程式中的「設定裝置」頁面

  1. 搜尋並選取您建立的動作。

Google Home 應用程式中的智慧型居家動作

  1. 請注意一組由五字元組成的專屬代碼,以便在之後使用。

專屬、五位數的英數字元代碼

  1. 輕觸「返回」。WebRTC 攝影機已新增至 Google Home 應用程式的結構中。

啟動 WebRTC 串流

  1. 在 CameraStream 用戶端應用程式的網頁中,於「Account link token value」文字方塊中輸入最後一部分的英數字元代碼,然後按一下「Submit」

帳戶連結權杖值文字方塊

  1. 如要透過 Google 智慧螢幕裝置啟動 WebRTC 工作階段,請執行下列任一操作:
  • 說出「Ok Google,串流播放 WebRTC 攝影機畫面」。
  • 在 Google 智慧螢幕裝置上,依序輕觸「居家控制系統」>「攝影機」>「WebRTC 攝影機」

在 Google 智慧型住宅 CameraStream 用戶端應用程式中,您會看到 Offer SPD 和 Answer SDP 已成功產生及交換。透過 WebRTC 串流在 Google 智慧螢幕裝置上的圖片。

6. 恭喜

恭喜!您已學會如何使用 WebRTC 通訊協定,將網路攝影機串流傳輸到 Google Nest 螢幕裝置。

瞭解詳情