Статей про 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 — пожалуй основная проблема, о которой почему-то мало пишут. Постоянно тестируя, мы заметили, что внутри одной сети все друг-друга слышали и прекрасно получали данные, но люди, которые сидели за роутерами испытывали постоянные проблемы. На это мы потратили огромное количество нервов, так как не особо тесно работали с сетевыми протоколами и не до конца понимали, зачем это нужно.
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
Автор: yetithefoot