ใช้งาน CameraStream กับ WebRTC

1. ก่อนเริ่มต้น

คุณลักษณะ CameraStream เป็นของอุปกรณ์ที่มีความสามารถในการสตรีมฟีดวิดีโอไปยังจออัจฉริยะ อุปกรณ์ Chromecast และสมาร์ทโฟน ตอนนี้CameraStreamรองรับโปรโตคอล WebRTC แล้ว ซึ่งหมายความว่าคุณจะลดเวลาในการเริ่มต้นและเวลาในการตอบสนองของการสตรีมจากอุปกรณ์กล้องไปยังอุปกรณ์จอแสดงผล Google Nest ได้อย่างมาก

อุปกรณ์กล้องที่สตรีมไปยังอุปกรณ์จอแสดงผล Google Nest

ข้อกำหนดเบื้องต้น

สิ่งที่คุณจะได้เรียนรู้

  • วิธีติดตั้งใช้งานบริการระบบคลาวด์สำหรับสมาร์ทโฮม
  • วิธีเชื่อมต่อบริการกับ Google Assistant
  • วิธีสตรีมไปยังอุปกรณ์จอแสดงผล Google Nest ด้วยโปรโตคอล WebRTC

สิ่งที่คุณต้องมี

  • เว็บเบราว์เซอร์ เช่น Google Chrome
  • อุปกรณ์ iOS หรือ Android ที่มีแอป Google Home
  • Node.js เวอร์ชัน 10.16 ขึ้นไป
  • แผน Blaze (จ่ายตามการใช้งานจริง) สำหรับ Firebase
  • อุปกรณ์เว็บแคมในตัวหรือภายนอกที่รองรับความละเอียดระดับ 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. ให้สิทธิ์ Firebase CLI ด้วยบัญชี Google โดยทำดังนี้
$ firebase login

สร้างโปรเจ็กต์

  1. ไปที่ Google Home Developer Console
  2. คลิกสร้างโปรเจ็กต์ ป้อนชื่อโปรเจ็กต์ แล้วคลิกสร้างโปรเจ็กต์

ตั้งชื่อโปรเจ็กต์

เรียกใช้แอปไคลเอ็นต์ CameraStream

ซอร์สโค้ดของโค้ดแล็บนี้มีไคลเอ็นต์ WebRTC ที่สร้าง เจรจา และจัดการเซสชัน WebRTC ระหว่างเว็บแคมกับอุปกรณ์จอแสดงผลสมาร์ทโฮมของ Google

หากต้องการเรียกใช้แอปไคลเอ็นต์ WebRTC ของ CameraStream ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้

  • คลิกปุ่มต่อไปนี้เพื่อดาวน์โหลดซอร์สโค้ดไปยังคอมพิวเตอร์สำหรับการพัฒนาซอฟต์แวร์

  • โคลนที่เก็บ 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 และฐานข้อมูลเรียลไทม์

โค้ดเริ่มต้นมีTODOความคิดเห็นที่ระบุตำแหน่งที่คุณต้องเพิ่มหรือเปลี่ยนโค้ด เช่น ตัวอย่างต่อไปนี้

// TODO: Implement full SYNC response.

เพิ่ม Firebase ไปยังโปรเจ็กต์ Google Home Developer Console

วิธีที่ 1: ผ่านคอนโซล Firebase

  1. ไปที่ Firebase
  2. คลิกสร้างโปรเจ็กต์ Firebase
    สร้างโปรเจ็กต์ Firebase
  3. ในหน้าจอสร้างโปรเจ็กต์ ให้คลิกเพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud
    เพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud
  4. ในหน้าจอเริ่มต้นใช้งาน ให้เลือกโปรเจ็กต์ Google Cloud ที่คุณเพิ่งสร้างใน Google Home Developer Console แล้วคลิกต่อไป
    เลือกโปรเจ็กต์ที่อยู่ใน Google Cloud

วิธีที่ 2: ผ่าน Firebase CLI

firebase projects:addfirebase

เลือกโปรเจ็กต์ Google Home Developer Console ที่คุณเพิ่งสร้างเพื่อเพิ่ม Firebase

เมื่อเพิ่ม Firebase ลงในโปรเจ็กต์ Google Home Developer Console แล้ว Firebase จะปรากฏในคอนโซล Firebase รหัสโปรเจ็กต์ของโปรเจ็กต์ Firebase จะสอดคล้องกับรหัสโปรเจ็กต์ Google Home Developer Console

เพิ่มโปรเจ็กต์ที่อยู่ในระบบคลาวด์แล้ว

เชื่อมต่อกับ Firebase

  1. ไปที่ไดเรกทอรี camerastream-start แล้วตั้งค่า Firebase CLI ด้วยโปรเจ็กต์ Actions ดังนี้
$ cd camerastream-start
$ firebase use <project-id>
  1. ในไดเรกทอรี camerastream-start ให้ไปที่โฟลเดอร์ functions แล้วติดตั้งทรัพยากร Dependency ที่จำเป็นทั้งหมด
$ cd functions
$ npm install
  1. หากเห็นข้อความต่อไปนี้ ให้เพิกเฉย คำเตือนนี้เกิดจาก Dependency ที่เก่ากว่า ดูข้อมูลเพิ่มเติมได้ที่ปัญหานี้ใน GitHub
found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
  1. เริ่มต้นโปรเจ็กต์ Firebase
$ firebase init
  1. เลือกฟังก์ชันและการโฮสต์ ซึ่งจะเริ่มต้น 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. กำหนดค่า Hosting ด้วยไดเรกทอรี 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. แลกเปลี่ยนข้อความ Session Description Protocol (SDP)

การแลกเปลี่ยนข้อความ SDP เป็นขั้นตอนสำคัญในการสร้างสตรีม WebRTC SDP เป็นโปรโตคอลแบบข้อความที่อธิบายลักษณะของเซสชันมัลติมีเดีย โดยใช้ใน WebRTC เพื่อเจรจาพารามิเตอร์ของการเชื่อมต่อแบบเพียร์ทูเพียร์ เช่น ตัวแปลงรหัสที่ใช้ ที่อยู่ IP ของผู้เข้าร่วม และพอร์ตที่ใช้สำหรับการรับส่งสื่อ

หากต้องการใช้ฐานข้อมูลเรียลไทม์เป็นโฮสต์เพื่อแลกเปลี่ยนข้อความ SDP ระหว่างเว็บแคมกับแอปไคลเอ็นต์ CameraStream ของสมาร์ทโฮม ให้ทำตามขั้นตอนต่อไปนี้

  1. ในคอนโซล Firebase ให้คลิกสร้าง > ฐานข้อมูลเรียลไทม์ > สร้างฐานข้อมูล

หน้าฐานข้อมูลเรียลไทม์ในคอนโซล Firebase

  1. ในเมนูแบบเลื่อนลงตำแหน่ง Realtime Database ให้เลือกตำแหน่งที่เหมาะสมเพื่อโฮสต์ฐานข้อมูล

เมนูแบบเลื่อนลงของตำแหน่ง Realtime Database ในกล่องโต้ตอบ &quot;ตั้งค่าฐานข้อมูล&quot;

  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

เมื่อกำหนดค่า Action แล้ว บริการระบบคลาวด์ของคุณจะต้องจัดการ Intent ต่อไปนี้

  • SYNC ความตั้งใจที่เกิดขึ้นเมื่อ Assistant ต้องการทราบว่าผู้ใช้เชื่อมต่ออุปกรณ์ใดไว้ ระบบจะส่งข้อมูลนี้ไปยังบริการของคุณเมื่อผู้ใช้ลิงก์บัญชี คุณควรตอบกลับด้วยเพย์โหลด JSON ของอุปกรณ์ของผู้ใช้และความสามารถของอุปกรณ์
  • EXECUTE/QUERY เจตนาที่เกิดขึ้นเมื่อ Assistant ต้องการควบคุมอุปกรณ์ในนามของผู้ใช้ คุณควรตอบกลับด้วยเพย์โหลด JSON ที่มีสถานะการดำเนินการของอุปกรณ์แต่ละเครื่องที่ขอ

ในส่วนนี้ คุณจะอัปเดตฟังก์ชันที่เคยติดตั้งใช้งานเพื่อจัดการเจตนาเหล่านี้

อัปเดตคำตอบของ SYNC

  1. ไปที่ไฟล์ functions/index.js มีโค้ดเพื่อตอบสนองต่อคำขอจาก Assistant
  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 เจตนาจะจัดการคำสั่งเพื่ออัปเดตสถานะอุปกรณ์ การตอบกลับจะแสดงสถานะของแต่ละคำสั่ง เช่น SUCCESS, ERROR หรือ PENDING และสถานะใหม่ของอุปกรณ์

หากต้องการจัดการEXECUTE Intent ให้แก้ไข Intent EXECUTE เพื่อส่งคืนปลายทาง signaling ของโปรเจ็กต์ Firebase ในไฟล์ functions/index.js

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)

หากต้องการจัดการ CORS เนื่องจากการใช้เมธอด POST เพื่อส่ง SDP ให้เพิ่ม URL ของ Firebase Hosting ลงในอาร์เรย์ allowlist ในไฟล์ functions/index.js

index.js

'use strict';
.....

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับ CORS ได้ที่กลไกการแชร์ทรัพยากรข้ามโดเมน (CORS)

จัดการการสิ้นสุดสตรีม

หากต้องการจัดการการสิ้นสุดสตรีม WebRTC ให้เพิ่ม URL ฟังก์ชัน "การส่งสัญญาณ" ของ 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

กำหนดค่าโปรเจ็กต์ใน Developer Console

  1. ไปที่ Developer Console
  2. คลิกสร้างโปรเจ็กต์ ป้อนชื่อโปรเจ็กต์ แล้วคลิกสร้างโปรเจ็กต์

ตั้งชื่อโปรเจ็กต์

เลือกการผสานรวมแบบคลาวด์ต่อคลาวด์

ในหน้าแรกของโปรเจ็กต์ใน Developer Console ให้เลือกเพิ่มการผสานรวมแบบคลาวด์ต่อคลาวด์ในส่วนคลาวด์ต่อคลาวด์

เพิ่มการผสานรวมแบบคลาวด์ต่อคลาวด์

  1. ป้อนชื่อการผสานรวม แล้วเลือกกล้องในส่วนประเภทอุปกรณ์ ชื่อนี้จะปรากฏในแอป Google Home ในภายหลังเมื่อมีอุปกรณ์ที่ต้องตั้งค่า สำหรับ Codelab นี้ เราป้อน WebRTC Codelab เป็นชื่อที่แสดง แต่คุณจะใช้ชื่ออื่นก็ได้

เพิ่มชื่อที่แสดง

  1. ในส่วนการสร้างแบรนด์แอป ให้อัปโหลดไฟล์ png สำหรับไอคอนแอปขนาด 144 x 144 พิกเซล และตั้งชื่อว่า .png

เพิ่มไอคอนแอป

เปิดใช้การลิงก์บัญชี

หากต้องการเปิดใช้การลิงก์บัญชีหลังจากที่ติดตั้งใช้งานโปรเจ็กต์แล้ว ให้ทำตามขั้นตอนต่อไปนี้

  1. ไปที่ Developer Console แล้วเปิดโปรเจ็กต์
  2. ในส่วนระบบคลาวด์ต่อระบบคลาวด์ ให้คลิกพัฒนา > แก้ไขข้างการผสานรวม
  3. ในหน้าการตั้งค่าและการกำหนดค่า ให้หาส่วนการลิงก์บัญชี แล้วป้อนข้อมูลต่อไปนี้ในกล่องข้อความที่เกี่ยวข้อง

รหัสลูกค้า

ABC123

รหัสลับไคลเอ็นต์

DEF456

URL สำหรับการอนุญาต

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

URL โทเค็น

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

อัปเดต URL การลิงก์บัญชี

  1. คลิกบันทึก > ทดสอบ

5. ทดสอบกล้อง WebRTC เสมือน

  1. ไปที่ URL ของ Hosting ที่คุณเห็นเมื่อทําการติดตั้งใช้งานโปรเจ็กต์ Firebase คุณจะเห็นอินเทอร์เฟซต่อไปนี้ ซึ่งเป็นแอปไคลเอ็นต์ CameraStream

อินเทอร์เฟซแอปไคลเอ็นต์ CameraStream

  1. ในแผงความละเอียดของวิดีโอในเครื่อง ให้เลือกวิดีโอที่ต้องการ
  2. ให้สิทธิ์แอปไคลเอ็นต์ CameraStream ในการเข้าถึงเว็บแคมและไมโครโฟน ฟีดวิดีโอจากเว็บแคมจะปรากฏในไคลเอ็นต์
  1. ในแอป Google Home ให้แตะเพิ่ม > ใช้ได้กับ Google

หน้าตั้งค่าอุปกรณ์ในแอป Google Home

  1. ค้นหาการดำเนินการที่คุณสร้างขึ้น แล้วเลือกการดำเนินการนั้น

การทำงานของสมาร์ทโฮมในแอป Google Home

  1. จดรหัสที่เป็นตัวอักษรและตัวเลขคละกัน 5 ตัวที่ไม่ซ้ำกันไว้เนื่องจากคุณต้องใช้ในภายหลัง

รหัสที่เป็นตัวอักษรและตัวเลขคละกัน 5 หลักที่ไม่ซ้ำกัน

  1. แตะนำฉันกลับไป ระบบจะเพิ่มกล้อง WebRTC ลงในโครงสร้างของคุณในแอป Google Home

เริ่มสตรีม WebRTC

  1. ในหน้าเว็บของแอปไคลเอ็นต์ CameraStream ให้ป้อนรหัสตัวอักษรและตัวเลขจากส่วนสุดท้ายในกล่องข้อความค่าโทเค็นการลิงก์บัญชี แล้วคลิกส่ง

กล่องข้อความค่าโทเค็นการลิงก์บัญชี

  1. หากต้องการเริ่มเซสชัน WebRTC จากอุปกรณ์จออัจฉริยะของ Google ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้
  • พูดว่า "Ok Google สตรีมกล้อง WebRTC"
  • ในอุปกรณ์ Google Smart Display ให้แตะการควบคุมบ้าน > กล้อง > กล้อง WebRTC

จากแอปไคลเอ็นต์ CameraStream ของสมาร์ทโฮมของ Google คุณจะเห็นว่าระบบสร้างและแลกเปลี่ยน Offer SPD และ Answer SDP ได้สำเร็จ ระบบจะสตรีมรูปภาพจากเว็บแคมไปยังอุปกรณ์จออัจฉริยะของ Google ด้วย WebRTC

6. ขอแสดงความยินดี

ยินดีด้วย คุณได้เรียนรู้วิธีไลฟ์สดจากเว็บแคมไปยังอุปกรณ์จอแสดงผล Google Nest ด้วยโปรโตคอล WebRTC

ดูข้อมูลเพิ่มเติม