В октябре прошло года мы объявили о нашем намерении поддержать ORTC в Microsoft Edge с особым фокусом на аудио/видео-коммуникации. С тех пор мы много над этим работали и сегодня рады анонсировать, что превью-версия нашей реализации доступна в свежей сборке Edge в рамках программы Windows Insider.



Поддержка ORTC в Microsoft Edge является результатом сотрудничества между командами операционных систем (OSG) и Skype. Объединив вместе 20-летний опыт построения веб-платформы и 12-летний опыт создания одного из крупнейших сервисов коммуникации в реальном времени для обычных и бизнес-пользователей, мы поставили перед собой цель сделать возможным построение в браузере опыта общения не только с пользователями Skype, но и другими коммуникационными сервисами, совместимыми c WebRTC.

Смотря в будущее, мы надеемся увидеть множество решений от сообщества, которые станут возможными благодаря использованию ORTC. В свою очередь, мы хотим подробнее рассказать, что включает наша предварительная реализация ORTC, и показать на простом примере, как построить аудио- и видео-коммуникацию в 1:1 сценарии.

Что мы предоставляем


Диаграмма ниже является часть обзорного раздела спецификации ORTC API. Она дает верхнеуровневое описание взаимосвящей между различными объектами ORTC и полезная для иллюстрации взаимодействия отдельных участков кода: от захвата медиа-потоков (треков) до объектов RtpSender, и далее путь к объектам RtpReceiver, которые могут быть направлены в video/audio теги. Мы рекомендуем использовать данную диаграмму в качестве справочного пособия при начале изучения ORTC API.



Наша начальная реализация ORTC включает следующие компоненты:

  • Поддержка ORTC API. Наш основной фокус сейчас – это аудио/видео-коммуникации. Мы реализовали поддержку следующих объектов: IceGatherer, IceTransport, DtlsTransport, RtpSender, RtpReceiver, а также интерфейсы RTCStats, которые напрямую не отображаются на диаграмме.
  • Поддержка пультиплексирования RTP/RTCP (необходима в работе с DtlsTransport). Также поддерживается мультиплексирование аудио/видео.
  • Поддержка STUN/TURN/ICE. Мы доддерживаем STUN (RFC 5389), TURN (RFC 5766) и ICE (RFC 5245). В рамках ICE поддерживает регулярная номинация, в то время, как агрессивный выбор поддерживается частично (для получателя). DTLS-SRTP (RFC 5764) поддерживается на базе DTLS 1.0 (RFC 4347).
  • Поддержка кодеков. Из аудиокодеков мы реализовали поддержку G.711, G.722, Opus и SILK. Мы также поддерживаем Comfort Noise (CN) и DTMF в соответствии с аудио требованиями RTCWEB. Для видео мы пока поддерживаем только кодек H.264UC используемый сервисами Skype (включая такие возможности, как одновременное и масштабируемое кодирование видео и опережающая коррекция ошибок). В будущем мы планируем реализовать совместимую поддержку видео на базе H.264.


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

Если вы знакомы с реализациями WebRTC 1.0 и заинтересованы узнать побольше об эволюции поддержки объектов в рамках WebRTC 1.0 и ORTC, рекумендуем познакомиться со следующей презентацией от Google, Microsoft и Hookflash с конференции IIT RTC 2014: “ORTC API Update.”

Как создать приложение для 1:1-взаимодействия


Теперь давайте обсудим, как от обзорной диаграммы ORTC перейти к реализации в коде простого сценария 1:1 аудио/видео-коммуникации. Для данного специфичного сценария вам понадобятся две машины с Windows 10, работающих в качестве двух клиентов (точек) взаимодействия, и веб-сервер, работающий как сигнализирующий канал для обмена информацией между этими точками, чтобы между ними можно было установить связь.

Шаги ниже относятся к операциями, осуществляемым одним из клиентов. Обе точки должны пройти через схожие шаги, чтобы установить 1:1-взаимодействие. Чтобы лучше прочувствовать примеры кода ниже, рекомендуем в качестве образца реализации использовать наш пример на Microsoft Edge Test Drive.

Шаг #1. Создание объекта MediaStream (например, через Media Capture API) с одним аудио-треком и одним видео-треком.


navigator.MediaDevices.getUserMedia ({
    "audio": true, 
    "video": {
        width: 640,
        height: 360,
        facingMode: "user"
    }
}).then(
    gotStream
).catch(
    gotMediaError
);

function gotStream(stream) {
    var mediaStreamLocal = stream;
    …
}

Подробнее о работе с Media Capture API можно прочитать в нашей статье с анонсом поддержки захвата медиа-сигналов в Microsoft Edge.

Шаг #2. Создать ICE-сборщик, и разрешить локальным кандидатам на установку взаимодействия по ICE-протоколу сообщать о себе удаленным точкам.


var iceOptions = new RTCIceGatherOptions;
iceOptions.gatherPolicy = "all";
iceOptions.iceservers = ... ;
var iceGathr = new RTCIceGatherer(iceOptions);
iceGathr.onlocalcandidate = function(evt) {
    mySignaller.signalMessage({
        "candidate": evt.candidate
    });
};

Чтобы помочь защитить приватность пользователей, мы добавили опцию, позволяющую пользователю контролировать, можно ли IP-адрес локального хоста передавать объектам IceGatherer. Соответствующий интерфейс настройки можно найти в настройках браузера Microsoft Edge.

В нашем примере на Test Drive мы развернули TURN-сервер. У него ограниченная пропускная способность, поэтому мы ограничили его только нашей демонстрационной страницей.

Шаг #3. Создать ICE-транспорт для аудио и видео и подготовиться к обработке удаленных ICE-кандидатов в ICE-транспорте


var iceTr = new RTCIceTransport();
mySignaller.onRemoteCandidate = function(remote) {
    iceTr.addRemoteCandidate(remote.candidate);
}


Другой вариант – это собрать всех удаленных ICE-кандидатов в массив remoteCandidates и вызвать функцию iceTr.setRemoteCandidates(remoteCandidates, чтобы сразу добавить всех удаленных кандидатов.

Шаг #4. Создать DTLS-транспорт


var dtlsTr = new RTCDtlsTransport(iceTr);


Шаг #5. Создать объект отправителя и получателя


var audioTrack = mediaStreamLocal.getAudioTracks()[0];
var videoTrack = mediaStreamLocal.getVideoTracks()[0];
var audioSender = new RtpSender(audioTrack, dtlsTr);
var videoSender = new RtpSender(videoTrack, dtlsTr);
var audioReceiver = new RtpReceiver(dtlsTr, "audio");
var videoReceiver = new RtpReceiver(dtlsTr, "video");


Шаг #6. Запросить возможности отправителя и получателя


var recvAudioCaps = RTCRtpReceiver.getCapabilities("audio"); 
var recvVideoCaps = RTCRtpReceiver.getCapabilities("video"); 
var sendAudioCaps = RTCRtpSender.getCapabilities("audio");
var sendVideoCaps = RTCRtpSender.getCapabilities("video"); 


Шаг #7. Обменяться ICE/DTLS-параметрами и возможностями на получение/отправку.


mySignaller.signalMessage({
    "ice": iceGathr.getLocalParameters(),
    "dtls": dtlsTr.getLocalParameters(),
    "recvAudioCaps": recvAudioCaps, 
    "recvVideoCaps": recvVideoCaps,
    "sendAudioCaps": sendAudioCaps,
    "sendVideoCaps": sendVideoCaps 
};

Шаг #8. Получить параметры удаленной точки, начать работу транспортов ICE и DTLS, установить параметры отправки и получения аудио/видео.


mySignaller.onRemoteParams = function(params) {
    // The responder answers with its preferences, parameters and capabilities
    // Derive the send and receive parameters.
    var audioSendParams = myCapsToSendParams(sendAudioCaps, params.recvAudioCaps); 
    var videoSendParams = myCapsToSendParams(sendVideoCaps, params.recvVideoCaps); 
    var audioRecvParams = myCapsToRecvParams(recvAudioCaps, params.sendAudioCaps);
    var videoRecvParams = myCapsToRecvParams(recvVideoCaps, params.sendVideoCaps); 
    iceTr.start(iceGathr, params.ice, RTCIceRole.controlling);
    dtlsTr.start(params.dtls);
    audioSender.send(audioSendParams);
    videoSender.send(videoSendParams);
    audioReceiver.receive(audioRecvParams);
    videoReceiver.receive(videoRecvParams);
};

Ниже приведен набросок для вспомогательной функции:

RTCRtpParameters function myCapsToSendParams (RTCRtpCapabilities sendCaps, RTCRtpCapabilities remoteRecvCaps) {
    // Function returning the sender RTCRtpParameters, based on intersection of the local sender and remote receiver capabilities.
    // Steps to be followed: 
    // 1. Determine the RTP features that the receiver and sender have in common. 
    // 2. Determine the codecs that the sender and receiver have in common.
    // 3. Within each common codec, determine the common formats and rtcpFeedback mechanisms.
    // 4. Determine the payloadType to be used, based on the receiver preferredPayloadType. 
    // 5. Set RTCRtcpParameters such as mux to their default values.  
}
 
RTCRtpParameters function myCapsToRecvParams(RTCRtpCapabilities recvCaps, RTCRtpCapabilities remoteSendCaps) {
    return myCapsToSendParams(remoteSendCaps, recvCaps);
}

Шаг #9. Отобразить и начать проигрывание удаленных медиа-потоков через video-тег


var videoRenderer = document.getElementById("myRtcVideoTag");
var mediaStreamRemote = new MediaStream();
mediaStreamRemote.addTrack(audioReceiver.track); 
mediaStreamRemote.addTrack(videoReceiver.track);
videoRenderer.srcObject = mediaStreamRemote;
videoRenderer.play();

В целом, это основные шаги при написании года. Как мы сказали, наш пример работы с ORTC включает дополнительно показ видео-превью, обработку сообщений об ошибках и др.

Как только вы разберетесь с настройкой 1:1-звонков, вам будет достаточно очевидно, как сделать групповой сеанс, используя топологию сетки, в которой каждая точка имеет 1:1-связь с остальной группой. Так как параллельное дублирование в нашей реализации не работает, вам нужно будет использовать 1:1-сигналы, так что независимые объекты IceGatherer и DtlsTransport будут использоваться для каждого соединения.

Дополнительные детали по реализации ORTC в Microsoft Edge


Мы обновляем нашу реализацию, чтобы соответствовать свежим обновлениям спецификации ORCT. В целом спецификация достаточно стабильна с момента выпуска «призыва к реализации» со стороны ORTC CG, поэтому мы не ожидаем значительных изменений на уровне JavaScript API. В связи с этим нам кажется, что наша реализация готова для того, чтобы начать тестирование кросс-браузерной совместимости на уровне протоколов.

Некоторые ограничения нашей реализации, которые мы должны обозначить:

  • Мы не поддерживаем RTCIceTransportController. Наша реализация обрабатывает команды заморозки/разморозки в ICE на уровне каждого транспорта, поэтому возможность отдачи указаний всем IceTransports не является обязательной. Думаем, это должно быть совместимо с существующими реализациями.
  • RtpListener еще не поддерживается. Это означает что SSRC необходимо указывать заранее в рамках RtpReceiver.
  • Дублирование (создание форка) не поддерживается ни в IceTransport, ни в IceGatherer, ни в DtlsTransport. Решение по реализации дублирования в DtlsTransport все еще обсуждается в ORTC CG.
  • Немультиплексорные RTP/RTCP не поддерживаются в DtlsTransport. При использовании DtlsTransport ваше приложение должно поддерживать мультиплексирование RTP/RTCP.
  • В RTCRtpEncodingParameters в настоящий момент мы игнорируем большинство настроек качества. Однако мы требуем установки атрибутов ‘active’ и ‘ssrc’.
  • Событие icecandidatepairchanged еще не поддерживается. Вы можете прлучить информацию о кандидате на установку связи через метод getNominatedCandidatePair.
  • На сегодня мы не поддерживаем функциональности DataChannel, определяемой спецификацией ORTC.

Что дальше


Хотя наша реализация носит предварительный характер, мы будем рады услышать ваши отзывы. Они помогут нам реализовать полноценную поддержку ORTC в Microsoft Edge в ближайшие месяцы. Наша цель – сделать реализацию стандарта, совместимую с современным вебом и остальными решениями индустрии коммуникаций реального времени в будущем.

На пути к этой цели в ближайшем будущем команда Skype начнет использовать ORTC API в Microsoft Edge, чтобы создать полноценный опыт аудио/видео-коммуникации и взаимодействия в веб-клиентах Skype и Skype for Business. Команда также инвестирует в совместимость со стандартным WebRTC-протоколом, чтобы быть увереными, что Skype работает на ключевых десктопных, мобильных и браузерных платформах. Для разработчиков, которые хотят интегрировать Skype и Skype for Business в свои приложения, Skype Web SDK также будет обновлен с учетом возможности использования ORTC и WebRTC API. Дополнительная информация на эту тему доступна в заметке "Enabling Seamless Communication Experiences for the Web with Skype, Skype for Business, and Microsoft Edge".

Более того, несколько членов ORTC CG плотно работали с нами над ранней адаптацией технологии. Мы планируем продолжить совместную работу над эволюцией технологии WebRTC в сторону “WebRTC Next Version (NV).” Мы ожидаем, что первопроходцы в работе с ORTC скоро начнут делаться своим опытом.

Дополнительные примеры: Связка ORTC + WebRTC, Звонок между ORTC и Twilio.

– Shijun Sun, Principal Program Manager, Microsoft Edge
– Hao Yan, Principal Program Manager, Skype
– Bernard Aboba, Architect, Skype

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


  1. Eternalko
    27.10.2015 18:15

    Под капотом у STCP только TCP или есть поддержка UDP?


    1. kichik
      27.10.2015 20:17

      А что вы понимаете под STCP?


      1. Eternalko
        28.10.2015 13:37

        STCP это транспортный уровень передачи данных в (Web)RTC со времен прадедушки. Поддержки для него нет вроде как нигде и браузеры его эмулируют поверх TCP/UDP.


        1. kichik
          28.10.2015 16:15

          Насколько я вижу, поддержка SCTP уровня в виде соответствующих API еще не реализована, поэтому никакого капота нет

          Это подразумевалось вот тут:

          На сегодня мы не поддерживаем функциональности DataChannel, определяемой спецификацией ORTC.


          1. Eternalko
            29.10.2015 00:02
            -1

            > мы не поддерживаем функциональности DataChannel

            Pfff… Bummer.

            А видео по TCP или UDP летает?