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 de Cloud Firestore pour la création de signaux. Cette application s'appelle FirebaseRTC et fonctionne comme un exemple simple qui vous apprend les bases de la création d'applications compatibles WebRTC.

Points abordés

  • Démarrer un appel vidéo dans une application Web à l'aide de WebRTC
  • Connexion à la partie distante à l'aide de Cloud Firestore

Ce dont vous avez besoin

Avant de démarrer cet atelier de programmation, assurez-vous que les éléments suivants sont installés:

  • npm qui est généralement fourni avec Node.js – 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 FirebaseRTC.

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 des 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 "Développer" du menu de la console Firebase, cliquez sur "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 renforcerons la sécurité de notre base de données plus tard dans 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 devrait 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 comprend une application WebRTC non fonctionnelle, mais nous le ferons fonctionner tout au long de cet atelier de programmation.

4. Installer l'interface de ligne de commande Firebase

L'interface de ligne de commande (CLI) 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. Exécutez la commande suivante pour vérifier que la CLI a été installée correctement : 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 défini le modèle d'application Web pour extraire la configuration de l'application Firebase pour l'hébergement à partir du répertoire local et des fichiers de votre application. Pour ce faire, vous devez associer votre application à votre projet Firebase.

  1. Pour associer votre application à votre projet Firebase, exécutez la commande suivante : sh firebase use --add

  2. Lorsque vous y êtes invité, sélectionnez l'ID de votre projet, puis attribuez-lui un alias.

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

  1. Suivez les instructions restantes dans votre ligne de commande.

5. Exécuter le serveur local

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

  1. Exécutez la commande de la 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 localement. L'application Web devrait maintenant être disponible à l'adresse http://localhost:5000.

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

Vous devriez voir votre copie de FirebaseRTC qui a été associée à votre projet Firebase.

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

6. Création d'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. Vous générez ainsi un ID que la partie distante peut utiliser pour rejoindre la même session. L'ID est utilisé comme clé dans Cloud Firestore pour chaque salle.

Chaque chambre contiendra le RTCSessionDescriptions pour l'offre et 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 salle 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. Cette valeur est ensuite définie en tant que description locale, puis écrite dans le nouvel objet de chambre de Cloud Firestore.

Ensuite, nous écouterons les modifications apportées à la base de données et détecterons si une réponse de l'appelant 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 attend que l'appelant écrive RTCSessionDescription pour la réponse et la définisse comme description à distance de l'appelant RTCPeerConnection.

7. Rejoindre un salon

L'étape suivante consiste à implémenter la logique permettant de rejoindre un salon existant. Pour ce faire, l'utilisateur clique sur le bouton Rejoindre le salon et saisissez l'ID de la salle. Votre tâche consiste ici à implémenter la création de RTCSessionDescription pour la réponse et à mettre à jour la salle 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 par créer une valeur RTCSessionDescription, que nous définirons comme description à distance. Nous créons ensuite la réponse, la définissons en tant que description locale et mettons à 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 définit la description à distance en fonction de la réponse de l'appelant. Cette opération permet d'échanger l'objet RTCSessionDescription entre l'appelant et l'appelant.

8. Recueillir des candidats ICE

Avant que l'appelant et l'appelant puissent se connecter, ils doivent également échanger des candidats ICE qui indiquent à WebRTC comment se connecter au pair distant. Votre tâche suivante consiste à implémenter le code qui écoute les candidats ICE et les ajoute à 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());
                peerConnection.addIceCandidate(candidate);
            }
        });
    })
}

Cette fonction a deux fonctions. Il collecte les candidats ICE de l'API WebRTC, les ajoute à la base de données, écoute les candidats ICE ajoutés auprès du pair distant, puis les ajoute à son instance RTCPeerConnection. Il est important de tenir compte des changements apportés à la base de données afin de filtrer les modifications qui n'ont pas déjà été apportées, car nous aurions dû ajouter toujours le même groupe 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. Vous avez également appris à utiliser cette fonctionnalité pour créer une application de chat vidéo simple.

Pour en savoir plus, consultez les ressources suivantes:

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