الدرس التطبيقي حول الترميز بين Firebase و WebRTC

1- مقدمة

ستتعلّم في هذا الدرس التطبيقي كيفية إنشاء تطبيق محادثة فيديو بسيط باستخدام واجهة برمجة تطبيقات WebRTC على متصفّحك وCloud Firestore للإشارة. يُطلق على التطبيق اسم FirebaseRTC وهو مثال بسيط يعلّمك أساسيات إنشاء تطبيقات تعمل بتقنية WebRTC.

ما ستتعرَّف عليه

  • بدء مكالمة فيديو في تطبيق ويب باستخدام WebRTC
  • إرسال إشارة إلى الطرف البعيد باستخدام Cloud Firestore

الأشياء التي تحتاج إليها

قبل بدء هذا الدرس التطبيقي حول الترميز، تأكّد من تثبيت ما يلي:

  • npm الذي يأتي عادةً مع Node.js - يُوصى بـ LTS للعقدة

2. إنشاء مشروع Firebase وإعداده

إنشاء مشروع على Firebase

  1. في وحدة تحكُّم Firebase، انقر على "إضافة مشروع"، ثم اختَر اسمًا لمشروع FirebaseRTC.

تذكّر رقم تعريف المشروع لمشروع Firebase.

  1. انقر على إنشاء مشروع.

يستخدم التطبيق الذي ستنشئه خدمتين من Firebase متاحتين على الويب:

  • Cloud Firestore لحفظ البيانات المنظَّمة على السحابة الإلكترونية والحصول على إشعار فوري عند تعديل البيانات
  • استضافة Firebase لعرض مواد العرض الثابتة وعرضها

بالنسبة إلى هذا الدرس التطبيقي حول الترميز، تكون قد سبق لك ضبط استضافة Firebase في المشروع الذي ستنسخه. ومع ذلك، بالنسبة إلى Cloud Firestore، سنرشدك خلال عملية ضبط الخدمات وتفعيلها باستخدام وحدة تحكُّم Firebase.

تفعيل Cloud Firestore

يستخدم التطبيق Cloud Firestore لحفظ رسائل المحادثة وتلقّي رسائل المحادثات الجديدة.

يجب تفعيل Cloud Firestore:

  1. في قائمة وحدة تحكُّم Firebase، انقر على Database (قاعدة البيانات).
  2. انقر على إنشاء قاعدة بيانات في جزء Cloud Firestore.
  3. اختر الخيار بدء في وضع الاختبار، ثم انقر على "تفعيل" بعد قراءة بيان إخلاء المسؤولية عن قواعد الأمان.

يضمن وضع الاختبار إمكانية الكتابة بحرية في قاعدة البيانات أثناء التطوير. سنجعل قاعدة بياناتنا أكثر أمانًا في وقت لاحق من هذا الدرس التطبيقي حول الترميز.

3. الحصول على نموذج الرمز

إنشاء نسخة طبق الأصل من مستودع GitHub من سطر الأوامر:

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

يجب نسخ الرمز النموذجي في الدليل FirebaseRTC. احرص على تشغيل سطر الأوامر من هذا الدليل من الآن فصاعدًا:

cd FirebaseRTC

استيراد تطبيق إجراء التفعيل

فتح الملفات في FirebaseRTC في أداة التعديل وتغييرها وفقًا للتعليمات الواردة أدناه. يحتوي هذا الدليل على رمز البداية للدرس التطبيقي حول الترميز الذي يتألف من تطبيق WebRTC غير مشترك حتى الآن. وسنجعله يعمل خلال هذا الدرس التطبيقي حول الترميز.

4. تثبيت واجهة سطر أوامر Firebase

تتيح لك واجهة سطر أوامر Firebase (CLI) عرض تطبيق الويب محليًا ونشر تطبيق الويب في استضافة Firebase.

  1. ثبِّت واجهة سطر الأوامر عن طريق تشغيل أمر npm التالي: sh npm -g install firebase-tools
  1. تأكَّد من تثبيت واجهة سطر الأوامر بشكل صحيح عن طريق تشغيل الأمر التالي: sh firebase --version

تأكَّد من أن إصدار واجهة سطر الأوامر في Firebase هو الإصدار 6.7.1 أو إصدار أحدث.

  1. يمكنك تفويض واجهة سطر أوامر Firebase (إدارة واجهة سطر الأوامر) من خلال تشغيل الأمر التالي: sh firebase login

لقد أعددت نموذج تطبيق الويب لسحب إعدادات تطبيقك على Firebase الاستضافة من ملف وملفات محلية في الدليل. ولكن لإجراء ذلك، عليك ربط تطبيقك بمشروع Firebase.

  1. اربط تطبيقك بمشروعك على Firebase من خلال تنفيذ الأمر التالي: sh firebase use --add

  2. اختَر رقم تعريف المشروع عندما يُطلب منك ذلك، ثم أدخِل اسمًا مستعارًا لمشروعك على Firebase.

يكون الاسم المستعار مفيدًا إذا كانت لديك بيئات متعددة (الإنتاج والمراحل وما إلى ذلك). ومع ذلك، بالنسبة إلى هذا الدرس التطبيقي حول الترميز، لنبدأ في استخدام الاسم المستعار لـ default.

  1. اتّبِع التعليمات المتبقية في سطر الأوامر.

5. تشغيل الخادم المحلي

أنت على استعداد لبدء العمل على تطبيقنا. لنبدأ تشغيل التطبيق محليًا.

  1. شغّل أمر واجهة سطر الأوامر التالي على 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 بكيفية الاتصال بالنظير البعيد. وتتمثل المهمة التالية في تنفيذ الرمز الذي يستمع إلى مرشحي 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);
            }
        });
    })
}

تؤدي هذه الدالة أمرَين. وتجمع مرشحات ICE من WebRTC API وتضيفها إلى قاعدة البيانات، وتستمع إلى مرشحات ICE الإضافية من نظيرها عن بُعد وتضيفها إلى مثيل RTCPeerConnection. من المهم عند الاستماع إلى تغييرات قاعدة البيانات أن تتم فلترة أي شيء ليس إضافة جديدة، لأننا سنضيف المجموعة نفسها من مرشحي ICE مرارًا وتكرارًا.

9- الخاتمة

في هذا الدرس التطبيقي حول الترميز، تعلّمت كيفية تنفيذ إشارات WebRTC باستخدام Cloud Firestore، وعلى كيفية استخدامها لإنشاء تطبيق محادثات فيديو بسيط.

لمزيد من المعلومات، يُرجى الاطّلاع على المراجع التالية:

  1. رمز مصدر FirebaseRTC
  2. عيّنات WebRTC
  3. Cloud Firestore