Include Page | WCS5RU:С экрана компьютера (screen sharing) в браузере по WebRTC | WCS5RU:С экрана компьютера (screen sharing) в браузере по WebRTC
---|
Table of Contents |
Описание
Поддерживаемые платформы и браузеры
Chrome | Firefox | Safari | |
---|---|---|---|
Windows | + | + | |
Mac OS | + | + | + |
Схема работы
- Браузер соединяется с сервером по протоколу Websocket и отправляет команду publish.
- Браузер захватывает экран и отправляет WebRTC поток на сервер.
- Второй браузер устанавливает соединение также по Websocket и отправляет команду play.
- Второй браузер получает WebRTC поток и воспроизводит этот поток на странице.
Краткое руководство по тестированию
Захват видеопотока с экрана компьютера и подготовка к его трансляции
1. Для теста используем демо-сервер demo.flashphoner.com и веб-приложение Screen Sharing в браузере Chrome
https://demo.flashphoner.com/client2/examples/demo/streaming/screen-sharing/screen-sharing.html
2. Нажмите кнопку "Start". Браузер запросит доступ к экрану, и начнется захват экрана и трансляция видеопотока:
3. Убедитесь, что поток отправляется на сервер и система работает нормально, откройте chrome://webrtc-internals
4. Откройте Two Way Streaming в отдельном окне, нажмите Connect и укажите идентификатор потока, затем нажмите Play.
5. Графики воспроизведения chrome://webrtc-internals
Последовательность выполнения операций (Call Flow)
Ниже описана последовательность вызовов при использовании примера Screen Sharing
1. Проверка необходимости установки расширения
Browser.isFirefox(), Browser.isChrome(); code
Code Block | ||||
---|---|---|---|---|
| ||||
if (Browser.isFirefox()) {
$("#installExtensionButton").show();
...
} else if (Browser.isChrome()) {
$('#mediaSourceForm').hide();
interval = setInterval(function() {
chrome.runtime.sendMessage(extensionId, {type: "isInstalled"}, function (response) {
. if (response) {
$("#extension").hide();
clearInterval(interval);
onExtensionAvailable();
} else {
(inIframe()) ? $("#installFromMarket").show() : $("#installExtensionButton").show();
}
});
}, 500);
} else {
$("#notify").modal('show');
return false;
} |
2. Установка соединения с сервером.
Flashphoner.createSession(); code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
//session connected, start streaming
startStreaming(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
setStatus(SESSION_STATUS.DISCONNECTED);
onStopped();
}).on(SESSION_STATUS.FAILED, function(){
setStatus(SESSION_STATUS.FAILED);
onStopped();
}); |
3. Получение от сервера события, подтверждающего успешное соединение.
ConnectionStatusEvent ESTABLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
//session connected, start streaming
startStreaming(session);
...
}); |
4. Публикация потока.
stream.publish(); code
Code Block | ||||
---|---|---|---|---|
| ||||
session.createStream({
name: streamName,
display: localVideo,
constraints: constraints
}).on(STREAM_STATUS.PUBLISHING, function(publishStream){
...
}).on(STREAM_STATUS.UNPUBLISHED, function(){
...
}).on(STREAM_STATUS.FAILED, function(stream){
...
}).publish();
|
5. Получение от сервера события, подтверждающего успешную публикацию потока.
StreamStatusEvent, статус PUBLISHING code
Code Block | ||||
---|---|---|---|---|
| ||||
session.createStream({
name: streamName,
display: localVideo,
constraints: constraints
}).on(STREAM_STATUS.PUBLISHING, function(publishStream){
...
setStatus(STREAM_STATUS.PUBLISHING);
//play preview
session.createStream({
name: streamName,
display: remoteVideo
}).on(STREAM_STATUS.PLAYING, function(previewStream){
document.getElementById(previewStream.id()).addEventListener('resize', function(event){
resizeVideo(event.target);
});
//enable stop button
onStarted(publishStream, previewStream);
}).on(STREAM_STATUS.STOPPED, function(){
publishStream.stop();
}).on(STREAM_STATUS.FAILED, function(stream){
//preview failed, stop publishStream
if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
setStatus(STREAM_STATUS.FAILED, stream);
publishStream.stop();
}
}).play();
}).on(STREAM_STATUS.UNPUBLISHED, function(){
...
}).on(STREAM_STATUS.FAILED, function(stream){
...
}).publish();
|
6. Отправка аудио-видео потока по WebRTC
7. Остановка публикации потока.
stream.stop(); code
Code Block | ||||
---|---|---|---|---|
| ||||
session.createStream({
name: streamName,
display: localVideo,
constraints: constraints
}).on(STREAM_STATUS.PUBLISHING, function(publishStream){
/*
* User can stop sharing screen capture using Chrome "stop" button.
* Catch onended video track event and stop publishing.
*/
document.getElementById(publishStream.id()).srcObject.getVideoTracks()[0].onended = function (e) {
publishStream.stop();
};
...
setStatus(STREAM_STATUS.PUBLISHING);
//play preview
session.createStream({
name: streamName,
display: remoteVideo
}).on(STREAM_STATUS.PLAYING, function(previewStream){
...
}).on(STREAM_STATUS.STOPPED, function(){
publishStream.stop();
}).on(STREAM_STATUS.FAILED, function(stream){
//preview failed, stop publishStream
if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
setStatus(STREAM_STATUS.FAILED, stream);
publishStream.stop();
}
}).play();
...
}).publish();
|
8. Получение от сервера события, подтверждающего остановку публикации потока.
StreamStatusEvent, статус UNPUBLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
session.createStream({
name: streamName,
display: localVideo,
constraints: constraints
}).on(STREAM_STATUS.PUBLISHING, function(publishStream){
...
}).on(STREAM_STATUS.UNPUBLISHED, function(){
setStatus(STREAM_STATUS.UNPUBLISHED);
//enable start button
onStopped();
}).on(STREAM_STATUS.FAILED, function(stream){
...
}).publish();
|
Разработчику
Функция демонстрации экрана может быть использована для публикации видеопотока, демонстрирующего рабочий стол или окно приложения.
Для демонстрации экрана WCS API использует расширение для браузера Chrome. Браузер Firefox, начиная с версии 52, не нуждается в расширении.
Excerpt Include | ||||||
---|---|---|---|---|---|---|
|
Известные проблемы
1. Если веб-приложение расположено внутри iframe элемента, публикация видеопотока может не пройти.
Симптомы: ошибки IceServer error в консоли браузера.
Решение: вынести приложение из iframe на отдельную страницу.
2. Если публикация потока идет с Windows 10 или Windows 8 и в браузере Google Chrome включено аппаратное ускорение, могут быть проблемы с битрейтом.
Симптомы: качество видео плохое, мутное, битрейт в chrome://webrtc-internals показывает меньше 100 kbps.
Решение: отключите аппаратное ускорение в браузере, переключите браузер или сервер на использование кодека VP8.
3. Остановка всех потоков, захваченных с экрана, при остановке одного из них
Симптомы: при создании нескольких потоков, захваченных с экрана, из одной вкладки браузера Chrome, и последующей остановке одного из них, останавливаются все потоки.
Решение: кешировать дорожки по источнику видео, и останавливать их всместе с последним потоком, использующим этот источник, например
Code Block | ||||
---|---|---|---|---|
| ||||
var handleUnpublished = function(stream) {
console.log("Stream unpublished with status " + stream.status());
//get track label
var video = document.getElementById(stream.id() + LOCAL_CACHED_VIDEO);
var track = video.srcObject.getVideoTracks()[0];
var label = track.label;
//see if someone using this source
if (countDisplaysWithVideoLabel(label) > 1) {
//remove srcObject but don't stop tracks
pushTrack(track);
video.srcObject = null;
} else {
var tracks = popTracks(track);
for (var i = 0; i < tracks.length; i++) {
tracks[i].stop();
}
}
//release resources
Flashphoner.releaseLocalMedia(streamVideoDisplay);
//remove stream display
display.removeChild(streamDisplay);
session.disconnect();
};
|
4. При сворачивании окна, с которогого захватывается поток, браузер Chrome перестает высылать трафик
Симптомы: если окно, с которого захватывается видеопоток, свернуто на панель задач, на стороне подписчика виден фриз, поток может завершиться по отсутствию трафика: Failed by RTP activity
Решение: в сборках до 5.2.1784 отключить контроль видео трафика для всех потоков
Code Block | ||
---|---|---|
| ||
rtp_activity_video=false |
в сборках, начиная с 5.2.1784, отключить контроль видео трафика для потоков с экрана по шаблону имени, например
Code Block | ||
---|---|---|
| ||
rtp_activity_video_exclude=.*-screen$ |