Предыдущая часть здесь.

Что такое сигналинг в контексте WebRTC?

Технология WebRTC как известно, основана на передачи данных - аудио, видео, текста, файлов - от одного конечного узла одноранговой сети другому. Существует термин, описывающий такую схему: p2p (peer to peer). Когда создается WebRTC-агент на одном из узлов сети, он еще ничего не знает об окружающих его других узлах. Он не знает кто хочет подключиться к нему, и какие данные будут передавать ему. Сигналинг - это самый первый шаг в установлении соединения между двумя узлами (далее буду для точности называть пирами). В ходе сингналинга пиры обмениваются между собой различными опциями и значениями, после чего между пирами устанавливается прямая связь без посредников.

Сообщения, которыми обмениваются узлы во время сигналинга, представляет собой простой текст. Обмен сообщениями в ходе сигналинга никак не определяется WebRTC: транспортом может быть протокол HTTP(S) или например, WebSockets.

Сообщения сигналинга представляют собой текст в формате SDP - Session Description Protocol. Сообщение SDP состоит из трех секций, каждая из которых - это набор строк, которые представляет собой ключ-значение. Ключи идут в определенном порядке, это сделано намеренно, чтобы упростить парсинг sdp-сообщения. Определены три секции SDP: описание сессии, тайминги и описание медиа-данных, которыми будут обмениваться пиры. Описание сессии:

v=  (версия протокола, всегда 0)
o=  (идентификатор источника и сессии, формат такой: имя пользователя, id, версия, IP-адрес)
s=  (имя сессии : не менее одного UTF-8 символа. Обычно сюда прописывается `-`)
i=* (краткая информация о сессии)
u=* (URI или описание)
e=* (email адрес)
p=* (телефон)
c=* (другая необязательная информация для соединения)
b=* (ширина канала)
Одно или более описание таймаингов (строки "t=" и "r="; см. ниже)
z=* (сдвиг временной зоны)
k=* (ключ шифрования)
a=* (ноль или более атрибутов сессии)
Ноль или более строк, описывающих медиа-секции (каждая медиа-секция начинается с "m="; см. ниже)

Звездочками обозначены ключи, которые вовсе не обязательны, и обычно при установлении связи webrtc отсутствуют. Описание таймингов:

t=  (время когда активен сеанс, должен быть равен 0 0)

Описание медиа-секции:

m=  (формат такой: <тип медиа - audio или video&> <порт> <протокол> <тип(ы) payload>)
a=* (необязательный атрибут, которых может быть несколько для каждой из медиа-секций)

В атрибутах медиа-секций описываются маппинг номера формата на поддерживаемые webrtc-пиром видео-аудио кодеки. Например в секции

m=audio 4000 RTP/AVP 111
a=rtpmap:111 OPUS/48000/2

описывается, что пир готов обмениваться аудио данными на порту 4000 используя RTP/AVP payload с типом 111. Атрибут указывает на то, что RTP/AVP данные типа 111 будут кодироваться кодеком OPUS с битрейтом 48000.

Полное и подробное описание SDP можно найти в RFC8866.

Рассмотрим более полный пример SDP:

v=0
o=- 0 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 4000 RTP/AVP 111
a=rtpmap:111 OPUS/48000/2
m=video 4002 RTP/AVP 96
a=rtpmap:96 VP8/90000
  • Ключи v, o, s, c, t здесь определены, но они не влияют на сеанс WebRTC.

  • Имеем две медиа-секции ("m="), одна описывает аудио-данные, другая - видео.

  • Каждая из секций имеет атрибуты, которые описывают отображение типа полезной нагрузки на ее особенности, поддерживаемые пиром, в данном случае описывается, что аудио может кодироваться с помощью opus, видео кодируется в vp8.

Работа SDP и WebRTC вместе

Разберемся далее как работают две технологии вместе. WebRTC для сигналинга использует модель офер-ответ: один webrtc-агент отправляет другому офер для начала соединения, второй агент посылает ответ первому. В процессе формирования ответа, второй агент формирует список поддерживаемых кодеков, а также отклоняет неподдерживаемые. Таким образом оба пира приходят к общему формату обмена медиа-данными.

В WebRTC существует такое понятие как трансиверы - пара интерфейсов RTCRtpSender и RTCRtpReceiver, имеющих некое общее состояние и служащих для описания каким образом будут передаваться медиа. Во многих приложениях (таких как видео-стриминг, конференции, трансляции) всегда присутствуют трансиверы, описываемые в медиа-секциях SDP. Каждая медиа-секция в WebRTC будет иметь атрибут, описывающий направление передачи. Это позволяет WebRTC агенту указать, что "я буду отправлять тебе данные закодированные таким-то кодеком, но обратно принимать ничего не собираюсь". Существует четыре значения направления:

  • send - означает, что поток будет только отправляться

  • recv - только для приема

  • sendrecv - двунаправленный поток

  • inactive - данный поток отключен

Бонус-подсказка. Что делать, если мы хотим например, организовать приложение по типу - стример - зритель. У зрителя нет камеры или микрофона, да и не нужно, однако если у зрителя создадим PeerConnection и не добавим никакой медиа-трек, то не произойдет события onnegotiationneeded:

let pc = new RTCPeerConnection();

pc.onnegotiationneeded = function() { // Это не сработает, пока не добавится трек
  pc.createOffer().then(function(offer) { // создаем sdp-офер 
    sendOfferToRemotePeer(offer); // отправляем офер другому пиру через http-сервер например
    return pc.setLocalDescription(offer); // после этого запускаются ICE-кандидаты
  });
};

И соединение не состоится. В таком случае можно либо добавить datachannel в peerconnection, либо добавить трансивер, который будет выступать только приемником:

pc.addTransceiver('video', {direction: "recvonly"});

Другие значения атрибутов медиа-секций

Далее опишу самые распространенные значения атрибутов, использующиеся в WebRTC медиа-секциях, которые вы встретите в SDP.

  • group:BUNDLE - бандлинг позволяет использовать одну коннекцию для передачи нескольких видов медиа-трафика. Некоторые простые или следующие устаревшей спецификации WebRTC используют отдельную коннекцию на каждый медиа-поток. Очевидно, что бандлинг должен быть предпочтительным, чем без него (поддержку бандлинга должен реализовывать WebRTC агент, во всех современных браузерах он поддерживается)

  • fingerprint:sha-256 - это SHA-256 хеш сертификата пира, используемого при установке DTLS соединения. О безопасности и DTLS в частности я буду писать в следующих статьях. Это поле используется для проверки сертификата, полученного после рукопожатия с пиром, с которым хотим установить WebRTC-сеанс, чтобы убедиться, что сертификат не подменили в ходе установки DTLS соединения (напомню, что обмен SDP сообщениями происходит до начала установки прямого DTLS-соединения).

  • setup: - поле для контроля DTLS-агента. Это поле определяет, как запускать DTLS-агента - как сервер или как клиент после ICE-соединения. Возможные значения:

    • setup:active - как клиент

    • setup:passive - как сервер

    • setup:actpass - спросить другого WebRTC агента

  • ice-ufrag - имя пользователя для аутентификации ICE-трафика. При реализации своего webrtc-сервера (называем его агентом), это просто случайная строка определенной длины.

  • ice-pwd - пароль для аутентификации ICE-трафика. Точно также генерируется из случайных букв.

  • rtpmap - используется для мапинга кодека на RTP payload тип.

  • fmtp - дополнительные значения для одного типа payload. Используется для указания настроек кодирования или видеопрофиля.

  • candidate - здесь указываются ICE-кандидаты. В самом простейшем случае (ICE light) здесь указываются транспортные адреса локальных интерфейсов ICE-агента. Проще говоря, при запуске Webrtc сессии на вашем компьютере собираются все сетевые интерфейсы, кроме loop и тех, которые отключены (DOWN). Далее биндятся на найденые IP-адреса этих интерфейсов слушатели (поднимаются маленькие сервера), система назначает случайные порты. Вот эти вот все "маленькие сервера" и есть ICE-кандидаты, то есть это интерфейсы, через которые потенциально можно соединиться с вашим компьютером (или телефоном) напрямую. Локальные ICE-кандидаты имеют наивысший приоритет. Далее идут по приоритету ICE-кандидаты - STUN и TURN (когда совсем все плохо с NAT). В данное поле атрибута SDP сообщения записываются найденые ICE-кандидаты, по одному на строчку для каждого медиа-потока.

  • ssrc - Synchronization Source определяет медиа трек

  • label - идентификатор отдельного потока. mslabel - это идентификатор контейнера, который может содержать несколько потоков.

Полный пример SDP-сообщения

v=0
o=- 3546004397921447048 1596742744 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256 0F:74:31:25:CB:A2:13:EC:28:6F:6D:2C:61:FF:5D:C2:BC:B9:DB:3D:98:14:8D:1A:BB:EA:33:0C:A4:60:A8:8E
a=group:BUNDLE 0 1
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=setup:active
a=mid:0
a=ice-ufrag:CsxzEWmoKpJyscFj
a=ice-pwd:mktpbhgREmjEwUFSIJyPINPUhgDqJlSd
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:350842737 cname:yvKPspsHcYcwGFTw
a=ssrc:350842737 msid:yvKPspsHcYcwGFTw DfQnKjQQuwceLFdV
a=ssrc:350842737 mslabel:yvKPspsHcYcwGFTw
a=ssrc:350842737 label:DfQnKjQQuwceLFdV
a=msid:yvKPspsHcYcwGFTw DfQnKjQQuwceLFdV
a=sendrecv
a=candidate:foundation 1 udp 2130706431 192.168.1.1 53165 typ host generation 0
a=candidate:foundation 2 udp 2130706431 192.168.1.1 53165 typ host generation 0
a=candidate:foundation 1 udp 1694498815 1.2.3.4 57336 typ srflx raddr 0.0.0.0 rport 57336 generation 0
a=candidate:foundation 2 udp 1694498815 1.2.3.4 57336 typ srflx raddr 0.0.0.0 rport 57336 generation 0
a=end-of-candidates
m=video 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 0.0.0.0
a=setup:active
a=mid:1
a=ice-ufrag:CsxzEWmoKpJyscFj
a=ice-pwd:mktpbhgREmjEwUFSIJyPINPUhgDqJlSd
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=ssrc:2180035812 cname:XHbOTNRFnLtesHwJ
a=ssrc:2180035812 msid:XHbOTNRFnLtesHwJ JgtwEhBWNEiOnhuW
a=ssrc:2180035812 mslabel:XHbOTNRFnLtesHwJ
a=ssrc:2180035812 label:JgtwEhBWNEiOnhuW
a=msid:XHbOTNRFnLtesHwJ JgtwEhBWNEiOnhuW
a=sendrecv

Вот что мы можем узнать из него:

  • Имеем две медиа-секции (m=): одна для аудио, другая для видео

  • Каждая является sendrecv трансивером, то есть агент может как принимать так и отправлять аудио-видео-данные.

  • Имеем ICE-кандидатов (a=candidate), и параметры аутентификации (a=ice-ufrag, a=ice-pwd), при этом указан атрибут a=group:BUNDLE, что означает, что потоки будут передаваться через одну коннекцию

  • Имеем отпечаток сертификата для проверки хендшейка DTLS соединения

В общем-то это основное, что нужно знать о сигналинге в WebRTC. В следующих версиях книги https://webrtcforthecurious.com/ обещают описать повторное соединение (renegotiation) и simulcast (передача нескольких потоков разного качества, битрейта для адаптирования к сложным условиям связи данного пира).

Комментарии (0)