В предыдущей статье мы описывали принципы разработки видеочата между браузером и Android — устройством. Теперь же попробуем усложнить задачу и заимплементить трехсторонний видеочат на следующих платформах: Google Chrome на десктопе, Android приложение на планшете, и iOS приложение для Apple iPhone.

Напомним два основных принципа построения видеочата:

  1. Каждый подключившийся пользователь может отправить (опубликовать) свой видеопоток на сервер.
  2. Пользователи знают имена видеопотоков друг-друга и имеют возможность их воспроизвести.

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


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

Публикуют потоки
1. Alice:	session.createStream({name:"stream_alice"}).publish();
2. Boris:	session.createStream({name:"stream_boris"}).publish();
3. Anna:	session.createStream({name:"stream_anna"}).publish();

Играют потоки
4. Alice:	session.createStream({name:"stream_anna"}).play();
5. Alice:	session.createStream({name:"stream_boris"}).play();
6. Boris:	session.createStream({name:"stream_alice"}).play();
7. Boris	session.createStream({name:"stream_anna"}).play();
8. Anna:	session.createStream({name:"stream_alice"}).play();
9. Anna:	session.createStream({name:"stream_boris"}).play();


От разработчика в данном случае требуется организовать передачу названий и статусов видеопотоков участникам видеочата. Это можно сделать на любой подходящей технологии, например PHP, websockets, Node.js и т.д., так как передача имени видеопотока ничем не отличается от передачи обычного текстового сообщения от одного пользователя к другому.

У потока может быть три основных статуса: PUBLISHING, PLAYING, STOPPED

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


На этой схеме показано, как именно можно реализовать обмен именами и статусами потоков, в упрощенном варианте, когда Алиса демонстрирует свой видеопоток Борису и Анне. Такая процедура занимает 8 шагов, и может быть названа сигналингом, т.к. В результате этой процедуры проводится согласование:

  1. Алиса отправляет видеопоток на WCS-сервер.
  2. Алиса получает от сервера подтверждение в виде статуса PUBLISHING
  3. Алиса отправляет Борису сообщение, о том, что ее поток готов к воспроизведению.
  4. Алиса отправляет Анне сообщение, о том, что ее поток готов к воспроизведению.
  5. Анна воспроизводит видеопоток с WCS-сервера.
  6. Анна получает подтверждение статус PLAYING.
  7. Борис воспроизводит видеопоток с WCS-сервера.
  8. Борис получает подтверждение статус PLAYING.

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

Комнаты


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

С другой стороны, для такой задачи напрашивается какое-то универсальное решение, которое могло бы помочь пользователям быстро согласовать потоки и попасть в чат. Такое решение называется Комнаты или Room API.

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

Таким образом, имеем четыре объекта, которые полностью покрывают работу с комнатами:

  • Room — комната
  • Stream — видеопоток
  • Participant — участник
  • Message — сообщение



Room API дает возможность кроссплатформенно использовать перечисленные выше абстракции: Room, Stream, Participant и Message для реализации следующих функций:

Подключение


  • Пользователь может подключиться к комнате.
  • Пользователь задает название комнаты при подключении.
  • Если комната с таким названием существует, то пользователь попадает в эту комнату.
  • Если комнаты с таким названием нет, то создается новая комната и пользователь попадает во вновь созданную комнату.
  • Пользователь получает уведомления о подключениях / отключениях других участников.
  • Пользователь может получить список участников.

Стриминг


  • Пользователь может опубликовать видеопоток внутри комнаты.
  • Пользователь получает уведомления о статусах видеопотоков других участников.
  • Пользователь может воспроизвести видеопоток внутри комнаты.

Сообщения


  • Пользователи могут обмениваться сообщениями внутри комнаты
  • Пользователи могут обмениваться изображениями или другим контентом, если он упакован в текстовый формат
  • Сообщение можно отправить одному или нескольким участникам

Room API


Для Web платформы, комнаты были реализованы в виде JavaScript — модуля со следующими основными функциями:

1. Получаем соединение с сервером.

var connection = Flashphoner.roomApi.connect({urlServer: "wss://host:8443", username: "Alice"});

2. Входим в комнату.

connection.join({name: "room1"});

3. Получаем список участников комнаты.

var participants = room.getParticipants();

4. Отправляем свой видеопоток в комнату.

room.publish({
	display: document.getElementById("localDisplay"),
        constraints: constraints,
        record: false,
        receiveVideo: false,
        receiveAudio: false
});

5. Воспроизводим поток участника.

participant.getStreams()[0].play(document.getElementById(pDisplay))

6. Следим за участниками комнаты:

connection.on(ROOM_EVENT.JOINED, function(participant){...});
connection.on(ROOM_EVENT.LEFT, function(participant){...});
connection.on(ROOM_EVENT.PUBLISHED, function(participant){...});

JOINED — к комнате присоединился новый участник
LEFT — участник вышел
PUBLISHED — участник опубликовал свой видеопоток

7. Получаем сообщения от других участников.

connection.on(ROOM_EVENT.MESSAGE, function(participant){...});

8. Отправляем приватное сообщение конкретному участнику

participants[i].sendMessage(message);

9. Отправляем сообщение всем участникам сразу.

var participants = room.getParticipants();
        for (var i = 0; i < participants.length; i++) {
            participants[i].sendMessage(message);
        }
}

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

Ограничения Room API


Вся логика при работе с комнатами ложится на клиента. Сервер управляет только только базовым функционалом комнаты:

  • уведомления о подключении / отключении пользователей в комнате
  • уведомления о создании / отключении видеопотоков пользователями внутри комнаты
  • маршрутизация сообщений указанным участникам

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

Комнаты для Web, Android, iOS


В каждой из SDK (Web, Android, iOS) для работы с сервером, есть API для работы с комнатами.
Примеры входа в комнату:

Web SDK

connection.join({name: "room1"});

Android SDK

Room room = roomManager.join(roomOptions);

iOS SDK

room = [roomManager join:options];

Таким образом в одну и ту же комнату может войти три участника с трех разных платформ:

  • Web — браузер
  • Мобильное приложение для Android
  • Мобильное приложение для iOS

Тестовые приложения для работы с комнатами


Ниже мы приведем три тестовых приложения для работы с комнатами. Каждое из них имеет открытый код и может быть собрано из исходников.

Каждое из следующих приложений позволяет обмениваться видеопотоками и сообщениями трём участникам:

  • Conference for Web
  • Conference for Android
  • Conference for iOS

Conference for Web


Код этого приложения доступен для скачивания здесь.

В HTML-коде можно найти два div-элемента

<div id="participant1Display" class="display"></div>

<div id="participant2Display" class="display"></div>

Эти элементы отвечают за отображение видео участников.

div — элемент localDisplay отвечает за отображение видео, захваченного с камеры.

<div id="localDisplay" class="fp-localVideo"></div>

С помощью кнопок Join / Leave можно войти и выйти из комнаты соответственно. С помощью Stop / Start можно отправить видео в комнату или остановить вещание. Поле Login должно быть уникальным, т.к. идентифицирует участника.


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


И последний элемент — это ссылка на приглашение. Если пользователь вошел первым, создается новая комната. В данном случае с именем roomName=room-fb41b7. Если второй пользователь укажет этот же roomName, он попадет в ту же комнату. В приложении Conference for Web приглашения реализованы генерацией ссылки входа, содержащей roomName в качестве параметра. В версиях приложения для Android и iOS, имя комнаты указывается напрямую в интерфейсе.


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

Ниже на скриншоте показано как работает комната с тремя участниками. Было открыто три вкладки браузера Google Chrome и на каждой из вкладок было инициировано подключение к комнате.


Conference for Android


Код этого приложения доступен для скачивания здесь.

В приложении можно ввести имя комнаты прямо из UI. В остальном приложение очень похоже на Conference for Web, которое было описано выше и имеет те же элементы интерфейса:

  • Кнопки Leave / Join для входа и выхода из комнаты.
  • Два видео окна для воспроизведения видео участников.
  • Одно видео окно для отображения захвата видео с камеры.
  • Текстовый чат с системной информацией и сообщениями участников


Conference for iOS


Код приложения доступен для скачивания здесь.

Интерфейс приложения для iOS уже практически ничем не отличается от приложения под Android, с точностью до названия кнопок и контролов.

В итоге мы сделали тест и собрали все три платформы в одной комнате с номером 3119d6.

Браузер Google Chrome — это заяц, который выбирается из норы:


Android 5.1.1 на планшете Asus — это цветочный горшок.


iOS 10.1.1 на iPhone 6 — это Фикус Бенджамина на подоконнике.


Ниже показан полный скриншот с iOS — устройства:


Таким образом, мы завершили тестирование и обзор всех трех приложений, построенных на основе Room API, и можем переходить к исходному коду и сборке.


Сборка приложения Conference for iOS из исходников


В предыдущей статье мы показывали как собрать пример видеочата под андроид и объясняли как устроен код видеочата в браузере.

Здесь покажем как собрать пример Conference for iOS и опишем основные куски кода примера.

Первым делом нужно обзавестись Mac-железом и установить последний Xcode.

Процедура сборки требует установки Cocoapods, скачивания кода примеров и SDK для iOS. Собирать будем в терминале, а потом откроем проект в Xcode.

1. Устанавливаем Cocoapods

sudo gem install cocoapods

2. Скачиваем все примеры с github

git clone https://github.com/flashphoner/wcs-ios-sdk-samples.git

3. Скачиваем iOS SDK

wget https://flashphoner.com/downloads/builds/flashphoner_client/wcs-ios-sdk/WCS-iOS-SDK-2.3.0.tar.gz

4. Распаковываем архив

tar -xvzf WCS-iOS-SDK-2.3.0.tar.gz


5. Копируем папку FPWCSApi2.framework в примеры

cp -R FPWCSApi2.framework wcs-ios-sdk-samples

6. Запускаем сборку.

./build_example.sh

Если сборка прошла успешно, в терминале выводится **ARCHIVE SUCCEDED**


После того как примеры собраны из консоли с помощью Cocoapods, подтянуты и сконфигурированы все зависимости и дальнейшие сборки примеров можно проводить непосредственно из Xcode.

7. Открываем WCSExample.xcworkspace в Xcode


8. Выбираем Generic iOS Device в целях сборки. Запускаем сборку примера Conference из меню Product / Build и дожидаемся завершения.


9. Подключаем iPhone по USB и запускаем собранное приложение Conference. В консоли появляется отладочная информация.


10. На экране iPhone появляется приложение Conference


Таким образом, мы собрали мобильное приложение Conference для iOS из исходников и использовали iOS SDK версии 2.3.0 + Cocoapods для этой сборки. В результате мы смогли запустить это приложение на iPhone 6, подключенном по USB к Mac, на котором производилась эта сборка.

Код для Web, Android, iOS видеочатов


Выше мы привели примеры приложений для трех платформ, которые используют Room API и обмениваются видеопотоками внутри созданной комнаты. Попытаемся кратко перечислить основные куски кода, отвечающие за работу видеочата в каждой из этих трех платформ:
  Web Android iOS
Код JavaScript Java Objective-C
Основной код conference.js ConferenceActivity.java ViewController.m
Подключение к серверу
connection = Flashphoner.roomApi.connect({urlServer: url, username: username});
roomManager = Flashphoner.createRoomManager(roomManagerOptions);
roomManager = [FPWCSApi2 createRoomManager:options error:&error];
Подключение к комнате
connection.join({name: getRoomName()});
room = roomManager.join(roomOptions);
room = [roomManager join:options];
Получение списка участников
var participants = room.getParticipants();
room.getParticipants()
NSDictionary *participants = [room getParticipants];
Отправка видеопотока в комнату
room.publish({
display: document.getElementById("localDisplay"),
constraints: constraints,
record: false,
receiveVideo: false,
receiveAudio: false
});
stream = room.publish(localRenderer);
publishStream = [room publish:_localDisplay];
Воспроизводим видеопоток участника
participant.getStreams()[0].play(document.getElementById(pDisplay));
participant.play(participantView.surfaceViewRenderer);
[participant play:pv.display];
Отслеживаем присоединение новых участников к комнате
connection.on(ROOM_EVENT.JOINED, function(participant){...});
public void onJoined(final Participant participant){...};
[room on:kFPWCSRoomParticipantEventJoined participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant){...}]
Отслеживаем покидание участниками комнаты
connection.on(ROOM_EVENT.LEFT, function(participant){...});
public void onLeft(final Participant participant){...}
[room on:kFPWCSRoomParticipantEventLeft participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant){...}]
Отслеживаем публикацию видеопотока участником комнаты
connection.on(ROOM_EVENT.PUBLISHED, function(participant){...});
public void onPublished(final Participant participant){...}
[room on:kFPWCSRoomParticipantEventPublished participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant){...}]
Получаем входящее сообщение от других участников
connection.on(ROOM_EVENT.MESSAGE, function(participant){...});
public void onMessage(final Message message){...}
[room onMessageCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomMessage *message){...}]
Отправляем сообщение одному из участников
participants[i].sendMessage(message);
participant.sendMessage(text);
[participant sendMessage:_messageBody.text];

Итого получаем по 10 основных конструкций на каждую из платформ. Каждую из перечисленных конструкций вы сможете найти в соответствующем файле с кодом.

Все три приложения Web, iOS и Android были протестированы с последней сборкой Web Call Server 5 — сервера для видеочатов и low-latency трансляций с поддержкой технологии WebRTC.

Ссылки


Web Call Server — сервер для WebRTC видеочатов
EC2 launch — запуск готового образа на Amazon EC2
Install — установка сервера на VPS или Dedicated хост
Cocoapods — менеджер зависимостей для сборки

  Web SDK Android SDK iOS SDK
SDK html html html
Скачать SDK tar.gz aar tar.gz
Пример приложения чата с комнатами WCS demo Google Play Только Ad hoc
Основной файл кода примера Conference.js ConferenceActivity.java ViewController.m
Исходный код всех примеров github github github
Описание процедуры сборки примеров из исходного кода html html html
Описание кода примера с комнатами Conference html html  
Поделиться с друзьями
-->

Комментарии (1)


  1. Krizai
    12.04.2017 22:23

    А WebRTC под ios полностью сами реализовывали или брали что-то готовое?