В данной статье мы расскажем как разработать многопользовательскую WebRTC видео трансляцию из браузера через свой сервер ретранслятор. Трансляция будет идти из браузера Google Chrome и обычной USB вебкамеры. Для трансляции видео будет создана отдельная HTML — страница Streamer, а воспроизведением будет заниматься HTML-страница Player.

Схема трансляции

Browser1 — транслирующий. Подключается к серверу и транслирует видео с веб камеры.
Browser2, Browser3, Browser4 — зрители. Подключаются и получают видео для воспроизведения. Для ре-трансляции видеопотоков по WebRTC будет использоваться Web Call Server.

Broadcast-diagram

Принцип понятен и можно переходить к написанию кода. Создадим две HTML-страницы. Первая будет называться streamer.html и будет отправлять видеопоток на сервер. Вторая будет называться player.html и играть видеопоток с сервера.

Streamer — HTML

<html>
<head>
   <script language="javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
</head>
<body onLoad="init()">
<h1>The streamer</h1>
<div id="localVideo" style="width:320px;height:240px;border: 1px solid"></div>
<input type="button" value="start" onClick="start()"/>
<p id="status"></p>
</body>
</html>

В заготовке html-страницы Streamer мы использовали следующие вещи:

1) Скрипт flashphoner.js

Этот скрипт является основным скриптом JavaScript API и его можно найти в последней сборке Web SDK.

<script type="text/javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>

2) Div элемент localVideo — это блок, в котором будет размещено видео, захваченное с вебкамеры.

<div id="localVideo" style="width:320px;height:240px;border: 1px solid"></div>

3) Кнопка Start, по которой будет происходить запуск трансляции с вызовом функции start().

<input type="button" value="start" onClick="start()"/>

4) Обратите внимание, что в body добавлена обработка события onLoad c вызовом функции инициализации.

<body onLoad="init()">

5) Элемент с id = status, используется для отображения статусов.

<p id="status"></p>

Streamer — JavaScript

Переходим к написанию JavaScript — кода. Мы намеренно не используем JQuery, Bootstrap или какие-либо другие фреймворки чтобы оставить код минимальным:

var localVideo;
 
function init(){
   Flashphoner.init();
   localVideo = document.getElementById("localVideo");
}
 
function start() {
   Flashphoner.createSession({urlServer: "wss://wcs5-eu.flashphoner.com:8443"}).on(Flashphoner.constants.SESSION_STATUS.ESTABLISHED, function (session) {
       //session connected, start streaming
       startStreaming(session);
   }).on(Flashphoner.constants.SESSION_STATUS.DISCONNECTED, function () {
       setStatus("DISCONNECTED");
   }).on(Flashphoner.constants.SESSION_STATUS.FAILED, function () {
       setStatus("FAILED");
   });
}
 
function startStreaming(session) {
   session.createStream({
       name: "stream222",
       display: localVideo,
       cacheLocalResources: true,
       receiveVideo: false,
       receiveAudio: false
   }).on(Flashphoner.constants.STREAM_STATUS.PUBLISHING, function (publishStream) {
       setStatus(Flashphoner.constants.STREAM_STATUS.PUBLISHING);
   }).on(Flashphoner.constants.STREAM_STATUS.UNPUBLISHED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.UNPUBLISHED);
   }).on(Flashphoner.constants.STREAM_STATUS.FAILED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.FAILED);
   }).publish();
}
 
function setStatus(status) {
   document.getElementById("status").innerHTML = status;
}

В этом примере всего четыре функции:

1) init

Отвечает за инициализацию JavaScript API и берет ссылку на div — элемент localVideo.

2) start

Эта функция создает подключение к серверу по протоколу websockets. Адрес подключения: wss://domain:8443. На месте domain должен быть домен вашего WCS сервера (предполагаем, что сервер уже установлен, настроен и имеет выделенный домен, например webrtc.mycompany.com. Порт TCP 8443 должен быть открыт для входящих подключений).

Из кода этой функции понятно, следующим действием после получения статуса ESTABLISHED, будет вызов функции startStreaming и отправка потока на сервер.

3) startStreaming

Здесь мы создаем новый объект Stream, используя функцию API: session.createStream();. При создании стрима в качестве основных параметров передаются:

  • streamName — имя видеопотока
  • display — это элемент div, в котором будет отображаться захваченное для данного видеопотока видео с веб-камеры

Имя потока желательно генерировать уникальное, но мы для теста используем просто stream222.

4) setStatus

Данная функция отображает статус сессии (session) или потока (stream) на HTML-странице.

Выносим наш скрипт в отдельный файл streamer.js. Код страницы streamer.html будет выглядеть так:

<html>
<head>
   <script language="javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
   <script language="javascript" src="streamer.js"></script>
</head>
<body onLoad="init()">
<h1>The streamer</h1>
<div id="localVideo" style="width:320px;height:240px;border: 1px solid"></div>
<input type="button" value="start" onClick="start()"/>
<p id="status"></p>
</body>
</html>

Streamer — тестирование

В итоге у нас получилось мини стриминг-приложение, состоящее из трех скриптов:

  • streaming.html
  • streaming.js
  • flashphoner.js

Копируем наши скрипты на web-сервер чтобы начать тестирование. В качестве веб-сервера мы используем Apache 2 со стандартным /var/www/html

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

Streamer_testing

Чтобы убедиться в том, что поток действительно отправляется, переходим во вкладку chrome://webrtc-internals. Здесь можно в режиме реального времени наблюдать что происходит с видеопотоком и отслеживать такие параметры как битрейт, разрешение, фреймрейт, количество отправленных пакетов, RTT и многое другое.

testing_streamer

Таким образом, наш стример заработал и WebRTC видеопоток корректно отправляется на сервер, откуда осталось его забрать. Для того чтобы забрать и воспроизвести поток, создадим новую страницу player.html

Player — HTML

Страницу плеера копипастим из стримера, с той лишь разницей, что будем использовать скрипт: player.js вместо streamer.js, и вместо localVideo, зададим id = remoteVideo для нашего div — элемента.

<html>
<head>
   <script language="javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
   <script language="javascript" src="player.js"></script>
</head>
<body onLoad="init()">
<h1>The player</h1>
<div id="remoteVideo" style="width:320px;height:240px;border: 1px solid"></div>
<input type="button" value="start" onClick="start()"/>
<p id="status"></p>
</body>
</html>

Player — JavaScript

В скрипте плеера также есть некоторые отличия, но подход остается прежним: инициализируется Flashphoner API, по кнопке Start открывается соединение с сервером через websocket, ждет события ESTABLISHED и начинает воспроизведение потока.

Список отличий скрипта player.js от скрипта streamer.js:

  • Используется remoteVideo вместо localVideo
  • После установки соединения вызываем startPlayback вместо startStreaming
  • При создании стрима методом createStream(), передаются параметры receiveAudio=true и receiveVideo=true
  • Вызывается метод play() вместо publish()
var remoteVideo;
 
function init(){
   Flashphoner.init();
   remoteVideo = document.getElementById("remoteVideo");
}
 
function start() {
   Flashphoner.createSession({urlServer: "wss://wcs5-eu.flashphoner.com:8443"}).on(Flashphoner.constants.SESSION_STATUS.ESTABLISHED, function (session) {
       //session connected, start streaming
       startPlayback(session);
   }).on(Flashphoner.constants.SESSION_STATUS.DISCONNECTED, function () {
       setStatus("DISCONNECTED");
   }).on(Flashphoner.constants.SESSION_STATUS.FAILED, function () {
       setStatus("FAILED");
   });
}
 
function startPlayback(session) {
   session.createStream({
       name: "stream222",
       display: remoteVideo,
       cacheLocalResources: true,
       receiveVideo: true,
       receiveAudio: true
   }).on(Flashphoner.constants.STREAM_STATUS.PLAYING, function (playStream) {
       setStatus(Flashphoner.constants.STREAM_STATUS.PLAYING);
   }).on(Flashphoner.constants.STREAM_STATUS.STOPPED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.STOPPED);
   }).on(Flashphoner.constants.STREAM_STATUS.FAILED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.FAILED);
   }).play();
}
 
function setStatus(status) {
   document.getElementById("status").innerHTML = status;
}

В результате получаем WebRTC-плеер, состоящий из двух скриптов:

  • player.html
  • player.js

Не забываем, что для работы плеера также необходим файл API flashphoner.js, поэтому копируем файлы плеера в ту же папку на web-сервере.

В итоге наше окончательное приложение для WebRTC онлайн трансляций состоит из пяти файлов:

  • streamer.html
  • streamer.js
  • player.html
  • player.js
  • flashphoner.js

Приступим к тестированию и снова отправим видеопоток через streamer.html. После этого откроем новую вкладку браузера с player.html и нажмем Start.

Player_HTML

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

HTML_player

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

3 минуты

Попробуем развернуть трансляцию за 3 минуты, учитывая следующее:

1) Уже установлен Web Call Server 5 для ретрансляции видеопотоков и настроен SSL. Без настройки SSL / HTTPS, трансляция в Google Chrome работать не будет, так как для доступа к веб камере и микрофону соединение должно быть безопасным и страница, на которой вы тестируете трансляцию должна быть открыта по HTTPS. Порт TCP 8443 открыт и готов принимать соединения по протоколу wss://

2) Уже установлен и сконфигурирован HTTP сервер, например Apache. Web-сервер настроен для работы через HTTPS и имеет FTP/SFTP/SSH доступ, через который можно залить / скачать тестовые скрипты.

WCS5 и Apache могут быть установлены на одной системе либо разнесены по разным серверам. Apache в данном случае просто отдает контент в виде HTML-страниц и скриптов, а WCS5 обслуживает подключения с видео.

Чтобы провести тестирование без установки, можно воспользоваться демо-сервером wss://wcs5-eu.flashphoner.com:8443 — он открыт для коннектов и тестирования.

Минута 1

Загружаем тестовые скрипты и распаковываем в папке /var/www/html на веб-сервере.

wget https://flashphoner.com//downloads/examples/webrtc-broadcasting-example-0.5.15.1977.2088.tar.gz
tar -xzf webrtc-broadcasting-example-0.5.15.1977.2088.tar.gz

Минута 2

Открываем скрипты streamer.js и player.js на редактирование, находим и меняем:

wss://wcs5-eu.flashphoner.com:8443

на

wss://domain.com:8443

здесь domain.com — доменное имя вашего сервера, на котором установлен WCS5

Минута 3

Открываем streamer.html в браузере по https:// и нажимаем Start. Открываем в новой вкладке player.html и нажимаем Start.

Трансляция с веб-камеры готова. Далее можно модифицировать текущие примеры и тестировать например трансляции многие-ко-многим с публикацией нескольких потоков со стримеров и их дальнейшей раздачей на плееры.

Ссылки

  1. Начальная установка и конфигурация сервера Web Call Server 5
  2. Web SDK для WCS5
  3. Скачать исходный код трансляции
  4. Статистика WebRTC в chrome://webrtc-internals

Web Call Server 5 — это стриминг медиасервер с поддержкой WebRTC, RTMP и других протоколов для разработки web приложений и мобильных приложений с низкой задержкой видео. Сервер включает в себя Web SDK, Android SDK и iOS SDK для разработки кросс-платформенных видеочатов, онлайн видеотрансляций, трансляций с IP-камер и других приложений потокового видео для браузеров и мобильных устройств.