- PVSM.RU - https://www.pvsm.ru -
Спойлер: никак. За них это делает разработчик.
Когда много лет назад начали убивать Flash, пострадали не только браузерные игры. Flash традиционно была сильна в голосовых и видеозвонках: прямой доступ к микрофону, камере, динамикам, возможность работать с UDP-пакетами. В HTML5 заменой стала технология WebRTC. Та самая, которая несколько месяцев назад наконец-то приземлилась в Safari и Edge. Теперь можно звонить с веб-страницы, открытой на iPhone, на другую веб-страницу, например, открытую в Firefox Quantum на линуксе.
Одна из «фишек» WebRTC, которой не было у Flash — это возможность P2P-соединений между браузерами. Но чтобы peer-to-peer работал, программисту придется помучиться. О том, как браузеры договариваются куда слать UDP-пакеты, и что при этом должен сделать разработчик — под катом.
Большинство тюториалов по WebRTC — это рассказ про крутую замену Flash, голосовые и видеозвонки из браузеров, красивая история про peer-to-peer и десятимегабитный видеопоток без задержек при видеозвонке с вашего iPhone на Windows-ноутбук, при условии что они подключены к одному WiFi. В качестве же кода обычно показывают несколько строк JavaScript, убедительно демонстрирующих как все просто.
Фокус в том, что обычно демонстрируется обертка над WebRTC. И кроме сокрытия от разработчика кишок RTCPeerConnection [1] и MediaDevices.getUserMedia [2], такие обертки прячут от разработчика все коммуникации между двумя браузерами, используя для этого собственное облако и стек технологий: будь это PubNub, Twilio или наш Voximplant. Делать работу за разработчика — хорошо и правильно. Но упрощая стек технологий, мы часто подкладываем себе мину замедленного действия, когда непонимание происходящих «под капотом» процессов приводит к срыву сроков, работающих через раз решениях и «техническим проблемам», о которых так любит с придыханием рассказывать техподдержка.
Этот рассказ — про сигнализацию в WebRTC, как ее делаем мы и другие компании, а также как ее можете сделать вы, если захотите создать свое решение «с нуля» и без использования готовых сервисов.
Слыша словосочетание «peer-to-peer», мы обычно вспоминаем торренты. У которых вроде как центрального сервера нет. Что такое «сигнализация» в WebRTC и где у нее сервер?
Предположим, вы сделали веб-страницу с WebRTC и JavaScript-кодом. Открыли ее на трех ноутбуках, подключенных к вашему WiFi и хотите, чтобы первый ноутбук сделал видеозвонок на третий. Как WebRTC на первом ноутбуке узнает, что нужно подключаться именно к третьему? Как бы мы поступили на месте разработчиков WebRTC?
Первый пришедший в голову способ — это передать WebRTC первого ноутбука IP-адрес третьего ноутбука и пусть отсылает UDP-пакеты. Но такой способ будет работать, только если оба устройства подключены к одной сети и эта сеть позволяет им принимать пакеты друг от друга (сюрприз — публичный WiFi в отелях и на площадках конференций чаще всего не позволяет). А что если у нас не одна, а три точки доступа WiFi? И все три ноутбука подключены к разным точкам доступа и имеют один и тот же виртуальный IP-адрес, например «192.168.0.5». Куда браузеру, запущенному на первом ноутбуке, отправлять пакеты?
Можно предположить, что в такой ситуации звонка не будет, и нам в любом случае потребуется внешний сервер с «настоящим» IP-адресом, через который браузеры на обоих ноутбуках смогут общаться друг с другом. Но авторы WebRTC посчитали, что голос и видео — это трафикоемкие коммуникации, и если миллионы пользователей Skype for Web или Google Hangouts будут звонить через публичные сервера, то эти сервера лопнут. Создатели WebRTC наделили технологию возможностью «пробивать» NAT и устанавливать P2P-подключения, даже если оба устройства имеют виртуальные IP-адреса и не могут напрямую обмениваться пакетами. Расплатой стала та самая «сигнализация». Разработчик не может просто передать WebRTC IP-адрес второго устройства или внешнего сервера. Ему нужно помочь обоим браузерам внимательно осмотреть сеть и договориться друг с другом. И для этого ему нужен свой Signaling Server.
Итак, как выглядит видеозвонок между двумя браузерами с точки зрения разработчика?
Все эти нюансы можно скрыть, если воспользоваться готовой платформой. Наш Web SDK правильно настраивает WebRTC, патчит SDP-пакеты, поддерживает WebSocket-подключение к облаку Voximplant и заботится еще о множестве деталей. И конечно же у нас есть собственные STUN- и TURN-сервера, чтобы подключение состоялось в любом случае. Но можно не скрывать нюансы и сделать самому! Доступные в браузерах API сейчас позволяют сделать сигнализацию разными способами, о них — ниже.
Первое, что приходит в голову — это простейший HTTP-сервер и xmlHttpRequest/fetch со стороны браузера. Увы, работать будет только для «hello world» из учебника. В реальной жизни сервер ляжет от такого количества запросов. Которые придется делать довольно часто, чтобы нажав «connect» пользователь не ждал несколько минут «установки соединения». И еще их придется делать часто потому, что WebRTC — это realtime история, и offer/answer/ice нужно передавать очень быстро. Задержка даже в несколько секунд может послужить сигналом для WebRTC что «ничего не получается», после чего движок прекратит попытки установить подключение. Как вариант можно попробовать технику «long polling», но на практике она не очень хорошо работает и промежуточная интернет-инфраструктура любит обрывать такие «медленные» HTTP-запросы.
Большинство решений, использующих WebRTC, для сигнализации использует WebSockets. Протокол уже достаточно «старый», чтобы его поддерживало подавляющее большинство используемых веб-браузеров и сетевого оборудования. А если использовать обертку вроде socket.io или SocketJS, то в тех редких случаях, когда WebSocket не работает, можно деградировать до HTTP long polling, который будет работать «хоть как-то». Со стороны сервера WebSockets-подключение, по которому не передаются данные, почти не потребляет ресурсов, и сервер может спокойно обслуживать десятки тысяч ожидающих звонка веб-страниц.
Какие проблемы могут быть с WebSockets? Ну, подключения иногда обрываются — это надо обрабатывать. Еще у них высокие таймауты keep alive — подключение может выглядеть живым, но на самом деле оно уже оборвано где-то на промежуточном оборудовании. А мы об этом узнаем только когда не придет очередной keep alive пакет, а это может быть десять минут. В течении которых до нас пытаются дозвониться, но не могут. Этот механизм отдан на откуп реализациям браузеров и серверов, так что ping-pong frame со стороны сервера небесполезно будет проверить и подкрутить в случае необходимости.
Когда 2-я версия HTTP станет более популярной, WebSockets и Server Side Events скорее всего уйдут в прошлое. Бинарный канал общения с сервером в обе стороны, по которому можно получить и HTML-страницу, и картинки, и организовать WebRTC сигнализацию — это очень круто. К сожалению, несмотря на поддержку последними версиями популярных браузеров, HTTP/2 все еще опасно использовать для проектов с широкой аудиторией. Причина — в промежуточном оборудовании, составляющим «скелет» интернета. Все эти роутеры, шлюзы, баррикадки и киски двадцатилетней давности часто завершают HTTP/2-соединения, не понимая что это такое и пытаясь «защитить» что-то от кого-то.
А еще для сигнализации WebRTC можно использовать другое подключение WebRTC! Звучит странно, но у этого способа есть свои плюсы. Если первое WebRTC-подключение установить между браузером и облаком (как это делается у нас для не P2P-звонков) с какой-нибудь другой сигнализацией, то у такого подключения затем можно использовать Data Channel API. Которое выгодно отличается от WebSockets тем, что может работать не только «как TCP», но и «как UDP», очень быстро отправляя пакеты без гарантированной доставки. Такой способ позволит очень быстро сигнализировать подключения — быстрее, чем WebSockets и HTTP/2. В ряде случаев такой способ это то, что нужно. Например, в играх.
Резюмируя все описанное: перед тем, как WebRTC установит подключение peer-to-peer, разработчик должен обеспечить возможность двум браузерам (или другим устройствам; библиотека libwebrtc от Google позволяет использовать webRTC на всем, что движется компилирует C++) обменяться несколькими текстовыми пакетами. Делать это надо быстро, иначе таймауты и ничего не получится. Платформы делают сигнализацию (и многое другое) за разработчика, но если очень надо, то можно сделать самому. Только помнить о куче нюансов, а потом все отладить.
Иллюстрация до ката с сайта www.elasticrtc.com [6]
Иллюстрация дракона с сайта www.sococo.com/blog/webrtc-signaling-here-be-dragons [7]
Автор: eyeofhell
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/270979
Ссылки в тексте:
[1] RTCPeerConnection: https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection
[2] MediaDevices.getUserMedia: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
[3] createOffer(): https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer
[4] setRemoteDescription(): https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setRemoteDescription
[5] addIceCandidate(): https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addIceCandidate
[6] www.elasticrtc.com: https://www.elasticrtc.com
[7] www.sococo.com/blog/webrtc-signaling-here-be-dragons: https://www.sococo.com/blog/webrtc-signaling-here-be-dragons
[8] Источник: https://habrahabr.ru/post/344794/?utm_campaign=344794
Нажмите здесь для печати.