Лаборатория кода Firebase + WebRTC

1. Введение

В этой лабораторной работе вы узнаете, как создать простое приложение для видеочата, используя WebRTC API в вашем браузере и Cloud Firestore для передачи сигналов. Приложение называется FirebaseRTC и работает как простой пример, который научит вас основам создания приложений с поддержкой WebRTC.

Что вы узнаете

  • Инициация видеозвонка в веб-приложении с использованием WebRTC
  • Сигнализация удаленной стороне с помощью Cloud Firestore

Что вам понадобится

Перед запуском этой кодлабы убедитесь, что вы установили:

  • npm, который обычно поставляется с Node.js — рекомендуется Node LTS

2. Создайте и настройте проект Firebase

Создайте проект Firebase

  1. В консоли Firebase нажмите «Добавить проект», затем назовите проект Firebase FirebaseRTC.

Запомните идентификатор проекта для вашего проекта Firebase.

  1. Щелкните Создать проект.

Приложение, которое вы собираетесь создать, использует две службы Firebase, доступные в Интернете:

  • Cloud Firestore для сохранения структурированных данных в облаке и получения мгновенных уведомлений при обновлении данных.
  • Хостинг Firebase для размещения и обслуживания ваших статических ресурсов

Для этой конкретной кодовой лаборатории вы уже настроили Firebase Hosting в проекте, который будете клонировать. Однако для Cloud Firestore мы проведем вас через настройку и включение служб с помощью консоли Firebase.

Включить облачное хранилище Firestore

Приложение использует Cloud Firestore для сохранения сообщений чата и получения новых сообщений чата.

Вам нужно включить Cloud Firestore:

  1. В разделе «Разработка» меню консоли Firebase нажмите «База данных».
  2. Нажмите Создать базу данных на панели Cloud Firestore.
  3. Выберите параметр « Начать в тестовом режиме », затем нажмите «Включить» после прочтения заявления об отказе от ответственности в отношении правил безопасности.

Тестовый режим гарантирует, что вы можете свободно писать в базу данных во время разработки. Мы сделаем нашу базу данных более безопасной позже в этой лаборатории кода.

3. Получите пример кода

Клонируйте репозиторий GitHub из командной строки:

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

Пример кода должен был быть клонирован в каталог FirebaseRTC . Убедитесь, что с этого момента ваша командная строка запускается из этого каталога:

cd FirebaseRTC

Импортировать стартовое приложение

Откройте файлы в FirebaseRTC в своем редакторе и измените их в соответствии с приведенными ниже инструкциями. Этот каталог содержит начальный код для лаборатории кода, который состоит из еще не работающего приложения WebRTC. Мы сделаем его функциональным в этой кодлабе.

4. Установите интерфейс командной строки Firebase

Интерфейс командной строки Firebase (CLI) позволяет вам обслуживать ваше веб-приложение локально и развертывать его на хостинге Firebase.

  1. Установите CLI, выполнив следующую команду npm: sh npm -g install firebase-tools
  1. Убедитесь, что CLI установлен правильно, выполнив следующую команду: sh firebase --version

Убедитесь, что версия интерфейса командной строки Firebase — 6.7.1 или более поздняя.

  1. Авторизуйте интерфейс командной строки Firebase, выполнив следующую команду: sh firebase login

Вы настроили шаблон веб-приложения, чтобы получить конфигурацию вашего приложения для Firebase Hosting из локального каталога и файлов вашего приложения. Но для этого вам нужно связать свое приложение с вашим проектом Firebase.

  1. Свяжите свое приложение с проектом Firebase, выполнив следующую команду: sh firebase use --add

  2. При появлении запроса выберите идентификатор проекта, а затем дайте псевдоним проекту Firebase.

Псевдоним полезен, если у вас несколько сред (производственная, промежуточная и т. д.). Однако для этой кодлабы давайте просто воспользуемся псевдонимом default .

  1. Следуйте оставшимся инструкциям в вашей командной строке.

5. Запустите локальный сервер

Вы готовы начать работу над нашим приложением! Давайте запустим приложение локально!

  1. Запустите следующую команду Firebase CLI: sh firebase serve --only hosting

  2. Ваша командная строка должна отобразить следующий ответ: hosting: Local server: http://localhost:5000

Мы используем эмулятор Firebase Hosting для локального обслуживания нашего приложения. Теперь веб-приложение должно быть доступно по адресу 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 из API WebRTC и добавляет их в базу данных, а также прослушивает добавленных кандидатов ICE от удаленного узла и добавляет их в свой экземпляр RTCPeerConnection . При прослушивании изменений в базе данных важно отфильтровывать все, что не является новым дополнением, поскольку в противном случае мы бы снова и снова добавляли один и тот же набор кандидатов ICE.

9. Заключение

В этой лабораторной работе вы узнали, как реализовать сигнализацию для WebRTC с помощью Cloud Firestore, а также как использовать ее для создания простого приложения для видеочата.

Чтобы узнать больше, посетите следующие ресурсы:

  1. Исходный код FirebaseRTC
  2. Примеры WebRTC
  3. Облако Firestore