...
Данный пример может использоваться для внедрения на веб-страницу плеера для воспроизведения живых (Live) потоков с веб-камер и IP камер. Поддерживаются следующие технологии воспроизведения:
- WebRTC
- MSE
- WSPlayer (Websocket + HTML5 Canvas)
Интерфейс страницы внедрения:
Код примера
Код данного примера находится на сервере по следующему пути:
/usr/local/FlashphonerWebCallServer/client2/examples/demo/streaming/embed_player
player.css
- файл стилейplayer.html
- страница с плееромplayer.js
- скрипт, обеспечивающий работу плеераsample.css
- файл стилей для страницы интерфейса внедренияsample.html
- страница интерфейса внедренияsample.js
- скрипт, обеспечивающий формирование кода внедрения
Тестировать данный пример можно по следующему адресу:
https://host:8888/client2/examples/demo/streaming/embed_player/sample.html
Здесь host
- адрес вашего WCS-сервера.
...
Для разбора кода возьмем версию файла player.js
с хешем ecbadc324a69e1, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.212225.
1. Инициализация API.
Flashphoner.init()
code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.init({ preferredMediaProviders: mediaProviders && mediaProviders !== "" ? mediaProviders.split(','): receiverLocation: '../../dependencies/websocket-player/WSReceiver2.js', decoderLocation: '../../dependencies/websocket-player/video-worker2.js', preferredMediaProviders: mediaProviders && mediaProviders !== "" ? mediaProviders.split(','): [] }); |
2. Подключение к серверу.
Flashphoner.createSession() code
Методу createSession() передаются параметры:
...
[] }); |
2. Подключение к серверу.
Flashphoner.createSession()
code
Методу createSession()
передаются параметры:
urlServer
- URL WCS-сервераmediaOptions
- параметры подключения к серверу через TURN-сервер
Code Block | ||||
---|---|---|---|---|
| ||||
let mediaOptions = {"iceServers": [{'url': 'turn:turn.flashphoner.com:443?transport=tcp', 'username': 'flashphoner', 'credential': 'coM77EMrV7Cwhyan'}]};
Flashphoner.createSession({urlServer: urlServer, mediaOptions: mediaOptions}).on(SESSION_STATUS.ESTABLISHED, function (session) {
...
}); |
3. Получение от сервера события, подтверждающего успешное соединение.
SESSION_STATUS.ESTABLISHED
code
Code Block | ||||
---|---|---|---|---|
| ||||
var mediaOptions = {"iceServers": [{'url': 'turn:turn.flashphoner.com:443?transport=tcp', 'username': 'flashphoner', 'credential': 'coM77EMrV7Cwhyan'}]};Flashphoner.createSession({urlServer: urlServer, mediaOptions: mediaOptions}).on(SESSION_STATUS.ESTABLISHED, function (session) { FlashphonersetStatus(session.createSession({urlServer: urlServer, mediaOptions: mediaOptionsstatus()); //session connected, start playback playStream(session); }).on(SESSION_STATUS.ESTABLISHEDDISCONNECTED, function (session) { ... }).on(SESSION_STATUS.FAILED, function () { ... }); |
3. Получение от сервера события, подтверждающего успешное соединение.
ConnectionStatusEvent ESTABLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: urlServer, mediaOptions: mediaOptions}).on(SESSION_STATUS.ESTABLISHED, function (session) |
4. Воспроизведение видеопотока.
Session.createStream()
, Stream.play()
code
В метод createStream
передаются:
- имя видеопотока
streamName
remoteVideo
-div
элемент, в котором будет отображаться видео- разрешение, с которым поток будет проигрываться (на сервере включается транскодинг
useControls
- включает использование стандартных элементов управления проигрыванием потокаunmutePlayOnStart: false
- отключает автоматическое воспроизведение звука при автозапуске воспроизведения для соблюдения требований браузеров
Code Block | ||||
---|---|---|---|---|
| ||||
let useVideoControls = true; ... let options = { name: streamName, setStatus(session.status()); display: remoteVideo, //session connected, start playbackuseControls: useVideoControls }; if (resolution) { playWidth playStream(session)= resolution.split("x")[0]; }).on(SESSION_STATUS.DISCONNECTED, function () {playHeight = resolution.split("x")[1]; options.constraints = { ... }).on(SESSION_STATUS.FAILED, function ()video: { ... }); |
...
session.createStream(), play() code
В метод createStream передаются:
- имя видеопотока streamName
- remoteVideo - div-элемент, в котором будет отображаться видео
- признак отображения кнопки полноэкранного режима
- разрешение для окна плеера
- unmutePlayOnStart: false - отключает автоматическое воспроизведение звука при autoplay для соблюдения требований браузеров
Code Block | ||||
---|---|---|---|---|
| ||||
var options =width: playWidth, height: playHeight }, audio: true }; } if (autoplay) { options.unmutePlayOnStart = false; } playingStream = session.createStream(options).on(STREAM_STATUS.PENDING, function (stream) { name: streamName, display: remoteVideo, flashShowFullScreenButton: true }; if (resolution_for_wsplayer) { options.playWidth = resolution_for_wsplayer.playWidth; options.playHeight = resolution_for_wsplayer.playHeight; } else if (resolution... }); playingStream.play(); |
5. Получение от сервера события, подтверждающего готовность потока к воспроизведению
STREAM_STATUS.PENDING
code
По данному событию:
- в браузере Chrome отключается собственный прелоадер, поскольку есть стандартный при включенных стандартных элементах управления
- настраивается обработчик изменения размера видео элемента по событию
resize
- настраиваются обработчики событий в браузере Safari и в остальных браузерах
Code Block | ||||
---|---|---|---|---|
| ||||
playingStream = session.createStream(options).on(STREAM_STATUS.PENDING, function (stream) { if (Browser.isChrome()) { options.playWidth = resolution.split("x")[0]; options.playHeight = resolution.split("x")[1]; // Hide a custom preloader in Chrome because there is a standard one with standard controls } if (autoplay) { hideItem('preloader'); } let options.unmutePlayOnStartvideo = falsedocument.getElementById(stream.id()); } stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(streamif (!video.hasListeners) { ... }video.hasListeners = true; setResizeHandler(video, stream, playWidth); stream.play(); |
5. Получение от сервера события, подтверждающего готовность потока к воспроизведению
StreamStatusEvent PENDING code
В обработчике данного события размер видео масштабируется под размер окна плеера
Code Block | ||||
---|---|---|---|---|
| ||||
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { if (Browser.isSafariWebRTC()) { var video = document.getElementById(stream.id()setWebkitEventHandlers(video); if (!video.hasListeners)} else { video.hasListeners = truesetEventHandlers(video); } video.addEventListener('playing'} }).on(STREAM_STATUS.PLAYING, function (stream) { ... }).on(STREAM_STATUS.STOPPED, function () { ... }).on(STREAM_STATUS.FAILED, function(stream) { $("#preloader").hide(); }); video.addEventListener('resize', function (event) ... }).on(STREAM_EVENT, function(streamEvent){ var streamResolution = stream.videoResolution(); if (Object.keys(streamResolution).length === 0) ... }); playingStream.play(); |
6. Получение от сервера события, подтверждающего успешное воспроизведение потока
STREAM_STATUS.PLAYING
code
По этому событию снимается с паузы проигрывание потока по MSE в браузере Android Firefox
Code Block | ||||
---|---|---|---|---|
| ||||
playingStream = session.createStream(options).on(STREAM_STATUS.PENDING, function (stream) { ... }).on(STREAM_STATUS.PLAYING, function (stream) { // Android Firefox may pause stream playback via resizeVideo(event.target); MSE even if video element is muted } elseif (Flashphoner.getMediaProviders()[0] == "MSE" && autoplay && Browser.isAndroidFirefox()) { let video = document.getElementById(stream.id()); if // Change aspect ratio to prevent video stretching (video && video.paused) { video.play(); } var} ratio = streamResolution.width / streamResolution.height setStatus(STREAM_STATUS.PLAYING); onStarted(); }).on(STREAM_STATUS.STOPPED, function () { ... }).on(STREAM_STATUS.FAILED, function(stream) { ... }).on(STREAM_EVENT, function(streamEvent){ var newHeight = Math.floor(options.playWidth / ratio); resizeVideo(event.target, options.playWidth, newHeight); } }); } }... }); playingStream.play(); |
7. Остановка воспроизведения видеопотока.
Stream.stop()
code
Code Block | ||||
---|---|---|---|---|
| ||||
playingStream.stop(); |
8. Получение от сервера события, подтверждающего успешную остановку воспроизведения потока
STREAM_STATUS.STOPPED
code
Code Block | ||||
---|---|---|---|---|
| ||||
playingStream = session.createStream(options).on(STREAM_STATUS.PLAYINGPENDING, function (stream) { ... }).on(STREAM_STATUS.STOPPEDPLAYING, function (stream) { ... }).on(STREAM_STATUS.FAILEDSTOPPED, function () { ...setStatus(STREAM_STATUS.STOPPED); onStopped(); }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTHFAILED, function (stream) { ... });}).on(STREAM_EVENT, function(streamEvent){ stream.... }); playingStream.play(); |
6. Получение от сервера события, подтверждающего успешное воспроизведение потока
StreamStatusEvent PLAYING 9. Автозапуск воспроизведения при загрузке страницы
Code Block | ||||
---|---|---|---|---|
| ||||
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(streamif (autoplay) { ... }).on(STREAM_STATUS.PLAYING, function (streamcentralButton.click(); } |
10. Настройка обработчика события resize
По данному событию меняется размер контейнера для video
элемента
Code Block | ||||
---|---|---|---|---|
| ||||
function setResizeHandler(video, stream, playWidth) { setStatus(stream.status());video.addEventListener('resize', function (event) { onStarted(stream); }).on(STREAM_STATUS.STOPPED, function () { let streamResolution = stream.videoResolution(); if ... }).on(STREAM_STATUS.FAILED, function ((Object.keys(streamResolution).length === 0) { ... }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function (stream) { resizeVideo(event.target); } else ... { }); stream.play(); |
7. Остановка воспроизведения видеопотока.
stream.stop() code
Code Block | ||||
---|---|---|---|---|
| ||||
// Change aspect ratio to prevent video stretching $that.find('.play-pause').bind('click', function () { let ratio = streamResolution.width / streamResolution.height; // If playing, etc, changelet classesnewHeight to show pause or play button= Math.floor(playWidth / ratio); resizeVideo(event.target, if (!$(this).prop('disabled')) {playWidth, newHeight); } if (stopped) { ... } else { if (stream) { stream.stop(); } ... } } }); |
8. Получение от сервера события, подтверждающего успешную остановку воспроизведения потока
StreamStatusEvent STOPPED code
Code Block | ||||
---|---|---|---|---|
| ||||
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { ... }).on(STREAM_STATUS.PLAYING, function (stream) { }); } |
11. Настройка обработчиков событий видео в браузере Safari
Обрабатываются следующие события:
playing
- скрывается собственный прелоадер при проигрывании потокаwebkitbeginfullscreen
,webkitendfullscreen
- определяется полноэранный режим для снятия потока с паузы при выходе из негоpause
- проигрывание снимается с паузы при выходе из полноэкранного режима; при нажатии на стандартную кнопку паузы в обычном режиме останавливается проигрывание потока
Code Block | ||||
---|---|---|---|---|
| ||||
function setWebkitEventHandlers(video) { let needRestart = false; let isFullscreen = false; // Hide custom preloader video.addEventListener('playing', function () { hideItem('preloader'); }); // Use webkitbeginfullscreen event to detect full screen mode in iOS Safari video.addEventListener("webkitbeginfullscreen", function () { ...isFullscreen = true; }).on(STREAM_STATUS.STOPPED, function () { ; setStatus(STREAM_STATUS.STOPPED); onStopped(); })video.on(STREAM_STATUS.FAILEDaddEventListener("pause", function () { ... if (needRestart) { }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function (stream) { console.log("Video paused after fullscreen, continue..."); }); stream.play(); |
9. Регулировка громкости воспроизведения
stream.unmuteRemoteAudio(), stream.setVolume(currentVolumeValue) code
Code Block | ||||
---|---|---|---|---|
| ||||
if video.play(stream) {; if (volume > 0) { needRestart = false; } else if (!firstUnmuted && slider && Browser.isAndroid((isFullscreen || document.webkitFullscreenElement)) { console.error("User should click volume unmute button to enable audio"); // Stop stream by standard play/pause control returnplayingStream.stop(false); } }); else if (stream.isRemoteAudioMuted()video.addEventListener("webkitendfullscreen", function () { video.play(); stream.unmuteRemoteAudio()needRestart = true; isFullscreen = false; }); firstUnmuted = true; } } } |
12. Настройка обработчиков событий видео в других браузерах
Обрабатываются следующие события:
playing
- скрывается собственный прелоадер при проигрывании потокаpause
- при нажатии на стандартную кнопку паузы в обычном режиме останавливается проигрывание потока
Code Block | ||||
---|---|---|---|---|
| ||||
function setEventHandlers(video) { // Hide stream.setVolume(volume); } // Save current volume in page element to restore it when mute/unmute custom preloader video.addEventListener('playing', function () { $hideItem('#volume-range').val(volumepreloader'); ... |
10. Автозапуск воспроизведения при загрузке страницы
Code Block | ||||
---|---|---|---|---|
| ||||
if (autoplay ) {}); // Use standard pause control to stop playback video.addEventListener("pause", function () { // Autoplay will start for muted video tag only, adjust mute button and slider view if (!(document.fullscreenElement || document.mozFullscreenElement)) { firstUnmuted = false; $('.volume').addClass('volume-none'); $('.volume').html(HTML_VOLUME_MUTE); // Stop stream by standard play/pause control if we're not in fullscreen $('#slider').slider( "value", 1 playingStream.stop(); $(".play-pause").click();} }); } |