Pull to refresh

Миграция сервиса виртуальных компаньонок на WebRTC

Reading time 10 min
Views 14K
Это история одного проекта по видеостримингу.

image

Интересный клиент


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

Через пару минут я увидел Ольгу, сопровождающую джентельмена азиатской наружности. На вид ему было около пятидесяти. На слегка морщинистой голове восседала серая шляпа с короткими полями. Они явно шли ко мне. Поравнявшись с кофейным автоматом, который уже журчал в стаканчик моим капучино, джентельмен произнес на ломаном русском: Здраствуйте, я относительный проекта WebRTC. Моя зовут Суконако, и протянул руку. Что привело сюда этого японца, подумал я, ответив на рукопожатие, и пригласил гостя в свой кабинет. Дальше нам пришлось перейти на английский язык, который нам обоим был более понятен.

Собираем требования


Я: Итак, чем могу быть полезен?

С: Мы работаем с 2000 года в стриминге и Flex для большого количества пользователей. Мы используем Adobe Flash Media Server (FMS) и сейчас хотели бы использовать WebRTC.

Я: Можно подробнее о том, чего вы хотели бы достичь использованием WebRTC-сервера?

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

Я: Без проблем, мы можем сделать решение на базе одного из WebRTC-серверов.

С: Adobe FMS нас полностью устраивает. Мы хотели бы расширить круг наших пользователей на WebRTC, не убирая FMS. Он работает хорошо.

В руках Суконако появился планшет, он подвинул его мне и ткнул пальцем в следующую схему:

image

C: Flex App – это доктор, Flex Apps – это пациенты, доктор использует веб камеру и консультирует сразу нескольких пациентов. Один из пациентов может запросить у доктора приватную консультацию, и тогда доктор остается один на один для приватной консультации с пациентом. В этот момент остальные пациенты не могут общаться с доктором и не видят его.

image

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

image

Я: Т.е. в результате устанавливается двухсторонняя видеосвязь доктора и пациента?

С: Не совсем. Пациент всегда видит доктора, но доктор может не видеть пациента. По умолчанию видео пациента отключено.

Я: Значит видео одностороннее – от доктора к пациенту?

С: В большинстве случаев да. Но иногда пациенты желают показать свое видео доктору. Это случается нечасто.

Я: Все понятно. Значит нужно чтобы и доктор и пациент могли использовать WebRTC-браузер, например Firefox или Google Chrome, а также IE, который будет работать через FMS. Верно?

С: Почти так. Все доктора используют разработанное нами стриминг-приложение на Flex. Пациенты же должны использовать либо наше приложение либо WebRTC.

Я: Т.е. в идеале, ваше приложение должно выглядеть так?

И набросал схему.

image

С: Да, верно. Это должно работать именно так. С одной стороны нативное Flex-приложение, а с другой WebRTC-браузер. Нас интересуют прежде всего браузеры на Android-смартфонах и iOS-устройствах. Вам наверное известно, что Flash так или иначе присутствует на всех десктопных браузерах: IE, Chrome, Firefox, Safari, но его нет на Android и iOS. Мы хотели бы сделать наш сервис доступным на мобильных браузерах и сохранить то, что работает хорошо на десктопах, т.е. FMS.

Я: На Android-браузерах WebRTC будет работать, а на iOS с этим проблема – WebRTC в iOS-браузерах не работает из-за ограничений платформы. Т.е. мы не сможем доставить WebRTC видеопоток на iOS и не можем стримить видео с вебкамеры iOS-браузера.

C: Постойте, мне известно что Safari не поддерживает WebRTC, но его поддержка есть в Google Chrome.

Я: Да, но не в случае iOS. Там Chrome натыкается на технические ограничения платформы и не имеет таких возможностей работы с WebRTC-видео, как на десктопе. Т.е. iOS браузер в данном случае не подходит. Почему бы вам не выгрузить собственное приложение в Apple App Store? Тогда пользователям iOS нужно будет всего лишь установить приложение и использовать чистый WebRTC, тот, что используется в Google Chrome?

С: К сожалению, мы не можем выгрузить приложение в App Store по внутренним причинам. Кроме этого, мы хотели бы дать нашим пользователям (пациентам) возможность не устанавливать дополнительных приложений на свой iPhone или iPad, а работать прямо из браузера. Какие у нас есть варианты?

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

Вариантов в действительности было не много и лучшим из них было нативное приложение с поддержкой WebRTC. iOS Safari, как известно поддерживает HLS (Apple HTTP Live Streaming), но этот вариант был отброшен, т.к. в общении доктора с пациентом предполагался определенный реалтайм и живое общение, для которого HLS совершенно не подходит при задержке около 20 секунд.

Оставался последний вариант: вебсокеты. Websockets сейчас поддерживается почти во всех браузерах – это фактически TCP-канал, по которому можно доставить видео с задержкой сравнимой с RTMP, т.е 3 секунды, а не 20. С доставкой понятно. Еще бы воспроизвести этот поток в <video/> HTML5 элементе и было бы все замечательно.

Я: Вариант, похоже, только один – вебсокеты. Причем в этом случае пациенты не смогут отправить свое видео на сервер. Возможна только односторонняя доставка от доктора к пациенту. Можно попробовать HLS, но там задержка больше 20 секунд и вероятно вам это не подойдет.

С: Хорошо. Правильно ли я понял, что мы сможем играть живые потоки с FMS прямо на iOS Safari браузере? Пусть без WebRTC, но с небольшой задержкой, сравнимой с RTMP?

Я: Да, абсолютно верно. Но нам нужно некоторое время это проверить. Давайте договоримся, скажем на понедельник, и я покажу вам демо.

С: Мне бы хотелось увидеть возможность интеграции FMS одновременно с WebRTC и с Websockets, чтобы быть уверенным, что это будет работать на iOS и на Android. Возможно ли так сделать?

Я: Да, думаю все получится.

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

Я: Да, конечно, к этому времени все будет готово.

Ищем решение


Как видно из разговора, требования немного изменились и теперь предстояло прикрутить к Adobe AMS два способа доставки: WebRTC для браузеров на Android и Websockets для браузера Safari под iOS. Осталось найти недостающий элемент, который позволит построить это демо и связать все участвующие в нем технологии и протоколы.

image

Проводив японского гостя, я первым делом отправился смотреть спецификацию Adobe AMS. Нашел в ней много интересного, кроме слов WebRTC и Websocket.

Дальше, не долго думая, забил в Гугл три нужных кейворда: rtmp, webrtc и websockets. Гугл выплюнул несколько релевантных сайтов. Пригодными, как оказалось были всего два: проприетарный проект Flashphoner и описание опенсорсного прототипа с сайта Phoboslab

image

Первый кандидат


Начать решил с Phoboslab, где была во всех красках описана проблема воспроизведения стрима в iOS Safari и предлагалось решение, очень похожее на опенсорсное.

Решение строится на ffmpeg, node.js и клиентском javascript для декодирования и воспроизведения видеопотока. Все компоненты были действительно опенсорсные и схема выглядела многообещающей.

Я поднял виртуальный сервер на DO, собрал ffmpeg и установил node.js. Все это заняло около двух часов.

image

Видео в iOS Safari действительно играло, и играло не плохо. Мой iPhone5 слегка грелся, но JavaScript стабильно лопатил видеотрафик с Websocket и показывал его на web-странице.

Фактичеки происходило декодирование стрима на JavaScript и последующая отрисовка в элементе страницы браузера iOS Safari. Оставались открытыми следующие вопросы:

— Как забрать стрим с FMS
— Как добавить к стриму звук
— Что насчет WebRTC

И здесь меня ждало некоторое разочарование. Оказалось, что JavaScript-плеер играет (отрисовывает) только видео. Для аудио пришлось бы пускать дополнительный поток, после чего их нужно как-то синхронизировать. Но данное решение этого не предусматривало. Таким образом, данное решение не подходило для передачи видео от доктора из-за отсутствия звука.

Второй кандидат


Следующим подопытным был Web Call Server с обещанной поддержкой RTMP, WebRTC, Websocket протоколов. Осталось проверить, применима ли поддержка данных протоколов в моем конкретном случае и как это работает.

Первым делом решил проверить конвертацию RTMP видеопотока в Websocket, по аналогии с предыдущим тестом. Ведь если это получится сделать, то далее можно перенаправить RTMP поток с FMS на Web Call Server и тем самым решить одну из задач.

image

Я вооружился iPhone-ом и открыл одну из демо-страниц, где предлагалось попробовать сделать это с демо-сервера. По заверениям техподдержки, Web Call Server можно быстро установить на свою Linux-систему, но это заняло бы некоторое время, а демо давало возможность сразу понять работает это или нет.

Демо-интерфейс представлял собой обычное Flash-приложение с неказистым дизайном и простым функционалом, под названием Flash Streaming.

image

Из этого Flash приложения можно подключиться к серверу по протоколу RTMP и опубликовать стрим с веб-камеры. Опубликовать (Publish) – значит захватить видеопоток с веб-камеры браузера с помощью Flash Player и отправить данные на сервер в реальном времени по протоколу RTMP.

Судя по статусам ‘Connected’ и ‘Publishing’, соединение было успешно установлено и стрим с веб-камеры отправлялся на сервер. Дабы не светить в стриме своим фейсом, я использовал виртуальную камеру и серию из пятого (?) сезона Game of Thrones.

Далее осталось увидеть и услышать это видео на iPhone в браузере Safari. Для этого рекомендовалось использовать отдельный плеер под названием WS Player Minimal.

image

На плеере удалось получить приличную картинку и звук без искажений или рассинхрона.

Пожалуй, я достиг некоторого прогресса в своем ресерче:

  • Удалось протестировать доставку стрима RTMP-Websocket
  • Стрим был со звуком и видео и корректно отображался на Safari браузере

Осталось проверить играет ли стрим в WebRTC и можно было переходить к интеграции с Adobe FMS. Для проверки этого же стрима c WebRTC, я открыл демо Streamer And Player Minimal в браузере Chrome и выполнил аналогичную нехитрую процедуру, вставив имя потока, и нажав на воспроизведение.

image

Какаова же была моя радость, Кхалиси!

Теперь в моем арсенале была доставка RTMP потока на Chrome, а значит на Android по WebRTC, и на iOS Safari по вебсокетам. И в том и в другом случае картинка была вполне плавной, со звуком и теоретически годилась для развертывания консалтингового сервиса.

Следующим вопросом была работа с FMS. Понятно, что RTMP протокол должен быть единым для всех реализаций, но предстояло выяснить а) Может ли FMS перенаправить RTMP стрим на Flashphoner и б) примет ли Flashphoner этот стрим, как принимал его с Flash в тестах выше.

Интеграция с Adobe Media Server


С FMS пришлось повозиться. Его установка и тесты заняли у меня пару часов. Первое, что я сделал, это протестировал FMS с помощью FMLE и убедился что FMS я установил и настроил правильно, и RTMP видеопотоки ходят на нем без каких-либо препятствий.

image

Следующим шагом была настройка перенаправления RTMP потока на Flashphoner. Здесь пришлось немного напрячь мозг, вооружиться документацией Adobe по Action Script и заимплементить такой скрипт: main.asc.

var wcsServer = "wcs5-eu.flashphoner.com";
var netConnections = new Object();
var streams = new Object();

application.onConnect = function (client){
    trace("onConnect "+client.id);
    var nc = new NetConnection();
    var obj = new Object();
    obj.login = "Alice";
    obj.appKey  = "flashChatApp";
    nc.connect("rtmp://"+wcsServer+":1935",obj);
    nc.onStatus = function(info){
        trace("onStatus info.code: "+info.code);
        if (info.code=="NetConnection.Connect.Success"){
            trace("connection opened "+wcsServer);
        }
    }
    netConnections[client.id]=nc;
    return true;
}

application.onDisconnect = function (client){
    trace("onDisconnect "+client.id);
    var nc = netConnections[client.id];
    if (nc){
        nc.close();
        trace("disconnected "+client.id);
    }
}

application.onPublish = function(client, myStream){
    trace("onPublish "+myStream.name);
    var nc = netConnections[client.id];
    ns = new NetStream(nc);
    ns.onStatus = function(info){
        if (info.code == "NetStream.Publish.Start"){
            trace("It is now publishing "+myStream.name);
        }
    }
    ns.attach(myStream);
    ns.publish(myStream.name);
    streams[myStream.name]=ns;
    trace("publish stream "+myStream.name+" to: "+wcsServer);
}

application.onUnpublish = function(client, myStream){
    trace("onUnpublish "+myStream.name);
    var ns = streams[myStream.name];
    if (ns){
        ns.publish(false);
        trace("unpublished "+ns.name);
    }
}


Скрипт достаточно простой и занимается тем, что делегирует входящие на FMS коннекты и видеопотоки Flashphoner-серверу. Например, при получении коннекта от приложения в методе onConnect, создается коннект к Flashphoner-серверу по RTMP.

При получении видеопотока onPublish, этот же видеопоток публикуется на Flashphoner.

При дисконнектах и остановке стримов, соответствующие вызовы делегируются для освобождения ресурсов. Так у меня получился мост, по которому будет прокидываться трафик между FMS и Flashphoner для дальнейшей раздачи по WebRTC и Websockets.

image

Для тестирования этой композиции я взял уже знакомый Flash-интерфейс Flash Streaming. Единственная разница была в том, что нужно было указать RTMP адрес FMS-сервера и далее положиться на скрипт main.asc, который делегирует этот видеопоток Flashphoner. В моем случае этим адресом был rtmp://my-fms:1935

image

При тестировании пришлось изрядно подебажить серверный скрипт main.asc от незнания Action Script и серверного программирования под FMS, но это все осталось в прошлом, и выше в листинге доступна рабочая на тот момент версия этого скрипта. FMS не подвел и передал RTMP стрим по назначению, что и позволило успешно проиграть его в Chrome и далее в Safari.

image

Установка Web Call Server


В итоге демо было готово. Оставалось поставить Web Call Server на своей системе чтобы избежать сбоев в момент презентации. Мало ли чего они там могут накрутить до понедельника.

На сайте разработчика нашлась инструкция по установке, состоящая из пяти пунктов. Пятый пункт с установкой SSL-сертификатов я опустил, т.к. пока не планировал использовать WebRTC-стриминг с камеры и микрофона.

  1. Download Web Call Server 5
  2. Install using the 'install.sh' script
  3. Launch using 'service webcallserver start'
  4. Open the web-interface http://host:9091 and activate your license

Установка прошла нормально. Я предусмотрительно отключил на тестовом сервере Firewall (service iptables stop) чтобы исключить проблемы с непрохождением трафика.

Через минуту после запуса сервера получилось открыть веб-интерфейс с админкой http://host:9091, активировать тестовую лицензию и получить у себя на Ubuntu демо-сервер, похожий на этот:

image

Дополнительный прогон тестов позволил убедиться, что схема работает и в моем окружении. С чувством выполненного дела, я завершил рабочий день и поставил напоминалку – еще раз проверить тесты в понедельник в 9:00 перед приходом Суконако.

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

Ссылки на используемые инструменты:

  1. FMS (Flash Media Server) он же AMS (Adobe Media Server) – RTMP медиа сервер.
  2. DO (Digital Ocean) – хостинг виртуальных серверов.
  3. WCS (Flashphoner Web Call Server) – WebRTC, Websocket медиа сервер.
  4. FMLE (Adobe Flash Media Live Encoder) – клиент для проверки RTMP-соединения с сервером.
  5. Phoboslab — опенсорсный прототип Websocket стриминга на Safari в iOS.
Tags:
Hubs:
+25
Comments 12
Comments Comments 12

Articles