Web Call Server без Web SDK

Tachyon

New Member
Здравствуйте. Заинтересовали возможности Web Call Server, в первую очередь встроенная поддержка RTSP, но есть один принципиальный вопрос:
Возможно ли работать с сервером без Web SDK (и, соответственно, без загрузки flashphoner.js на сторону клиента), используя только стандартные функции WebRTC - getUserMedia и RTCPeerConnection?
Поддержка кроссбраузерности не требуется, планируется использовать браузеры с нативной поддержкой WebRTC.

Если такая возможность есть, скажите, пожалуйста, можно ли где-нибудь увидеть краткий и простой пример такого подключения к тестовому серверу (wss://wcs5-eu.flashphoner.com:8443)?
Что-то типа вот этой инструкции, но без flashphoner.js. В общем, что-нибудь, чтобы я мог быстро продемонстрировать начальству, а вдумчиво читать документацию уже потом - если будет принято решение в пользу Web Call Server.
Заранее спасибо.
 

camaro396

Member
Можно при билде из исходников вырезать ненужные MediaProvider и оставить WebRTC. Получится файлик порядка 150 Кб в минифицированном виде. Мне кажется, это лучше, чем с нуля писать, WebRTC - лес густой :)
 

camaro396

Member
Просто там же ещё и управляющее соединение через вебсокет, всё равно придётся смотреть исходники.
 

Tachyon

New Member
Если работа с Web Call Server невозможна через нативный WebRTC, боюсь, придется искать дальше другие серверные решения, или изобретать велосипед самим.
 

camaro396

Member
Хм... WebRTC там вполне себе нативный. Значит, дём комментариев от разработчиков.
 

Max

Administrator
Staff member
Добрый день.

только стандартные функции WebRTC - getUserMedia и RTCPeerConnection?
Реализация Web SDK как раз использует стандартные нативные функции WebRTC правда через WebRTC адаптер для кроссбраузерности.
Несмотря на то, что функции стандартные, в разных WebRTC браузерах они могут работать немного по-разному, требовать разные параметры, адаптации, и т.д.
Поэтому одна из функций Web SDK - адаптация к браузерами и их особенностям реализации WebRTC. Например в мобильных браузерах пользователю нужно кликнуть (сделать действие) чтобы начать играть поток.

В любом случае, перечисленных двух функций не хватит, т.к. требуется обмен SDP (информацией о кодеках и потоках).
Обмен этой информацией идет через Websocket. Т.е. вторая функция Web SDK - это реализация сигналинга.

Если такая возможность есть, скажите, пожалуйста, можно ли где-нибудь увидеть краткий и простой пример такого подключения к тестовому серверу
Самый простой способ - посмотреть websocket фреймы.
Пример в Chrome:
https://demo.flashphoner.com/client2/examples/demo/streaming/player/player.html

upload_2018-7-31_14-42-26.png


1. Подключение к серверу.
Code:
{"message":"connection","data":[{"appKey":"defaultApp","mediaProviders":["WebRTC","MSE","WSPlayer"],"clientVersion":"0.5.28","clientOSVersion":"5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36","clientBrowserVersion":"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"}]}
2. Подтверждение коннекта от сервера.
Code:
{"message":"getUserData","data":[{"useWsTunnel":false,"useWsTunnelPacketization2":false,"useBase64BinaryEncoding":false,"mediaProviders":["WebRTC","MSE","WSPlayer"],"authToken":"/202.210.205.45:64372/188.40.244.249:8443","status":"ESTABLISHED","clientVersion":"0.5.28","clientOSVersion":"5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36","clientBrowserVersion":"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36","keepAlive":false}]}
3. Запрос на воспроизведение потока.
Code:
{"message":"playStream","data":[{"mediaSessionId":"2bc4b5f0-9495-11e8-83a7-192d3c9f0b3f","name":"rtsp://str81.creacast.com/grandlilletv/low","published":false,"hasVideo":true,"hasAudio":true,"status":"PENDING","record":false,"width":0,"height":0,"mediaProvider":"WebRTC","sdp":"v=0\r\no=- 8918722932488166491 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:BumE\r\na=ice-pwd:nFl572IoWaEumzS2g63GnyT7\r\na=ice-options:trickle\r\na=fingerprint:sha-256 20:6E:21:BA:DA:31:76:07:75:69:10:01:76:1E:77:AF:25:8A:F3:BC:15:22:0A:1F:C6:33:65:53:F8:EA:67:10\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=recvonly\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:BumE\r\na=ice-pwd:nFl572IoWaEumzS2g63GnyT7\r\na=ice-options:trickle\r\na=fingerprint:sha-256 20:6E:21:BA:DA:31:76:07:75:69:10:01:76:1E:77:AF:25:8A:F3:BC:15:22:0A:1F:C6:33:65:53:F8:EA:67:10\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:123 rtx/90000\r\na=fmtp:123 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 red/90000\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 ulpfec/90000\r\n","bitrate":0,"minBitrate":0,"maxBitrate":0,"quality":0}]}
4. Получение SDP от сервера.
Code:
{"message":"setRemoteSDP","data":["2bc4b5f0-9495-11e8-83a7-192d3c9f0b3f","v=0\r\no=Flashphoner 0 1533022817048 IN IP4 188.40.244.249\r\ns=Flashphoner/1.0\r\nc=IN IP4 188.40.244.249\r\nt=0 0\r\nm=audio 31898 RTP/SAVPF 111 8 9\r\nc=IN IP4 188.40.244.249\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:9 G722/8000\r\na=ptime:20\r\na=ice-pwd:vijhfobbbptcado8rcghpjaus\r\na=ice-ufrag:2bc4b5f0-9495-11e8-83a7-192d3c9f0b3ffntk71cjnkfion\r\na=fingerprint:SHA-256 60:FF:50:FA:58:EB:37:21:33:63:A5:91:FA:30:18:8E:A0:C3:F5:F9:70:13:33:F6:14:86:6C:C9:7D:7B:1A:AA\r\na=candidate:1 1 udp 2130706431 188.40.244.249 31898 typ host\r\na=candidate:1 2 udp 2130706431 188.40.244.249 31898 typ host\r\na=end-of-candidates\r\na=rtcp-mux\r\na=rtcp:31898 IN IP4 188.40.244.249\r\na=sendonly\r\na=ssrc:789120446 cname:rtp/audio/2bc4b5f0-9495-11e8-83a7-192d3c9f0b3f\r\nm=video 31950 RTP/SAVPF 100 102 127 125 96\r\nc=IN IP4 188.40.244.249\r\na=rtpmap:100 H264/90000\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:102 H264/90000\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:127 H264/90000\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:125 H264/90000\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:* ccm fir\r\na=rtcp-fb:* nack\r\na=rtcp-fb:* nack pli\r\na=rtcp-fb:* goog-remb\r\na=ice-pwd:vijhfobbbptcado8rcghpjaus\r\na=ice-ufrag:2bc4b5f0-9495-11e8-83a7-192d3c9f0b3ffntk71cjnkfion\r\na=fingerprint:SHA-256 60:FF:50:FA:58:EB:37:21:33:63:A5:91:FA:30:18:8E:A0:C3:F5:F9:70:13:33:F6:14:86:6C:C9:7D:7B:1A:AA\r\na=candidate:1 1 udp 2130706431 188.40.244.249 31950 typ host\r\na=candidate:1 2 udp 2130706431 188.40.244.249 31950 typ host\r\na=end-of-candidates\r\na=rtcp-mux\r\na=rtcp:31950 IN IP4 188.40.244.249\r\na=sendonly\r\na=ssrc:1950636409 cname:rtp/video/2bc4b5f0-9495-11e8-83a7-192d3c9f0b3f\r\n",true]}
5. Подтверждение воспроизведения и статус PLAYING.
Code:
{"message":"notifyStreamStatusEvent","data":[{"mediaSessionId":"2bc4b5f0-9495-11e8-83a7-192d3c9f0b3f","name":"rtsp://str81.creacast.com/grandlilletv/low","published":false,"hasVideo":true,"hasAudio":true,"status":"PLAYING","audioCodec":"opus","videoCodec":"H264","info":"Unknown","record":false,"width":0,"height":0,"bitrate":0,"minBitrate":0,"maxBitrate":0,"quality":0,"timeShift":-1,"createDate":1533022817047,"streamInfo":{"nodeId":null,"appKey":null,"sessionId":null,"mediaSessionId":"2bc4b5f0-9495-11e8-83a7-192d3c9f0b3f","name":"rtsp://str81.creacast.com/grandlilletv/low","samplingTime":null,"recordTimestamp":null,"recordStarted":false},"mediaProvider":"WebRTC"}]}
Эти 5 вызовов и есть сигналинг и обмен SDP.
Обмен SDP происходит на шаге 3 и 4.
Если у вас есть SDP вы можете уже писать кастомный WebRTC код, который использует стандартные функции. Т.е. использовать websocket только для сигналинга с сервером и обмена SDP.

Текущую реализацию можно найти здесь:
https://github.com/flashphoner/flashphoner_client/blob/wcs_api-2.0/src/webrtc-media-provider.js
 

Tachyon

New Member
Несмотря на то, что функции стандартные, в разных WebRTC браузерах они могут работать немного по-разному
Я знаю. Но нам требуется только один браузер. Это промышленное решение, и выбор клиентского ПО за нами. В идеале - три (chrome, firefox и opera), поддержка мобильных браузеров не нужна в принципе.
Текущую реализацию можно найти здесь
Спасибо. Разобрать 50 кб кода намного проще, чем мегабайт. К сожалению, это тоже не вполне подходит под определение "быстрого простого примера", т.к. требует детального разбора функций, что и как вызывать из html для организации, например, трансляции видео с веб-камеры, как в прекрасном и наглядном примере с хабра, который я упоминал в начале.

Возможно, впоследствии мы используем adapter.js от разработчиков стандарта для обеспечения совместимости нужных браузеров. Возможно, используем оболочку типа PeerJS от них же, или будем писать свою. Возможность выбора - необходимое условие. Flasphoner.js не устраивает по целому ряду причин (кроме размера и обилия не требующегося функционала), например, создание элемента video вместо работы с существующими. Разумеется, это все можно изменить, разобравшись в приведенном Вами примере, но это требует времени, при том, что окончательный выбор серверного решения еще не сделан.

К сожалению, мне, как веб-программисту, ранее не приходилось работать с видеопотоками, подбный проект возник впервые, так что приходится учиться на ходу, попутно разбираясь с уже существующими готовыми решениями. Отсюда и пожелание простого работающего примера, т.к., как было упомянуто выше, WebRCT само по себе не самая простая тема.
 
Last edited:

Tachyon

New Member
PS: Приведенный Вами в пример webrtc-media-provider.js, беусловно, интересен, но он не является stand-alone кодом, и в качестве примера не очень познавателен, т.к. для его понимания (и приведения в действие) по прежнему требуется перебрать мегабайт кода flashphoner.js.
 

Max

Administrator
Staff member
У нас есть в roadmap разработка минимального API с прямыми вызовами WebRTC и соответствующими примерами.
Когда выйдет - сообщим. Текущий код в любом случае придется изучать чтобы вычленить из него прямое API если это необходимо.
 

Tachyon

New Member
Понял, спасибо. Если это не является секретом, ориентировочно в какие сроки ожидается выход этой версии? Не сказать, что у нас эта задача прямо срочная, пока на стадии предварительного рассмотрения возможностей, но в какие-то разумные сроки придется начать работу, учитывая то, что и сисадмину, и программистам еще придется осваивать новые для себя задачи.
 

Max

Administrator
Staff member
По срокам информации нет. Приоритеты могут меняться.
 
Top