...
Поддерживаемые платформы и браузеры
Chrome | Firefox | Safari 11 | Edge | |
---|---|---|---|---|
Windows | + | + | + | |
Mac OS | + | + | + | |
Android | + | + | ||
iOS | - | - | + |
Схема работы
- Браузер соединяется с сервером по протоколу Websocket и отправляет команду publish.
- Браузер захватывает микрофон и камеру и отправляет WebRTC поток на сервер.
- Второй браузер устанавливает соединение также по Websocket и отправляет команду play.
- Второй браузер получает WebRTC поток и воспроизводит этот поток на странице.
...
Code Block | ||||
---|---|---|---|---|
| ||||
session.createStream({
name: streamName,
display: localVideo,
cacheLocalResources: true,
receiveVideo: false,
receiveAudio: false
...
}).on(STREAM_STATUS.UNPUBLISHED, function () {
setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
onUnpublished();
...
}).publish(); |
Публикация с отображением локального видео в Delight Player
При захвате потока с вебкамеры возможно отображение локального видео в браузерном VR-плеере, например, Delight Player. Таким образом можно проигрывать поток в устройствах виртуальной и смешанной реальности, если на этом устройстве работает один из поддерживаемых браузеров. Для интеграции стороннего плеера используются возможности JavaScript и HTML5.
Тестирование
1. Для теста возьмем:
- WCS сервер
- тестовую страницу с VR-плеером Delight для воспроизведения потока при публикации
2. Укажем имя потока test и нажмем Publish. Публикуемый поток отображается в плеере
Пример кода страницы с плеером
1. Объявление видеоэлемента для воспроизведения потока, поля ввода имени потока и кнопок запуска и остановки воспроизведения
Code Block | ||||
---|---|---|---|---|
| ||||
<div style="width: 50%;">
<dl8-live-video id="remoteVideo" format="STEREO_TERPON" muted="true">
<source>
</dl8-live-video>
</div>
<input class="form-control" type="text" id="streamName" placeholder="Stream Name">
<button id="publishBtn" type="button" class="btn btn-default" disabled>Publish</button>
<button id="unpublishBtn" type="button" class="btn btn-default" disabled>UnPublish</button> |
2. Обработка события готовности плеера к воспроизведению
Code Block | ||||
---|---|---|---|---|
| ||||
document.addEventListener('x-dl8-evt-ready', function () {
dl8video = $('#remoteVideo').get(0);
$('#publishBtn').prop('disabled', false).click(function() {
publishStream();
});
}); |
3. Создание псевдоэлементов для воспроизведения потока
Code Block | ||||
---|---|---|---|---|
| ||||
var mockLocalDisplay = $('<div></div>');
var mockLocalVideo = $('<video></video>',{id:'mock-LOCAL_CACHED_VIDEO'});
mockLocalDisplay.append(mockLocalVideo); |
4. Установка соединения с сервером и создание потока
Code Block | ||||
---|---|---|---|---|
| ||||
var video = dl8video.contentElement;
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
var session = Flashphoner.getSessions()[0];
session.createStream({
name: $('#streamName').val(),
display: mockLocalDisplay.get(0)
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
...
}).publish();
}) |
5. Запуск воспроизведения в VR-плеере и обработка нажатия кнопки остановки воспроизведения
Code Block | ||||
---|---|---|---|---|
| ||||
...
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
var srcObject = mockLocalVideo.get(0).srcObject;
video.srcObject = srcObject;
dl8video.start();
mockLocalVideo.get(0).pause();
mockLocalVideo.get(0).srcObject = null;
$('#unpublishBtn').prop('disabled', false).click(function() {
stream.stop();
$('#publishBtn').prop('disabled', false);
$('#unpublishBtn').prop('disabled', true);
dl8video.exit();
});
}).publish(); |
Полный код примера страницы с VR-плеером
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<!DOCTYPE html> <html> <head> <title>WebRTC Delight</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script type="text/javascript" src="../../../../flashphoner.js"></script> <script type="text/javascript" src="../../dependencies/jquery/jquery-1.12.0.js"></script> <script type="text/javascript" src="../../dependencies/js/utils.js"></script> <script src="dl8-66b250447635476d123a44a391c80b09887e831e.js" async></script> <meta name="dl8-custom-format" content='{"name": "STEREO_TERPON","base":"STEREO_MESH","params":{"uri": "03198702.json"}}'> </head> <body> <div style="width: 50%;"> <dl8-live-video id="remoteVideo" format="STEREO_TERPON" muted="true"> <source> </dl8-live-video> </div> <input class="form-control" type="text" id="streamName" placeholder="Stream Name"> <button id="publishBtn" type="button" class="btn btn-default" disabled>Publish</button> <button id="unpublishBtn" type="button" class="btn btn-default" disabled>UnPublish</button> <script> Flashphoner.init({flashMediaProviderSwfLocation: '../../../../media-provider.swf'}); var SESSION_STATUS = Flashphoner.constants.SESSION_STATUS; var STREAM_STATUS = Flashphoner.constants.STREAM_STATUS; var STREAM_STATUS_INFO = Flashphoner.constants.STREAM_STATUS_INFO; var publishBtn = $('#publishBtn').get(0); var dl8video = null; var url = setURL(); document.addEventListener('x-dl8-evt-ready', function () { dl8video = $('#remoteVideo').get(0); $('#publishBtn').prop('disabled', false).click(function() { publishStream(); }); }); var mockLocalDisplay = $('<div></div>'); var mockLocalVideo = $('<video></video>',{id:'mock-LOCAL_CACHED_VIDEO'}); mockLocalDisplay.append(mockLocalVideo); function publishStream() { $('#publishBtn').prop('disabled', true); $('#unpublishBtn').prop('disabled', false); var video = dl8video.contentElement; Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) { var session = Flashphoner.getSessions()[0]; session.createStream({ name: $('#streamName').val(), display: mockLocalDisplay.get(0) }).on(STREAM_STATUS.PUBLISHING, function (stream) { var srcObject = mockLocalVideo.get(0).srcObject; video.srcObject = srcObject; dl8video.start(); mockLocalVideo.get(0).pause(); mockLocalVideo.get(0).srcObject = null; $('#unpublishBtn').prop('disabled', false).click(function() { stream.stop(); $('#publishBtn').prop('disabled', false); $('#unpublishBtn').prop('disabled', true); dl8video.exit(); }); }).publish(); }) } </script> </body> </html> |
Известные проблемы
1.Если Если веб-приложение расположено внутри iframe элемента, публикация видеопотока может не пройти.
Симптомы: ошибки IceServer error в консоли браузера.
Решение: вынести приложение из iframe на отдельную страницу.
2. Если публикация потока идет с Windows 10 или Windows 8 и в браузере Google Chrome включено аппаратное ускорение, могут быть проблемы с битрейтом.
Симптомы: качество видео плохое, мутное, битрейт в chrome://webrtc-internals показывает меньше 100 kbps.
Решение: отключите аппаратное ускорение в браузере, переключите браузер или сервер на использование кодека VP8.
3. Публикация потока с воспроизведением локального видео в Delight Player не работает в MS Edge
Симптомы: при публикации потока в MS Edge не запускается воспроизведение локального видео в Delight Player
Решение: использовать другой браузер для публикации