Firebase + WebRTC Codelab

1. บทนำ

ใน Codelab นี้ คุณจะได้ดูวิธีสร้างแอปพลิเคชันวิดีโอแบบง่ายโดยใช้ WebRTC API ในเบราว์เซอร์และ Cloud Firestore สําหรับการส่งสัญญาณ แอปพลิเคชันนี้เรียกว่า FirebaseRTC และใช้เป็นตัวอย่างง่ายๆ ที่จะสอนพื้นฐานการสร้างแอปพลิเคชันที่เปิดใช้ WebRTC

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

  • การเริ่มต้นวิดีโอคอลในเว็บแอปพลิเคชันโดยใช้ WebRTC
  • การลงชื่อเข้าใช้ฝ่ายระยะไกลโดยใช้ Cloud Firestore

สิ่งที่ต้องมี

ก่อนเริ่มต้น Codelab ดังกล่าว โปรดตรวจสอบว่าคุณได้ติดตั้ง

  • npm ซึ่งโดยปกติแล้วมาพร้อมกับ Node.js - แนะนําให้ใช้ Node LTS

2. สร้างและตั้งค่าโปรเจ็กต์ Firebase

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

  1. ในคอนโซล Firebase ให้คลิกเพิ่มโปรเจ็กต์ แล้วตั้งชื่อโปรเจ็กต์ FirebaseRTC

จดจํารหัสโปรเจ็กต์สําหรับโปรเจ็กต์ Firebase

  1. คลิกสร้างโปรเจ็กต์

แอปพลิเคชันที่คุณจะสร้างใช้บริการ Firebase 2 อย่างที่ใช้ได้บนเว็บ ได้แก่

  • Cloud Firestore เพื่อบันทึกข้อมูลที่มีโครงสร้างในระบบคลาวด์และรับการแจ้งเตือนทันทีเมื่อมีการอัปเดตข้อมูล
  • โฮสติ้งของ Firebase เพื่อโฮสต์และแสดงเนื้อหาแบบคงที่

สําหรับ Codelab นี้ คุณได้กําหนดค่าโฮสติ้งของ Firebase ในโปรเจ็กต์ที่คุณจะโคลนแล้ว แต่สําหรับ Cloud Firestore เราจะอธิบายการกําหนดค่าและเปิดใช้บริการโดยใช้คอนโซล Firebase

เปิดใช้ Cloud Firestore

แอปใช้ Cloud Firestore เพื่อบันทึกข้อความแชทและรับข้อความแชทใหม่

คุณจะต้องเปิดใช้ Cloud Firestore

  1. ในเมนูคอนโซล Firebase's การพัฒนา ให้คลิกฐานข้อมูล
  2. คลิกสร้างฐานข้อมูลในแผง Cloud Firestore
  3. เลือกตัวเลือกเริ่มในโหมดทดสอบ แล้วคลิก "เปิดใช้" หลังจากอ่านข้อจํากัดความรับผิดเกี่ยวกับกฎความปลอดภัย

โหมดทดสอบจะช่วยให้คุณเขียนไปยังฐานข้อมูลได้อย่างอิสระระหว่างการพัฒนา เราจะทําให้ฐานข้อมูลของเราปลอดภัยมากขึ้นภายหลังใน Codelab นี้

3. รับโค้ดตัวอย่าง

โคลนที่เก็บ GitHub จากบรรทัดคําสั่ง:

git clone https://github.com/webrtc/FirebaseRTC

โค้ดตัวอย่างควรอยู่ในไดเรกทอรี FirebaseRTC ตรวจสอบว่าบรรทัดคําสั่งทํางานจากไดเรกทอรีนี้นับจากนี้เป็นต้นไป

cd FirebaseRTC

นําเข้าแอปเริ่มต้น

เปิดไฟล์ใน FirebaseRTC ในตัวแก้ไข แล้วทําตามวิธีการด้านล่าง ไดเรกทอรีนี้มีโค้ดเริ่มต้นสําหรับ Codelab ซึ่งประกอบด้วยแอป WebRTC ที่ใช้งานได้ซึ่งยังไม่ทํางาน โดยเราจะทําให้โค้ดทํางานทั่วทั้ง Codelab นี้

4. ติดตั้งอินเทอร์เฟซบรรทัดคําสั่ง Firebase

Firebase Command Line Interface (CLI) ช่วยให้คุณแสดงเว็บแอปในเครื่องและทําให้เว็บแอปใช้งานได้บนโฮสติ้งของ Firebase

  1. ติดตั้ง CLI โดยเรียกใช้คําสั่ง npm ต่อไปนี้ sh npm -g install firebase-tools
  1. ยืนยันว่าติดตั้ง CLI อย่างถูกต้องแล้วโดยเรียกใช้คําสั่งต่อไปนี้ sh firebase --version

ตรวจสอบว่า Firebase CLI เวอร์ชันคือ v6.7.1 ขึ้นไป

  1. ให้สิทธิ์ Firebase CLI โดยเรียกใช้คําสั่งต่อไปนี้ sh firebase login

คุณได้ตั้งค่าเทมเพลตเว็บแอปเพื่อดึงการกําหนดค่าของแอปสําหรับ Firebase Hosting จากไดเรกทอรีและไฟล์ในเครื่องของแอปแล้ว แต่จะต้องเชื่อมโยงแอปกับโปรเจ็กต์ Firebase ก่อน

  1. เชื่อมโยงแอปกับโปรเจ็กต์ Firebase โดยใช้คําสั่งต่อไปนี้ sh firebase use --add

  2. เมื่อได้รับข้อความแจ้ง ให้เลือกรหัสโปรเจ็กต์ จากนั้นจึงกําหนดชื่อแทนให้โปรเจ็กต์ Firebase

ชื่อแทนจะมีประโยชน์ในกรณีที่คุณมีหลายสภาพแวดล้อม (การใช้งานจริง การทดลองใช้ ฯลฯ) อย่างไรก็ตาม สําหรับ Codelab นี้ ให้ลองใช้ชื่อแทนของ default

  1. ทําตามวิธีการที่เหลือในบรรทัดคําสั่ง

5. เรียกใช้เซิร์ฟเวอร์ภายใน

คุณพร้อมเริ่มทํางานจริงในแอปของเราแล้ว มาเรียกใช้แอปในพื้นที่กัน

  1. เรียกใช้คําสั่ง Firebase CLI ต่อไปนี้ sh firebase serve --only hosting

  2. บรรทัดคําสั่งของคุณควรแสดงการตอบกลับต่อไปนี้ hosting: Local server: http://localhost:5000

เราจะใช้โปรแกรมจําลองโฮสติ้งของ Firebase เพื่อแสดงแอปในเครื่อง เว็บแอปควรพร้อมให้บริการจาก http://localhost:5000

  1. เปิดแอปที่ http://localhost:5000

คุณควรเห็นสําเนา FirebaseRTC ที่เชื่อมต่อกับโปรเจ็กต์ Firebase ของคุณ

แอปเชื่อมต่อกับโปรเจ็กต์ Firebase โดยอัตโนมัติแล้ว

6. การสร้างห้องใหม่

ในแอปพลิเคชันนี้ เซสชันวิดีโอแชทแต่ละเซสชันจะเรียกว่าห้องแชท ผู้ใช้จะสร้างห้องแชทใหม่ได้โดยคลิกปุ่มในแอปพลิเคชัน การดําเนินการนี้จะสร้างรหัสที่ฝ่ายระยะไกลใช้เพื่อเข้าร่วมห้องแชทเดียวกันได้ รหัสจะใช้เป็นคีย์ใน Cloud Firestore สําหรับแต่ละห้อง

แต่ละห้องจะมี RTCSessionDescriptions สําหรับทั้งข้อเสนอและคําตอบ รวมถึงคอลเล็กชัน 2 รายการที่มีผู้สมัคร ICE แยกกันจากแต่ละฝ่าย

งานแรกคือการนําโค้ดที่ขาดหายไปในการสร้างห้องใหม่ที่มีข้อเสนอเริ่มต้นจากผู้โทร เปิด public/app.js แล้วค้นหาความคิดเห็น // Add code for creating a room here และเพิ่มโค้ดต่อไปนี้

const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);

const roomWithOffer = {
    offer: {
        type: offer.type,
        sdp: offer.sdp
    }
}
const roomRef = await db.collection('rooms').add(roomWithOffer);
const roomId = roomRef.id;
document.querySelector('#currentRoom').innerText = `Current room is ${roomId} - You are the caller!`

บรรทัดแรกจะสร้าง RTCSessionDescription ที่แสดงถึงข้อเสนอจากผู้โทร ซึ่งระบบจะตั้งค่าเป็นคําอธิบายในเครื่อง และสุดท้ายจะเขียนลงในออบเจ็กต์ห้องแชทใหม่ใน Cloud Firestore

ถัดไป เราจะฟังการเปลี่ยนแปลงในฐานข้อมูลและตรวจจับเมื่อเพิ่มคําตอบจากผู้โทร

roomRef.onSnapshot(async snapshot -> {
    console.log('Got updated room:', snapshot.data());
    const data = snapshot.data();
    if (!peerConnection.currentRemoteDescription && data.answer) {
        console.log('Set remote description: ', data.answer);
        const answer = new RTCSessionDescription(data.answer)
        await peerConnection.setRemoteDescription(answer);
    }
});

จะรอจนกว่าผู้โทรจะเขียน RTCSessionDescription เพื่อหาคําตอบและตั้งค่าเป็นคําอธิบายระยะไกลในผู้โทร RTCPeerConnection

7. การเข้าร่วมห้องแชท

ขั้นตอนต่อไปคือใช้ตรรกะสําหรับการเข้าร่วมห้องแชทที่มีอยู่ ผู้ใช้จะทําได้โดยการคลิกปุ่มเข้าร่วมห้องแชท และป้อนรหัสสําหรับห้องแชทที่จะเข้าร่วม งานของคุณคือการสร้าง RTCSessionDescription สําหรับคําตอบและอัปเดตห้องแชทในฐานข้อมูลให้สอดคล้องกัน

const offer = roomSnapshot.data().offer;
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);

const roomWithAnswer = {
    answer: {
        type: answer.type,
        sdp: answer.sdp
    }
}
await roomRef.update(roomWithAnswer);

ในโค้ดด้านบน เราจะเริ่มจากการแยกข้อเสนอจากผู้โทรและสร้าง RTCSessionDescription ที่เราตั้งค่าเป็นคําอธิบายระยะไกล ต่อไป เราจะสร้างคําตอบ กําหนดเป็นคําอธิบายในเครื่อง และอัปเดตฐานข้อมูล การอัปเดตฐานข้อมูลจะเรียกใช้โค้ดเรียกกลับ onSnapshot ในฝั่งของผู้โทร ซึ่งในทางกลับกันก็จะตั้งค่าคําอธิบายระยะไกลตามคําตอบจากผู้โทร ซึ่งจะทําให้การแลกเปลี่ยน RTCSessionDescription ทํางานระหว่างผู้โทรกับผู้โทร

8. รวบรวมผู้สมัคร ICE

ก่อนที่ผู้โทรและผู้โทรจะเชื่อมต่อกันได้ จะต้องแลกเปลี่ยนตัวเลือก ICE ที่บอกให้ WebRTC ทราบวิธีเชื่อมต่อกับเครื่องระยะไกล งานต่อไปคือการติดตั้งใช้งานโค้ดที่ฟังสําหรับผู้สมัคร ICE และเพิ่มการทํางานเหล่านั้นลงในคอลเล็กชันในฐานข้อมูล ค้นหาฟังก์ชัน collectIceCandidates และเพิ่มโค้ดต่อไปนี้

async function collectIceCandidates(roomRef, peerConnection,
                                    localName, remoteName) {
    const candidatesCollection = roomRef.collection(localName);

    peerConnection.addEventListener('icecandidate', event -> {
        if (event.candidate) {
            const json = event.candidate.toJSON();
            candidatesCollection.add(json);
        }
    });

    roomRef.collection(remoteName).onSnapshot(snapshot -> {
        snapshot.docChanges().forEach(change -> {
            if (change.type === "added") {
                const candidate = new RTCIceCandidate(change.doc.data());
                peerConnection.addIceCandidate(candidate);
            }
        });
    })
}

ฟังก์ชันนี้ทําได้ 2 รายการ โดยจะรวบรวมผู้สมัคร ICE จาก WebRTC API แล้วเพิ่มไปยังฐานข้อมูล และรับฟังผู้สมัคร ICE ที่เพิ่มเข้ามาจากเพียร์ระยะไกลและเพิ่มไปยังอินสแตนซ์ RTCPeerConnection ของตน เมื่อฟังการเปลี่ยนแปลงฐานข้อมูลจะเป็นเรื่องสําคัญเพื่อกรองข้อมูลที่ไม่ได้เป็นส่วนใหม่ออก เนื่องจากเราอาจเพิ่มผู้สมัคร ICE ชุดเดิมซ้ําแล้วซ้ําเล่า

9. บทสรุป

ใน Codelab นี้ คุณดูวิธีใช้สัญญาณสําหรับ WebRTC โดยใช้ CloudFirestore รวมถึงวิธีนําไปใช้ในการสร้างแอปพลิเคชันวิดีโอแชทแบบง่าย

ดูข้อมูลเพิ่มเติมได้ที่แหล่งข้อมูลต่อไปนี้

  1. ซอร์สโค้ด FirebaseRTC
  2. ตัวอย่างของ WebRTC
  3. Cloud Firestore