Atelier de programmation Firebase et WebRTC

1. Présentation

Dans cet atelier de programmation, vous allez apprendre à créer une application de chat vidéo simple à l'aide de l'API WebRTC dans votre navigateur et Cloud Firestore pour la signalisation. L'application s'appelle FirebaseRTC et fonctionne comme un exemple simple qui vous apprendra les bases de la création d'applications compatibles avec WebRTC.

Ce que vous allez apprendre

  • Lancer un appel vidéo dans une application Web à l'aide de WebRTC
  • Se connecter à la partie distante avec Cloud Firestore

Prérequis

Avant de démarrer cet atelier de programmation, assurez-vous d'avoir installé:

  • npm, qui est généralement fourni avec Node.js : Node LTS est recommandé

2. Créer et configurer un projet Firebase

Créer un projet Firebase

  1. Dans la console Firebase, cliquez sur "Ajouter un projet", puis nommez le projet Firebase RTRTC.

Prenez note de l'ID de votre projet Firebase.

  1. Cliquez sur "Créer un projet".

L'application que vous allez créer utilise deux services Firebase disponibles sur le Web:

  • Cloud Firestore pour enregistrer les données structurées sur le cloud et recevoir une notification instantanée en cas de mise à jour des données
  • Firebase Hosting pour héberger et diffuser vos éléments statiques

Pour cet atelier de programmation, vous avez déjà configuré Firebase Hosting dans le projet que vous allez cloner. Cependant, pour Cloud Firestore, nous vous guiderons tout au long de la configuration et de l'activation des services à l'aide de la console Firebase.

Activer Cloud Firestore

L'application utilise Cloud Firestore pour enregistrer les messages de chat et en recevoir de nouveaux.

Vous devez activer Cloud Firestore:

  1. Dans la section "Develop" du menu de la console Firebase, cliquez sur "Database" (Base de données).
  2. Cliquez sur Créer une base de données dans le volet Cloud Firestore.
  3. Sélectionnez l'option Démarrer en mode test, puis cliquez sur "Activer" après avoir lu la clause de non-responsabilité concernant les règles de sécurité.

Le mode test vous permet d'écrire librement dans la base de données pendant le développement. Nous améliorerons la sécurité de notre base de données dans une étape ultérieure de cet atelier de programmation.

3. Obtenir l'exemple de code

Clonez le dépôt GitHub à partir de la ligne de commande:

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

L'exemple de code doit avoir été cloné dans le répertoire FirebaseRTC. Assurez-vous que votre ligne de commande est désormais exécutée à partir de ce répertoire:

cd FirebaseRTC

Importer l'application de départ

Ouvrez les fichiers dans FirebaseRTC dans votre éditeur et modifiez-les en suivant les instructions ci-dessous. Ce répertoire contient le code de départ de l'atelier de programmation, qui correspond à une application WebRTC fonctionnelle. Nous la verrons tout au long de cet atelier de programmation.

4. Installer l'interface de ligne de commande Firebase

L'interface de ligne de commande (CLI) de Firebase vous permet de diffuser votre application Web en local et de la déployer sur Firebase Hosting.

  1. Installez la CLI en exécutant la commande npm suivante : sh npm -g install firebase-tools
  1. Vérifiez que la CLI a été correctement installée en exécutant la commande suivante : sh firebase --version

Assurez-vous que la version de la CLI Firebase est la version 6.7.1 ou ultérieure.

  1. Autorisez la CLI Firebase en exécutant la commande suivante : sh firebase login

Vous avez configuré le modèle d'application Web pour extraire la configuration de votre application pour Firebase Hosting à partir du répertoire local et des fichiers de votre application. Toutefois, pour ce faire, vous devez associer votre application à votre projet Firebase.

  1. Associez votre application à votre projet Firebase en exécutant la commande suivante : sh firebase use --add

  2. Lorsque vous y êtes invité, sélectionnez votre ID de projet, puis attribuez un alias à votre projet Firebase.

Un alias est utile si vous disposez de plusieurs environnements (production, préproduction, etc.). Pour cet atelier de programmation, nous allons toutefois utiliser l'alias default.

  1. Suivez les autres instructions de votre ligne de commande.

5. Exécuter le serveur local

Vous êtes prêt à travailler sur notre application. Exécuter l'application en local

  1. Exécutez la commande CLI Firebase suivante : sh firebase serve --only hosting

  2. Votre ligne de commande doit afficher la réponse suivante : hosting: Local server: http://localhost:5000

Nous utilisons l'émulateur Firebase Hosting pour diffuser notre application en local. L'application Web devrait maintenant être disponible à partir de http://localhost:5000.

  1. Ouvrez votre application à l'adresse http://localhost:5000.

Votre copie de FirebaseRTC, qui a été connectée à votre projet Firebase, doit s'afficher.

L'application s'est automatiquement connectée à votre projet Firebase.

6. Créer un salon

Dans cette application, chaque session de chat vidéo est appelée "salon". Un utilisateur peut créer un salon en cliquant sur un bouton dans son application. Cela génère un ID que le groupe distant peut utiliser pour rejoindre la même salle. L'ID est utilisé comme clé dans Cloud Firestore pour chaque chambre.

Chaque chambre contient le RTCSessionDescriptions de l'offre et de la réponse, ainsi que deux collections distinctes avec des candidats ICE de chaque partie.

Votre première tâche consiste à implémenter le code manquant pour créer une chambre avec l'offre initiale de l'appelant. Ouvrez public/app.js et recherchez le commentaire // Add code for creating a room here, puis ajoutez le code suivant:

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!`

La première ligne crée une RTCSessionDescription qui représente l'offre de l'appelant. Ce champ est ensuite défini en tant que description locale, puis écrit dans le nouvel objet Room dans Cloud Firestore.

Nous allons ensuite écouter les modifications apportées à la base de données et détecter si une réponse du participant a été ajoutée.

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);
    }
});

Cela permet d'attendre que la personne appelante écrit RTCSessionDescription pour la réponse et la définit en tant que description distante sur l'appelant RTCPeerConnection.

7. Rejoindre un salon

L'étape suivante consiste à mettre en œuvre la logique permettant de rejoindre une salle existante. Pour ce faire, l'utilisateur doit cliquer sur le bouton Rejoindre le salon et saisir l'ID du salon à rejoindre. Votre tâche ici est de mettre en œuvre la création de RTCSessionDescription pour la réponse et de mettre à jour la chambre dans la base de données en conséquence.

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);

Dans le code ci-dessus, nous commençons par extraire l'offre de l'appelant et nous créons un RTCSessionDescription que nous avons défini comme description à distance. Vous allez ensuite créer la réponse, la définir en tant que description locale, puis mettre à jour la base de données. La mise à jour de la base de données déclenche le rappel onSnapshot du côté de l'appelant, qui à son tour définit la description à distance en fonction de la réponse du participant. Cela met fin à l'échange des objets RTCSessionDescription entre l'appelant et l'appelant.

8. Collecter les candidats ICE

Pour que l'appelant et le participant puissent se connecter l'un à l'autre, ils doivent également échanger des candidats ICE qui indiquent à WebRTC comment se connecter au pair distant. Votre prochaine tâche consiste à mettre en œuvre le code qui écoute les candidats ICE et à les ajouter à une collection de la base de données. Recherchez la fonction collectIceCandidates et ajoutez le code suivant:

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);
            }
        });
    })
}

Cette fonction effectue deux opérations. Il collecte les candidats ICE à partir de l'API WebRTC, les ajoute à la base de données, puis écoute les candidats ICE ajoutés depuis le pair distant, puis les ajoute à son instance RTCPeerConnection. Il est important d'écouter les modifications apportées à la base de données afin d'exclure tout élément qui n'est pas un nouvel ajout, car nous aurions autrement ajouté le même ensemble de candidats ICE.

9. Conclusion

Dans cet atelier de programmation, vous avez appris à mettre en œuvre la signalisation pour WebRTC à l'aide de Cloud Firestore, et à utiliser cela pour créer une application de chat vidéo simple.

Pour en savoir plus, consultez les ressources suivantes:

  1. Code source FirebaseRTC
  2. Exemples WebRTC
  3. Cloud Firestore