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

1. Введение

В этой лабораторной работе вы узнаете, как создать простое приложение для видеочата, используя API WebRTC в вашем браузере и 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 в проекте, который будете клонировать. Однако для Cloud Firestore мы покажем вам настройку и включение сервисов с помощью консоли Firebase.

Включить Cloud 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 CLI — v6.7.1 или новее.

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

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

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

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

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

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

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

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

  1. Выполните следующую команду интерфейса командной строки Firebase: sh firebase serve --only hosting

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

Мы используем эмулятор хостинга Firebase для локального обслуживания нашего приложения. Веб-приложение теперь должно быть доступно по адресу 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. Облачный пожарный магазин