Введение в протокол реального времени (RTP)
Протокол реального времени (RTP), определённый в RFC 3550, является стандартным протоколом IETF, обеспечивающим подключение в реальном времени для обмена данными, требующими приоритета в реальном времени. Эта статья предоставляет обзор того, что такое RTP и как он функционирует в контексте WebRTC.
Примечание: WebRTC фактически использует SRTP (Протокол защищенного реального времени) для обеспечения безопасности и аутентификации обмениваемых данных.
Минимизация задержки особенно важна для WebRTC, так как общение лицом к лицу должно осуществляться с минимальной возможной задержкой. Чем больше задержка между тем, как один пользователь что-то говорит, и тем, как другой его слышит, тем выше вероятность перебивания и других форм путаницы.
Основные характеристики RTP
Прежде чем изучить использование RTP в контексте WebRTC, полезно иметь общее представление о том, что RTP делает и чего не делает. RTP — это протокол передачи данных, задача которого — перемещать данные между двумя конечными точками максимально эффективно при текущих условиях. Эти условия могут быть связаны с чем угодно, от базовых слоёв стека сети до физического подключения к сети, промежуточных сетей, производительности удалённой конечной точки, уровня шума, уровня трафика и так далее.
Так как RTP — это протокол передачи данных, он дополняется тесно связанным протоколом управления RTP (RTCP), который определён в RFC 3550, раздел 6. RTCP добавляет функции, включая мониторинг качества обслуживания (QoS), обмен информацией о участниках и т. п. Он не подходит для полного управления пользователями, членством, разрешениями и т. д., но предоставляет базовые возможности для неограниченной сессии общения нескольких пользователей.
Сам тот факт, что RTCP определён в том же RFC, что и RTP, является подсказкой о том, насколько тесно эти два протокола связаны.
Возможности RTP
Основные преимущества RTP в контексте WebRTC включают:
- Обычно низкая задержка.
- Пакеты имеют порядковый номер и отметку времени для повторного сборки, если они прибывают в неправильном порядке. Это позволяет передавать данные с помощью RTP на транспортных средствах, которые не гарантируют порядок или даже не гарантируют доставку вообще.
- Это означает, что RTP может, но не обязан, использоваться поверх UDP для достижения высокой производительности, а также для функций множественного назначения и контрольной суммы.
- RTP поддерживает многоадресную рассылку; хотя это пока не важно для WebRTC, это может стать важным в будущем, когда WebRTC (в идеале) будет расширен для поддержки многопользовательских разговоров.
- RTP не ограничивается использованием в аудиовизуальной связи. Он может использоваться для любого вида непрерывной или активной передачи данных, включая потоковую передачу данных, активные значки или обновления отображения статуса, или транспорт управляющей и измерительной информации.
Функции, которые RTP не выполняет
Сам RTP не предоставляет все возможные функции, поэтому в WebRTC используются и другие протоколы. Некоторые из наиболее важных функций, которые RTP не включает:
- RTP не гарантирует качество обслуживания (QoS).
- Хотя RTP предназначен для использования в сценариях с критическим значением задержки, он не предоставляет встроенных функций, гарантирующих качество обслуживания. Вместо этого он только предоставляет информацию, необходимую для реализации QoS в других частях стека.
- RTP не обрабатывает выделение или резервирование ресурсов, которые могут потребоваться.
В случаях, когда это важно для WebRTC, ими занимаются различные части инфраструктуры WebRTC. Например, RTCP обрабатывает мониторинг качества обслуживания.
RTCPeerConnection и RTP
Каждый RTCPeerConnection имеет методы, предоставляющие доступ к списку транспортных средств RTP, обслуживающих соединение peer. Они соответствуют трём типам транспорта, поддерживаемым RTCPeerConnection:
RTCRtpSender-
RTCRtpSenderобрабатывают кодирование и передачу данныхMediaStreamTrackудалённому участнику. Отправители для данного соединения могут быть получены путём вызоваRTCPeerConnection.getSenders(). RTCRtpReceiver-
RTCRtpReceiverпозволяют просматривать и получать информацию о входящихMediaStreamTrackданных. Получатели соединения могут быть получены путём вызоваRTCPeerConnection.getReceivers(). RTCRtpTransceiver-
RTCRtpTransceiver— это пара из одного отправителя RTP и одного получателя RTP, которые разделяют атрибут SDPmid, что означает, что они используют одну и ту же строку SDP media m (представляющую двусторонний поток SRTP). Они возвращаются методомRTCPeerConnection.getTransceivers(), и каждыйmidи трансмиттер имеют отношение один к одному, причёмmidуникален для каждогоRTCPeerConnection.
Использование RTP для реализации функции «приостановить»
Поскольку потоки для RTCPeerConnection реализованы с использованием RTP и интерфейсов выше, вы можете воспользоваться доступом к внутренностям потоков для внесения корректировок. Среди простейших действий — реализация функции «удержания», при которой участник звонка может нажать кнопку, чтобы отключить микрофон, начать передавать музыку другому участнику и перестать принимать входящий аудиопоток.
Примечание: Этот пример использует современные возможности JavaScript, включая асинхронные функции и оператор await. Это значительно упрощает и делает более читаемым код, работающий с обещаниями, возвращаемыми методами WebRTC.
В примерах ниже мы будем ссылаться на участника, включающего и выключающего режим «удержание», как на локального участника, а на пользователя, помещенного на удержание, как на удаленного участника.
Включение режима удержания
Локальный участник
Когда локальный пользователь решает включить режим удержания, вызывается метод enableHold() ниже. Он принимает в качестве входного параметра MediaStream, содержащий аудио для воспроизведения во время удержания звонка.
async function enableHold(audioStream) {
try {
await audioTransceiver.sender.replaceTrack(audioStream.getAudioTracks()[0]);
audioTransceiver.receiver.track.enabled = false;
audioTransceiver.direction = "sendonly";
} catch (err) {
/* handle the error */
}
}
Три строки кода в блоке try выполняют следующие действия:
- Заменить исходящий аудиопоток на
MediaStreamTrack, содержащий музыку для удержания. - Отключить входящий аудиопоток.
- Переключить аудио-трансивер в режим только отправки.
Это инициирует переподключение RTCPeerConnection, отправив ему событие negotiationneeded, на которое ваш код реагирует, генерируя предложение SDP с помощью RTCPeerConnection.createOffer и отправляя его через сервер сигнализации удаленному участнику.
audioStream, содержащий аудио для воспроизведения вместо аудио микрофона локального участника, может поступать откуда угодно. Один из вариантов — использовать скрытый элемент <audio> и получить его аудиопоток с помощью HTMLAudioElement.captureStream().
Удаленный участник
На удаленном участнике, при получении предложения SDP с направленностью, установленной на "sendonly", мы обрабатываем его с помощью метода holdRequested(), который принимает в качестве входного параметра строку предложения SDP.
async function holdRequested(offer) {
try {
await peerConnection.setRemoteDescription(offer);
await audioTransceiver.sender.replaceTrack(null);
audioTransceiver.direction = "recvonly";
await sendAnswer();
} catch (err) {
/* handle the error */
}
}
Выполненные здесь действия:
- Установить удаленное описание на указанное
offer, вызвавRTCPeerConnection.setRemoteDescription(). - Заменить аудио-трансивер
RTCRtpSenderтрекомnull, что означает отсутствие трека. Это останавливает передачу аудио на трансивере. - Установить свойство
directionаудио-трансивера на"recvonly", что указывает трансиверу принимать аудио, но не передавать его. - Ответ SDP генерируется и отправляется с помощью метода
sendAnswer(), который генерирует ответ с помощьюcreateAnswer(), а затем отправляет полученный SDP другому участнику через службу сигнализации.
Отключение режима удержания
Локальный участник
Когда локальный пользователь нажимает на элемент интерфейса для отключения режима удержания, вызывается метод disableHold(), чтобы начать процесс восстановления нормальной функциональности.
async function disableHold(micStream) {
await audioTransceiver.sender.replaceTrack(micStream.getAudioTracks()[0]);
audioTransceiver.receiver.track.enabled = true;
audioTransceiver.direction = "sendrecv";
}
Это действие обращает шаги, выполненные в enableHold(), следующим образом:
- Трек аудио-трансивера
RTCRtpSenderзаменяется первым аудио-треком указанного потока. - Входящий аудио-трек трансивера снова активируется.
- Направление аудио-трансивера устанавливается на
"sendrecv", что указывает, что он должен снова принимать и отправлять аудиопотоки, а не только отправлять.
Как и при включении удержания, это снова инициирует переподключение, в результате чего ваш код отправляет новое предложение удаленному участнику.
Удаленный участник
Когда удаленный участник получает предложение "sendrecv", он вызывает свой метод holdEnded().
async function holdEnded(offer, micStream) {
try {
await peerConnection.setRemoteDescription(offer);
await audioTransceiver.sender.replaceTrack(micStream.getAudioTracks()[0]);
audioTransceiver.direction = "sendrecv";
await sendAnswer();
} catch (err) {
/* handle the error */
}
}
Шаги, выполненные внутри блока try здесь:
- Полученное предложение сохраняется как удаленное описание путем вызова
setRemoteDescription(). - Метод
replaceTrack()аудио-трансивераRTCRtpSenderиспользуется для установки исходящего аудио-трека на первый трек аудиопотока микрофона. - Направление трансивера устанавливается на
"sendrecv", что указывает на возобновление приема и отправки аудио.
С этого момента микрофон снова активирован, и удаленный пользователь снова может слышать и разговаривать с локальным пользователем.
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Intro_to_RTP