Привет!
Недавно мы выпустили новую версия Mail.Ru Агента 5.10 для платформы Windows, и в списке новых «фич» этой версии появилась неприметная строчка: «улучшено качество голосовых и видеозвонков».
На первый взгляд, минорное изменение – но только на первый взгляд. На самом деле мы полностью отказались от медиа-библиотеки, которой пользовались до сих пор, и перешли к использованию собственного «движка», построенного на открытом решении WebRTC. Об этом мы хотели бы сегодня рассказать поподробнее.
История
Итак, до последнего времени (то есть до версии 5.9) мы использовали в нашем десктопном клиенте «движок», лицензированный несколько лет назад у компании Global IP Solutions (GIPS). Идея лицензирования чужого продукта казалась на тот момент вполне удачной: мы получали готовое решение от одного из лидеров рынка, а вместе с ним – возможность в короткий срок добавить в Mail.Ru Агент функциональность звонков, необходимость в которой стала очевидной.
Правда, на практике все оказалось не так безоблачно: «из коробки» библиотека GIPS работала не вполне корректно, ее закрытый код не способствовал быстрому решению проблем, и в итоге нам даже пришлось принимать в офисе Mail.Ru Group «десант» шведских инженеров, которые прямо на месте исправляли ошибки в своем «движке». Однако в итоге мы получили то, что хотели – звонки в Агенте, реализованные «с нуля» в короткий срок (2-3 месяца).
С момента запуска этого сервиса мы получили огромное количество отзывов и пожеланий, а также множество жалоб и баг-репортов. К сожалению, не в наших силах было удовлетворить все запросы пользователей – закрытость библиотеки и зависимость от сторонней компании лишали нас необходимой гибкости в решении возникающих проблем. Поэтому начиная с определенного момента мы начали задумываться об отказе от решения GIPS. Окончательный гвоздь в гроб лицензированного «движка» вбила компания Google, которая купила Global IP Solutions летом 2009 года. После покупки стало ясно, что улучшений в библиотеке ждать бессмысленно (Google обычно покупает команду и технологии, а не клиентскую базу). Таким образом, мы лишались не только баг-фиксов в будущем, но и надежд на завоевание мобильных платформ.
К тому же примерно в то же время мы сами приобрели ICQ у AOL, и вопрос о единой медиа-платформе встал весьма остро.
Мы рассматривали многие варианты, от собственной разработки до лицензирования «движка» у другого поставщика, но коррективы снова внесла компания Google, которая неожиданно открыла часть исходного кода GIPS в рамках своего нового проекта WebRTC.
WebRTC
Суть инициативы WebRTC заключается в том, чтобы предоставить возможность совершения голосовых и видеозвонков прямо с веб-страниц, без установки дополнительных плагинов. Предполагается, что для этого разработчики должны встраивать в свои веб-браузеры некоторый набор медиа-компонентов, и обеспечивать к ним доступ через общепринятый (стандартный) высокоуровневый JavaScript API.
Что ж, идея благая – впрочем, ее статус пока довольно туманен. Единственный браузер, в котором сейчас поддерживается WebRTC – это девелоперская версия Chrome (так называемые «ночные сборки»), до статуса стандарта W3C этой технологии пока далеко, да и Microsoft не дремлет, активно продвигая свой Silverlight.
Короче говоря, никакой революции в звонках из веба с выходом WebRTC пока не произошло. Однако нас интересовало в этой библиотеке совсем другое – непосредственно код медиа-компонентов: акустических фильтров, кодеков, механизмов для преодоления NAT и т.д.
Первые исследования репозитория WebRTC дали обнадеживающие результаты:
- лицензия BSD (возможность использования и модификации библиотеки без обязательств раскрывать исходный код всего продукта);
- наличие всех необходимых компонентов для реализации звонков между клиентами;
- семантика API, близкая к движку от GIPS, который мы использовали ранее;
- частое обновление кода, свидетельствующее об активном развитии проекта.
Однако более детальное знакомство с WebRTC привело к первым неприятным открытиям:
- проект был полон багов, «из коробки» почти ничего не работало;
- качество видео оказалось довольно низким (особенно в части адаптации к потерям в канале);
- поддерживалась только платформа Windows (в репозитории присутствовал зачаточный код для Android, но на момент его изучения он даже не собирался);
- реализация одного из наиболее важных акустических компонентов, подавителя эхо (AEC – Acoustic Echo Canceller), в WebRTC оказалась хуже, чем в GIPS;
- кодек VP8, включенный в WebRTC, в некоторых ситуациях оказался хуже проприетарного кодека GIPS LSVX, который мы использовали ранее;
- большое количество «мусора» – неиспользуемого кода.
Основной вывод, который мы сделали по окончании исследования – часть, отвечающая за видео, в библиотеке WebRTC «сломана» и требует тщательной работы по исправлению ошибок.
Тем не менее, несмотря на множество обнаруженных недостатков, мы решили, что WebRTC – это неплохая основа для собственного «движка», и начали его разработку собственными силами. Мы посчитали, что полный контроль над кодом и независимость от стороннего производителя в долгосрочной перспективе для нас важнее, чем быстрый запуск Mail.Ru Агента и ICQ с лицензированным «движком» от нового поставщика.
Итак, наша стратегия была следующей – сначала довести код WebRTC до production-качества, а затем решить более сложные задачи: переписать ряд особенно проблемных модулей, добавить поддержку видеокодека h.264 («из коробки» идет только VP8), портировать код на мобильные платформы и т.д.
Собственно, первую часть задачи мы успешно решили, и Mail.Ru Агент 5.10 является своего рода proof of concept – первым реальным продуктом, на котором была «обкатана» библиотека WebRTC с нашими доработками.
Что нового в звонках в Агенте 5.10?
Если сравнивать новую версию с предыдущими (в части звонков), то изменений, на первый взгляд, немного. Однако сразу же обращает на себя внимание резко возросшая скорость установления сессии между клиентами. Достигнуто это было благодаря использованию libjingle – одного из компонентов WebRTC.
Libjingle представляет собой довольно навороченный фреймворк для организации P2P-сессий, изначально разработанный для реализации звонков в мессенджере Google Talk. Поскольку Google Talk работает по протоколу XMPP, изрядная часть кода libjingle решает задачу сигнализации (то есть обмена данными о параметрах сессии) поверх этого IM-протокола.
Поскольку мы XMPP не используем, сигнализацию мы сохранили свою, однако взяли из libjingle код, отвечающий непосредственно за организацию соединения всеми возможными способами, включая прохождение различных NAT, firewall и т.д.
Сама по себе идея преодоления NAT несложна – двум клиентам достаточно просто «договориться» о внешних IP-адресах, а также о портах, на которых нужно открывать исходящие соединения и которые нужно «слушать», и установить с этими параметрами двустороннее соединение транспортного уровня (в нашем случае – по протоколу RTP/RTCP поверх UDP). Однако на практике это оказывается не так легко сделать – из-за разных типов NAT, за которыми могут находиться клиенты, из-за firewall'ов (на которых могут быть закрыты определенные диапазоны портов или даже целые протоколы – например, UDP), из-за ошибок реализации сетевых компонентов в различных домашних роутерах и других особенностей сетевых конфигураций.
Ранее мы решали задачу прохождения NAT с помощью «самодельного» (и достаточно примитивного) механизма. В libjingle же реализована гораздо более «умная» логика установления соединения. Среди наиболее интересных особенностей – оптимизация сортировки «кандидатов» (пар IP: порт), использование для попыток подключения всех доступных на компьютере сетевых интерфейсов и IP-адресов (если одному интерфейсу присвоено более 1 IP-адреса), инкапсуляция UDP-пакетов в TCP-соединение (на случай, если UDP заблокирован в сети), использование STUN-серверов и т.д.
Использование libjingle значительно улучшило коннективити Mail.Ru Агента: количество соединений, установленных напрямую между клиентами (без использования промежуточных релеев), выросло по сравнению с нашим предыдущим решением в 3 раза, что весьма позитивно повлияло на качество звука и видео за счет уменьшения количества задержек и потерь пакетов по пути. Скорость установления соединения также была значительно повышена. Оба этих эффекта вполне заметны визуально.
Также мы проделали определенную работу по улучшению адаптации к каналу, а также перешли на кодек VP8. Это тоже способствовало улучшению качества, хотя здесь нам еще есть над чем работать.
Протестировать новый «движок» можно, загрузив с официального сайта последнюю версию клиента (5.10). Разумеется, у вашего собеседника тоже должна быть установлена эта версия.
Планы
На данный момент у нас 3 основных приоритета:
- улучшение качества видео (включая лучшую адаптацию к пропускной способности канала и потерям пакетов);
- расширение диапазонов возможных разрешений видео (сейчас, как и в прошлой версии, поддерживается только CIF, т.е. 352x288 – мы же планируем добавить, как минимум, VGA и 720p);
- портирование «движка» на мобильные платформы Android и iOS.
Изменения в коде, предполагаемые нами для решения этих задач, настолько масштабны, что в дальнейшем мы не планируем сохранять синхронизацию с репозиторием WebRTC – то есть по сути медиадвижок становится полностью нашей разработкой. Она абстрагирована в отдельную библиотеку, не привязанную к конкретной платформе или продукту, и со временем мы будем рады опубликовать его код. Но, к сожалению, мы сейчас вносим в него такое количество изменений, что говорить о стабильном публичном релизе пока рано.
Для постоянного улучшения субъективного качества мы меняем ключевые компоненты «движка»: jitter buffer, ARS (automatic rate selection), FEC (forward error correction), AEC (Acoustic Echo Canceller ) и т.д. Мы также начали исследовательское сравнение h.264 против VP8 – весьма вероятно, что в будущих версиях при различных параметрах вызова (пропускная способность канала, тип и производительность клиентского устройства) у нас будут использоваться различные видеокодеки.
Что касается мобильных платформ, то с каждой из них есть свои специфические проблемы, которые также придется решать. Главные из них – это производительность и совместимость с «железом», причем во многом они переплетены. Особенно это характерно для платформы Android, на которой сейчас выпускается огромное количество устройств, построенных на совершенно разных аппаратных решениях.
Так, например, большинство современных SoC-решений (System-on-a-Chip) для архитектуры ARM содержат аппаратный акселератор кодирования и декодирования видео в стандарте h.264 (именно поэтому мы начали работу по включению кодека h.264 в наш движок). Сложность заключается в том, что интерфейсы управления акселераторами различных производителей не имеют между собой ничего общего. Это не представляет проблемы для «родного» софта телефона или планшета: такому софту достаточно уметь работать только с одним акселератором. Однако стороннему приложению необходимо поддерживать все распространенные на данный момент чипсеты – а это не так просто, учитывая, что открытая документация зачастую отсутствует.
Вообще, большинство проблем на Android связано, главным образом, с различными уровнями абстракции ОС, то есть с программными «прослойками» между приложением и «железом». При этом часть таких «прослоек» (например, драйвера) часто отличаются от производителя к производителю, от модели к модели. Основные усилия связаны с поддержкой этого «зоопарка». Кроме того, в ряде случаев необходима оптимизация ресурсоемкого кода, изначально рассчитанного на платформу x86, под платформу ARM.
Все усугубляется большим разнообразием версий ОС Android, существенно отличающихся друг от друга в самых неожиданных местах. Например, поведение стека Wi-Fi при отключенном экране (нормальное состояние приложенного к уху телефона) меняется от версии 2.2 к версии 4.0.
В iOS свои приколы. Конечно, с «железом» там проблем существенно меньше – количество конфигураций строго ограничено, тестирование не представляет сложностей. Но здесь на первый план выходят ограничения операционной системы – многие вещи невозможно сделать через публичные API (например, доступ к тому же акселератору кодирования), а использование приватных методов чревато проблемами с прохождением «цензуры» перед попаданием в App Store.
Несмотря на все эти сложности, работа по портированию активно ведется, и уже в ближайшее время мы представим клиент под Android с поддержкой звонков.
Stay tuned!
Илья Наумов,
руководитель проекта Mail.Ru Агент
Автор: cameloid