Make liveGrid more friendly to large number

better-liveGrid-monitor-item
Moe 2023-02-20 14:44:25 -08:00
parent 123ee93594
commit 980a96196d
1 changed files with 268 additions and 214 deletions

View File

@ -6,6 +6,8 @@ var liveGrid = $('#monitors_live')
var liveGridData = null
var liveGridOpenCountElements = $('.liveGridOpenCount')
var liveGridOpenCount = 0
var liveGridPauseScrollTimeout = null;
var liveGridPauseStates = {};
//
var onLiveStreamInitiateExtensions = []
function onLiveStreamInitiate(callback){
@ -337,7 +339,9 @@ function drawLiveGridBlock(monitorConfig,subStreamChannel){
}
}
function initiateLiveGridPlayer(monitor,subStreamChannel){
var livePlayerElement = loadedLiveGrids[monitor.mid]
var monitorId = monitor.mid
var livePlayerElement = loadedLiveGrids[monitorId]
var monitorItem = liveGridElements[monitorId].monitorItem
var details = monitor.details
var groupKey = monitor.ke
var monitorId = monitor.mid
@ -346,213 +350,217 @@ function initiateLiveGridPlayer(monitor,subStreamChannel){
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
var isInView = isScrolledIntoView(monitorItem[0])
if(location.search === '?p2p=1'){
websocketPath = '/socket.io'
// websocketQuery.machineId = machineId
}
if(!isInView){
return;
}
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('<style>img{width:100%;height:100%}</style>')
},1000)
})
}
setSource()
liveStreamElement.on('error',function(err){
setTimeout(function(){
liveStreamElement.contents().find("body").append('<style>img{width:100%;height:100%}</style>')
},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 +670,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 +880,60 @@ function signalCheckLiveStream(options){
delete(liveGridData.signal);
}
}
function pauseMonitorItem(monitorId){
liveGridPauseStates[monitorId] = false
closeLiveGridPlayer(monitorId,false)
}
function resumeMonitorItem(monitorId){
// needs to know about substream
liveGridPauseStates[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(!liveGridPauseStates[monitorId])resumeMonitorItem(monitorId);
}else{
pauseMonitorItem(monitorId)
}
})
}
function setPauseScrollTimeout(){
clearTimeout(liveGridPauseScrollTimeout)
if(tabTree.name === 'liveGrid'){
liveGridPauseScrollTimeout = setTimeout(function(){
setPauseStatusForMonitorItems()
},1500)
}
}
$(document).ready(function(e){
liveGrid
.on('dblclick','.stream-block',function(){
@ -882,16 +946,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 +1086,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 +1101,10 @@ $(document).ready(function(e){
saveLiveGridBlockPositions()
});
addOnTabReopen('liveGrid', function () {
loadPreviouslyOpenedLiveGridBlocks()
pauseAllLiveGridPlayers(true)
})
addOnTabAway('liveGrid', function () {
closeAllLiveGridPlayers()
pauseAllLiveGridPlayers(false)
})
onInitWebsocket(function (d){
loadPreviouslyOpenedLiveGridBlocks()
@ -1059,9 +1114,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 +1237,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){