Статьи

Создание приложения для видеочата WebRTC с помощью SimpleWebRTC

Эта статья включена в нашу книгу « 6 проектов JavaScript» . Создавайте проекты, которые познакомят вас с разработкой Modern JavaScript.

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

Если вам нужно немного опыта относительно WebRTC и одноранговой связи, я рекомендую прочитать «Рассвет WebRTC» и « Введение в API getUserMedia» .

Что такое SimpleWebRTC

Прежде чем мы продолжим, важно понять, какой основной инструмент мы будем использовать. SimpleWebRTC — это библиотека JavaScript, которая упрощает одноранговые данные, видео и аудио вызовы WebRTC.

SimpleWebRTC действует как оболочка для реализации WebRTC в браузере. Как вы, возможно, уже знаете, производители браузеров не совсем согласны с одним способом реализации различных функций, а это означает, что для каждого браузера есть своя реализация для WebRTC. Как разработчик, вам придется писать разные коды для каждого браузера, который вы планируете поддерживать. SimpleWebRT действует как оболочка для этого кода. Предоставляемый им API-интерфейс прост в использовании и понимании, что делает его действительно хорошим кандидатом для реализации кросс-браузерного WebRTC.

Создание приложения для видеочата WebRTC

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

Обратите внимание, что вы можете загрузить код для этого урока из нашего репозитория GitHub . Чтобы запустить его или следовать дома, вам нужно установить Node и npm. Если вы не знакомы с ними или вам нужна помощь в их установке, ознакомьтесь с нашими предыдущими руководствами:

Вам также нужен ПК или ноутбук с веб-камерой. Если нет, вам понадобится веб-камера USB, которую можно прикрепить к верхней части монитора. Вам, вероятно, понадобится друг или второе устройство для проверки удаленных подключений.

зависимости

Мы будем использовать следующие зависимости для построения нашего проекта:

  • SimpleWebRTC — библиотека WebRTC
  • Semantic UI CSS — элегантный CSS-фреймворк
  • jQuery — используется для выбора элементов на странице и обработки событий.
  • Handlebars — библиотека шаблонов JavaScript, которую мы будем использовать для генерации HTML для сообщений.
  • Экспресс — сервер NodeJS.

Настройка проекта

Зайдите в рабочее пространство и создайте папку simplewebrtc-messenger Откройте папку в VSCode или вашем любимом редакторе и создайте следующие файлы и структуру папок:

 simplewebrtc-messenger
├── public
│   ├── images
│   │   └── image.png
│   ├── index.html
│   └── js
│       └── app.js
├── README.md
└── server.js

Или, если хотите, сделайте то же самое через командную строку:

 mkdir -p simplewebrtc-messenger/public/{images,js}
cd simplewebrtc-messenger
touch public/js/app.js public/index.html .gitignore README.md server.js

Откройте README.md

 # Simple WebRTC Messenger

A tutorial on building a WebRTC video chat app using SimpleWebRTC.

Добавьте строку node_modules.gitignore Создайте файл package.json

 npm init -y

Вы должны получить следующий вывод:

 {
  "name": "simplewebrtc-messenger",
  "version": "1.0.0",
  "description": "A tutorial on building a WebRTC video chat app using SimpleWebRTC.",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Теперь давайте установим наши зависимости:

 npm install express handlebars jquery semantic-ui-css simplewebrtc

В процессе установки скопируйте этот код в server.js

 const express = require('express');

const app = express();
const port = 3000;

// Set public folder as root
app.use(express.static('public'));

// Provide access to node_modules folder from the client-side
app.use('/scripts', express.static(`${__dirname}/node_modules/`));

// Redirect all traffic to index.html
app.use((req, res) => res.sendFile(`${__dirname}/public/index.html`));

app.listen(port, () => {
  console.info('listening on %d', port);
});

Код сервера довольно стандартный. Просто прочитайте комментарии, чтобы понять, что происходит.

Далее, давайте настроим наш файл public/index.html

 <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="scripts/semantic-ui-css/semantic.min.css">
  <title>SimpleWebRTC Demo</title>
  <style>
    html { margin-top: 20px; }
    #chat-content { height: 180px;  overflow-y: scroll; }
  </style>
</head>
<body>
  <!-- Main Content -->
  <div class="ui container">
    <h1 class="ui header">Simple WebRTC Messenger</h1>
    <hr>
  </div>

  <!-- Scripts -->
  <script src="scripts/jquery/dist/jquery.min.js"></script>
  <script src="scripts/semantic-ui-css/semantic.min.js"></script>
  <script src="scripts/handlebars/dist/handlebars.min.js "></script>
  <script src="scripts/simplewebrtc/out/simplewebrtc-with-adapter.bundle.js"></script>
  <script src="js/app.js"></script>
</body>
</html>

Далее, давайте настроим наш базовый клиентский код JavaScript. Скопируйте этот код в public/js/app.js

 window.addEventListener('load', () => {
  // Put all client-side code here
});

Наконец, загрузите это изображение из нашего репозитория GitHub и сохраните его в папке public/images

Теперь мы можем запустить наше приложение:

 npm start

Откройте URL localhost: 3000 в вашем браузере, и вы должны увидеть следующее:

Настройка проекта

наценка

Давайте теперь поработаем над public/index.html Для простоты (особенно если вы уже знакомы с Handlebars) вы можете скопировать весь код разметки из нашего репозитория GitHub . В противном случае, давайте пройдемся по шагам. Прежде всего, скопируйте этот код и поместите его после <hr>ui container

 <div class="ui two column stackable grid">

  <!-- Chat Section -->
  <div class="ui ten wide column">
    <div class="ui segment">
      <!-- Chat Room Form -->
      <div class="ui form">
        <div class="fields">
          <div class="field">
            <label>User Name</label>
            <input type="text" placeholder="Enter user name" id="username" name="username">
          </div>
          <div class="field">
            <label>Room</label>
            <input type="text" placeholder="Enter room name" id="roomName" name="roomName">
          </div>
        </div>
        <br>
        <div class="ui buttons">
          <div id="create-btn" class="ui submit orange button">Create Room</div>
          <div class="or"></div>
          <div id="join-btn" class="ui submit green button">Join Room</div>
        </div>
      </div>
      <!-- Chat Room Messages -->
      <div id="chat"></div>
    </div>
  </div>
  <!-- End of Chat Section -->

  <!-- Local Camera -->
  <div class="ui six wide column">
    <h4 class="ui center aligned header" style="margin:0;">
      Local Camera
    </h4>
    <img id="local-image" class="ui large image" src="images/image.png">
    <video id="local-video" class="ui large image hidden" autoplay></video>
  </div>

</div>

<!-- Remote Cameras -->
<h3 class="ui center aligned header">Remote Cameras</h3>
<div id="remote-videos" class="ui stackable grid">
  <div class="four wide column">
    <img class="ui centered medium image" src="images/image.png">
  </div>
  <div class="four wide column">
    <img class="ui centered medium image" src="images/image.png">
  </div>
  <div class="four wide column">
    <img class="ui centered medium image" src="images/image.png">
  </div>
  <div class="four wide column">
    <img class="ui centered medium image" src="images/image.png">
  </div>
</div>

Просмотрите код разметки и прочитайте комментарии, чтобы понять, для чего предназначен каждый раздел. Также ознакомьтесь с документацией по семантическому интерфейсу, если вы не знакомы с библиотекой CSS. Обновите ваш браузер. Вы должны иметь следующий вид:

Вид разметки

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

Шаблоны

Теперь давайте добавим три шаблона Handlebar, которые сделают нашу веб-страницу интерактивной.

Поместите следующую разметку сразу после div ui container Мы начнем с контейнера чата, который просто состоит из:

  • Номер комнаты
  • пустой контейнер сообщений чата (будет добавлен позже через JavaScript)
  • вход для размещения сообщений.
 <!-- Chat Template -->
<script id="chat-template" type="text/x-handlebars-template">
  <h3 class="ui orange header">Room ID -> <strong>{{ room }}</strong></h3>
  <hr>
  <div id="chat-content" class="ui feed"> </div>
  <hr>
  <div class="ui form">
    <div class="ui field">
      <label>Post Message</label>
      <textarea id="post-message" name="post-message" rows="1"></textarea>
    </div>
    <div id="post-btn" class="ui primary submit button">Send</div>
  </div>
</script>

Затем добавьте следующий шаблон, который будет использоваться для отображения сообщений чата:

 <!-- Chat Content Template -->
<script id="chat-content-template" type="text/x-handlebars-template">
  {{#each messages}}
    <div class="event">
      <div class="label">
        <i class="icon blue user"></i>
      </div>
      <div class="content">
        <div class="summary">
          <a href="#"> {{ username }}</a> posted on
          <div class="date">
            {{ postedOn }}
          </div>
        </div>
        <div class="extra text">
          {{ message }}
        </div>
      </div>
    </div>
  {{/each}}
</script>

Наконец, добавьте следующий шаблон, который будет использоваться для отображения потоков с удаленной камеры:

 <!-- Remote Video Template -->
<script id="remote-video-template" type="text/x-handlebars-template">
  <div id="{{ id }}" class="four wide column"></div>
</script>

Надеюсь, код разметки довольно понятен, поэтому давайте перейдем к написанию клиентского JavaScript-кода для нашего приложения.

Основной скрипт приложения

Откройте файл public/js/app.js

 // Chat platform
const chatTemplate = Handlebars.compile($('#chat-template').html());
const chatContentTemplate = Handlebars.compile($('#chat-content-template').html());
const chatEl = $('#chat');
const formEl = $('.form');
const messages = [];
let username;

// Local Video
const localImageEl = $('#local-image');
const localVideoEl = $('#local-video');

// Remote Videos
const remoteVideoTemplate = Handlebars.compile($('#remote-video-template').html());
const remoteVideosEl = $('#remote-videos');
let remoteVideosCount = 0;

// Add validation rules to Create/Join Room Form
formEl.form({
  fields: {
    roomName: 'empty',
    username: 'empty',
  },
});

Здесь мы инициализируем несколько элементов, которыми планируем манипулировать. Мы также добавили в форму правила проверки, чтобы пользователь не мог оставить ни одно из полей пустым.

Далее, давайте инициализируем наш код WebRTC:

 // create our WebRTC connection
const webrtc = new SimpleWebRTC({
  // the id/element dom element that will hold "our" video
  localVideoEl: 'local-video',
  // the id/element dom element that will hold remote videos
  remoteVideosEl: 'remote-videos',
  // immediately ask for camera access
  autoRequestMedia: true,
});

// We got access to local camera
webrtc.on('localStream', () => {
  localImageEl.hide();
  localVideoEl.show();
});

Теперь вы знаете, почему он называется SimpleWebRTC. Это все, что нам нужно сделать, чтобы инициализировать наш код WebRTC. Заметили, что мы даже не указали ни ICE-серверов, ни STUN-серверов. Это просто работает. Однако вы можете использовать другие сервисы TURN, такие как Xirsys . Вам нужно будет настроить локальный сервер SignalMaster для обработки сигналов WebRTC.

Давайте сделаем быстрое обновление веб-страницы, чтобы убедиться, что новый код работает:

Локальная камера

Страница должна запрашивать доступ к вашей камере и микрофону. Просто нажмите « Принять», и вы должны получить вид выше.

Скрипт чата

Теперь давайте сделаем форму функциональной. Нам нужно написать логику для создания комнаты и присоединения к ней. Кроме того, нам нужно написать дополнительную логику для отображения чата. Для этого мы будем использовать chat-room-template Давайте начнем с прикрепления обработчиков кликов к кнопкам формы:

 $('.submit').on('click', (event) => {
  if (!formEl.form('is valid')) {
    return false;
  }
  username = $('#username').val();
  const roomName = $('#roomName').val().toLowerCase();
  if (event.target.id === 'create-btn') {
    createRoom(roomName);
  } else {
    joinRoom(roomName);
  }
  return false;
});

Далее нам нужно объявить функции createRoomjoinRoom Поместите следующий код перед кодом обработчика кликов:

 // Register new Chat Room
const createRoom = (roomName) => {
  console.info(`Creating new room: ${roomName}`);
  webrtc.createRoom(roomName, (err, name) => {
    showChatRoom(name);
    postMessage(`${username} created chatroom`);
  });
};

// Join existing Chat Room
const joinRoom = (roomName) => {
  console.log(`Joining Room: ${roomName}`);
  webrtc.joinRoom(roomName);
  showChatRoom(roomName);
  postMessage(`${username} joined chatroom`);
};

Создать комнату или присоединиться к ней очень просто: просто используйте методы SimpleWebRTC createRoom и joinRoom .

Возможно, вы также заметили, что у нас есть функции showChatroompostMessage Давайте сделаем это сейчас, вставив следующий код перед вызывающим кодом:

 // Post Local Message
const postMessage = (message) => {
  const chatMessage = {
    username,
    message,
    postedOn: new Date().toLocaleString('en-GB'),
  };
  // Send to all peers
  webrtc.sendToAll('chat', chatMessage);
  // Update messages locally
  messages.push(chatMessage);
  $('#post-message').val('');
  updateChatMessages();
};

// Display Chat Interface
const showChatRoom = (room) => {
  // Hide form
  formEl.hide();
  const html = chatTemplate({ room });
  chatEl.html(html);
  const postForm = $('form');
  // Post Message Validation Rules
  postForm.form({
    message: 'empty',
  });
  $('#post-btn').on('click', () => {
    const message = $('#post-message').val();
    postMessage(message);
  });
  $('#post-message').on('keyup', (event) => {
    if (event.keyCode === 13) {
      const message = $('#post-message').val();
      postMessage(message);
    }
  });
};

Потратьте некоторое время на просмотр кода, чтобы понять логику. Вскоре вы столкнетесь с другой функцией, которую мы не объявили, updateChatMessages Давайте добавим это сейчас:

 // Update Chat Messages
const updateChatMessages = () => {
  const html = chatContentTemplate({ messages });
  const chatContentEl = $('#chat-content');
  chatContentEl.html(html);
  // automatically scroll downwards
  const scrollHeight = chatContentEl.prop('scrollHeight');
  chatContentEl.animate({ scrollTop: scrollHeight }, 'slow');
};

Цель этой функции — просто обновить интерфейс чата новыми сообщениями. Нам нужна еще одна функция, которая принимает сообщения от удаленных пользователей. Добавьте следующую функцию в app.js

 // Receive message from remote user
webrtc.connection.on('message', (data) => {
  if (data.type === 'chat') {
    const message = data.payload;
    messages.push(message);
    updateChatMessages();
  }
});

Вот и вся логика, необходимая для работы чата. Обновите страницу и войдите в систему:

Вход в комнату

Нажмите кнопку « Создать комнату» . Вы будете приняты к этой точке зрения. Разместите несколько сообщений, чтобы убедиться, что чат работает.

Чат

Как только вы подтвердите, что это работает, переходите к следующему заданию.

Удаленная видеокамера

Как упоминалось ранее, SimpleWebRTC поддерживает несколько пиров. Вот код для добавления удаленных видеопотоков, когда новый пользователь присоединяется к комнате:

 // Remote video was added
webrtc.on('videoAdded', (video, peer) => {
  const id = webrtc.getDomId(peer);
  const html = remoteVideoTemplate({ id });
  if (remoteVideosCount === 0) {
    remoteVideosEl.html(html);
  } else {
    remoteVideosEl.append(html);
  }
  $(`#${id}`).html(video);
  $(`#${id} video`).addClass('ui image medium'); // Make video element responsive
  remoteVideosCount += 1;
});

Вот и все. Извините, если вы ожидали чего-то более сложного. Мы просто добавили прослушиватель событий для videoAddedvideo Он также получает peer

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

Самое простое решение для тестирования приведенного выше кода — развернуть его на общедоступном сервере, который поддерживает протокол HTTPS.

развертывание

Этот метод, который мы собираемся выполнить, является одним из самых простых способов развертывания приложения NodeJS. Все, что нам нужно сделать, это сначала зарегистрировать аккаунт на now.sh.

Просто выберите бесплатный тариф. Вам нужно будет указать свой адрес электронной почты. Вам также необходимо подтвердить свой адрес электронной почты для активации вашей учетной записи. Затем установите now

 npm install -g now

После завершения установки вы можете развернуть приложение. Просто выполните следующую команду в корне папки вашего проекта:

 now --public

Если вы запускаете команду впервые, вас попросят ввести адрес электронной почты. Затем вы получите электронное письмо, которое понадобится вам для подтверждения вашего логина. После проверки вам нужно будет снова выполнить команду now --public Через несколько секунд ваше приложение будет запущено по указанному URL, который будет распечатан на терминале.

Если вы используете встроенный терминал VSCode, просто нажмите ALT и щелкните, чтобы открыть URL в вашем браузере.

Развернуть разрешить камеру

Вам нужно разрешить странице доступ к вашей камере и микрофону. Далее создайте комнату, как и раньше. После входа в систему вам необходимо получить доступ к другому устройству — например, к другому ноутбуку или смартфону с фронтальной камерой. Вы также можете попросить друга с подключением к Интернету помочь вам в этом. Просто получите доступ к тому же URL-адресу и введите новое имя пользователя и то же имя комнаты. Удаленный пользователь должен будет нажать кнопку Присоединиться к комнате . В течение нескольких секунд оба устройства должны быть подключены к чату. Если на устройстве нет камеры, это нормально, так как функция чата все равно будет работать.

Удаленная камера

Вывод

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

Не забывайте, что код, используемый в этом руководстве, доступен на GitHub . Клонируй, делай что-нибудь классное и веселись!