Firebase + WebRTC Codelab

1. מבוא

בשיעור הקוד הזה תלמדו איך לבנות אפליקציה פשוטה לצ'אט בווידאו באמצעות ה-API של WebRTC בדפדפן ו-Cloud Firestore לאותות. האפליקציה נקראת FirebaseRTC והיא משמשת כדוגמה פשוטה שמלמדת את העקרונות הבסיסיים של יצירת אפליקציות התומכות ב-WebRTC.

מה תלמדו

  • התחלת שיחת וידאו באפליקציית אינטרנט באמצעות WebRTC
  • איתות לגורם המרוחק באמצעות Cloud Firestore

מה תצטרך להכין

לפני שמתחילים את ה-Codec הזה, חשוב לוודא שהתקנתם:

  • npm שמגיע בדרך כלל עם Node.js – מומלץ להשתמש ב-Node LTS

2. יצירה והגדרה של פרויקט Firebase

יצירה של פרויקט Firebase

  1. במסוף Firebase, לוחצים על 'הוספת פרויקט' ואז נותנים שם לפרויקט FirebaseRTC.

חשוב לזכור את מזהה הפרויקט ב-Firebase.

  1. לוחצים על 'יצירת פרויקט'.

האפליקציה שברצונך ליצור משתמשת בשני שירותי Firebase הזמינים באינטרנט:

  • Cloud Firestore כדי לשמור נתונים מובנים ב-Cloud ולקבל הודעה מיידית כאשר הנתונים מתעדכנים
  • אירוח ב-Firebase ואירוח של הנכסים הסטטיים שלך

עבור מעבדת הקוד הספציפית הזו, כבר הגדרת אירוח ב-Firebase בפרויקט שברצונך לשכפל. עם זאת, לגבי Cloud Firestore, נדריך אותך בהגדרה ובהפעלה של השירותים באמצעות מסוף Firebase.

הפעלת Cloud Firestore

האפליקציה משתמשת ב-Cloud Firestore כדי לשמור את ההודעות בצ'אט ולקבל הודעות צ'אט חדשות.

יהיה עליך להפעיל את Cloud Firestore:

  1. בקטע 'פיתוח' בתפריט המסוף של Firebase, לוחצים על 'מסד נתונים'.
  2. לוחצים על יצירת מסד נתונים בחלונית Cloud Firestore.
  3. בוחרים באפשרות Start in test mode (התחלת במצב בדיקה) ולוחצים על כתב הוויתור אחרי שקוראים את כתב הוויתור על כללי האבטחה.

מצב בדיקה מבטיח שאפשר לכתוב מסדי נתונים באופן חופשי בזמן הפיתוח. בהמשך נהפוך את מסד הנתונים שלנו למאובטח יותר בהמשך במעבדת הקוד הזו.

3. קבלת הקוד לדוגמה

שכפול המאגר של GitHub משורת הפקודה:

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

היה צריך לשכפל את הקוד לדוגמה לספרייה FirebaseRTC. ודאו ששורת הפקודה מופעלת מהספרייה הזו מעכשיו:

cd FirebaseRTC

ייבוא האפליקציה למתחילים

פותחים את הקבצים בכלי העריכה של FirebaseRTC ומשנים אותם בהתאם להוראות שלמטה. הספרייה הזו מכילה את קוד ההתחלה עבור ה-codelab שמכיל אפליקציה שעדיין לא פועלת ב-WebRTC. אנחנו נהפוך אותה לפונקציונלית בכל מעבדת הקוד הזו.

4. מתקינים את ממשק שורת הפקודה של Firebase

ממשק שורת הפקודה (CLI) של Firebase מאפשר לכם להציג את אפליקציית האינטרנט שלכם באופן מקומי ולפרוס את אפליקציית האינטרנט שלכם ב-Firebase Hosting.

  1. מתקינים את CLI על ידי הרצת פקודת npm: sh npm -g install firebase-tools
  1. כדי לוודא ש-CLI הותקן כראוי, יש להפעיל את הפקודה הבאה: sh firebase --version

יש לוודא שהגרסה של Firebase CLI היא גרסה 6.7.1 ואילך.

  1. יש לאשר את CLI Firebase על ידי הרצת הפקודה הבאה: sh firebase login

הגדרת את התבנית של אפליקציית האינטרנט כך שתשלוף את תצורת האפליקציה שלך ב-Firebase. לשם כך, עליך לשייך את האפליקציה לפרויקט Firebase.

  1. משייכים את האפליקציה לפרויקט Firebase באמצעות הפקודה הבאה: sh firebase use --add

  2. כשתוצג לכם הודעה, בוחרים את מזהה הפרויקט, ואז נותנים לפרויקט ב-Firebase כינוי אחר.

אפשר להשתמש בכינוי אם יש לכם כמה סביבות (ייצור, Staging וכו'). עם זאת, עבור קוד Lab זה, צריך להשתמש בכינוי של default.

  1. מבצעים את שאר ההוראות בשורת הפקודה.

5. הפעלה של השרת המקומי

אתם מוכנים להתחיל לעבוד על האפליקציה שלנו! רוצה להפעיל את האפליקציה באופן מקומי?

  1. מריצים את פקודת CLI הבאה ב-Firebase: 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 עבור ההצעה וגם עבור התשובה, וגם עבור שני אוספים נפרדים עם מועמדים מ-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 איך להתחבר לאפליקציות דומות. המשימה הבאה שלכם היא ליישם את הקוד שמאזינים למועמדים לקרח, ומוסיף אותם לאוסף במסד הנתונים. צריך למצוא את הפונקציה 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());
                peerConneciton.addIceCandidate(candidate);
            }
        });
    })
}

פונקציה זו מבצעת שתי פעולות. האפליקציה אוספת מועמדי ICE מ-WebRTC API ומוסיפה אותם למסד הנתונים. היא מאזינה למועמדים ב-ICE שנוספו על ידי העמית המרוחק ומוסיפה אותם למופע שלה ב-RTCPeerConnection. חשוב להאזין לשינויים במסד הנתונים כדי לסנן כל דבר שאינו תוספת חדשה, כי אז היינו מוסיפים שוב את אותה קבוצה של מועמדים ב-ICE שוב ושוב.

9. סיכום

ב-Codelab הזה למדתם איך להטמיע אות עבור WebRTC באמצעות Cloud Firestore, וגם איך להשתמש בזה ליצירת אפליקציה פשוטה של וידאו צ'אט.

מידע נוסף זמין בקישורים הבאים:

  1. קוד מקור של FirebaseRTC
  2. דוגמאות WebRTC
  3. Cloud Firestore