diff --git a/web/assets/js/bs5.liveGrid.js b/web/assets/js/bs5.liveGrid.js
index 0b478c9f..770e407d 100644
--- a/web/assets/js/bs5.liveGrid.js
+++ b/web/assets/js/bs5.liveGrid.js
@@ -6,6 +6,8 @@ var liveGrid = $('#monitors_live')
var liveGridData = null
var liveGridOpenCountElements = $('.liveGridOpenCount')
var liveGridOpenCount = 0
+var liveGridPauseScrollTimeout = null;
+var liveGridPlayingNow = {};
//
var onLiveStreamInitiateExtensions = []
function onLiveStreamInitiate(callback){
@@ -337,222 +339,225 @@ function drawLiveGridBlock(monitorConfig,subStreamChannel){
}
}
function initiateLiveGridPlayer(monitor,subStreamChannel){
- var livePlayerElement = loadedLiveGrids[monitor.mid]
+ var monitorId = monitor.mid
var details = monitor.details
var groupKey = monitor.ke
var monitorId = monitor.mid
+ var livePlayerBlocks = liveGridElements[monitorId]
+ var monitorItem = livePlayerBlocks.monitorItem
var loadedMonitor = loadedMonitors[monitorId]
- var loadedPlayer = loadedLiveGrids[monitor.mid]
+ var loadedPlayer = loadedLiveGrids[monitorId]
var websocketPath = checkCorrectPathEnding(location.pathname) + 'socket.io'
var containerElement = $(`#monitor_live_${monitor.mid}`)
var streamType = subStreamChannel ? details.substream ? details.substream.output.stream_type : 'hls' : details.stream_type
- if(location.search === '?p2p=1'){
- websocketPath = '/socket.io'
- // websocketQuery.machineId = machineId
+ var isInView = isScrolledIntoView(monitorItem[0])
+ if(!isInView){
+ return;
}
+ liveGridPlayingNow[monitorId] = true
switch(streamType){
- case'jpeg':
- startJpegStream(monitorId)
- break;
- case'b64':
- if(loadedPlayer.Base64 && loadedPlayer.Base64.connected){
- loadedPlayer.Base64.disconnect()
- }
- loadedPlayer.Base64 = io(location.origin,{ path: websocketPath, query: websocketQuery, transports: ['websocket'], forceNew: false})
- var ws = loadedPlayer.Base64
- var buffer
- ws.on('diconnect',function(){
- console.log('Base64 Stream Disconnected')
- })
- ws.on('connect',function(){
- ws.emit('Base64',{
- auth: $user.auth_token,
- uid: $user.uid,
- ke: monitor.ke,
- id: monitor.mid,
- channel: subStreamChannel
+ case'jpeg':
+ startJpegStream(monitorId)
+ break;
+ case'b64':
+ if(loadedPlayer.Base64 && loadedPlayer.Base64.connected){
+ loadedPlayer.Base64.disconnect()
+ }
+ loadedPlayer.Base64 = io(location.origin,{ path: websocketPath, query: websocketQuery, transports: ['websocket'], forceNew: false})
+ var ws = loadedPlayer.Base64
+ var buffer
+ ws.on('diconnect',function(){
+ console.log('Base64 Stream Disconnected')
})
- if(!loadedPlayer.ctx || loadedPlayer.ctx.length === 0){
- loadedPlayer.ctx = containerElement.find('canvas');
- }
- var ctx = loadedPlayer.ctx[0]
- var ctx2d = ctx.getContext("2d")
- loadedPlayer.image = new Image()
- var image = loadedPlayer.image
- image.onload = function() {
- loadedPlayer.imageLoading = false
- var x = 0
- var y = 0
- ctx.getContext("2d").drawImage(image,x,y,ctx.width,ctx.height)
- URL.revokeObjectURL(loadedPlayer.imageUrl)
- }
- ws.on('data',function(imageData){
- try{
- if(loadedPlayer.imageLoading === true)return console.log('drop');
- loadedPlayer.imageLoading = true
- var arrayBufferView = new Uint8Array(imageData);
- var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
- loadedPlayer.imageUrl = URL.createObjectURL( blob );
- loadedPlayer.image.src = loadedPlayer.imageUrl
- loadedPlayer.last_frame = 'data:image/jpeg;base64,'+base64ArrayBuffer(imageData)
- }catch(er){
- debugLog('base64 frame')
+ ws.on('connect',function(){
+ ws.emit('Base64',{
+ auth: $user.auth_token,
+ uid: $user.uid,
+ ke: monitor.ke,
+ id: monitor.mid,
+ channel: subStreamChannel
+ })
+ if(!loadedPlayer.ctx || loadedPlayer.ctx.length === 0){
+ loadedPlayer.ctx = containerElement.find('canvas');
}
- // $.ccio.init('signal',d);
+ var ctx = loadedPlayer.ctx[0]
+ var ctx2d = ctx.getContext("2d")
+ loadedPlayer.image = new Image()
+ var image = loadedPlayer.image
+ image.onload = function() {
+ loadedPlayer.imageLoading = false
+ var x = 0
+ var y = 0
+ ctx.getContext("2d").drawImage(image,x,y,ctx.width,ctx.height)
+ URL.revokeObjectURL(loadedPlayer.imageUrl)
+ }
+ ws.on('data',function(imageData){
+ try{
+ if(loadedPlayer.imageLoading === true)return console.log('drop');
+ loadedPlayer.imageLoading = true
+ var arrayBufferView = new Uint8Array(imageData);
+ var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
+ loadedPlayer.imageUrl = URL.createObjectURL( blob );
+ loadedPlayer.image.src = loadedPlayer.imageUrl
+ loadedPlayer.last_frame = 'data:image/jpeg;base64,'+base64ArrayBuffer(imageData)
+ }catch(er){
+ debugLog('base64 frame')
+ }
+ // $.ccio.init('signal',d);
+ })
})
- })
- break;
- case'mp4':
- setTimeout(function(){
- var stream = containerElement.find('.stream-element');
- var onPoseidonError = function(){
- // setTimeout(function(){
- // mainSocket.f({f:'monitor',ff:'watch_on',id:monitorId})
- // },2000)
- }
- if(!loadedPlayer.PoseidonErrorCount)loadedPlayer.PoseidonErrorCount = 0
- if(loadedPlayer.PoseidonErrorCount >= 5)return
- if(subStreamChannel ? details.substream.output.stream_flv_type === 'ws' : monitor.details.stream_flv_type === 'ws'){
- if(loadedPlayer.Poseidon){
- loadedPlayer.Poseidon.stop()
+ break;
+ case'mp4':
+ setTimeout(function(){
+ var stream = containerElement.find('.stream-element');
+ var onPoseidonError = function(){
+ // setTimeout(function(){
+ // mainSocket.f({f:'monitor',ff:'watch_on',id:monitorId})
+ // },2000)
+ }
+ if(!loadedPlayer.PoseidonErrorCount)loadedPlayer.PoseidonErrorCount = 0
+ if(loadedPlayer.PoseidonErrorCount >= 5)return
+ if(subStreamChannel ? details.substream.output.stream_flv_type === 'ws' : monitor.details.stream_flv_type === 'ws'){
+ if(loadedPlayer.Poseidon){
+ loadedPlayer.Poseidon.stop()
+ revokeVideoPlayerUrl(monitorId)
+ }
+ try{
+ loadedPlayer.Poseidon = new Poseidon({
+ video: stream[0],
+ auth_token: $user.auth_token,
+ ke: monitor.ke,
+ uid: $user.uid,
+ id: monitor.mid,
+ url: location.origin,
+ path: websocketPath,
+ query: websocketQuery,
+ onError : onPoseidonError,
+ channel : subStreamChannel
+ })
+ loadedPlayer.Poseidon.start();
+ }catch(err){
+ // onPoseidonError()
+ console.log('onTryPoseidonError',err)
+ }
+ }else{
+ stream.attr('src',getApiPrefix(`mp4`)+'/'+monitor.mid + (subStreamChannel ? `/${subStreamChannel}` : '')+'/s.mp4?time=' + (new Date()).getTime())
+ stream[0].onerror = function(err){
+ console.error(err)
+ }
+ }
+ },1000)
+ break;
+ case'flv':
+ if (flvjs.isSupported()) {
+ if(loadedPlayer.flv){
+ loadedPlayer.flv.destroy()
revokeVideoPlayerUrl(monitorId)
}
- try{
- loadedPlayer.Poseidon = new Poseidon({
- video: stream[0],
+ var options = {};
+ if(monitor.details.stream_flv_type==='ws'){
+ if(monitor.details.stream_flv_maxLatency&&monitor.details.stream_flv_maxLatency!==''){
+ monitor.details.stream_flv_maxLatency = parseInt(monitor.details.stream_flv_maxLatency)
+ }else{
+ monitor.details.stream_flv_maxLatency = 20000;
+ }
+ options = {
+ type: 'flv',
+ isLive: true,
auth_token: $user.auth_token,
ke: monitor.ke,
uid: $user.uid,
id: monitor.mid,
+ maxLatency: monitor.details.stream_flv_maxLatency,
+ hasAudio:false,
url: location.origin,
path: websocketPath,
- query: websocketQuery,
- onError : onPoseidonError,
- channel : subStreamChannel
- })
- loadedPlayer.Poseidon.start();
- }catch(err){
- // onPoseidonError()
- console.log('onTryPoseidonError',err)
- }
- }else{
- stream.attr('src',getApiPrefix(`mp4`)+'/'+monitor.mid + (subStreamChannel ? `/${subStreamChannel}` : '')+'/s.mp4?time=' + (new Date()).getTime())
- stream[0].onerror = function(err){
- console.error(err)
- }
- }
- },1000)
- break;
- case'flv':
- if (flvjs.isSupported()) {
- if(loadedPlayer.flv){
- loadedPlayer.flv.destroy()
- revokeVideoPlayerUrl(monitorId)
- }
- var options = {};
- if(monitor.details.stream_flv_type==='ws'){
- if(monitor.details.stream_flv_maxLatency&&monitor.details.stream_flv_maxLatency!==''){
- monitor.details.stream_flv_maxLatency = parseInt(monitor.details.stream_flv_maxLatency)
+ channel : subStreamChannel,
+ query: websocketQuery
+ }
}else{
- monitor.details.stream_flv_maxLatency = 20000;
- }
- options = {
- type: 'flv',
- isLive: true,
- auth_token: $user.auth_token,
- ke: monitor.ke,
- uid: $user.uid,
- id: monitor.mid,
- maxLatency: monitor.details.stream_flv_maxLatency,
- hasAudio:false,
- url: location.origin,
- path: websocketPath,
- channel : subStreamChannel,
- query: websocketQuery
- }
- }else{
- options = {
- type: 'flv',
- isLive: true,
- url: getApiPrefix(`flv`)+'/'+monitor.mid + (subStreamChannel ? `/${subStreamChannel}` : '')+'/s.flv'
- }
- }
- loadedPlayer.flv = flvjs.createPlayer(options);
- loadedPlayer.flv.attachMediaElement(containerElement.find('.stream-element')[0]);
- loadedPlayer.flv.on('error',function(err){
- console.log(err)
- });
- loadedPlayer.flv.load();
- loadedPlayer.flv.play();
- }else{
- new PNotify({title:'Stream cannot be started',text:'FLV.js is not supported on this browser. Try another stream type.',type:'error'});
- }
- break;
- case'hls':
- function createSteamNow(){
- clearTimeout(loadedPlayer.m3uCheck)
- var url = getApiPrefix(`hls`) + '/' + monitor.mid + (subStreamChannel ? `/${subStreamChannel}` : '') + '/s.m3u8'
- $.get(url,function(m3u){
- if(m3u == 'File Not Found'){
- loadedPlayer.m3uCheck = setTimeout(function(){
- createSteamNow()
- },2000)
- }else{
- var video = containerElement.find('.stream-element')[0]
- if (isAppleDevice) {
- video.src = url;
- video.addEventListener('loadedmetadata', function() {
- setTimeout(function(){
- video.play();
- },3000)
- }, false);
- }else{
- var hlsOptions = safeJsonParse(dashboardOptions().hlsOptions) || {}
- if(hlsOptions instanceof String){
- hlsOptions = {}
- new PNotify({
- title: lang['Invalid JSON'],
- text: lang.hlsOptionsInvalid,
- type: `warning`,
- })
- }
- if(loadedPlayer.hls){
- loadedPlayer.hls.destroy()
- revokeVideoPlayerUrl(monitorId)
- }
- loadedPlayer.hls = new Hls(hlsOptions)
- loadedPlayer.hls.loadSource(url)
- loadedPlayer.hls.attachMedia(video)
- loadedPlayer.hls.on(Hls.Events.MANIFEST_PARSED,function() {
- if (video.paused) {
- video.play();
- }
- });
+ options = {
+ type: 'flv',
+ isLive: true,
+ url: getApiPrefix(`flv`)+'/'+monitor.mid + (subStreamChannel ? `/${subStreamChannel}` : '')+'/s.flv'
}
}
- })
- }
- createSteamNow()
- break;
- case'mjpeg':
- var liveStreamElement = containerElement.find('.stream-element')
- var setSource = function(){
- liveStreamElement.attr('src',getApiPrefix(`mjpeg`)+'/'+monitorId + (subStreamChannel ? `/${subStreamChannel}` : ''))
- liveStreamElement.unbind('ready')
- liveStreamElement.ready(function(){
+ loadedPlayer.flv = flvjs.createPlayer(options);
+ loadedPlayer.flv.attachMediaElement(containerElement.find('.stream-element')[0]);
+ loadedPlayer.flv.on('error',function(err){
+ console.log(err)
+ });
+ loadedPlayer.flv.load();
+ loadedPlayer.flv.play();
+ }else{
+ new PNotify({title:'Stream cannot be started',text:'FLV.js is not supported on this browser. Try another stream type.',type:'error'});
+ }
+ break;
+ case'hls':
+ function createSteamNow(){
+ clearTimeout(loadedPlayer.m3uCheck)
+ var url = getApiPrefix(`hls`) + '/' + monitor.mid + (subStreamChannel ? `/${subStreamChannel}` : '') + '/s.m3u8'
+ $.get(url,function(m3u){
+ if(m3u == 'File Not Found'){
+ loadedPlayer.m3uCheck = setTimeout(function(){
+ createSteamNow()
+ },2000)
+ }else{
+ var video = containerElement.find('.stream-element')[0]
+ if (isAppleDevice) {
+ video.src = url;
+ video.addEventListener('loadedmetadata', function() {
+ setTimeout(function(){
+ video.play();
+ },3000)
+ }, false);
+ }else{
+ var hlsOptions = safeJsonParse(dashboardOptions().hlsOptions) || {}
+ if(hlsOptions instanceof String){
+ hlsOptions = {}
+ new PNotify({
+ title: lang['Invalid JSON'],
+ text: lang.hlsOptionsInvalid,
+ type: `warning`,
+ })
+ }
+ if(loadedPlayer.hls){
+ loadedPlayer.hls.destroy()
+ revokeVideoPlayerUrl(monitorId)
+ }
+ loadedPlayer.hls = new Hls(hlsOptions)
+ loadedPlayer.hls.loadSource(url)
+ loadedPlayer.hls.attachMedia(video)
+ loadedPlayer.hls.on(Hls.Events.MANIFEST_PARSED,function() {
+ if (video.paused) {
+ video.play();
+ }
+ });
+ }
+ }
+ })
+ }
+ createSteamNow()
+ break;
+ case'mjpeg':
+ var liveStreamElement = containerElement.find('.stream-element')
+ var setSource = function(){
+ liveStreamElement.attr('src',getApiPrefix(`mjpeg`)+'/'+monitorId + (subStreamChannel ? `/${subStreamChannel}` : ''))
+ liveStreamElement.unbind('ready')
+ liveStreamElement.ready(function(){
+ setTimeout(function(){
+ liveStreamElement.contents().find("body").append('')
+ },1000)
+ })
+ }
+ setSource()
+ liveStreamElement.on('error',function(err){
setTimeout(function(){
- liveStreamElement.contents().find("body").append('')
- },1000)
+ setSource()
+ },4000)
})
- }
- setSource()
- liveStreamElement.on('error',function(err){
- setTimeout(function(){
- setSource()
- },4000)
- })
- break;
- }
+ break;
+ }
$.each(onLiveStreamInitiateExtensions,function(n,extender){
extender(streamType,monitor,loadedPlayer,subStreamChannel)
})
@@ -662,13 +667,15 @@ function loadPreviouslyOpenedLiveGridBlocks(){
})
}
function closeAllLiveGridPlayers(rememberClose){
- var watchedOn = dashboardOptions().watch_on || {}
- $.each(watchedOn,function(n,groupOfMons){
- $.each(groupOfMons,function(monitorId,monitor){
- if(monitor === 1){
- mainSocket.f({f:'monitor',ff:'watch_off',id: monitorId})
- }
+ $.each(loadedMonitors,function(monitorId,monitor){
+ mainSocket.f({
+ f: 'monitor',
+ ff: 'watch_off',
+ id: monitor.mid
})
+ setTimeout(function(){
+ saveLiveGridBlockOpenState(monitorId,$user.ke,0)
+ },1000)
})
}
function saveLiveGridBlockOpenState(monitorId,groupKey,state){
@@ -870,6 +877,60 @@ function signalCheckLiveStream(options){
delete(liveGridData.signal);
}
}
+
+function pauseMonitorItem(monitorId){
+ liveGridPlayingNow[monitorId] = false
+ closeLiveGridPlayer(monitorId,false)
+}
+function resumeMonitorItem(monitorId){
+ // needs to know about substream
+ liveGridPlayingNow[monitorId] = true
+ resetMonitorCanvas(monitorId,true,null)
+}
+function isScrolledIntoView(elem){
+ var el = $(elem)
+ var theWindow = $(window)
+ var docViewTop = theWindow.scrollTop();
+ var docViewBottom = docViewTop + theWindow.height();
+
+ var elemTop = el.offset().top;
+ var elemBottom = elemTop + el.height();
+
+ return (
+ elemTop >= docViewTop && elemTop <= docViewBottom ||
+ elemBottom >= docViewTop && elemBottom <= docViewBottom
+ );
+}
+function pauseAllLiveGridPlayers(unpause){
+ $('.monitor_item').each(function(n,el){
+ var monitorId = $(el).attr('data-mid')
+ if(!unpause){
+ pauseMonitorItem(monitorId)
+ }else{
+ resumeMonitorItem(monitorId)
+ }
+ })
+}
+function setPauseStatusForMonitorItems(){
+ $('.monitor_item').each(function(n,el){
+ var monitorId = $(el).attr('data-mid')
+ var isVisible = isScrolledIntoView(el)
+ console.log(monitorId,isVisible)
+ if(isVisible){
+ if(!liveGridPlayingNow[monitorId])resumeMonitorItem(monitorId);
+ }else{
+ pauseMonitorItem(monitorId)
+ }
+ })
+}
+function setPauseScrollTimeout(){
+ clearTimeout(liveGridPauseScrollTimeout)
+ if(tabTree.name === 'liveGrid'){
+ liveGridPauseScrollTimeout = setTimeout(function(){
+ setPauseStatusForMonitorItems()
+ },700)
+ }
+}
$(document).ready(function(e){
liveGrid
.on('dblclick','.stream-block',function(){
@@ -882,16 +943,16 @@ $(document).ready(function(e){
})
.on('click','.launch-live-grid-monitor',function(){
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
- // if(isMobile){
- // createLivePlayerTab(loadedMonitors[monitorId])
- // }else{
+ if(isMobile){
+ createLivePlayerTab(loadedMonitors[monitorId])
+ }else{
mainSocket.f({
f: 'monitor',
ff: 'watch_on',
id: monitorId
})
openLiveGrid()
- // }
+ }
})
.on('click','.monitor-live-group-open',function(){
var monitorIds = $(this).attr('monitor-ids').split(',')
@@ -1022,16 +1083,7 @@ $(document).ready(function(e){
})
})
$('.close-all-monitors').click(function(){
- $.each(loadedMonitors,function(monitorId,monitor){
- mainSocket.f({
- f: 'monitor',
- ff: 'watch_off',
- id: monitor.mid
- })
- setTimeout(function(){
- saveLiveGridBlockOpenState(monitorId,$user.ke,0)
- },1000)
- })
+ closeAllLiveGridPlayers()
});
var dontShowDetectionSelectionOnStart = dashboardOptions().dontShowDetection != 1
liveGridData = GridStack.init();
@@ -1046,10 +1098,10 @@ $(document).ready(function(e){
saveLiveGridBlockPositions()
});
addOnTabReopen('liveGrid', function () {
- loadPreviouslyOpenedLiveGridBlocks()
+ pauseAllLiveGridPlayers(true)
})
addOnTabAway('liveGrid', function () {
- closeAllLiveGridPlayers()
+ pauseAllLiveGridPlayers(false)
})
onInitWebsocket(function (d){
loadPreviouslyOpenedLiveGridBlocks()
@@ -1059,9 +1111,6 @@ $(document).ready(function(e){
})
onWebSocketEvent(function (d){
switch(d.f){
- case'init_success':
- // loadPreviouslyOpenedLiveGridBlocks()
- break;
case'video_build_success':
d.status = 1
d.mid = d.id || d.mid
@@ -1185,12 +1234,14 @@ $(document).ready(function(e){
})
$(window).focus(function(){
if(canBackgroundStream()){
- loadPreviouslyOpenedLiveGridBlocks()
+ pauseAllLiveGridPlayers(true)
}
}).blur(function(){
if(canBackgroundStream()){
- closeAllLiveGridPlayers()
+ pauseAllLiveGridPlayers(false)
}
+ }).scroll(function(){
+ setPauseScrollTimeout()
})
dashboardSwitchCallbacks.monitorOrder = function(toggleState){
if(toggleState !== 1){