Реализация WebRTC в медиа сервере – практика и политика

в 0:00, , рубрики: браузеры, разработка под windows, Разработка систем связи, Расширения для браузеров

1. Стриминг в браузеры в реальном времени – решения нет. Или есть?

Вот уже примерно как 20 лет пропускная способность сетей и вычислительные возможности компьютеров позволяют сжатие и транслирование звука и видео по IP протоколу в режиме, близком к реальному времени. За это время центральными стандартизирующими организациями, такими как W3C и IETF, а также множеством больших и малых компаний, разработаны сотни стандартов и протоколов для эффективного сжатия, упаковывания, пересылки, синхронизации и проигрывания аудио-видео контента на компьютерах и мобильных устройствах. Видеозахвату, сжатию и трансляции по IP в реальном времени было уделено особое внимание, так как, во-первых, именно IP наиболее дёшев и общедоступен на всех уровнях, а во-вторых, технологии видеоконференций и видеонаблюдения жизненно необходимы и пользуются огромным спросом.

Казалось бы, столько лет прошло и столько работы проделано. Какие же прекрасные достижения в этой области мы можем наблюдать по прошествии 20 лет? Давайте снимем крышку ящика (конечно, это не ящик Пандоры и не «can of worms») и посмотрим, какие замечательные технологии и возможности стали доступны после многолетних трудов десятков тысяч талантливых софтверных инженеров. Программист из 1998 года, впервые переславший звук по сети, доктор, желающий простого, дешевого и надёжного телемедицинского решения, учитель, которому нужно провести удалённый урок – вот они открывают эту крышку, полные радужных надежд, и что они видят? В зловонной кипящей кастрюле, полной умопомрачительного маркетинга, циничного капитализма и отчаянных попыток энтузиастов поправить положение дел, плавают всякие кодеки, протоколы, форматы и аппы. Вот какой суп IT «сообщество» предлагает потребителю стриминга в реальном времени. Вылавливайте сами, что меньше пахнет, пробуйте, тестируйте, покупайте. Нет простого и эффективного решения. В отличие от стриминга, не требующего реального времени: там всё-таки уже лет 5 есть стандарт HLS, работающий на любых браузерах и устройствах, где solution provider может просто установить HLS segmenter у себя на сервере и спать спокойно.

Вот RTSP – его играют куча приставок и профессионального оборудования, но не играют браузеры. Вот RTMP – его не хочет играть Safari на iOS и не все Androids его играют. Его запрещает Chrome как неблагонадёжного. Вот MPEG2-TS – его тоже браузеры не играют. HTML5 Media Source Extensions (MSE) – хорош для видео сегментов длины 5-10 секунд (т.е. для HLS/Dash), но для коротких сегментов менее одной секунды — не всегда стабилен, работает по разному в разных браузерах и опять-таки не поддерживается на iOS.

Как, спрашивается, детскому саду посылать видео от камер, установленных в группах, родителям, которые хотят открыть браузер в любое время на любом устройстве, и без установки каких-то плагинов смотреть на своих детей в реальном времени? Почему таких услуг не предлагают все поголовно садики? Да потому что обеспечить такую услугу очень дорого. Нужно разработать Аппы для мобильных устройств, где видео будет проигрываться – ведь браузеры не играют. Нужно многое другое.

Давайте определим понятие «близко к реальному времени». Это меньше 5 секунд задержки для видеонаблюдения и менее 1 секунды для видеоконференции. Средняя задержка протокола HLS – 20-30 секунд. Может быть, для садиков еще как-то сойдёт, но для охранного видеонаблюдения, видеоконференций и вебинаров нужна другая технология.

Итак, до сих пор, точнее до лета 2017 года, не существовало единого стандарта или протокола для трансляции звука-видео в любой браузер на любом устройстве в реальном времени. Причины, по которым сложилась такая ситуация, мы рассмотрим в этой статье позже. Они не технического рода, эти причины. А пока посмотрим, что же всё-таки произошло летом 2017 года, что худо-бедно, но все же предоставило технологию, позволяющую решить вышеобозначенные задачи. Технология эта – WebRTC, о ней много написано и на этом ресурсе и вообще в сети. Ее уже нельзя назвать абсолютно новой и на момент написания этой статьи W3C считает WebRTC 1.0 завершённым проектом. Мы не будем здесь рассказывать, что такое WebRTC; если читатель не знаком с этой технологией, то предлагаем сделать поиск на хабре или в гугле и ознакомиться, для чего она применяется и как в общих чертах работает. Здесь мы лишь скажем, что технология эта была разработана для peer-to-peer коммуникации в браузерах, с помощью неё можно реализовать видео-чат и голосовые приложения без всякого сервера – браузер общается напрямую с браузером. WebRTC поддерживают все браузеры на всех устройствах, а летом 2017 года наконец-то и Apple снизошёл до нас и добавил её в свой Safari на iOS. Именно это событие сделало WebRTC самой универсальной и общепринятой технологией для реал-тайм стриминга в браузеры, со времен заката RTMP который начался в 2015 году.

Однако, при чем же здесь стриминг в браузеры от камер? А дело в том что WebRTC очень гибка в своей функциональности, и позволяет посылать звук-видео только одному из двоих участников (peers), а другому только принимать. Поэтому родилась идея адаптировать WebRTC в медиа серверах. Медиа сервер может получить видео от камеры, наладить коммуникацию с браузером, и договориться, что только он будет посылать, а браузер будет получать. Таким образом, Медиа Сервер может одновременно посылать видео от камеры многим браузерам / зрителям. И наоборот, медиа сервер может получать поток от браузера, и пересылать его, скажем, многим другим браузерам, реализуя столь желанную «one-to-many» функцию.

Значит, наконец-то всё образовалось? Акуна-матата, и садик сможет установить такой медиа сервер где-то на хостинге или на AWS, посылать один поток от каждой камеры туда, и оттуда он будет уже раздаваться в браузеры родителей, всё с задержкой не более одной секунды. В целом – да, жизнь налаживается. Но есть проблемы. И проблемы эти связаны с тем что WebRTC как бы притянут за уши для таких задач, он не для них проектировался и не совсем для них подходит. Проблемы, помимо совместимости кодеков, существуют прежде всего с масштабируемостью такого медиа сервера. То есть одновременно 100 родителей можно обслужить с одного серверского компьютера, а 500 – уже сложно. Хотя сеть позволяет. А посмотришь на загрузку процессора на сервере при 100 соединениях – она уже близка к 90%. Как так? Ведь всего-лишь посылаем звук-видео.

С таким же потоком, если посылать по RTMP протоколу в Flash player, то можно с одного сервера легко поддержать 2000 одновременных соединений. А по WebRTC всего 100?
Почему? Причины две: во-первых, сам WebRTC протокол значительно вычислительно дороже – там, к примеру обязательно шифрование всех данных, а оно забирает довольно много процессорного времени. И вторая причина, о которой мы расскажем поподробней – чрезвычайно неэффективная реализация протокола его создателем – Google, который и предоставляет исходный c++ код этой самой реализации для адаптирования в серверах, шлюзах и других приложениях, желающих поддержать WebRTC: webrtc.org/native-code

2. Google’s Native WebRTC API и его совместимость с медиа сервером

Напомним, что WebRTC создавался для передачи звука-видео из браузера в браузер и задачи поддержать множество одновременных соединений не было. Поэтому, и не только поэтому, реализация WebRTC в браузере совершенно наплевала на основной принцип проектирования и архитектуры технических систем – элегантность (ничего лишнего), эффективность, высокопроизводительность. Акцент был сделан на надежность и справляемость с ошибками и крайними ситуациями в сети – потерю пакетов, соединений и т.п. Что, конечно, есть хорошо. Однако, при детальном рассмотрении, выясняется, что это единственное, что есть хорошо в гугльской реализации WebRTC.

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

2.a Кода в 10 раз больше, чем должно быть и он крайне неэффективен

Это проверенная цифра. Для начала вы сгружаете около 5 гигабайт кода, из которых к WebRTC имеет отношение только 500 мегабайт. Затем вы пытаетесь избавиться от ненужного кода. Ведь вам для нужд медиа сервера не нужен энкодинг/декодинг; сервер должен только получить контент и переслать его всем желающим. Когда вы убрали всё ненужное, что смогли (а смогли вы убрать гораздо меньше, чем хотелось бы), всё равно осталось 100 мегабайт кода. Это чудовищная цифра. Именно она в 10 раз больше, чем должна быть.

Кстати, на этом месте многие скажут – как это не нужен энкодинг/декодинг? А транскодинг из AAC в Opus и обратно? А транскодинг VP9->H264? Если вы собираетесь делать такой транскодинг на сервере, то вам и 5 одновременных соединений не потянуть. Транскодингом, если он действительно необходим, должен заниматься не медиа сервер, а другая программа.

Но давайте вернемся к проблеме раздутого кода и проиллюстрируем ее. Как вы думаете, какова глубина стека вызовов функций при отправке уже сжатого видео фрейма? Один вызов winsock (на Windows) функции send или sendto (WSASend / WSASendTo)? Нет, нужно, конечно, проделать ещё кое-какую работу. В случае WebRTC, нужно упаковать фрейм по RTP протоколу и зашифровать его, что в сумме дает нам SRTP протокол. Нужно сохранить фрейм на случай потери пакетов, чтобы выслать потом ещё раз. Сколько c++ объектов и threads (потоков) должно быть в это вовлечено?

Вот как это делает WebRTC 61:

image

Как видно из этого скриншота, с момента когда мы подаём в WebRTC сжатый фрейм, до момента когда его положат в очередь объекта Paced_Sender, глубина стека вызовов равна 8 (!) и задействовано 7 объектов!

Затем отдельный thread (поток) PacedSender вытаскивает наш фрейм из очереди и посылает его дальше в обработку:

image

И наконец, мы пришли к этапу 4, где уже RTP-упакованный и зашифрованный фрейм положится в очередь на отправку в сеть, которой занимается ещё один поток. К этому моменту глубина стека вызовов (на потоке PacedSender) равна 7, и вовлечено ещё 3 новых объекта. Поток, занятый отправкой, вызовет конечные WSASend/WSASendTo также после 3-4 вложенных вызовов функций и вовлечет еще 3-4 новых объекта.

Итак, мы увидели 3 потока, каждый из которых проделывает огромную работу. Каждый, кто программировал подобные системы, имеет представление о том как делаются такие вещи, и что реально должно быть сделано. По нашим оценкам, как минимум 90% объектов и кода здесь – лишние и нарушают принципы объектно-ориентированного программирования.

2.b На одно соединение отводится 4-5 threads (потоков)

Спору нет, с количеством потоков в данном примере всё в порядке. Нужно обеспечить асинхронную обработку, никого не блокировать, и все 3 потока нужны. В целом, на один PeerConnection WebRTC отводит в 4-5 потоков. Ну можно было бы уложиться в 3. Но не меньше. Проблема в том что это – на каждое соединение! В сервере, к примеру, можно сохранить 3 потока, но они будут обслуживать все соединения вместе, а не отводить 3 потока на каждое соединение. Пул потоков – несомненное серверское решение для таких задач.

2.c Асинхронные сокеты, работающие через windows messages

Гугльский WebRTC код на Windows использует асинхронные сокеты через WSAAsyncSelect. Серверные программисты знают, что использование функции select на сервере – самоубийство, и WSAAsyncSelect, хотя и улучшает ситуацию, но не на порядок. Если вы хотите поддержать сотни и тысячи соединений, на Windows есть решение лучше, чем асинхронные сокеты. Должны быть задействованы Overlapped sockets и IO Completion Ports, посылающие нотификации пулу потоков, выполняющему работу.

2.d Заключение

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

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

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

3. Почему все так грустно

Такая ситуация со стримингом в браузеры в реальном времени – очень характерная иллюстрация того, к чему иногда приводит “business driven technology”. Технология, мотивируемая бизнесом, развивается в том направлении, в каком она необходима бизнесу и постольку, поскольку она угодна этому бизнесу. Именно благодаря бизнес-подходу у нас сейчас есть персональные компьютеры и мобильные телефоны — никакое правительство или центральное плановое министерство никогда не могло бы быть так заинтересовано разработать и внедрить в массы все эти потребительские технологии. Частный бизнес, мотивируемый личной выгодой своих хозяев, сделал это как только появилась техническая возможность.

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

Мы, дети Советского Союза и менталитета «давайте сделаем технически правильную и сильную технологию, чтобы люди могли ей пользоваться и всем было хорошо», могли бы, конечно, утверждать, что в плановой советской системе (если бы вдруг правительство решило), технология стриминга по IP в реальном времени могла бы быть разработана и внедрена за год и была бы на порядок лучше всего того, что бизнес наработал сейчас за 20 лет. Но мы также понимаем, что потом она не развивалась бы, устарела и, в конце концов, в далёкой перспективе, всё же проиграла бы какой-нибудь коммерческой западной технологии.

Поэтому, так как без стриминга-шмиминга вполне можно обойтиться, он справедливо отдан на откуп частному бизнесу. Который развивает его в своих интересах, а не в интересах потребителя. Как так не в интересах потребителя? А как же спрос-предложение? Что потребителю надо, то бизнес и предложит? А вот не предлагает. Все потребители кричат – Google, поддержи AAC audio в WebRTC, но Google никогда на это не пойдет, хотя ему раз плюнуть, чтобы это сделать. Apple абсолютно на всех наплевал и ничего вообще не внедряет из столь необходимых потоковых технологий у себя в гаджетах. Почему? Да потому что не всегда бизнес делает то что надо потребителю. Он не делает этого тогда, когда является монополистом и не боится потребителя потерять. Тогда бизнес занят укреплением своих позиций. Вот Google купил в последние годы кучу производителей звуковых кодеков. И проталкивает теперь Opus audio, и заставляет весь мир делать транскодинг AAC->Opus для соответствия с WebRTC, так как вся технология давно перешла на AAC audio. Google оправдывает это якобы тем, что AAC – платная технология, а Opus — бесплатная. А на самом деле, это делается для того, чтобы установить свою технологию как стандарт. Как когда-то сделал Apple со своим убогим HLS, который нас заставили любить, или как еще раньше сделал Adobe со своим невменяемым RTMP протоколом. Гаджеты и браузеры – всё-таки довольно технически сложные вещи для разработки, отсюда и возникают монополисты, отсюда, как говорится, воз и ныне там. А W3C и IETF спонсируются теми же самыми монополистами, поэтому менталитета «давайте сделаем технически правильную и сильную технологию, чтобы люди могли ей пользоваться и всем было хорошо» — там нет и не будет. А должен был бы быть.

Какой выход из этой ситуации? Видимо, просто ждать, когда «правильная» business-driven технология, результат конкуренции и всяких других прекрасностей, наконец, разродится чем-то демократичным, подходящим для простого сельского доктора, чтобы тот со своим обычным интернетом смог давать телемедицинские услуги. Ведь, надо сделать поправку, не для простого сельского доктора, а для тех, кто может платить большие деньги, бизнес давно предлагает решения по стримингу в реальном времени. Хорошие, надёжные, требующие выделенных сетей и специального оборудования. Во многих случаях и не работающих по IP протоколу. Который – и это ещё одна причина такой печальной ситуации — и не был создан для для реального времени, и не всегда гарантирует его обеспечить. Не всегда, но не в жизненно-важных ситуациях вполне подходит на данный момент. Так что давайте пробовать WebRTC. Пока из всех зол он является наименьшим и вполне демократичным. За что, всё-таки, нужно сказать спасибо Гуглу.

4. Немного о медиа серверах, реализующих WebRTC

Wowza, Flashphoner, Kurento, Flussonic, Red5 Pro, Unreal Media Server — вот некоторые из медиа серверов, поддерживающие WebRTC. Они обеспечивают публикацию видео из браузеров на сервер и трансляцию видео в браузеры по WebRTC от сервера.

Проблемы, описанные в этой статье, по разному и с той или иной степенью успеха, решены в этих софтверных продуктах. Некоторые из них, например Kurento и Wowza, делают аудио-видео транскодинг прямо в сервере, другие, к примеру Unreal Media Server, транскодинга сами не делают, но предоставляют для этого другие программы. Некоторые сервера, такие как Wowza и Unreal Media Server, поддерживают стриминг по всем соединениям через один центральный TCP и UDP порт, ведь сам WebRTC отводит отдельный порт на каждое соединение, так что провайдеру приходится открывать множество портов в firewall, что создает проблемы с безопасностью.

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

Автор: Чёрный властелин

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js