Что такое сигнализация?
Сигнализация — это процесс координации коммуникации. Чтобы приложение WebRTC могло установить звонок, его клиентам необходимо обменяться следующей информацией:
- Сообщения управления сеансом, используемые для открытия или закрытия связи
- Сообщения об ошибках
- Метаданные мультимедиа, такие как кодеки, настройки кодеков, пропускная способность и типы мультимедиа
- Ключевые данные, используемые для установления безопасных соединений
- Сетевые данные, такие как IP-адрес и порт хоста, видимые извне
Этот процесс сигнализации требует от клиентов возможности передавать сообщения друг другу. Этот механизм не реализован в API WebRTC. Вам необходимо реализовать его самостоятельно. Далее в этой статье вы узнаете, как создать службу сигнализации. Однако сначала вам потребуется немного контекста.
Почему сигнализация не определена в WebRTC?
Во избежание избыточности и для максимальной совместимости с существующими технологиями методы и протоколы сигнализации не регламентируются стандартами WebRTC. Этот подход описан в протоколе установления сеанса JavaScript (JSEP) :
Архитектура JSEP также избавляет браузер от необходимости сохранять состояние, то есть выполнять функции сигнального автомата. Это было бы проблематично, если бы, например, сигнальные данные терялись при каждой перезагрузке страницы. Вместо этого сигнальное состояние можно сохранять на сервере.

JSEP требует обмена между участниками предложениями и ответами , упомянутыми выше метаданными медиа. Предложения и ответы передаются в формате протокола описания сеанса (SDP), который выглядит следующим образом:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
Хотите узнать, что на самом деле означает вся эта тарабарщина SDP? Взгляните на примеры от Internet Engineering Task Force (IETF) .
Имейте в виду, что WebRTC разработан таким образом, что предложение или ответ можно настроить перед установкой в качестве локального или удалённого описания, отредактировав значения в тексте SDP. Например, функцию preferAudioCodec()
в appr.tc можно использовать для установки кодека и битрейта по умолчанию. SDP довольно сложно модифицировать с помощью JavaScript, и ведутся дискуссии о том, следует ли в будущих версиях WebRTC использовать JSON. Однако использование SDP имеет ряд преимуществ .
API RTCPeerConnection
и сигнализация: предложение, ответ и кандидат
RTCPeerConnection
— это API, используемый приложениями WebRTC для создания соединения между одноранговыми узлами и передачи аудио и видео.
Для инициализации этого процесса RTCPeerConnection
выполняет две задачи:
- Определите локальные условия медиаконтента, такие как разрешение и возможности кодека. Эти метаданные используются для механизма «предложение-ответ».
- Получите потенциальные сетевые адреса для хоста приложения, известные как кандидаты .
После того, как локальные данные будут выяснены, ими необходимо обменяться с удаленным узлом посредством механизма сигнализации.
Представьте, что Алиса пытается позвонить Еве . Вот полный механизм предложения/ответа во всех подробностях:
- Алиса создает объект
RTCPeerConnection
. - Алиса создает предложение (описание сеанса SDP) с помощью метода
RTCPeerConnection
createOffer()
. - Алиса вызывает
setLocalDescription()
со своим предложением. - Алиса преобразует предложение в строку и использует механизм сигнализации, чтобы отправить его Еве.
- Ева вызывает
setRemoteDescription()
с предложением Алисы, чтобы ееRTCPeerConnection
знал о настройках Алисы. - Ева вызывает
createAnswer()
, и успешному обратному вызову передается локальное описание сеанса — ответ Евы. - Ева задает свой ответ как локальное описание, вызывая
setLocalDescription()
. - Затем Ева использует механизм сигнализации, чтобы отправить свой строковый ответ Алисе.
- Алиса устанавливает ответ Евы в качестве описания удаленного сеанса с помощью
setRemoteDescription()
.
Алисе и Еве также необходимо обмениваться сетевой информацией. Выражение «поиск кандидатов» относится к процессу поиска сетевых интерфейсов и портов с использованием фреймворка ICE .
- Алиса создает объект
RTCPeerConnection
с обработчикомonicecandidate
. - Обработчик вызывается, когда становятся доступны сетевые кандидаты.
- В обработчике Алиса отправляет Еве строковые данные о кандидатах через свой сигнальный канал.
- Когда Ева получает сообщение о кандидате от Алисы, она вызывает
addIceCandidate()
чтобы добавить кандидата в описание удаленного однорангового узла.
JSEP поддерживает технологию ICE Candidate Trickling , которая позволяет вызывающему абоненту постепенно предоставлять кандидатов вызываемому абоненту после первоначального предложения, а вызываемый абонент может начать действовать в рамках вызова и установить соединение, не дожидаясь прибытия всех кандидатов.
Код WebRTC для сигнализации
Следующий фрагмент кода представляет собой пример кода W3C , описывающий весь процесс сигнализации. Код предполагает наличие некоего механизма сигнализации, SignalingChannel
. Сигнализация будет подробно рассмотрена далее.
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
Чтобы увидеть процессы «предложение/ответ» и «обмен кандидатами» в действии, см. раздел RTCPeerConnection на сайте simpl.info и пример одностраничного видеочата в журнале консоли. Для получения дополнительной информации загрузите полный дамп сигналов и статистики WebRTC со страницы about://webrtc-internals в Google Chrome или со страницы opera://webrtc-internals в Opera.
Открытие сверстников
Это изящный способ спросить: «Как мне найти человека, с которым можно поговорить?»
Для телефонных звонков нужны телефонные номера и справочники. Для онлайн-видеочатов и обмена сообщениями необходимы системы управления идентификацией и присутствием, а также средства для инициирования сеансов пользователями. Приложениям WebRTC необходимо, чтобы клиенты могли сообщать друг другу о желании начать звонок или присоединиться к нему.
Механизмы обнаружения одноранговых участников не определены в WebRTC, и здесь не нужно вникать в их параметры. Процесс может быть таким же простым, как отправка URL-адреса по электронной почте или в сообщении. В приложениях для видеочатов, таких как Talky , tawk.to и Browser Meeting , вы приглашаете участников к звонку, делясь пользовательской ссылкой. Разработчик Крис Болл провёл интересный эксперимент с использованием бессерверного WebRTC , который позволяет участникам WebRTC-звонка обмениваться метаданными через любой удобный им сервис обмена сообщениями, например, IM, электронную почту или почтовые голуби.
Как построить сигнальную службу?
Повторюсь, протоколы и механизмы сигнализации не определены стандартами WebRTC. Какой бы вариант вы ни выбрали, вам понадобится промежуточный сервер для обмена сигнальными сообщениями и данными приложения между клиентами. К сожалению, веб-приложение не может просто крикнуть в интернет: «Соедините меня с моим другом!»
К счастью, сигнальные сообщения небольшие и передаются в основном в начале разговора. В ходе тестирования сеанса видеочата с appr.tc сигнальная служба обработала в общей сложности около 30–45 сообщений общим размером около 10 КБ.
Помимо того, что службы сигнализации WebRTC относительно нетребовательны к пропускной способности, они не потребляют много вычислительных ресурсов или памяти, поскольку им нужно только передавать сообщения и сохранять небольшой объем данных о состоянии сеанса, например, о том, какие клиенты подключены.
Передача сообщений с сервера на клиент
Служба сообщений для сигнализации должна быть двунаправленной: клиент-сервер и сервер-клиент. Двунаправленная связь противоречит HTTP-модели «запрос-ответ» клиент-сервер, но за многие годы были разработаны различные способы, такие как длинные опросы, для передачи данных из службы, работающей на веб-сервере, в веб-приложение, работающее в браузере.
В последнее время широкое распространение получил API EventSource
. Он позволяет обрабатывать события, отправленные сервером, — данные, отправляемые с веб-сервера в браузер клиента по протоколу HTTP. EventSource
предназначен для одностороннего обмена сообщениями, но его можно использовать в сочетании с XHR для создания сервиса обмена сигнальными сообщениями. Сервис сигнализации передаёт сообщение от вызывающего объекта, доставленное XHR-запросом, через EventSource
вызываемому объекту.
WebSocket — более естественное решение, разработанное для полнодуплексного клиент-серверного взаимодействия, когда сообщения могут передаваться в обоих направлениях одновременно. Одним из преимуществ сигнальной службы, построенной на чистом WebSocket или событиях, отправляемых сервером ( EventSource
), является то, что бэкенд для этих API может быть реализован на различных веб-фреймворках, распространённых в большинстве пакетов веб-хостинга для таких языков, как PHP, Python и Ruby.
Все современные браузеры, кроме Opera Mini, поддерживают WebSocket , и, что ещё важнее, все браузеры с поддержкой WebRTC также поддерживают WebSocket, как на настольных компьютерах, так и на мобильных устройствах. Для всех соединений следует использовать TLS , чтобы предотвратить перехват незашифрованных сообщений и снизить проблемы с обходом прокси-сервера . (Подробнее о WebSocket и обходе прокси-сервера см. в главе о WebRTC в книге Ильи Григорика «Высокопроизводительные сетевые браузеры» .)
Также можно организовать сигнализацию, заставив WebRTC-клиентов многократно опрашивать сервер обмена сообщениями через Ajax, но это приводит к большому количеству избыточных сетевых запросов, что особенно проблематично для мобильных устройств. Даже после установления сеанса одноранговые узлы должны опрашивать сигнальные сообщения в случае изменений или завершения сеанса другими одноранговыми узлами. В примере приложения WebRTC Book этот вариант реализован с некоторой оптимизацией частоты опроса.
Масштабная сигнализация
Хотя сигнальная служба потребляет относительно мало полосы пропускания и ресурсов процессора на клиента, сигнальным серверам популярного приложения может потребоваться обрабатывать множество сообщений из разных источников с высоким уровнем параллелизма. Приложениям WebRTC с большим трафиком требуются сигнальные серверы, способные выдерживать значительную нагрузку. Мы не будем вдаваться в подробности, но существует ряд вариантов для высокопроизводительной передачи больших объёмов сообщений, включая следующие:
eXtensible Messaging and Presence Protocol (XMPP), изначально известный как Jabber — протокол, разработанный для обмена мгновенными сообщениями, который можно использовать для сигнализации (серверные реализации включают ejabberd и Openfire . Клиенты JavaScript, такие как Strophe.js , используют BOSH для эмуляции двунаправленной потоковой передачи, но по разным причинам BOSH может быть не таким эффективным, как WebSocket, и по тем же причинам может плохо масштабироваться.) (Кстати, Jingle — это расширение XMPP для поддержки голоса и видео. Проект WebRTC использует сетевые и транспортные компоненты из библиотеки libjingle — реализации Jingle на C++.)
Библиотеки с открытым исходным кодом, такие как ZeroMQ (которую использует TokBox для своей службы Rumour ) и OpenMQ ( NullMQ применяет концепции ZeroMQ к веб-платформам, используя протокол STOMP по протоколу WebSocket).
Коммерческие облачные платформы обмена сообщениями, использующие WebSocket (хотя они могут прибегать к длительному опросу), такие как Pusher , Kaazing и PubNub (PubNub также имеет API для WebRTC ).
Коммерческие платформы WebRTC, такие как vLine
( Руководство разработчика Фила Леггеттера по технологиям веб в реальном времени содержит полный список служб и библиотек обмена сообщениями.)
Создайте сигнальную службу с помощью Socket.io на Node
Ниже представлен код простого веб-приложения, использующего сигнальный сервис, созданный с помощью Socket.io на Node . Архитектура Socket.io упрощает создание сервиса для обмена сообщениями, и Socket.io особенно подходит для сигнализации через WebRTC благодаря встроенной концепции комнат. Этот пример не предназначен для масштабирования до уровня сервиса сигнализации промышленного уровня, но прост для понимания относительно небольшим количеством пользователей.
Socket.io использует WebSocket с запасными вариантами: длинными опросами AJAX, многокомпонентной потоковой передачей AJAX, Forever Iframe и опросами JSONP. Он был портирован на различные бэкенды, но, пожалуй, наиболее известен своей версией для Node, использованной в этом примере.
В этом примере WebRTC не используется. Он предназначен только для демонстрации интеграции сигнализации в веб-приложение. Просмотрите журнал консоли, чтобы увидеть, что происходит, когда клиенты присоединяются к комнате и обмениваются сообщениями. В этой лабораторной работе по WebRTC представлены пошаговые инструкции по интеграции этого процесса в полноценное приложение для видеочата на базе WebRTC.
Вот клиентский index.html
:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
Вот файл JavaScript main.js
, на который есть ссылка в клиенте:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
Вот полное серверное приложение:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
(Для этого вам не нужно знать node-static. Он просто используется в этом примере.)
Для запуска этого приложения на локальном хосте необходимо установить Node, Socket.IO и node-static . Node можно скачать с сайта Node.js (установка простая и быстрая). Чтобы установить Socket.IO и node-static, запустите менеджер пакетов Node из терминала в каталоге вашего приложения:
npm install socket.io
npm install node-static
Чтобы запустить сервер, выполните следующую команду из терминала в каталоге вашего приложения:
node server.js
В браузере откройте localhost:2013
. Откройте новую вкладку или окно в любом браузере и снова откройте localhost:2013
. Чтобы увидеть, что происходит, проверьте консоль. В Chrome и Opera доступ к консоли можно получить через Инструменты разработчика Google Chrome, нажав Ctrl+Shift+J
(или Command+Option+J
на Mac).
Какой бы подход вы ни выбрали для сигнализации, ваше бэкэнд-приложение и клиентское приложение, как минимум, должны предоставлять службы, аналогичные этому примеру.
Сигнальные ошибки
-
RTCPeerConnection
не начнёт сбор кандидатов, пока не будет вызванsetLocalDescription()
. Это предписано в проекте JSEP IETF . - Воспользуйтесь преимуществами Trickle ICE. Вызывайте
addIceCandidate()
сразу после появления кандидатов.
Готовые сигнальные серверы
Если вы не хотите разрабатывать свой собственный сервер, существует несколько сигнальных серверов WebRTC, которые используют Socket.IO, как и предыдущий пример, и интегрированы с клиентскими библиотеками JavaScript для WebRTC:
- webRTC.io — одна из первых библиотек абстракции для WebRTC.
- Signalmaster — это сигнальный сервер, созданный для использования с клиентской библиотекой JavaScript SimpleWebRTC .
Если вы вообще не хотите писать код, то существуют готовые коммерческие платформы WebRTC от таких компаний, как vLine , OpenTok и Asterisk .
Кстати, Ericsson создал сигнальный сервер на PHP на Apache ещё в ранние годы WebRTC. Сейчас он уже несколько устарел, но стоит взглянуть на его код, если вы рассматриваете что-то подобное.
Безопасность сигнализации
«Безопасность — это искусство не допускать ничего.»
Салман Рушди
Шифрование обязательно для всех компонентов WebRTC.
Однако механизмы сигнализации не определены стандартами WebRTC, поэтому обеспечение безопасности сигнализации зависит от вас. Если злоумышленнику удастся перехватить сигнализацию, он сможет останавливать сеансы, перенаправлять соединения, а также записывать, изменять или внедрять контент.
Важнейшим фактором безопасности сигнализации является использование защищенных протоколов HTTPS и WSS (например, TLS), которые гарантируют невозможность перехвата незашифрованных сообщений. Кроме того, будьте осторожны и не передавайте сигнальные сообщения таким образом, чтобы к ним могли получить доступ другие абоненты, использующие тот же сигнальный сервер.
После сигнализации: используйте ICE для работы с NAT и брандмауэрами
Для передачи метаданных приложения WebRTC используют промежуточный сервер, но для фактической потоковой передачи мультимедиа и данных после установления сеанса RTCPeerConnection
пытается подключить клиентов напрямую или по одноранговой связи.
В более простом мире каждая конечная точка WebRTC имела бы уникальный адрес, которым она могла бы обмениваться с другими узлами для прямого взаимодействия.

В реальности большинство устройств находятся за одним или несколькими уровнями NAT , некоторые оснащены антивирусным ПО, блокирующим определённые порты и протоколы, а многие находятся за прокси-серверами и корпоративными брандмауэрами. На самом деле, брандмауэр и NAT могут быть реализованы одним и тем же устройством, например, домашним Wi-Fi-роутером.

Приложения WebRTC могут использовать фреймворк ICE для решения задач, связанных с реальными сетями. Для этого ваше приложение должно передавать URL-адреса серверов ICE в RTCPeerConnection
, как описано в этой статье.
ICE пытается найти наилучший путь для соединения одноранговых узлов. Он параллельно пробует все варианты и выбирает наиболее эффективный из работающих. Сначала ICE пытается установить соединение, используя адрес хоста, полученный из операционной системы и сетевой карты устройства. Если это не удаётся (что случается с устройствами за NAT), ICE получает внешний адрес с помощью STUN-сервера, и, если это не удается, трафик маршрутизируется через TURN-сервер-ретранслятор.
Другими словами, сервер STUN используется для получения внешнего сетевого адреса, а серверы TURN используются для ретрансляции трафика в случае сбоя прямого (однорангового) соединения.
Каждый TURN-сервер поддерживает STUN. TURN-сервер — это STUN-сервер с дополнительными встроенными функциями ретрансляции. ICE также справляется со сложными настройками NAT. В действительности, для обхода NAT может потребоваться нечто большее, чем просто публичный адрес в паре «IP:порт».
URL-адреса серверов STUN и/или TURN (опционально) указываются приложением WebRTC в объекте конфигурации iceServers
, который является первым аргументом конструктора RTCPeerConnection
. Для appr.tc это значение выглядит следующим образом:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
Как только RTCPeerConnection
получает эту информацию, волшебство ICE происходит автоматически. RTCPeerConnection
использует фреймворк ICE для определения оптимального пути между одноранговыми узлами, взаимодействуя при необходимости с серверами STUN и TURN.
ОГЛУШЕНИЕ
NAT предоставляет устройству IP-адрес для использования внутри частной локальной сети, но этот адрес не может быть использован извне. Без публичного адреса невозможно взаимодействие между пирами WebRTC. Чтобы обойти эту проблему, WebRTC использует STUN .
STUN-серверы находятся в публичном интернете и выполняют одну простую задачу: проверяют адрес IP:порт входящего запроса (от приложения, работающего за NAT) и отправляют этот адрес обратно в качестве ответа. Другими словами, приложение использует STUN-сервер для определения своего IP:порта с точки зрения публичного устройства. Этот процесс позволяет пиру WebRTC получить свой общедоступный адрес и передать его другому пиру через сигнальный механизм для установления прямого соединения. (На практике разные NAT работают по-разному, и может быть несколько уровней NAT, но принцип остаётся тем же.)
От серверов STUN не требуется многого: они не обладают слишком высокой производительностью и не запоминают много данных, поэтому серверы STUN с относительно низкими техническими характеристиками могут обрабатывать большое количество запросов.
Большинство вызовов WebRTC успешно устанавливают соединение с использованием STUN — 86% по данным Webrtcstats.com , хотя этот показатель может быть ниже для вызовов между одноранговыми устройствами за брандмауэрами и сложными конфигурациями NAT.

ПОВЕРНУТЬ
RTCPeerConnection
пытается установить прямое соединение между одноранговыми узлами по протоколу UDP. В случае неудачи RTCPeerConnection
переходит на TCP. В противном случае в качестве резервного варианта можно использовать TURN-серверы для ретрансляции данных между конечными точками.
Еще раз напомним, что TURN используется для ретрансляции аудио, видео и потоковых данных между одноранговыми узлами, а не для передачи данных!
У TURN-серверов есть публичные адреса, поэтому к ним могут обращаться одноранговые узлы, даже если они находятся за брандмауэрами или прокси-серверами. Задача TURN-серверов, по сути, проста — ретрансляция потока. Однако, в отличие от STUN-серверов, они изначально потребляют большой объём полосы пропускания. Другими словами, TURN-серверам требуется больше ресурсов.

На этой диаграмме показан TURN в действии. Чистый STUN не сработал, поэтому каждый одноранговый узел прибегает к использованию TURN-сервера.
Развертывание серверов STUN и TURN
Для тестирования Google использует публичный STUN-сервер stun.l.google.com:19302, используемый appr.tc. Для производственной эксплуатации STUN/TURN-сервера используйте rfc5766-turn-server. Исходный код STUN- и TURN-серверов доступен на GitHub , где также можно найти ссылки на несколько источников информации об установке серверов. Также доступен образ виртуальной машины для Amazon Web Services .
Альтернативный TURN-сервер — Restund, доступный в виде исходного кода , а также для AWS. Ниже приведены инструкции по настройке Restund в Compute Engine.
- При необходимости откройте брандмауэр для tcp=443, udp/tcp=3478.
- Создайте четыре экземпляра, по одному для каждого публичного IP-адреса, стандартный образ Ubuntu 12.06.
- Настройте конфигурацию локального брандмауэра (разрешите ЛЮБОЙ из ЛЮБОГО).
- Инструменты для установки:
shell sudo apt-get install make sudo apt-get install gcc
- Установить libre с creytiv.com/re.html .
- Загрузите restund с сайта creytiv.com/restund.html и распакуйте.
-
wget
hancke.name/restund-auth.patch и примените с помощьюpatch -p1 < restund-auth.patch
. - Запустите
make
,sudo make install
для libre и restund. - Адаптируйте
restund.conf
под свои нужды (замените IP-адреса и убедитесь, что он содержит тот же общий секрет) и скопируйте в/etc
. - Скопируйте
restund/etc/restund
в/etc/init.d/
. - Настроить рестунд:
- Установите
LD_LIBRARY_PATH
. - Скопируйте
restund.conf
в/etc/restund.conf
. - Настройте
restund.conf
на использование правильного 10. IP-адреса.
- Установите
- Run restund
- Тест с использованием клиента stund с удаленной машины:
./client IP:port
Больше, чем просто «один к одному»: многопользовательский WebRTC
Вы также можете ознакомиться с предложенным Джастином Уберти стандартом IETF для REST API для доступа к службам TURN .
Легко представить себе сценарии использования потоковой передачи мультимедиа, выходящие за рамки простого личного звонка. Например, видеоконференция между группой коллег или публичное мероприятие с одним докладчиком и сотнями или миллионами зрителей.
Приложение WebRTC может использовать несколько соединений RTCPeerConnection, чтобы каждая конечная точка подключалась к каждой другой конечной точке в конфигурации mesh. Этот подход используется в таких приложениях, как talky.io , и отлично работает для небольшого количества одноранговых сетей. При превышении этого лимита потребление ресурсов процессора и пропускной способности становится чрезмерным, особенно для мобильных клиентов.

В качестве альтернативы, приложение WebRTC может выбрать одну конечную точку для распределения потоков по всем остальным в конфигурации «звезда». Также можно запустить конечную точку WebRTC на сервере и создать собственный механизм перераспределения ( пример клиентского приложения доступен на сайте webrtc.org).
Начиная с Chrome 31 и Opera 18, MediaStream
из одного RTCPeerConnection
может использоваться в качестве входных данных для другого. Это позволяет создавать более гибкие архитектуры, поскольку позволяет веб-приложению управлять маршрутизацией вызовов, выбирая, к какому другому одноранговому узлу подключиться. Чтобы увидеть это в действии, см. примеры WebRTC «Ретрансляция однорангового соединения» и примеры WebRTC «Множественные одноранговые соединения» .
Многоточечный блок управления
Для большого количества конечных точек лучшим вариантом является использование многоточечного блока управления (MCU). Это сервер, который служит мостом для распределения медиаконтента между большим количеством участников. MCU могут работать с различными разрешениями, кодеками и частотой кадров в видеоконференции, выполнять перекодирование, выборочную переадресацию потоков, а также микшировать или записывать аудио и видео. При многосторонних вызовах необходимо учитывать ряд вопросов, в частности, как отображать несколько видеовходов и микшировать аудио из разных источников. Облачные платформы, такие как vLine , также стремятся оптимизировать маршрутизацию трафика.
Можно купить полный комплект оборудования MCU или собрать свой собственный.

Доступно несколько вариантов программного обеспечения для микроконтроллеров с открытым исходным кодом. Например, Licode (ранее известный как Lynckia) выпускает микроконтроллеры с открытым исходным кодом для WebRTC. У OpenTok есть Mantis .
За пределами браузеров: VoIP, телефоны и обмен сообщениями
Стандартизированная природа WebRTC позволяет устанавливать связь между приложением WebRTC, работающим в браузере, и устройством или платформой, работающей на другой коммуникационной платформе, например, телефоном или системой видеоконференцсвязи.
SIP — это протокол сигнализации, используемый системами VoIP и видеоконференцсвязи. Для обеспечения связи между веб-приложением WebRTC и SIP-клиентом, например, системой видеоконференцсвязи, WebRTC необходим прокси-сервер для передачи сигналов. Сигнализация должна проходить через шлюз, но после установления соединения трафик SRTP (видео и аудио) может передаваться напрямую между узлами.
Телефонная сеть общего пользования (PSTN) — это сеть с коммутацией каналов, используемая всеми «старыми» аналоговыми телефонами. Для звонков между веб-приложениями WebRTC и телефонами трафик должен проходить через шлюз PSTN. Аналогично, веб-приложениям WebRTC необходим промежуточный XMPP-сервер для взаимодействия с конечными точками Jingle , такими как клиенты обмена мгновенными сообщениями. Jingle был разработан Google как расширение XMPP для обеспечения голосовой и видеосвязи в службах обмена сообщениями. Текущие реализации WebRTC основаны на библиотеке C++ libjingle , реализации Jingle, изначально разработанной для Talk.
Ряд приложений, библиотек и платформ используют возможности WebRTC для связи с внешним миром:
- sipML5 : JavaScript SIP-клиент с открытым исходным кодом
- jsSIP : библиотека JavaScript SIP
- Phono : API телефона на JavaScript с открытым исходным кодом, созданный в виде плагина
- Zingaya : встраиваемый виджет телефона
- Twilio : голосовое управление и обмен сообщениями
- Uberconference : конференц-связь
Разработчики sipML5 также создали шлюз webrtc2sip . Tethr и Tropo продемонстрировали фреймворк для экстренной связи «в портфеле» с использованием соты OpenBTS , обеспечивающей связь между обычными телефонами и компьютерами через WebRTC. Это телефонная связь без оператора!
Узнать больше
В лабораторной работе WebRTC представлены пошаговые инструкции по созданию приложения для видео- и текстового чата с использованием сигнальной службы Socket.io, работающей на Node.
Презентация Google I/O WebRTC 2013 года с техническим руководителем WebRTC Джастином Уберти
Презентация Криса Уилсона SFHTML5 — Введение в приложения WebRTC
Книга объемом 350 страниц «WebRTC: API и протоколы RTCWEB HTML5 Real-Time Web» содержит массу подробностей о путях передачи данных и сигналов, а также включает ряд подробных схем топологии сети.
WebRTC и сигнализация: чему нас научили два года — запись в блоге TokBox о том, почему исключение сигнализации из спецификации было хорошей идеей
Практическое руководство по созданию приложений WebRTC Бена Стрэнга содержит обширную информацию о топологиях и инфраструктуре WebRTC.
Глава, посвященная WebRTC, в книге Ильи Григорика « Высокопроизводительные сетевые браузеры» подробно рассматривает архитектуру WebRTC, варианты использования и производительность.