Как мы делали сервис на WebRTC



    Статей про WebRTC уже достаточно много и в интернетах, и на Хабре (здесь и здесь), повторять их ещё раз не имеет особого смысла, поэтому тут приведем наш личный опыт и впечатления, полученные при разработке live.pics.io.

    Идея



    Live.pics.io позволяет создавать приватные сессии для совместного просмотра и обсуждения изображений голосом. Это могут быть любые изображения: от фотографий, до макетов дизайна и презентаций. Pазрабатывая pics.io, мы достаточно хорошо научились работать с разными raw форматами в браузере, поэтому можно не заморачиваться с конвертацией и закидывать фотографии сразу после съемки (будут рады владельцы Canon’ов и Nikon’ов, остальные камеры пока требуют конвертации в DNG).

    Очень коротко о webRTC


    На самом деле, использовать WebRTC — это практически то же самое, что использовать сокеты. Но немного по-другому (совсем чуть-чуть). Нам нужно передавать изображение и звук. Берем RTCPeerConnection для соединения между пирами, MediaStream для трансляции аудио и RTCDataChannel для передачи изображений. Еще, для того, чтобы все это заработало, понадобится небольшой серверсайд для соединения пиров и передачи управляющих инструкций. Но об этом чуть позже.


    Exoskeleton vs Backbone




    Так уж случилось, что наш основной проект (pics.io) разрабатывается на Backbone. Мы давно хотели попробовать распиареный Exoskeleton, который, как бы, то же самое… Но не совсем. В нашем случае Exoskeleton не так уж необходим, но нам просто захотелось поиграться с новой штукой и выпустить ее в продакшн. Помоему мы не прогадали. Еще надо отдать должное автору @PaulMiller, который очень активно поддерживает свое детище. Вообще, мы не то чтобы ненавидим jQuery, от которого Exoskeleton спасает, но мы убедились, что под современные браузеры можно писать на чистом JS. Я искренне надеюсь, что Exoskeleton повторит путь Lodash и завоюет сердца бекбонщиков.

    WebRTC via PeerJS


    Мы решили, что правильнее и быстрее для развёртывания WebRTC части будет использовать готовое и протестированное решение. После изучения нескольких open source проектов, которые оборачивают WebRTC сервисы, выбор пал на PeerJS: отчасти из-за большого количества звездочек на GitHub, а отчасти из-за совета @Lvivsky, который собаку съел на создании библиотеки speaker на Dart/WebRTC.

    PeerJS — это обертка над WebRTC, которая позволяет абстрагироваться от его внутренностей. В конце концов нам всё же пришлось поковыряться в его исходниках, когда мы наткнулись на ограничение передаваемых файлов по RTCDataChannel в ~6Mb. В целом, библиотека оставила только приятные впечатления, да и мейнтейнеры проекта оперативно нам помогали.
    Первое впечатление от PeerJS было изумительным: одна строка на сервер сайде, отличный интерфейс на клиенте, поддержка Media call (audio/video) и DataConnections. И что самое приятное PeerJS помогает продолеть ограничение на объем передаваемых данных через DataConnections в Chrome 31, который пока не научился передавать больше 1100 байт. Но не все коту масленица, RTCDataChannel падает с абсолютно неинформативным ворнингом Uncaught SyntaxError: An invalid or illegal string was specified. После пары литров кофе и общения с контрибьюторами PeerJS выяснилось, что Chrome ограничивает скорость передачи данных до 60kb/s. Вдобавок оказалось что максимальный размер передаваемого файла получился ~6,3M. В приниципе, этого достаточно для того, чтобы передавать jpeg, извлеченный из raw-файла.


    NAT, NAT, NAT




    Накануне релиза мы не могли не облажаться. Соединение в локальной сети работало превосходно (как MediaStream, так и DataChannel), но когда кто-то подключался не из офиса, наш восторг пропадал, начинались необъяснимые проблемы, которые воспроизводились нестабильно. То звук, то данные до гостей не доходили.
    Мы выделили несколько пунктов которые могли влиять на это:
    • DataChannel — который был коннектором между всеми пирами
    • Банальный баг, который было трудно воспроизвести
    • Непроходимость NAT

    Начали с того, что вместо DataChannel добавили Signaling сервер на WebSocket, c помощью которого связали существующие пиры, но это не решило проблему.
    Поиски бага тоже не увенчались успехом. Их было найдена уйма, но и это не помогло.

    “Все-таки NAT” — решили мы и, как оказались, правы. Странно, но решение этой проблемы не очень хорошо описано в документации. Изначально большинство библиотек использует по умолчанию сервера:

    [{url:'stun:stun.l.google.com:19302'},
    {url:'turn:homeo@turn.bistri.com:80', credential: 'homeo'}]
    

    Но, к сожалению, нам не хватило этого и пришлось серфить в поисках дополнительных серверов. В итоге мы получили огромный конфиг для ICEServers

    [{url:'stun:stun01.sipphone.com'},
    {url:'stun:stun.ekiga.net'},
    {url:'stun:stun.fwdnet.net'},
    {url:'stun:stun.ideasip.com'},
    {url:'stun:stun.iptel.org'},
    {url:'stun:stun.rixtelecom.se'},
    {url:'stun:stun.schlund.de'},
    {url:'stun:stun.l.google.com:19302'},
    {url:'stun:stun1.l.google.com:19302'},
    {url:'stun:stun2.l.google.com:19302'},
    {url:'stun:stun3.l.google.com:19302'},
    {url:'stun:stun4.l.google.com:19302'},
    {url:'stun:stunserver.org'},
    {url:'stun:stun.softjoys.com'},
    {url:'stun:stun.voiparound.com'},
    {url:'stun:stun.voipbuster.com'},
    {url:'stun:stun.voipstunt.com'},
    {url:'stun:stun.voxgratia.org'},
    {url:'stun:stun.xten.com'},
    {
    	url: 'turn:numb.viagenie.ca',
    	credential: 'muazkh',
    	username: 'webrtc@live.com'
    },
    {
    	url: 'turn:192.158.29.39:3478?transport=udp',
    	credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
    	username: '28224511:1379330808'
    },
    {
    	url: 'turn:192.158.29.39:3478?transport=tcp',
    	credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
    	username: '28224511:1379330808'
    }]
    

    После этого мы благополучно пробили стены NAT и услышали голоса людей из других подсетей, городов и стран.

    Проблемы технологии и реализации


    Кроссбраузерная совместимость.

    На данный момент у реализаций WebRTC есть проблема c работой между разными браузерами, но и Firefox и Chrome активно двигаются в этом направлении. Через пару-тройку версий web уже получит эту поддержку.

    Пробивание NAT.

    STUN и TURN — пожалуй основная проблема, о которой почему-то мало пишут. Постоянно тестируя, мы заметили, что внутри одной сети все друг-друга слышали и прекрасно получали данные, но люди, которые сидели за роутерами испытывали постоянные проблемы. На это мы потратили огромное количество нервов, так как не особо тесно работали с сетевыми протоколами и не до конца понимали, зачем это нужно. Теперь знаем — из приватных сетей, класса A, B, C, люди в сети класса public выходят только через NAT. Эта технология не удобна тем, что два хоста за NAT'ами не могут общаться друг с другом. Поэтому и придумали эти технологии.

    Non-Stop coding.

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

    Выводы


    • скорость передачи данных в PeerJS ограничена 60kb/s
    • максимальный передаваемый размер файла ~6MB
    • нужно подчеркивать момент с NAT+STUN+TURN
    • вакансия jQuery-разработчик должна стать менее популярной
    • не забывайте указывать схему для ваших URI
    • рано или поздно WebRTC захватит мир
    • WebRTC разработчики ненавидят свой голос
    • мы любим все новое, сырое и поломанное
    • недельный безпрерывный педалинг жутко выматывает


    Любимые ссылки

    www.html5rocks.com/en/tutorials/webrtc/basics
    www.youtube.com/watch?v=p2HzZkd2A40
    www.youtube.com/watch?v=E8C8ouiXHHk
    www.webrtc-experiment.com
    www.webrtc.org
    speakerdeck.com/feross/webrtc-data-black-magic
    TopTechPhoto
    Компания
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

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

      0
      можно кстати даже свой TURN сервер поднять code.google.com/p/rfc5766-turn-server/
      Так а расскажите подробнее, про то что пилили, знаете скандалы, интриги ;)
        +1
        можно кстати даже свой TURN сервер поднять code.google.com/p/rfc5766-turn-server/

        Да, думали об этом, но пока публичные справляются на 5 баллов.

        Так а расскажите подробнее, про то что пилили, знаете скандалы, интриги ;)

        А видео-то и забыли вставить. А вообще, лучше заходите поклацайте.
        +1
        Приятно видеть настоящий, не экспериментальный проект на WebRTC. Желаю вам удачи!

        В свое время, кстати, тоже много намучился со STUN серверами. И свои пытался поднимать, и разные сторонние использовал. Но соединения все равно периодически становились нестабильными. Причем, в самый неподходящий момент, когда клиенту уже через пару часов показывать. :)
          0
          Желаю вам удачи!

          Спасибо!

          Причем, в самый неподходящий момент, когда клиенту уже через пару часов показывать. :)

          Это всегда так.

          В свое время, кстати, тоже много намучился со STUN серверами

          Какое решение в итоге оказалось самым стабильным?
            0
            Откровенно говоря, уже не помню точно. Использовали несколько публичных STUNов, и еще свой один подняли. Полностью стабильное решение получить так и не удалось, но проект был для внутреннего использования, так что просто добились, чтобы в сети клиента работало приемлемо.
              0
              у нас Chrome <--> Chrome очень прилично работает со своим TURN сервером (rfc5766-turn-server) стоящим у Hetzner.
            0
            Тогда вам наверное интересно будет прочитать про remote.st.
            0
            Я просто оставлю это здесь: 2x.io/read/security-by-obscurity
              0
              Как сейчас обстоят дела с совместимостью браузеров?
                0
                Соединение стабильно работает мжду последними+одинаковыми версиями одинаковых браузеров, так как реализации технологии в FF и Chrome сейчас немного отличаются. Но судя по багтрекерам, они движутся навстречу друг другу.

                Т.е. Chrome 31 — Chrome 31, Canary 33 — Canary 33, FF 25 — FF 25 будет работать, но не между разными браузерами.
                  0
                  Все равно неплохой прогресс если они стали добавлять в стабильные ветки технологию без необходимости задания флагов.
                0
                > STUN и TURN — пожалуй основная проблема, о которой почему-то мало пишут…

                Ваша статья не исключение:)
                  +1
                  Ну, они хотя бы рабочую, отлаженную конфигурацию привели. Это тоже не мало. Можно, наверное, взять если что, и попробовать у себя.
                  0
                  Сейчас добавлю немного. Из приватных сетей, класса A, B, C, люди в сети класса public выходят только через NAT. Эта технология не удобна тем, что два хоста за NAT'ами не могут общаться друг с другом. По этому и придумали эти технологии.
                  +1
                  Круто! Получилось удобно и интересно. Хорошо, что решили проблемы с NAT-ами :) И за это время я уже успел переписать Start на Яваскрипт с сохранением API ;) github.com/lvivski/dialup

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

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