+wiczenia z programowania w Firebase + WebRTC

1. Wstęp

Z tego ćwiczenia dowiesz się, jak utworzyć prostą aplikację do czatowania wideo przy użyciu interfejsu WebRTC API w przeglądarce oraz Cloud Firestore do wywoływania. Aplikacja nazywa się FirebaseRTC i jest prostym przykładem, który pokazuje podstawy tworzenia aplikacji obsługujących WebRTC.

Czego się dowiesz

  • Rozpoczynanie rozmowy wideo w aplikacji internetowej przy użyciu WebRTC
  • Logowanie do punktu zdalnego przy użyciu Cloud Firestore

Niezbędne elementy

Zanim zaczniesz wykonywać te ćwiczenia z programowania, sprawdź, czy:

  • npm, który zwykle jest dołączony do Node.js – węzeł LTS jest zalecany

2. Tworzenie i konfigurowanie projektu Firebase

Tworzenie projektu Firebase

  1. W konsoli Firebase kliknij Dodaj projekt, a następnie nazwij projekt FirebaseRTC.

Zapamiętaj identyfikator projektu Firebase.

  1. Kliknij Utwórz projekt.

Aplikacja, którą chcesz utworzyć, korzysta z dwóch usług Firebase dostępnych w internecie:

  • Cloud Firestore zapisze uporządkowane dane w chmurze i od razu wyświetli powiadomienie o ich aktualizacji
  • Hosting Firebase do hostowania zasobów statycznych i ich wyświetlania

W tym konkretnym ćwiczeniach z programowania masz już skonfigurowany Firebase Hosting w projekcie, który chcesz skopiować. Jednak w Cloud Firestore przeprowadzimy Cię przez konfigurację i włączanie usług za pomocą konsoli Firebase.

Włącz Cloud Firestore

Aplikacja używa Cloud Firestore do zapisywania wiadomości czatu i odbierania nowych wiadomości czatu.

Musisz włączyć Cloud Firestore:

  1. W sekcji menu programisty w konsoli Firebase kliknij Baza danych.
  2. W panelu Cloud Firestore kliknij Utwórz bazę danych.
  3. Wybierz opcję Start in test mode (Rozpocznij w trybie testowym), a po przeczytaniu wyłączenia odpowiedzialności dotyczącego reguł zabezpieczeń kliknij „Enable” (Włącz).

Tryb testowy pozwala na pisanie w bazie danych w dowolnym momencie. Bazę danych zwiększymy później w tym module ćwiczeń.

3. Pobieranie przykładowego kodu

Skopiuj repozytorium GitHub z poziomu wiersza poleceń:

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

Przykładowy kod powinien zostać skopiowany do katalogu FirebaseRTC. Upewnij się, że wiersz poleceń jest uruchamiany w tym katalogu:

cd FirebaseRTC

Importowanie aplikacji startowej

Otwórz pliki w edytorze FirebaseRTC w edytorze i zmień je zgodnie z podanymi niżej instrukcjami. Ten katalog zawiera kod początkowy ćwiczeń z programowania, który składa się z jeszcze niefunkcjonalnej aplikacji WebRTC. Zrobimy to w ramach tych ćwiczeń z programowania.

4. Instalowanie interfejsu wiersza poleceń Firebase

Interfejs wiersza poleceń Firebase umożliwia wyświetlanie aplikacji internetowej lokalnie i wdrażanie aplikacji internetowej w Hostingu Firebase.

  1. Zainstaluj interfejs wiersza poleceń, uruchamiając następujące polecenie npm: sh npm -g install firebase-tools
  1. Sprawdź, czy interfejs wiersza poleceń został prawidłowo zainstalowany, uruchamiając to polecenie: sh firebase --version

Upewnij się, że interfejs wiersza poleceń Firebase ma wersję 6.7.1 lub nowszą.

  1. Autoryzuj wiersz poleceń Firebase, uruchamiając następujące polecenie: sh firebase login

Szablon aplikacji internetowej został skonfigurowany tak, by pobierać konfigurację aplikacji pod kątem Hostingu Firebase z katalogu lokalnego i plików aplikacji. Aby to zrobić, musisz powiązać aplikację z projektem Firebase.

  1. Powiąż aplikację z projektem Firebase, uruchamiając następujące polecenie: sh firebase use --add

  2. Gdy pojawi się prośba, wybierz identyfikator projektu, a następnie nadaj projektowi Firebase alias.

Alias jest przydatny, jeśli masz wiele środowisk (produkcyjnych, testowych) itp. Na potrzeby tego ćwiczenia z programowania użyjmy po prostu aliasu default.

  1. Postępuj zgodnie z pozostałymi instrukcjami w wierszu polecenia.

5. Uruchom serwer lokalny

Możesz już zacząć pracę w naszej aplikacji. Uruchommy aplikację lokalnie.

  1. Uruchom to polecenie wiersza poleceń Firebase: sh firebase serve --only hosting

  2. Wiersz poleceń powinien zawierać następującą odpowiedź: hosting: Local server: http://localhost:5000

Korzystamy z emulatora Hostingu Firebase do lokalnego wyświetlania naszej aplikacji. Aplikacja internetowa powinna być teraz dostępna pod adresem http://localhost:5000.

  1. Otwórz aplikację na stronie http://localhost:5000.

Powinna wyświetlić się kopia projektu FirebaseRTC połączonego z Twoim projektem Firebase.

Aplikacja automatycznie połączyła się z projektem Firebase.

6. Tworzę nowy pokój

W tej aplikacji każda sesja czatu wideo nosi nazwę pokoju. Użytkownik może utworzyć nowy pokój, klikając przycisk w swojej aplikacji. Wygeneruje to identyfikator, którego zdalny członek może użyć, aby dołączyć do tego samego pokoju. Identyfikator jest używany jako klucz w Cloud Firestore dla każdej sali.

Każda sala będzie zawierać RTCSessionDescriptions zarówno oferty, jak i odpowiedzi, a także dwie osobne kolekcje z kandydatami do ICE od każdej ze stron.

Pierwszym zadaniem jest wdrożenie brakującego kodu na potrzeby tworzenia nowego pokoju z początkową ofertą od dzwoniącego. Otwórz public/app.js i znajdź komentarz // Add code for creating a room here oraz dodaj ten kod:

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

W pierwszym wierszu znajduje się obiekt RTCSessionDescription, który będzie reprezentować ofertę specjalną od rozmówcy. Potem jest ustawiany jako opis lokalny i w końcu zapisywany w nowym obiekcie pokoju w Cloud Firestore.

Następnie będziemy monitorować zmiany w bazie danych i wykryć dodanie odpowiedzi od rozmówcy.

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

Poczekaj, aż rozmówca zapisze RTCSessionDescription jako odpowiedź i ustawi go jako zdalny opis dla rozmówcy RTCPeerConnection.

7. Dołączanie do pokoju

Następnym krokiem jest wdrożenie logiki dołączenia do istniejącego pokoju. Użytkownik chce to zrobić, klikając przycisk Dołącz do pokoju i wpisując identyfikator pokoju, do którego chcesz dołączyć. Twoim zadaniem jest zaimplementowanie utworzenia odpowiedzi RTCSessionDescription i zaktualizowanie odpowiednio pokoju w bazie danych.

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

W powyższym kodzie zaczynamy od wyodrębnienia oferty od rozmówcy i utworzenia RTCSessionDescription, który wyznaczymy jako zdalny opis. Następnie tworzymy odpowiedź, ustawiamy ją jako opis lokalny i aktualizujemy bazę danych. Aktualizacja bazy danych uruchomi wywołanie zwrotne onSnapshot po stronie rozmówcy, co z kolei spowoduje zdalny opis na podstawie odpowiedzi rozmówcy. To koniec wymiany obiektów RTCSessionDescription między elementem wywołującym i wywołującym.

8. Zbieranie kandydatów w ICE

Aby rozmówca i osoba, która dzwoniła, mogli się połączyć, musi wymienić ICE, które informują WebRTC o połączeniu ze zdalnym peerem. Następnym zadaniem jest wdrożenie kodu, który nasłuchuje kandydatów ICE, i dodanie ich do kolekcji w bazie danych. Znajdź funkcję collectIceCandidates i dodaj ten kod:

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

Ta funkcja pełni dwie funkcje. Zbiera on propozycje ICE z interfejsu API WebRTC i dodaje je do bazy danych, a następnie nasłuchuje dodanych kandydatów ICE ze zdalnego peera i dodaje je do instancji RTCPeerConnection. Ważne jest, aby słuchać zmian w bazie danych, odfiltrowywać dane, które nie są niczym nowym, ponieważ w przeciwnym razie musielibyśmy wielokrotnie dodawać ten sam zestaw kandydatów do ICE.

9. Podsumowanie

Dzięki temu ćwiczeniu z programowania nauczyliśmy się implementować sygnał dla WebRTC w CloudFirestore, a także jak używać tej funkcji do tworzenia prostej aplikacji do obsługi czatów wideo.

Więcej informacji znajdziesz w tych materiałach:

  1. Kod źródłowy FirebaseRTC
  2. Przykłady w WebRTC
  3. Cloud Firestore