Codelab Firebase + WebRTC

1. Introduzione

In questo codelab, imparerai come creare una semplice applicazione di chat video utilizzando l'API WebRTC nel tuo browser e Cloud Firestore per la segnalazione. L'applicazione è chiamata FirebaseRTC e funziona come un semplice esempio che illustra le nozioni di base della creazione di applicazioni abilitate per WebRTC.

Cosa scoprirai

  • Avvio di una videochiamata in un'applicazione web utilizzando WebRTC
  • Registrazione al gruppo remoto utilizzando Cloud Firestore

Che cosa ti serve

Prima di avviare questo codelab, assicurati di aver installato:

  • npm che in genere include Node.js: è consigliato l'LTS del nodo

2. Creare e configurare un progetto Firebase

Creare un progetto Firebase

  1. Nella console Firebase, fai clic su Aggiungi progetto, quindi assegna il nome FirebaseRTC al progetto Firebase.

Ricorda l'ID progetto per il tuo progetto Firebase.

  1. Fai clic su Crea progetto.

L'applicazione che intendi creare utilizza due servizi Firebase disponibili sul Web:

  • Cloud Firestore per salvare dati strutturati sul cloud e ricevere una notifica immediata quando i dati vengono aggiornati
  • Firebase Hosting per ospitare e pubblicare le tue risorse statiche

Per questo codelab specifico, hai già configurato Firebase Hosting nel progetto che clonerai. Tuttavia, nel caso di Cloud Firestore, ti guideremo attraverso la configurazione e l'attivazione dei servizi utilizzando la Console Firebase.

Abilita Cloud Firestore

L'app utilizza Cloud Firestore per salvare i messaggi di chat e ricevere nuovi messaggi di chat.

Devi abilitare Cloud Firestore:

  1. Nella sezione Sviluppo del menu della console Firebase, fai clic su Database.
  2. Fai clic su Crea database nel riquadro Cloud Firestore.
  3. Seleziona l'opzione Inizia in modalità di test, quindi fai clic su Attiva dopo aver letto il disclaimer sulle regole di sicurezza.

La modalità di test assicura che sia possibile scrivere liberamente nel database durante lo sviluppo. Renderemo il nostro database più sicuro in seguito in questo codelab.

3. Recupera il codice campione

Clona il repository GitHub dalla riga di comando:

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

Il codice di esempio avrebbe dovuto essere clonato nella directory FirebaseRTC. Assicurati d'ora in poi che la riga di comando venga eseguita da questa directory:

cd FirebaseRTC

Importa l'app di avvio

Apri i file in FirebaseRTC nell'editor e modificali in base alle istruzioni riportate di seguito. Questa directory contiene il codice iniziale per il codelab, che consiste in un'app WebRTC non ancora funzionale. La renderemo funzionante durante questo codelab.

4. Installare l'interfaccia a riga di comando di Firebase

L'interfaccia a riga di comando di Firebase ti consente di pubblicare la tua app web localmente ed eseguire il deployment dell'app web in Firebase Hosting.

  1. Installa l'interfaccia a riga di comando eseguendo il seguente comando npm: sh npm -g install firebase-tools
  1. Verifica che l'interfaccia a riga di comando sia stata installata correttamente eseguendo il seguente comando: sh firebase --version

Assicurati che la versione dell'interfaccia a riga di comando di Firebase sia 6.7.1 o successiva.

  1. Autorizza l'interfaccia a riga di comando di Firebase eseguendo il comando: sh firebase login

Hai impostato il modello di app web per eseguire la configurazione dell'app per Firebase Hosting dalla directory locale e dai file dell'app. Per farlo, devi associare l'app al progetto Firebase.

  1. Associa la tua app al progetto Firebase eseguendo il comando:sh firebase use --add

  2. Quando richiesto, seleziona l'ID progetto, quindi assegna un alias al tuo progetto Firebase.

L'alias è utile in presenza di più ambienti (produzione, staging e così via). Tuttavia, per questo codelab, utilizziamo semplicemente l'alias di default.

  1. Segui le istruzioni rimanenti sulla riga di comando.

5. Esegui il server locale

Puoi iniziare a lavorare nella nostra app. Eseguiamo l'app a livello locale.

  1. Esegui il seguente comando dell'interfaccia a riga di comando di Firebase: sh firebase serve --only hosting

  2. Nella riga di comando dovrebbe essere visualizzata la seguente risposta: hosting: Local server: http://localhost:5000

Utilizziamo l'emulatore Firebase Hosting per gestire la nostra app a livello locale. L'app web dovrebbe essere disponibile all'indirizzo http://localhost:5000.

  1. Apri l'app all'indirizzo http://localhost:5000.

Dovresti vedere la tua copia di FirebaseRTC collegata al tuo progetto Firebase.

L'app si è connessa automaticamente al progetto Firebase.

6. Creazione di una nuova stanza virtuale

In questa applicazione, ogni sessione di chat video viene chiamata stanza virtuale. Un utente può creare una nuova stanza virtuale facendo clic su un pulsante nella sua applicazione. Verrà generato un ID che l'altra parte può utilizzare per partecipare alla stessa stanza virtuale. L'ID viene utilizzato come chiave in Cloud Firestore per ogni sala.

Ogni stanza virtuale conterrà RTCSessionDescriptions sia per l'offerta che per la risposta, nonché due collezioni separate con candidati ICE di ogni partito.

La prima attività è implementare il codice mancante per la creazione di una nuova camera con l'offerta iniziale dal chiamante. Apri public/app.js, trova il commento // Add code for creating a room here e aggiungi il codice seguente:

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 prima riga crea un elemento RTCSessionDescription che rappresenta l'offerta dal chiamante. Verrà quindi impostato come descrizione locale e infine scritto nel nuovo oggetto stanza in Cloud Firestore.

Successivamente, ascolteremo le modifiche al database e rileveremo quando è stata aggiunta una risposta dal chiamante.

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

In questo modo, il chiamante scrive la risposta RTCSessionDescription per la risposta e la imposta come descrizione remota sul chiamanteRTCPeerConnection.

7. Stai entrando in una stanza virtuale

Il passaggio successivo consiste nell'implementazione della logica per partecipare a una stanza virtuale esistente. L'utente può fare clic sul pulsante Partecipa alla stanza virtuale e inserire l'ID per entrare nella stanza virtuale. L'obiettivo è implementare la creazione della RTCSessionDescription per la risposta e aggiornare di conseguenza la stanza virtuale nel database.

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

Nel codice riportato sopra, iniziamo estraendo l'offerta dal chiamante e creando un RTCSessionDescription che abbiamo impostato come descrizione remota. Ora creiamo la risposta, la impostiamo come descrizione locale e aggiorniamo il database. L'aggiornamento del database attiverà il callback onSnapshot sul lato chiamante, che a sua volta imposterà la descrizione remota in base alla risposta del chiamante. Questo completa lo scambio degli oggetti RTCSessionDescription tra il chiamante e il chiamante.

8. Raccogli candidati ICE

Prima che il chiamante e il chiamante possano connettersi l'uno all'altro, devono anche scambiare i candidati ICE che indicano a WebRTC come connettersi al peer remoto. La tua prossima attività è quella di implementare il codice per ascoltare i candidati ICE e aggiungerli a una raccolta nel database. Trova la funzione collectIceCandidates e aggiungi il codice seguente:

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

Questa funzione ha due funzioni. Raccogli i candidati ICE dall'API WebRTC e li aggiunge al database, ascolta i candidati ICE aggiunti dal peer remoto e li aggiunge alla propria istanza RTCPeerConnection. Quando si ascoltano le modifiche del database, è importante filtrare qualsiasi elemento che non sia una nuova aggiunta, perché in caso contrario lo aggiungeremo ancora una volta allo stesso gruppo di candidati ICE.

9. Conclusioni

In questo codelab hai imparato come implementare la segnalazione per WebRTC utilizzando Cloud Firestore e come utilizzarla per creare una semplice applicazione di chat video.

Per saperne di più, consulta le seguenti risorse:

  1. Codice sorgente Firebase
  2. Esempi di WebRTC
  3. Cloud Firestore