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(従量課金制)プラン。
  • フル HD 解像度に対応できる内蔵または外付けのウェブカメラ デバイス。
  • Google Nest ディスプレイ デバイス。

2. 始める

Firebase CLI をインストールする

Firebase CLI を使用すると、ウェブアプリをローカルで提供し、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 Developer Console に移動します。
  2. [プロジェクトを作成] をクリックし、プロジェクトの名前を入力して [プロジェクトを作成] をクリックします。

プロジェクトに名前を付ける

CameraStream クライアント アプリを実行する

この Codelab のソースコードには、ウェブカメラと Google スマートホーム ディスプレイ デバイス間の WebRTC セッションを確立、ネゴシエート、管理する WebRTC クライアントが含まれています。

CameraStream WebRTC クライアント アプリを実行するには、次のいずれかを行います。

  • 次のボタンをクリックして、ソースコードを開発マシンにダウンロードします。

  • この GitHub リポジトリのクローンを作成します。
    $ git clone https://github.com/google-home/smarthome-camerastream-webrtc.git
    

コードには次のディレクトリが含まれています。

  • camerastream-start ディレクトリ。構築するスターター コードが含まれています。
  • camerastream-done ディレクトリには、完成した Codelab の解答コードが含まれています。

camerastream-start ディレクトリには、次のサブディレクトリが含まれています。

  • public サブディレクトリ。カメラ デバイスの状態を簡単に制御、モニタリングするためのフロントエンド UI が含まれています。
  • functions サブディレクトリ。Cloud Functions for Firebase と Realtime Database を使用してカメラを管理する、実装が完了したクラウド サービスが含まれています。

スターター コードには、コードを追加または変更する必要がある場所を示す TODO コメントが含まれています。たとえば、次のようになります。

// TODO: Implement full SYNC response.

Google Home Developer Console プロジェクトに Firebase を追加する

方法 1: Firebase コンソールを使用する

  1. Firebase に移動します。
  2. [Firebase プロジェクトを作成する] をクリックします。
    Firebase プロジェクトを作成する
  3. [プロジェクトを作成] 画面で、[Google Cloud プロジェクトに Firebase を追加] をクリックします。
    Firebase を Google Cloud プロジェクトに追加する
  4. [スタートガイド] 画面で、Google Home Developer Console で作成した Google Cloud プロジェクトを選択し、[続行] をクリックします。
    Google Cloud プロジェクトを選択する

方法 2: Firebase CLI を使用する

firebase projects:addfirebase

作成したばかりの Google Home Developer Console プロジェクトを選択して、Firebase を追加します。

Firebase が Google Home Developer Console プロジェクトに追加されると、Firebase コンソールに表示されます。Firebase プロジェクトのプロジェクト ID は、Google Home Developer Console のプロジェクト ID と一致します。

Cloud プロジェクトを追加しました

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 features do you want to set up for this directory? Press Space to select features, then Enter
 to confirm your choices. (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to
 proceed)
>( ) Data Connect: Set up a Firebase Data Connect service
 ( ) Firestore: Configure security rules and indexes files for Firestore
 ( ) Genkit: Setup a new Genkit project with Firebase
 (*) Functions: Configure a Cloud Functions directory and its files
 ( ) App Hosting: Configure an apphosting.yaml file for App Hosting
 (*) Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
 ( ) Storage: Configure a security rules file for Cloud Storage
 ( ) Emulators: Set up local emulators for Firebase products
 ( ) Remote Config: Configure a template file for Remote Config
 ( ) Extensions: Set up an empty Extensions manifest
 (*) Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision
default instance
 ( ) Data Connect: Set up a Firebase Data Connect service
 ( ) Firestore: Configure security rules and indexes files for Firestore
  1. デフォルト ファイルを使用して 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
  1. プロジェクト コード内の public ディレクトリと既存の index.html ファイルが使用されるように Hosting を構成します。
? 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 [プロジェクトの設定] > [プロジェクトの設定] > e584a9026e2b407f.png[ウェブアプリに Firebase を追加] を選択して、設定ワークフローを開始します。
  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. [コンソールに進む] をクリックして、プロセスを完了します。新しく作成したウェブアプリが [プロジェクト設定] ページに表示されます。

4. WebRTC カメラを作成する

アクションを構成したので、クラウド サービスで次のインテントを処理する必要があります。

  • SYNC インテント。ユーザーがリンク済みのデバイスについてアシスタントが問い合わせたときに発生します。これは、ユーザーがアカウントをリンクしたときにサービスに送信されます。ユーザーのデバイスとその機能を格納した JSON ペイロードで応答する必要があります。
  • アシスタントがユーザーに代わってデバイスを制御するときに発生する EXECUTE/QUERY インテント。リクエストされた各デバイスの実行状態を格納した JSON ペイロードで応答する必要があります。

このセクションでは、すでにデプロイした関数を、これらのインテントを処理できるように更新します。

SYNC レスポンスを更新する

  1. functions/index.js ファイルに移動します。このファイルには、アシスタントからのリクエストに応答するコードが含まれています。
  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
      },
    }],
  },
};
});
  1. USER_ID がコードで定義されていません。const _ = require('underscore'); の下に以下を追加します。
// Hardcoded user ID
const USER_ID = '123';

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 を処理するには、functions/index.js ファイルの allowlist 配列に Firebase Hosting の URL を追加します。

index.js

'use strict';
.....

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

CORS の詳細については、クロスオリジン リソース シェアリング(CORS)をご覧ください。

ストリームの終了を処理する

WebRTC ストリームの終了を処理するには、Firebase の「シグナリング」関数の URL を 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

Developer Console プロジェクトを構成する

  1. デベロッパー コンソールに移動します。
  2. [プロジェクトを作成] をクリックし、プロジェクトの名前を入力して [プロジェクトを作成] をクリックします。

プロジェクトに名前を付ける

クラウド間統合を選択する

デベロッパー コンソールの [プロジェクト ホーム] で、[Cloud-to-cloud] の [Add cloud-to-cloud integration] を選択します。

Cloud-to-cloud 統合を追加する

  1. [統合名] を入力し、[デバイスタイプ] で [カメラ] を選択します。この名前は、後で Google Home アプリに表示されます。この Codelab では、表示名として「WebRTC Codelab」と入力しましたが、別の名前を使用することもできます。

表示名を追加する

  1. [アプリのブランディング] で、144×144 ピクセルのサイズで .png という名前のアプリ アイコンの png ファイルをアップロードします。

アプリアイコンを追加する

アカウント リンクを有効にする

プロジェクトのデプロイ後にアカウント リンクを有効にする手順は次のとおりです。

  1. デベロッパー コンソールに移動して、プロジェクトを開きます。
  2. [Cloud-to-Cloud] セクションで、インテグレーションの横にある [開発] > [編集] をクリックします。
  3. [設定と構成] ページで、[アカウントのリンク] セクションを見つけ、対応するテキスト ボックスに次の情報を入力します。

クライアント ID

ABC123

クライアント シークレット

DEF456

認証 URL

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

トークンの URL

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

アカウント リンクの URL を更新する

  1. [保存] > [テスト] をクリックします。

5. 仮想 WebRTC カメラをテストする

  1. Firebase プロジェクトをデプロイしたときに表示された Hosting URL に移動します。次のインターフェース(CameraStream クライアント アプリ)が表示されます。

CameraStream クライアント アプリのインターフェース

  1. [ローカル動画の解像度] パネルで、目的の動画を選択します。
  2. CameraStream クライアント アプリにウェブカメラとマイクへのアクセスを許可します。ウェブカメラからの動画フィードがクライアントに表示されます。
  1. Google Home アプリで、[追加] > [Google と連携させる] をタップします。

Google Home アプリの [デバイスのセットアップ] ページ

  1. 作成したアクションを検索して選択します。

Google Home アプリのスマートホーム アクション

  1. 後で必要になるため、5 文字の英数字の固有コードをメモしておきます。

一意の 5 桁の英数字コード

  1. [元に戻す] をタップします。WebRTC カメラが Google Home アプリのストラクチャに追加されます。

WebRTC ストリームを開始する

  1. CameraStream クライアント アプリのウェブページで、最後のセクションの英数字コードを [Account linking token value] テキスト ボックスに入力し、[Submit] をクリックします。

[Account linking token value](アカウントのリンク トークン値)テキスト ボックス

  1. Google スマート ディスプレイ デバイスから WebRTC セッションを開始するには、次のいずれかを行います。
  • 「OK Google, WebRTC カメラをストリーミングして」と話しかけます。
  • Google スマート ディスプレイで、[ホーム コントロール] > [カメラ] > [WebRTC カメラ] をタップします。

Google スマートホームの CameraStream クライアント アプリで、Offer SPD と Answer SDP が正常に生成され、交換されたことを確認します。ウェブカメラの画像は、WebRTC を使用して Google スマートディスプレイ デバイスにストリーミングされます。

6. 完了

おめでとうございます!WebRTC プロトコルを使用してウェブカメラから Google Nest ディスプレイ デバイスにストリーミングする方法を学習しました。

その他の情報