1. ก่อนเริ่มต้น
ลักษณะ CameraStream เป็นของอุปกรณ์ที่มีความสามารถในการสตรีมฟีดวิดีโอไปยังจออัจฉริยะ อุปกรณ์ Chromecast และสมาร์ทโฟน ตอนนี้โปรโตคอล WebRTC ได้รับการสนับสนุนในลักษณะ CameraStream แล้ว ซึ่งหมายความว่าคุณจะลดเวลาในการตอบสนองของอุปกรณ์กล้องในการเริ่มต้นและเริ่มสตรีมไปยังอุปกรณ์จอแสดงผล 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 ให้ทําตามขั้นตอนต่อไปนี้
- ดาวน์โหลดและติดตั้ง Firebase CLI ในเทอร์มินัล โดยทำดังนี้
 
$ npm install -g firebase-tools
- ตรวจสอบว่าติดตั้ง CLI อย่างถูกต้องแล้ว โดยทำดังนี้
 
$ firebase --version
- ให้สิทธิ์ Firebase CLI ด้วยบัญชี Google โดยทำดังนี้
 
$ firebase login
สร้างโปรเจ็กต์
- ไปที่ Google Home Developer Console
 - คลิกสร้างโปรเจ็กต์ ป้อนชื่อโปรเจ็กต์ แล้วคลิกสร้างโปรเจ็กต์
 

เรียกใช้แอปไคลเอ็นต์ 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 และ Realtime Database 
โค้ดเริ่มต้นมีความคิดเห็น TODO ที่ระบุตําแหน่งที่คุณจําเป็นต้องเพิ่มหรือเปลี่ยนแปลงโค้ด เช่น ตัวอย่างต่อไปนี้
// TODO: Implement full SYNC response.
เพิ่ม Firebase ไปยังโปรเจ็กต์ Google Home Developer Console
วิธีที่ 1: ผ่านคอนโซล Firebase
- ไปที่ Firebase
 - คลิกสร้างโปรเจ็กต์ Firebase 

 - ในหน้าจอสร้างโปรเจ็กต์ ให้คลิกเพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud 

 - ในหน้าจอเริ่มต้นใช้งาน ให้เลือกโปรเจ็กต์ Google Cloud ที่คุณเพิ่งสร้างในคอนโซลนักพัฒนาแอป Google Home แล้วคลิกต่อไป 

 
วิธีที่ 2: ผ่าน Firebase CLI
firebase projects:addfirebase
เลือกโปรเจ็กต์ Google Home Developer Console ที่คุณเพิ่งสร้างขึ้นเพื่อเพิ่ม Firebase
เมื่อเพิ่ม Firebase ลงในโปรเจ็กต์ Google Home Developer Console แล้ว โปรเจ็กต์ดังกล่าวจะปรากฏในคอนโซล Firebase รหัสโปรเจ็กต์ของโปรเจ็กต์ Firebase จะสอดคล้องกับรหัสโปรเจ็กต์ในคอนโซลนักพัฒนาแอป Google Home

เชื่อมต่อกับ Firebase
- ไปที่ไดเรกทอรี 
camerastream-startแล้วตั้งค่า Firebase CLI กับโปรเจ็กต์ Actions โดยทำดังนี้ 
$ cd camerastream-start $ firebase use <project-id>
- ในไดเรกทอรี 
camerastream-startให้ไปที่โฟลเดอร์functionsแล้วติดตั้ง Dependency ที่จําเป็นทั้งหมด ดังนี้ 
$ 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
- เลือกฟังก์ชันและโฮสติ้ง ซึ่งจะเริ่มต้น 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
- กำหนดค่า 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ในโค้ดโปรเจ็กต์ และใช้ไฟล์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 Session Description Protocol (SDP)
การแลกเปลี่ยนข้อความ SDP เป็นขั้นตอนสำคัญในการสร้างสตรีม WebRTC SDP เป็นโปรโตคอลแบบข้อความที่อธิบายลักษณะของเซสชันมัลติมีเดีย ซึ่งใช้ใน WebRTC เพื่อเจรจาต่อรองพารามิเตอร์ของการเชื่อมต่อแบบ peer-to-peer เช่น ตัวแปลงรหัสที่ใช้ ที่อยู่ IP ของผู้เข้าร่วม และพอร์ตที่ใช้สำหรับสื่อกลาง
หากต้องการใช้ Realtime Database ในฐานะโฮสต์เพื่อแลกเปลี่ยนข้อความ SDP ระหว่างเว็บแคมกับแอปไคลเอ็นต์ CameraStream สมาร์ทโฮม ให้ทําตามขั้นตอนต่อไปนี้
- ในคอนโซล Firebase ให้คลิกสร้าง > ฐานข้อมูลเรียลไทม์ > สร้างฐานข้อมูล
 

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

- เลือกเริ่มในโหมดทดสอบ แล้วคลิกเปิดใช้ เมื่อเปิดใช้ Realtime Database คุณจะต้องอ้างอิงจากแอปไคลเอ็นต์ CameraStream ได้
 
- ในคอนโซล Firebase ให้เลือก 
 การตั้งค่าโปรเจ็กต์ > การตั้งค่าโปรเจ็กต์ > 
เพิ่ม Firebase ลงในเว็บแอปเพื่อเปิดเวิร์กโฟลว์การตั้งค่า - หากคุณเพิ่มแอปลงในโปรเจ็กต์ 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"
};
- คลิกไปที่คอนโซลเพื่อดำเนินการให้เสร็จสมบูรณ์ คุณจะเห็นเว็บแอปที่สร้างขึ้นใหม่ในหน้าการตั้งค่าโปรเจ็กต์
 
4. สร้างกล้อง WebRTC
เมื่อกำหนดค่าการดำเนินการแล้ว บริการระบบคลาวด์จะต้องจัดการ Intent ต่อไปนี้
- Intent 
SYNCที่เกิดขึ้นเมื่อ Assistant ต้องการทราบว่าผู้ใช้เชื่อมต่ออุปกรณ์ใดอยู่ ระบบจะส่งข้อมูลนี้ไปยังบริการของคุณเมื่อผู้ใช้ลิงก์บัญชี คุณควรตอบกลับด้วยเพย์โหลด JSON ของอุปกรณ์ของผู้ใช้และความสามารถของอุปกรณ์ - Intent 
EXECUTE/QUERYที่เกิดขึ้นเมื่อ Assistant ต้องการควบคุมอุปกรณ์ในนามของผู้ใช้ คุณควรตอบกลับด้วยเพย์โหลด JSON ที่มีสถานะการดําเนินการของอุปกรณ์ที่ขอแต่ละเครื่อง 
ในส่วนนี้ คุณจะอัปเดตฟังก์ชันที่ติดตั้งใช้งานก่อนหน้านี้เพื่อจัดการความตั้งใจเหล่านี้
อัปเดตคําตอบ SYNC
- ไปที่ไฟล์ 
functions/index.jsซึ่งมีโค้ดสําหรับตอบคําขอจาก Assistant - แก้ไข Intent 
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
      },
    }],
  },
};
});
- ไม่ได้กำหนด 
USER_IDในโค้ด เพิ่มข้อมูลต่อไปนี้ในส่วนconst _ = require('underscore'); 
// Hardcoded user ID
const USER_ID = '123';
จัดการ Intent EXECUTE
Intent EXECUTE จะจัดการคําสั่งเพื่ออัปเดตสถานะอุปกรณ์ การตอบกลับจะแสดงสถานะของคําสั่งแต่ละรายการ เช่น SUCCESS, ERROR หรือ PENDING และสถานะอุปกรณ์ใหม่
หากต้องการจัดการ Intent EXECUTE ให้แก้ไข 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 ลงในอาร์เรย์ 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 ของฟังก์ชัน "signaling" ของ 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
กำหนดค่าโปรเจ็กต์คอนโซลนักพัฒนาซอฟต์แวร์
- ไปที่คอนโซลนักพัฒนาแอป
 - คลิกสร้างโปรเจ็กต์ ป้อนชื่อโปรเจ็กต์ แล้วคลิกสร้างโปรเจ็กต์
 

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

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

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

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

- คลิกบันทึก > ทดสอบ
 
5. ทดสอบกล้องเสมือน WebRTC
- ไปที่ URL โฮสติ้งที่คุณเห็นเมื่อทำให้โปรเจ็กต์ Firebase ใช้งานได้ คุณจะเห็นอินเทอร์เฟซต่อไปนี้ ซึ่งเป็นแอปไคลเอ็นต์ CameraStream
 

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

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

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

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

- หากต้องการเริ่มเซสชัน WebRTC จากอุปกรณ์จออัจฉริยะของ Google ให้ทําอย่างใดอย่างหนึ่งต่อไปนี้
 
- พูดว่า "Ok Google สตรีมกล้อง WebRTC"
 - ในอุปกรณ์จออัจฉริยะของ Google ให้แตะการควบคุมอุปกรณ์สมาร์ทโฮม > กล้อง > กล้อง WebRTC
 
จากแอปไคลเอ็นต์ CameraStream สมาร์ทโฮมของ Google คุณจะเห็นการสร้างและแลกเปลี่ยน SPD ของข้อเสนอและ SDP ของคำตอบเรียบร้อยแล้ว ระบบจะสตรีมรูปภาพจากเว็บแคมไปยังอุปกรณ์จออัจฉริยะของ Google ด้วย WebRTC
6. ขอแสดงความยินดี
ยินดีด้วย คุณได้เรียนรู้วิธีสตรีมจากเว็บแคมไปยังอุปกรณ์จอแสดงผล Google Nest ด้วยโปรโตคอล WebRTC