Грабли WebRTC: как мы допиливали чужой велосипед

    В пике на нашей образовательной платформе проходит до 4 тысяч уроков в час. Основной инструмент общения преподавателя и студента — видеосвязь, потому что для обучения важно видеть и слышать друг друга. В самом начале мы использовали Skype, но его нельзя было интегрировать в платформу и логировать уроки. Потом мы перешли на SaaS-решения, но это оказалось очень дорого. Мы начали искать альтернативы и в 2016 году отказались от покупных решений в пользу WebRTC и Janus. Теперь дорабатываем видеоконференции под образовательную платформу силами собственной команды. Да, пришлось копнуть глубже и потоптаться по граблям чужой технологии.

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

    Протокол имеет значение

    Когда мы впервые интегрировали видеозвонки в учебную платформу, то пошли по самому простому и очевидному пути — обратились к людям, которые предлагают готовые решения. Это быстро, удобно и не надо вкладываться в развитие инфраструктуры. Связь работала по TCP и UDP, звук и картинка нас устраивали, но был фатальный недостаток — дорого. Поискали еще, нашли решение почти в 5 раз дешевле — все то же самое, но работает только по UDP. Подключились к нему.

    Но тут приходит новый крупный корпоративный клиент, система безопасности которого блокирует UDP.

    Возвращаться к старому — дорого, а новый в TCP не умеет. Чтобы не терять клиентов, мы пару лет работали с двумя подрядчиками, но каждая оплата счетов причиняла боль.

    Долго так продолжаться не могло. Мы прикинули, что дешевле будет собрать свою команду и вложиться в инфраструктуру. Стали смотреть в сторону связки WebRTC и опенсорсного Janus: он выполнял бы роль сигнального сервера, обязательного элемента для организации связи по WebRTC. У него была фронтовая либа janus-lib.js, с которой можно просто встроить видеоконференции в нашу платформу. Была возможность записывать аудио и видеопотоки. Казалось, нам оставалось только дописывать фичи для своих нужд, потому что в самом WebRTC мы ничего не можем поменять. И хотя запустить и настроить его с помощью Janus получилось без особых проблем, тут были и свои подводные камни.

    Ты умный, но WebRTC умнее (нет)

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

    А когда WebRTC снижал трафик на пробном уроке, конверсия снижалась на 10%.
    А когда WebRTC снижал трафик на пробном уроке, конверсия снижалась на 10%.

    С другой стороны, когда связь у клиента хорошая, WebRTC использует канал по максимуму, увеличивая битрейт. А это уже грозит перегрузкой сети на сервере, т.к. если на него пустить больше трафика, чем может переварить Janus, то у многих клиентов произойдет обрыв соединения. Был и второй минус: если битрейт очень высокий, то исходные записи занимают больше места на диске и могут его переполнить. Мы подумали и установили ограничение для битрейта 256 кбит/с, чтобы точнее рассчитывать нагрузку на сервера и качество видео было приемлемым.

    Но иногда случается то, на что мы повлиять не в силах. Например, когда клиент сидит на уроке рядом с работающей микроволновкой, которая блокирует радиосигнал между роутером и компьютером (да, у нас был такой случай). Пока её не выключат, даже умное понижение битрейта не поможет. Чтобы успокоить пользователя, мы стали выводить подсказки и предупреждения, что с интернет-соединением что-то не так.

    Вот такие подсказки стали появляться. Чтобы их понять, надо учить английский :)
    Вот такие подсказки стали появляться. Чтобы их понять, надо учить английский :)

    Мощнее значит лучше

    Запуская WebRTC, мы наивно полагали, что если у нас будет мощное железо с хорошим каналом, то все будет работать легко и быстро. Рассчитали плановую нагрузку, прописали нужные конфигурации серверов, но что-то пошло не так. Жалобы на связь от учителей стали прилетать гораздо раньше, чем мы уперлись в потолок. Мы не изучали, но видимо, какие-то ограничения были внутри самого Janus gateway. Тогда мы попробовали снизить лимит пропускной способности с 300 до 200 мбит/с — проблемы ушли. Копать дальше не стали, но закупили сервера попроще и с меньшими лимитами.

    Еще мы нашли ошибку в алгоритме, по которому строился маршрут между клиентами. По умолчанию выбирался сервер помощнее и с лучшей пропускной способностью, без оглядки на то, где он находится физически. В итоге учитель и ученик из одного города могли связываться через сервер из другого — путь усложнялся, потерять пакеты было проще. Мы переписали алгоритм так, чтобы по пингам от пары клиентов к серверам выбирался самый ближний.

    Как только мы сократили путь, пакеты стали меньше теряться.
    Как только мы сократили путь, пакеты стали меньше теряться.

    WebRTC одинаково хорошо работает с разными браузерами

    А если нет, то  проблема решается с помощью волшебной таблетки библиотеки webrtc-adapter. Да, но не совсем.

    Например, Китай нас радует не только разнообразием товаров с Али, но и мобильных браузеров типа QQ и UC. Когда мы пробовали войти на китайский рынок, то обнаружилось, что WebRTC они поддерживают только в одну сторону: запрещают доступ к микрофону и камере устройства, при этом воспроизводят видео от второго клиента. Та же проблема возникла в Европе с браузером DuckDuckGo. А однажды к нам прилетела жалоба, что не получается заниматься через браузер Tesla! И так как повлиять на это все мы не можем, то просим клиентов пользоваться последней версией Google Chrome.

    Ничего не работает? Используй Google Chrome!
    Ничего не работает? Используй Google Chrome!

    Хотя и с ним до недавнего времени было не все гладко на iOS-устройствах: когда пользователи запускают в Chrome видеосвязь с мобильного устройства, iOS ругается и требует открывать Safari. А Safari только недавно получил поддержку WebRTC, и не все в нем работает так как надо. Например, его не устраивает маленькое разрешение для камеры (для экономии трафика мы передаем картинку 640 на 480), и он требует установить более качественную видеосвязь.

    И еще один сюрприз: на iOS-устройствах ученикам нельзя одновременно быть на связи и воспроизводить видеофайл с заданием. Поэтому сейчас им приходится делать выбор и что-то отключать. И с этим нам тоже пришлось смириться.

    Нельзя просто взять и разрешить доступ к видеокамере

    Для видеоурока нужно включить камеру и микрофон. Казалось бы, это очевидно. Но мы заметили, что часто связь не устанавливается из-за того, что пользователь блокирует и то, и другое. И делает он это машинально, потому что окно с запросом похоже на другие запросы, от других сайтов, еще и появляется в том же месте. Тогда мы стали показывать это уведомление непосредственно в момент входа на первый урок и для надёжности — дополнительный попап в другом месте экрана. Стало гораздо понятней и проблема решилась.

    Если вдруг доступа к камере и микрофону нет, перед началом урока обязательно еще раз его запросим.
    Если вдруг доступа к камере и микрофону нет, перед началом урока обязательно еще раз его запросим.

    Что в итоге

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

    Кстати, Илья Левин, старший разработчик команды видео, подготовил доклад о том, как запустить видеоконференцию на базе WebRTC и Janus и жить с этим дальше — приходите послушать в прямом эфире 27 февраля. Начало в 11-00 по Москве.

    Что еще посмотреть и почитать по теме:

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

    • Кирилл Роговой рассказывает, что у WebRTC под капотом и почему от вас почти ничего не зависит.

    • Доклад с советами, как использовать WebRTC в вашем продукте.

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

    Skyeng
    Крупнейшая онлайн-школа Европы. Удаленная работа

    Комментарии 20

      0
      Хотя и с ним до недавнего времени было не все гладко на iOS-устройствах: когда пользователи запускают в Chrome видеосвязь с мобильного устройства, iOS ругается и требует открывать Safari. А Safari только недавно получил поддержку WebRTC, и не все в нем работает так как надо.

      сторонние браузеры на iOS не поддерживают WebRTC. это реальность, данная нам Apple в ощущениях. поэтому для публикации — только Safari, в остальных можно играть HLS.
      А Safari только недавно получил поддержку WebRTC, и не все в нем работает так как надо. Например, его не устраивает маленькое разрешение для камеры (для экономии трафика мы передаем картинку 640 на 480), и он требует установить более качественную видеосвязь.

      с таким не приходилось сталкиваться. на MacOS Safari 14 перестал транслировать 4:3 c камеры FacetimeHD, только 16:9. обходится просто: публикуешь 640x360, например.
      И еще один сюрприз: на iOS-устройствах ученикам нельзя одновременно быть на связи и воспроизводить видеофайл с заданием.

      да, но вторую сессию WebRTC на той же странице играть можно.
        0

        Добрый день. Спасибо за статью!


        Несколько вопросов:


        1. Какие основные проблемы у вас сейчас остались с Janus, если не секрет? Или всё устраивает после починки эстиматоров?
        2. Вы используете Simulcast? Если да, то ловили с ним каких-нибудь проблем?
        3. В каком разрешении, с каким битрейтом и на каких кодеках вы в итоге работаете и почему?
        4. Зачем вам вообще сервер нужен? У вас же наверняка в большинстве случаев (1 учитель – 1 ученик) можно обойтись P2P?
        5. Чем обусловлена проблема с 200 мбит/сек на сервер? На дворе 2021 год, и эта цифра что-то совсем не впечатляет :)
        • НЛО прилетело и опубликовало эту надпись здесь
            +1
            Добрый день!
            Какие основные проблемы у вас сейчас остались с Janus, если не секрет?

            Основная проблема — это ошибка «User ID… already exists». Возникает, когда один и тот же пользователь пытается зайти в комнату одновременно с двух вкладок браузера или двух разных устройств. Janus не дропает автоматически старое подключение пользователя, если он повторно заходит в комнату. Приходится на уровне приложения обрабатывать эту ошибку.

            Вы используете Simulcast? Если да, то ловили с ним каких-нибудь проблем?

            Используем. Проблем нет.

            В каком разрешении, с каким битрейтом и на каких кодеках вы в итоге работаете и почему?

            640x480, 256 Кбит/с. Подобрали на глаз, чтобы картинка норм была и записи не все пространство на серверах выжирали. Кодеки в основном vp9, т.к. чисто субъективно кажется, что при одинаковом битрейте качество картинке лучше, чем у vp8. Для Safari используем h264.

            Зачем вам вообще сервер нужен? У вас же наверняка в большинстве случаев (1 учитель – 1 ученик) можно обойтись P2P?

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

            Чем обусловлена проблема с 200 мбит/сек на сервер? На дворе 2021 год, и эта цифра что-то совсем не впечатляет :)

            Не копали эту тему в глубь, просто закидали проблему железом :))
              0
              Основная проблема — это ошибка «User ID… already exists».

              Если я правильно понимаю, то вы в теле `join` запроса указываете один и тот же `id`? Как вариант, это можно решить через флаг `string_ids`, доступный в последних версиях Janus, и задавать id составным вида `<user_id>-<random_string>`. Но тогда вопрос переходит в другую плоскость — нужен механизм для остановки/удаления сессии на неактивной вкладке…
            0
            Я правильно понимаю что вы меняли код Janus? А дальше как? Pull Request или живете со своим отдельным репозиторием?
              0
              Нет. Мы код Janus не меняли.
                0
                Еще мы нашли ошибку в алгоритме, по которому строился маршрут между клиентами.

                А как вы тогда влияли на выбор ICE Candidate в этом контексте? Это же делается на уровне libnice?
                  0
                  Кажется понял, речь идет не о выборе ICE Candidate, а о выборе физического Janus Server перед началом создания комнаты…
                    0
                    Да. Все верно.
              +1
              Интересен был ваш опыт работы с WebRTC, а на деле просто рассказали про возникшие проблемы без технических деталей(
              Планируете подробнее раскрыть тему?
                0
                Приходите на онлайн-доклад через субботу, там можно будет @bkston (один из разработчиков в команде видео) задать вопрос текстом или голосом. Плюс будем благодарны, если напишете, что интересует — чтобы мы могли подумать, как об этом лучше рассказать.
                  +2
                  Вопросов на самом деле много, часть из них перечислю:
                  — как вы определяете с технической стороны корректный видеозвонок?
                  — собираете ли вы статистику по звонкам, корректный поток у пользователя и у репетитора?
                  — допустим у пользователя заблокирована камера, возникают ли проблемы при соединению?
                  — вы как нибудь технически определяете успешность звонка или полагаетесь на отклик пользователя/репетитора? я как помню мне сразу предлагали в skype)) в обход вашего решения
                  — вы думали в сторону jitsi?
                  — как поступаете если ошибки на стороне медиасервера? есть какие-нибудь технические примеры, например реконнекта?
                  — собираете статистику WebRTC? rtt, jitter и другие метрики для определения состояния соединения?
                0
                При ваших бюджетах и размерах команды не проще ли было сделать своё нативное приложение под macOS, отдельно под Windows+Linux на каком-нибудь Qt, как вы это делаете для iOS и Android, чтобы не заниматься вознёй с кучей браузеров, которые меняются каждый день?
                И протоколы можно стандартные тюнинговать под каждую систему, или свои изобретать, и кодеки практически какие угодно, и доступ ко всем устройствам без особых проблем.
                  +3
                  При ваших бюджетах и размерах команды

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

                  С продактом видеокоманды (у него крутой технический бэкграунд, с WebRTC работает с 13-го года) сейчас как раз думаем о тезисах доклада на HighLoad на тему, как пилить видеосвязь с небольшой командой и скромным по меркам, например, соцсетей, бюджетом.
                  0
                  Правильно понимаю, что бутылочным горлышком является пропускная способность сервера, а не CPU, RAM, IOPS? И учитывая битрейт в 256 кбит, на одном сервере у вас может транслироваться одновременно 800 потоков? (на самом деле наверное чуть меньше из-за оверхеда, но порядок должен быть примерно такой)
                    +1
                    Не совсем. Нам не удавалось загрузить сеть, CPU, RAM и IOPS на все 100%. Предполагаю, что есть какие-то особенности на уровне Janus. Если на него направить много трафика, то некоторые соединения начинают неожиданно закрываться, при этом ресурсов на сервере и пропускной способности сети достаточно.
                    0

                    Вы решили, что поддерживать свое приложение под iOS будет труднее, чем разбираться с причудами Safari?

                      +1
                      Приложение под iOS и Android с видеосвязью тоже есть. Но их разрабатывает другая команда. Мы для них только бэк предоставляем.
                      0
                      Кстати, UC Browser раньше был прекрасен, несколько лет назад. Умел кэшировать содержимое вкладок, не перегружая при нехватке памяти, как когда то Opera Mini. Работал быстро.
                      Сейчас это нечто медленно работающее, с кучей постоянно выскакивающей рекламы.

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

                      Самое читаемое