1102 lines
44 KiB
JavaScript
1102 lines
44 KiB
JavaScript
var loadedLiveGrids = {}
|
|
var monitorPops = {}
|
|
var liveGridElements = {}
|
|
var runningJpegStreams = {}
|
|
var liveGrid = $('#monitors_live')
|
|
var liveGridOpenCountElements = $('.liveGridOpenCount')
|
|
var liveGridOpenCount = 0
|
|
//
|
|
var onLiveStreamInitiateExtensions = []
|
|
function onLiveStreamInitiate(callback){
|
|
onLiveStreamInitiateExtensions.push(callback)
|
|
}
|
|
var onLiveStreamCloseExtensions = []
|
|
function onLiveStreamClose(callback){
|
|
onLiveStreamCloseExtensions.push(callback)
|
|
}
|
|
var onSignalCheckLiveStreamExtensions = []
|
|
function onSignalCheckLiveStream(callback){
|
|
onSignalCheckLiveStreamExtensions.push(callback)
|
|
}
|
|
var onBuildStreamElementExtensions = []
|
|
function onBuildStreamElement(callback){
|
|
onBuildStreamElementExtensions.push(callback)
|
|
}
|
|
//
|
|
function setLiveGridOpenCount(addOrRemove){
|
|
liveGridOpenCount += addOrRemove
|
|
liveGridOpenCountElements.text(liveGridOpenCount)
|
|
}
|
|
function getLiveGridData(){
|
|
return liveGrid.data('gridstack')
|
|
}
|
|
function getMonitorsPerRow(){
|
|
var x
|
|
switch(dashboardOptions().montage){
|
|
case'1':
|
|
x = '12'
|
|
break;
|
|
case'2':
|
|
x = '6'
|
|
break;
|
|
case'3':
|
|
x = '4'
|
|
break;
|
|
case'4':
|
|
x = '3'
|
|
break;
|
|
case'5':
|
|
x = '5'
|
|
break;
|
|
case'6':
|
|
x = '2'
|
|
break;
|
|
default://3
|
|
x = '4'
|
|
break;
|
|
}
|
|
return x
|
|
}
|
|
function saveLiveGridBlockPositions() {
|
|
var monitors = {}
|
|
liveGrid.find(" .monitor_item").each(function(n,v){
|
|
var el = $(v)
|
|
var item = {}
|
|
item.ke = el.attr('data-ke')
|
|
item.mid = el.attr('data-mid')
|
|
item.x = el.attr('data-gs-x')
|
|
item.y = el.attr('data-gs-y')
|
|
item.height = el.attr('data-gs-height')
|
|
item.width = el.attr('data-gs-width')
|
|
monitors[item.ke+''+item.mid] = item
|
|
})
|
|
$user.details.monitorOrder = monitors;
|
|
mainSocket.f({f:'monitorOrder',monitorOrder:monitors})
|
|
}
|
|
function buildStreamElementHtml(streamType){
|
|
var html = ''
|
|
if(window.jpegModeOn === true){
|
|
html = '<img class="stream-element">';
|
|
}else{
|
|
switch(streamType){
|
|
case'hls':case'flv':case'mp4':
|
|
html = `<video class="stream-element" playsinline muted autoplay></video>`;
|
|
break;
|
|
case'mjpeg':
|
|
html = '<iframe class="stream-element"></iframe>';
|
|
break;
|
|
case'jpeg':
|
|
html = '<img class="stream-element">';
|
|
break;
|
|
default://base64//h265
|
|
html = '<canvas class="stream-element"></canvas>';
|
|
break;
|
|
}
|
|
$.each(onBuildStreamElementExtensions,function(n,extender){
|
|
var newHtml = extender(streamType)
|
|
html = newHtml ? newHtml : html
|
|
})
|
|
}
|
|
return html
|
|
}
|
|
function resetMonitorCanvas(monitorId,initiateAfter,subStreamChannel){
|
|
var monitor = loadedMonitors[monitorId]
|
|
var details = monitor.details
|
|
var streamType = subStreamChannel ? details.substream ? details.substream.output.stream_type : 'hls' : details.stream_type
|
|
if(!liveGridElements[monitorId])return;
|
|
var streamBlock = liveGridElements[monitorId].monitorItem.find('.stream-block')
|
|
closeLiveGridPlayer(monitorId,false)
|
|
streamBlock.find('.stream-element').remove()
|
|
streamBlock.append(buildStreamElementHtml(streamType))
|
|
if(initiateAfter)initiateLiveGridPlayer(monitor,subStreamChannel)
|
|
}
|
|
function replaceMonitorInfoInHtml(htmlString,monitor){
|
|
var monitorMutes = dashboardOptions().monitorMutes || {}
|
|
return htmlString
|
|
.replaceAll('$GROUP_KEY',monitor.ke)
|
|
.replaceAll('$MONITOR_ID',monitor.mid)
|
|
.replaceAll('$MONITOR_MODE',monitor.mode)
|
|
.replaceAll('$MONITOR_NAME',monitor.name)
|
|
.replaceAll('$MONITOR_MUTE_ICON',(monitorMutes[monitor.mid] !== 1 ? 'volume-up' : 'volume-off'));
|
|
}
|
|
function buildLiveGridBlock(monitor){
|
|
if(monitor.mode === 'stop'){
|
|
new PNotify({
|
|
title: lang.sorryNo,
|
|
text: lang[`Cannot watch a monitor that isn't running.`],
|
|
type: 'danger'
|
|
})
|
|
return
|
|
}
|
|
var monitorDetails = safeJsonParse(monitor.details)
|
|
var monitorLiveId = `monitor_live_${monitor.mid}`
|
|
var subStreamChannel = monitor.subStreamChannel
|
|
var streamType = subStreamChannel ? monitorDetails.substream ? monitorDetails.substream.output.stream_type : 'hls' : monitorDetails.stream_type
|
|
var streamElement = buildStreamElementHtml(streamType)
|
|
var streamBlockInfo = definitions['Monitor Stream Window']
|
|
if(!loadedLiveGrids[monitor.mid])loadedLiveGrids[monitor.mid] = {}
|
|
var baseHtml = `<div
|
|
id="${monitorLiveId}"
|
|
data-ke="${monitor.ke}"
|
|
data-mid="${monitor.mid}"
|
|
data-mode="${monitor.mode}"
|
|
class="grid-stack-item monitor_item glM${monitor.mid} ${streamBlockInfo.gridBlockClass || ''}"
|
|
>
|
|
<div class="grid-stack-item-content ui-draggable-handle">
|
|
<div class="stream-block no-padding mdl-card__media mdl-color-text--grey-50">
|
|
${streamBlockInfo.streamBlockPreHtml || ''}
|
|
<div class="stream-objects"></div>
|
|
<div class="stream-hud">
|
|
${streamBlockInfo.streamBlockHudHtml || ''}
|
|
<div class="controls">
|
|
${streamBlockInfo.streamBlockHudControlsHtml || ''}
|
|
</div>
|
|
</div>
|
|
${streamElement}
|
|
</div>
|
|
</div>
|
|
${streamBlockInfo.gridBlockAfterContentHtml || ''}
|
|
<div class="mdl-overlay-menu-backdrop hidden">
|
|
<ul class="mdl-overlay-menu list-group">`
|
|
var buttons = streamBlockInfo.links
|
|
if(!monitor.details.control === '1'){
|
|
delete(buttons["Control"])
|
|
}
|
|
if(!permissionCheck('video_view',monitor.mid)){
|
|
delete(buttons["Videos List"])
|
|
delete(buttons["Time-lapse"])
|
|
delete(buttons["Power Viewer"])
|
|
delete(buttons["Calendar"])
|
|
}
|
|
if(!permissionCheck('monitor_edit',monitor.mid)){
|
|
delete(buttons["Monitor Settings"])
|
|
}
|
|
$.each(buttons,function(n,v){
|
|
baseHtml += `<li class="list-item cursor-pointer ${v.class}" title="${v.label}" ${v.attr}><i class="fa fa-${v.icon}"></i> ${v.label}</li>`
|
|
})
|
|
baseHtml += `</ul>
|
|
</div>
|
|
</div>`
|
|
return replaceMonitorInfoInHtml(baseHtml,monitor)
|
|
}
|
|
function drawPtzControlsOnLiveGridBlock(monitorId){
|
|
var monitorItem = $('#monitor_live_' + monitorId)
|
|
var ptzControls = monitorItem.find('.PTZ_controls');
|
|
if(ptzControls.length>0){
|
|
ptzControls.remove()
|
|
}else{
|
|
var html = `<div class="PTZ_controls">
|
|
<div class="pad">
|
|
<div class="control top run-live-grid-monitor-ptz" data-ptz-control="up"></div>
|
|
<div class="control left run-live-grid-monitor-ptz" data-ptz-control="left"></div>
|
|
<div class="control right run-live-grid-monitor-ptz" data-ptz-control="right"></div>
|
|
<div class="control bottom run-live-grid-monitor-ptz" data-ptz-control="down"></div>
|
|
<div class="control middle run-live-grid-monitor-ptz" data-ptz-control="center"></div>
|
|
</div>
|
|
<div class="btn-group btn-group-sm btn-group-justified">
|
|
<a title="${lang['Zoom In']}" class="zoom_in btn btn-default run-live-grid-monitor-ptz" data-ptz-control="zoom_in"><i class="fa fa-search-plus"></i></a>
|
|
<a title="${lang['Zoom Out']}" class="zoom_out btn btn-default run-live-grid-monitor-ptz" data-ptz-control="zoom_out"><i class="fa fa-search-minus"></i></a>
|
|
</div>
|
|
<div class="btn-group btn-group-sm btn-group-justified">
|
|
<a title="${lang['Enable Nightvision']}" class="nv_enable btn btn-default run-live-grid-monitor-ptz" data-ptz-control="enable_nv"><i class="fa fa-moon-o"></i></a>
|
|
<a title="${lang['Disable Nightvision']}" class="nv_disable btn btn-default run-live-grid-monitor-ptz" data-ptz-control="disable_nv"><i class="fa fa-sun-o"></i></a>
|
|
</div>
|
|
${safeJsonParse(loadedMonitors[monitorId].details,{}).is_onvif === '1' ? `
|
|
<div class="btn-group btn-group-sm btn-group-justified">
|
|
<a title="${lang['Set Home Position (ONVIF-only)']}" class="btn btn-default run-live-grid-monitor-ptz" data-ptz-control="setHome"><i class="fa fa-h-square"></i> ${lang['Set Home']}</a>
|
|
</div>` : ``}
|
|
</div>`
|
|
monitorItem.append(html)
|
|
}
|
|
}
|
|
function drawVideoCardToMiniList(monitorId,video,skipLimitCheck){
|
|
var theVideoList = liveGridElements[monitorId].miniVideoList
|
|
if(!skipLimitCheck){
|
|
var rowsDrawn = theVideoList.find('.video-row')
|
|
if(rowsDrawn.length > 10)rowsDrawn.last().remove()
|
|
}
|
|
theVideoList.prepend(createVideoRow(video,`col-12 mb-2`))
|
|
}
|
|
function loadVideoMiniList(monitorId){
|
|
getVideos({
|
|
monitorId: monitorId,
|
|
limit: 10,
|
|
},function(data){
|
|
var videos = data.videos
|
|
$.each(videos.reverse(),function(n,video){
|
|
drawVideoCardToMiniList(monitorId,video,true)
|
|
})
|
|
})
|
|
}
|
|
function drawLiveGridBlock(monitorConfig,subStreamChannel){
|
|
var monitorId = monitorConfig.mid
|
|
if($('#monitor_live_' + monitorId).length === 0){
|
|
var x = 0;
|
|
var y = 0;
|
|
var monitorsPerRow = getMonitorsPerRow()
|
|
var width = monitorsPerRow
|
|
var height = width;
|
|
var isSmallMobile = isMobile && window.innerWidth <= 812;
|
|
var html = buildLiveGridBlock(monitorConfig)
|
|
if($user.details && $user.details.monitorOrder && $user.details.monitorOrder[monitorConfig.ke+''+monitorId]){
|
|
var saved = $user.details.monitorOrder[monitorConfig.ke+''+monitorId];
|
|
x = saved.x;
|
|
y = saved.y;
|
|
width = saved.width;
|
|
height = saved.height;
|
|
}
|
|
var autoPlacement = false
|
|
if(dashboardOptions().switches.monitorOrder !== 1){
|
|
autoPlacement = true
|
|
}
|
|
liveGrid.data('gridstack').addWidget($(html), x, y, isSmallMobile ? 4 : height, isSmallMobile ? 4 : height, autoPlacement);
|
|
var theBlock = $('#monitor_live_' + monitorId);
|
|
var streamElement = theBlock.find('.stream-element')
|
|
liveGridElements[monitorId] = {
|
|
monitorItem: theBlock,
|
|
streamElement: streamElement,
|
|
eventObjects: theBlock.find('.stream-objects'),
|
|
motionMeter: theBlock.find('.indifference .progress-bar'),
|
|
motionMeterText: theBlock.find('.indifference .progress-bar span'),
|
|
width: streamElement.width(),
|
|
height: streamElement.height(),
|
|
miniVideoList: theBlock.find('.videos-mini'),
|
|
}
|
|
try{
|
|
if(safeJsonParse(monitorConfig.details).control === "1"){
|
|
theBlock.find('[monitor="control_toggle"]').show()
|
|
}else{
|
|
theBlock.find('.pad').remove();
|
|
theBlock.find('[monitor="control_toggle"]').hide()
|
|
}
|
|
}catch(re){
|
|
debugLog(re)
|
|
}
|
|
setCosmeticMonitorInfo(loadedMonitors[monitorId],subStreamChannel)
|
|
setLiveGridOpenCount(1)
|
|
}
|
|
initiateLiveGridPlayer(loadedMonitors[monitorId],subStreamChannel)
|
|
}
|
|
function initiateLiveGridPlayer(monitor,subStreamChannel){
|
|
var livePlayerElement = loadedLiveGrids[monitor.mid]
|
|
var details = monitor.details
|
|
var groupKey = monitor.ke
|
|
var monitorId = monitor.mid
|
|
var loadedMonitor = loadedMonitors[monitorId]
|
|
var loadedPlayer = loadedLiveGrids[monitor.mid]
|
|
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
|
|
}
|
|
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
|
|
})
|
|
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')
|
|
}
|
|
// $.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:monitor.mid})
|
|
// },5000)
|
|
}
|
|
if(!loadedPlayer.PoseidonErrorCount)loadedPlayer.PoseidonErrorCount = 0
|
|
if(loadedPlayer.PoseidonErrorCount >= 5)return
|
|
if(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)
|
|
}
|
|
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,
|
|
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();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
})
|
|
}
|
|
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(){
|
|
setSource()
|
|
},4000)
|
|
})
|
|
break;
|
|
}
|
|
$.each(onLiveStreamInitiateExtensions,function(n,extender){
|
|
extender(streamType,monitor,loadedPlayer,subStreamChannel)
|
|
})
|
|
var monitorMutes = dashboardOptions().monitorMutes || {}
|
|
if(dashboardOptions().switches.monitorMuteAudio === 1){
|
|
containerElement.find('video').each(function(n,el){
|
|
el.muted = "muted"
|
|
})
|
|
}else{
|
|
var hasFocus = windowFocus && window.hadFocus
|
|
$.each(loadedMonitors,function(frontId,monitor){
|
|
setTimeout(() => {
|
|
var monitorId = monitor.mid
|
|
var muted = monitorMutes[monitorId]
|
|
try{
|
|
var vidEl = $('.monitor_item[mid="' + monitorId + '"] video')[0]
|
|
if(vidEl.length === 0)return;
|
|
if(muted === 1){
|
|
vidEl.muted = true
|
|
}else{
|
|
if(hasFocus){
|
|
vidEl.muted = false
|
|
}else{
|
|
console.error('User must have window active to unmute.')
|
|
}
|
|
}
|
|
}catch(err){
|
|
// console.log(err)
|
|
}
|
|
},2000)
|
|
})
|
|
}
|
|
//initiate signal check
|
|
if(streamType !== 'useSubstream'){
|
|
var signalCheckInterval = (isNaN(loadedMonitor.details.signal_check) ? 10 : parseFloat(loadedMonitor.details.signal_check)) * 1000 * 60
|
|
if(signalCheckInterval > 0){
|
|
clearInterval(loadedPlayer.signal)
|
|
loadedPlayer.signal = setInterval(function(){
|
|
signalCheckLiveStream({
|
|
mid: monitorId,
|
|
checkSpeed: 1000,
|
|
})
|
|
},signalCheckInterval);
|
|
}
|
|
}
|
|
}
|
|
function revokeVideoPlayerUrl(monitorId){
|
|
try{
|
|
URL.revokeObjectURL(liveGridElements[monitorId].streamElement[0].src)
|
|
}catch(err){
|
|
debugLog(err)
|
|
}
|
|
}
|
|
function closeLiveGridPlayer(monitorId,killElement){
|
|
try{
|
|
var livePlayerElement = loadedLiveGrids[monitorId]
|
|
if(livePlayerElement){
|
|
if(livePlayerElement.hls){livePlayerElement.hls.destroy()}
|
|
if(livePlayerElement.Poseidon){livePlayerElement.Poseidon.stop()}
|
|
if(livePlayerElement.Base64){livePlayerElement.Base64.disconnect()}
|
|
if(livePlayerElement.dash){livePlayerElement.dash.reset()}
|
|
if(livePlayerElement.jpegInterval){
|
|
stopJpegStream(monitorId)
|
|
}
|
|
$.each(onLiveStreamCloseExtensions,function(n,extender){
|
|
extender(livePlayerElement)
|
|
})
|
|
}
|
|
if(liveGridElements[monitorId])revokeVideoPlayerUrl(monitorId)
|
|
clearInterval(livePlayerElement.signal)
|
|
}catch(err){
|
|
console.log(err)
|
|
}
|
|
if(killElement){
|
|
var theElement = $('#monitor_live_'+monitorId)
|
|
if(theElement.length > 0){
|
|
getLiveGridData().removeWidget(theElement)
|
|
setLiveGridOpenCount(-1)
|
|
delete(loadedLiveGrids[monitorId])
|
|
delete(liveGridElements[monitorId])
|
|
}
|
|
}
|
|
}
|
|
function callMonitorToLiveGrid(v){
|
|
var watchedOn = dashboardOptions().watch_on || {}
|
|
if(watchedOn[v.ke] && watchedOn[v.ke][v.mid] === 1 && loadedMonitors[v.mid] && loadedMonitors[v.mid].mode !== 'stop'){
|
|
mainSocket.f({f:'monitor',ff:'watch_on',id:v.mid})
|
|
openLiveGrid()
|
|
}
|
|
}
|
|
function loadPreviouslyOpenedLiveGridBlocks(){
|
|
$.getJSON(getApiPrefix(`monitor`),function(data){
|
|
$.each(data,function(n,v){
|
|
callMonitorToLiveGrid(v)
|
|
})
|
|
setTimeout(function(){
|
|
sortListMonitors()
|
|
if(dashboardOptions().switches.jpegMode === 1){
|
|
mainSocket.f({
|
|
f: 'monitor',
|
|
ff: 'jpeg_on'
|
|
})
|
|
}
|
|
},1000)
|
|
drawMonitorGroupList()
|
|
})
|
|
}
|
|
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})
|
|
}
|
|
})
|
|
})
|
|
}
|
|
function saveLiveGridBlockOpenState(monitorId,groupKey,state){
|
|
var openBlocks = dashboardOptions().watch_on || {}
|
|
openBlocks[groupKey] = openBlocks[groupKey] ? openBlocks[groupKey] : {}
|
|
openBlocks[groupKey][monitorId] = state || 0
|
|
dashboardOptions('watch_on',openBlocks)
|
|
}
|
|
function openLiveGrid(){
|
|
if(tabTree.name !== 'liveGrid'){
|
|
openTab('liveGrid',{})
|
|
}
|
|
}
|
|
function popOutMonitor(monitorId){
|
|
var monitorPop = monitorPops[monitorId]
|
|
function finish(img){
|
|
if(monitorPop){
|
|
monitorPop.close()
|
|
}
|
|
monitorPop = window.open(getApiPrefix() + '/embed/' + $user.ke + '/' + monitorId + '/fullscreen|jquery|relative|gui','pop_' + monitorId + $user.auth_token,'height='+img.height+',width='+img.width);
|
|
}
|
|
if(loadedLiveGrids[monitorId]){
|
|
getSnapshot(loadedMonitors[monitorId],function(url){
|
|
$('#temp').html('<img>')
|
|
var img=$('#temp img')[0]
|
|
img.onload = function(){
|
|
finish(img)
|
|
}
|
|
img.src = url
|
|
})
|
|
}else{
|
|
var img = {
|
|
height: 720,
|
|
width: 1280
|
|
}
|
|
finish(img)
|
|
}
|
|
}
|
|
function fullScreenLiveGridStream(monitorItem){
|
|
var videoElement = monitorItem.find('.stream-element')
|
|
monitorItem.addClass('fullscreen')
|
|
if(videoElement.is('canvas')){
|
|
var theBody = $('body')
|
|
videoElement.attr('height',theBody.height())
|
|
videoElement.attr('width',theBody.width())
|
|
}
|
|
fullScreenInit(videoElement[0])
|
|
}
|
|
function toggleJpegMode(){
|
|
var sendData = {
|
|
f: 'monitor',
|
|
ff: 'jpeg_on'
|
|
}
|
|
if(window.jpegModeOn === true){
|
|
sendData.ff = 'jpeg_off'
|
|
}
|
|
mainSocket.f(sendData)
|
|
}
|
|
function startJpegStream(monitorId){
|
|
if(loadedLiveGrids[monitorId]){
|
|
var monitor = loadedMonitors[monitorId]
|
|
var loadedBlock = loadedLiveGrids[monitorId]
|
|
var jpegInterval = !isNaN(monitor.details.jpegInterval) ? parseFloat(monitor.details.jpegInterval) : 1
|
|
resetMonitorCanvas(monitorId,false)
|
|
var streamElement = $('#monitor_live_' + monitorId + ' .stream-element');
|
|
// stopJpegStream(monitorId)
|
|
var jpegUrl = getApiPrefix('jpeg') + '/' + monitorId + '/s.jpg?time='
|
|
function drawNewFrame(){
|
|
streamElement.attr('src',jpegUrl + (new Date()).getTime())
|
|
}
|
|
streamElement.on('load',function(){
|
|
loadedBlock.jpegInterval = setTimeout(drawNewFrame,1000/jpegInterval)
|
|
}).on('error',function(){
|
|
loadedBlock.jpegInterval = setTimeout(drawNewFrame,1000/jpegInterval)
|
|
})
|
|
drawNewFrame()
|
|
}
|
|
}
|
|
function stopJpegStream(monitorId){
|
|
var livePlayerElement = loadedLiveGrids[monitorId]
|
|
if(!livePlayerElement)return;
|
|
try{
|
|
liveGridElements[monitorId].streamElement.off('load').off('error')
|
|
clearTimeout(livePlayerElement.jpegInterval)
|
|
}catch(err){
|
|
console.log(err)
|
|
console.log(monitorId)
|
|
}
|
|
}
|
|
function startAllJpegStreams(monitorId){
|
|
$.each(loadedMonitors,function(n,monitor){
|
|
startJpegStream(monitor.mid)
|
|
})
|
|
}
|
|
function stopAllJpegStreams(monitorId){
|
|
$.each(loadedMonitors,function(n,monitor){
|
|
stopJpegStream(monitor.mid)
|
|
})
|
|
}
|
|
function canBackgroundStream(){
|
|
return tabTree.name === 'liveGrid' && dashboardOptions().switches.backgroundStream === 1
|
|
}
|
|
function resetLiveGridDimensionsInMemory(monitorId){
|
|
var theRef = liveGridElements[monitorId]
|
|
theRef.width = theRef.streamElement.width()
|
|
theRef.height = theRef.streamElement.height()
|
|
}
|
|
function resetAllLiveGridDimensionsInMemory(monitorId){
|
|
$.each(liveGridElements,function(monitorId,data){
|
|
resetLiveGridDimensionsInMemory(monitorId)
|
|
})
|
|
}
|
|
function signalCheckLiveStream(options){
|
|
try{
|
|
var monitorId = options.mid
|
|
var monitorConfig = loadedMonitors[monitorId]
|
|
var liveGridData = liveGridElements[monitorId]
|
|
var monitorItem = liveGridData.monitorItem
|
|
var monitorDetails = monitorConfig.details
|
|
var checkCount = 0
|
|
var base64Data = null;
|
|
var checkSpeed = options.checkSpeed || 1000
|
|
var subStreamChannel = monitor.subStreamChannel
|
|
var streamType = subStreamChannel ? monitorDetails.substream ? monitorDetails.substream.output.stream_type : 'hls' : monitorDetails.stream_type
|
|
function failedStreamCheck(){
|
|
if(monitorConfig.signal_check_log == 1){
|
|
logWriterDraw('[mid="'+monitorId+'"]',{
|
|
log: {
|
|
type: 'Stream Check',
|
|
msg: lang.clientStreamFailedattemptingReconnect
|
|
}
|
|
})
|
|
}
|
|
mainSocket.f({f:'monitor',ff:'watch_on',id:monitorId});
|
|
}
|
|
function succeededStreamCheck(){
|
|
if(monitorConfig.signal_check_log == 1){
|
|
logWriterDraw('[mid="'+monitorId+'"]',{
|
|
log: {
|
|
type: 'Stream Check',
|
|
msg : lang.Success
|
|
}
|
|
})
|
|
}
|
|
}
|
|
function executeCheck(){
|
|
switch(streamType){
|
|
case'b64':
|
|
monitorItem.resize()
|
|
break;
|
|
case'hls':case'flv':case'mp4':
|
|
if(monitorItem.find('video')[0].paused){
|
|
failedStreamCheck()
|
|
}else{
|
|
succeededStreamCheck()
|
|
}
|
|
break;
|
|
default:
|
|
if(dashboardOptions().jpeg_on === true){return}
|
|
getSnapshot({
|
|
monitor: loadedMonitors[monitorId],
|
|
},function(url){
|
|
base64Data = url;
|
|
setTimeout(function(){
|
|
getSnapshot({
|
|
monitor: loadedMonitors[monitorId],
|
|
},function(url){
|
|
if(base64Data === url){
|
|
if(checkCount < 3){
|
|
++checkCount;
|
|
setTimeout(function(){
|
|
executeCheck();
|
|
},checkSpeed)
|
|
}else{
|
|
failedStreamCheck()
|
|
}
|
|
}else{
|
|
succeededStreamCheck()
|
|
}
|
|
});
|
|
},checkSpeed)
|
|
});
|
|
break;
|
|
}
|
|
$.each(onSignalCheckLiveStreamExtensions,function(n,extender){
|
|
extender(streamType,monitorItem)
|
|
})
|
|
}
|
|
executeCheck();
|
|
}catch(err){
|
|
var errorStack = err.stack;
|
|
function phraseFoundInErrorStack(x){return errorStack.indexOf(x) > -1}
|
|
if(phraseFoundInErrorStack("The HTMLImageElement provided is in the 'broken' state.")){
|
|
mainSocket.f({f:'monitor',ff:'watch_on',id:monitorId});
|
|
}
|
|
clearInterval(liveGridData.signal);
|
|
delete(liveGridData.signal);
|
|
}
|
|
}
|
|
$(document).ready(function(e){
|
|
liveGrid
|
|
.on('dblclick','.stream-hud',function(){
|
|
$(this).parents('[data-mid]').find('[monitor="fullscreen"]').click();
|
|
})
|
|
$('body')
|
|
.resize(function(){
|
|
resetAllLiveGridDimensionsInMemory()
|
|
})
|
|
.on('click','.launch-live-grid-monitor',function(){
|
|
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
|
|
// if(isMobile){
|
|
// createLivePlayerTab(loadedMonitors[monitorId])
|
|
// }else{
|
|
mainSocket.f({
|
|
f: 'monitor',
|
|
ff: 'watch_on',
|
|
id: monitorId
|
|
})
|
|
openLiveGrid()
|
|
// }
|
|
})
|
|
.on('click','.reconnect-live-grid-monitor',function(){
|
|
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
|
|
mainSocket.f({
|
|
f: 'monitor',
|
|
ff: 'watch_on',
|
|
id: monitorId
|
|
})
|
|
})
|
|
.on('click','.close-live-grid-monitor',function(){
|
|
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
|
|
mainSocket.f({
|
|
f: 'monitor',
|
|
ff: 'watch_off',
|
|
id: monitorId
|
|
})
|
|
setTimeout(function(){
|
|
saveLiveGridBlockOpenState(monitorId,$user.ke,0)
|
|
},1000)
|
|
})
|
|
.on('click','.snapshot-live-grid-monitor',function(){
|
|
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
|
|
getSnapshot({
|
|
monitor: loadedMonitors[monitorId],
|
|
},function(url){
|
|
$('#temp').html('<a href="'+url+'" download="'+formattedTimeForFilename()+'_'+monitorId+'.jpg">a</a>').find('a')[0].click();
|
|
})
|
|
})
|
|
.on('click','.toggle-live-grid-monitor-logs',function(){
|
|
var monitorItem = $(this).parents('[data-mid]')
|
|
var monitorId = monitorItem.attr('data-mid')
|
|
monitorItem.toggleClass('show_data')
|
|
var dataBlocks = monitorItem.find('.stream-block,.mdl-data_window')
|
|
if(monitorItem.hasClass('show_data')){
|
|
loadVideoMiniList(monitorId)
|
|
dataBlocks.addClass('col-md-6').removeClass('col-md-12')
|
|
}else{
|
|
dataBlocks.addClass('col-md-12').removeClass('col-md-6')
|
|
}
|
|
})
|
|
.on('click','.toggle-live-grid-monitor-ptz-controls',function(){
|
|
var monitorItem = $(this).parents('[data-mid]').attr('data-mid')
|
|
drawPtzControlsOnLiveGridBlock(monitorItem)
|
|
})
|
|
.on('click','.toggle-live-grid-monitor-menu,.mdl-overlay-menu-backdrop',function(){
|
|
var monitorItem = $(this).parents('[data-mid]')
|
|
var monitorId = monitorItem.attr('data-mid')
|
|
monitorItem.find('.mdl-overlay-menu-backdrop').toggleClass('hidden')
|
|
})
|
|
.on('click','.mdl-overlay-menu',function(e){
|
|
e.stopPropagation()
|
|
return false;
|
|
})
|
|
.on('click','.toggle-live-grid-monitor-fullscreen',function(){
|
|
var monitorItem = $(this).parents('[data-mid]')
|
|
fullScreenLiveGridStream(monitorItem)
|
|
})
|
|
.on('click','.run-live-grid-monitor-pop',function(){
|
|
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
|
|
popOutMonitor(monitorId)
|
|
})
|
|
.on('click','.toggle-monitor-substream',function(){
|
|
var monitorId = $(this).parents('[data-mid]').attr('data-mid')
|
|
toggleSubStream(monitorId)
|
|
})
|
|
.on('click','.run-live-grid-monitor-ptz',function(){
|
|
var el = $(this)
|
|
var monitorId = el.parents('[data-mid]').attr('data-mid')
|
|
var switchChosen = el.attr('data-ptz-control')
|
|
runPtzCommand(monitorId,switchChosen)
|
|
})
|
|
.on('click','.run-monitor-detection-trigger-test',function(){
|
|
var el = $(this)
|
|
var monitorId = el.parents('[data-mid]').attr('data-mid')
|
|
runTestDetectionTrigger(monitorId)
|
|
})
|
|
$('.open-all-monitors').click(function(){
|
|
$.each(loadedMonitors,function(monitorId,monitor){
|
|
mainSocket.f({
|
|
f: 'monitor',
|
|
ff: 'watch_on',
|
|
id: monitor.mid
|
|
})
|
|
openLiveGrid()
|
|
})
|
|
})
|
|
$('.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)
|
|
})
|
|
})
|
|
liveGrid
|
|
.gridstack({
|
|
cellHeight: 80,
|
|
verticalMargin: 0,
|
|
})
|
|
.on('dragstop', function(event,ui){
|
|
setTimeout(function(){
|
|
saveLiveGridBlockPositions()
|
|
},700)
|
|
})
|
|
.on('gsresizestop', function(){
|
|
resetAllLiveGridDimensionsInMemory()
|
|
saveLiveGridBlockPositions()
|
|
});
|
|
addOnTabReopen('liveGrid', function () {
|
|
loadPreviouslyOpenedLiveGridBlocks()
|
|
})
|
|
addOnTabAway('liveGrid', function () {
|
|
closeAllLiveGridPlayers()
|
|
})
|
|
onInitWebsocket(function (d){
|
|
loadPreviouslyOpenedLiveGridBlocks()
|
|
})
|
|
onWebSocketEvent(function (d){
|
|
switch(d.f){
|
|
case'init_success':
|
|
// loadPreviouslyOpenedLiveGridBlocks()
|
|
break;
|
|
case'video_build_success':
|
|
d.status = 1
|
|
d.mid = d.id || d.mid
|
|
if(liveGridElements[d.mid] && liveGridElements[d.mid].streamElement)drawVideoCardToMiniList(d.mid,createVideoLinks(d),false)
|
|
break;
|
|
case'monitor_watch_off':case'monitor_stopping':
|
|
var monitorId = d.mid || d.id
|
|
closeLiveGridPlayer(monitorId,(d.f === 'monitor_watch_off'))
|
|
break;
|
|
case'monitor_status':
|
|
if(
|
|
tabTree.name === 'liveGrid' &&
|
|
(
|
|
d.code === 2 ||
|
|
d.code === 3
|
|
)
|
|
){
|
|
var monitorId = d.mid || d.id
|
|
setTimeout(function(){
|
|
callMonitorToLiveGrid(loadedMonitors[monitorId])
|
|
},2000)
|
|
}
|
|
break;
|
|
case'substream_start':
|
|
loadedMonitors[d.mid].subStreamChannel = d.channel
|
|
setTimeout(() => {
|
|
resetMonitorCanvas(d.mid,true,d.channel)
|
|
},3000)
|
|
break;
|
|
case'substream_end':
|
|
loadedMonitors[d.mid].subStreamChannel = null
|
|
resetMonitorCanvas(d.mid,true,null)
|
|
break;
|
|
case'monitor_watch_on':
|
|
var monitorId = d.mid || d.id
|
|
var loadedMonitor = loadedMonitors[monitorId]
|
|
var subStreamChannel = d.subStreamChannel
|
|
if(!loadedMonitor.subStreamChannel && loadedMonitor.details.stream_type === 'useSubstream'){
|
|
toggleSubStream(monitorId,function(){
|
|
drawLiveGridBlock(loadedMonitors[monitorId],subStreamChannel)
|
|
saveLiveGridBlockOpenState(monitorId,$user.ke,1)
|
|
})
|
|
}else{
|
|
drawLiveGridBlock(loadedMonitors[monitorId],subStreamChannel)
|
|
saveLiveGridBlockOpenState(monitorId,$user.ke,1)
|
|
}
|
|
break;
|
|
case'mode_jpeg_off':
|
|
window.jpegModeOn = false
|
|
$.each(loadedMonitors,function(n,v){
|
|
stopJpegStream(v.mid)
|
|
resetMonitorCanvas(v.mid)
|
|
initiateLiveGridPlayer(v)
|
|
})
|
|
$('body').removeClass('jpegMode')
|
|
break;
|
|
case'mode_jpeg_on':
|
|
window.jpegModeOn = true
|
|
startAllJpegStreams()
|
|
$('body').addClass('jpegMode')
|
|
break;
|
|
case'detector_trigger':
|
|
var monitorId = d.id
|
|
var liveGridElement = liveGridElements[monitorId]
|
|
if(liveGridElement){
|
|
var monitorElement = liveGridElement.monitorItem
|
|
var livePlayerElement = loadedLiveGrids[monitorId]
|
|
if(d.doObjectDetection === true){
|
|
monitorElement.addClass('doObjectDetection')
|
|
clearTimeout(livePlayerElement.detector_trigger_doObjectDetection_timeout)
|
|
livePlayerElement.detector_trigger_doObjectDetection_timeout = setTimeout(function(){
|
|
monitorElement.removeClass('doObjectDetection')
|
|
},3000)
|
|
}else{
|
|
monitorElement.removeClass('doObjectDetection')
|
|
}
|
|
if(d.details.matrices&&d.details.matrices.length>0){
|
|
drawMatrices(d,{
|
|
theContainer: liveGridElement.eventObjects,
|
|
height: liveGridElement.height,
|
|
width: liveGridElement.width,
|
|
})
|
|
}
|
|
if(d.details.confidence){
|
|
var eventConfidence = d.details.confidence
|
|
if(eventConfidence > 100)eventConfidence = 100
|
|
liveGridElement.motionMeter.css('width',eventConfidence + '%');
|
|
liveGridElement.motionMeterText[0].innerHtml = d.details.confidence+'% change in <b>'+d.details.name+'</b>'
|
|
}
|
|
monitorElement.addClass('detector_triggered')
|
|
clearTimeout(livePlayerElement.detector_trigger_timeout);
|
|
livePlayerElement.detector_trigger_timeout = setTimeout(function(){
|
|
monitorElement.removeClass('detector_triggered');
|
|
liveGridElement.eventObjects.find('.stream-detected-object,.stream-detected-point').remove()
|
|
},800);
|
|
playAudioAlert()
|
|
var monitorPop = monitorPops[monitorId]
|
|
if($user.details.event_mon_pop === '1' && (!monitorPop || monitorPop.closed === true)){
|
|
popOutMonitor(monitorId)
|
|
}
|
|
// console.log({
|
|
// ke: d.ke,
|
|
// mid: monitorId,
|
|
// log: {
|
|
// type: lang['Event Occurred'],
|
|
// msg: d.details,
|
|
// }
|
|
// })
|
|
}
|
|
break;
|
|
}
|
|
})
|
|
$(window).focus(function(){
|
|
if(canBackgroundStream()){
|
|
loadPreviouslyOpenedLiveGridBlocks()
|
|
}
|
|
}).blur(function(){
|
|
if(canBackgroundStream()){
|
|
closeAllLiveGridPlayers()
|
|
}
|
|
})
|
|
dashboardSwitchCallbacks.monitorOrder = function(toggleState){
|
|
if(toggleState !== 1){
|
|
$('.monitor_item').attr('data-gs-auto-position','yes')
|
|
}else{
|
|
$('.monitor_item').attr('data-gs-auto-position','no')
|
|
}
|
|
}
|
|
dashboardSwitchCallbacks.monitorMuteAudio = function(toggleState){
|
|
var monitorMutes = dashboardOptions().monitorMutes || {}
|
|
$('.monitor_item video').each(function(n,vidEl){
|
|
var el = $(this)
|
|
var monitorId = el.parents('[data-mid]').attr('data-mid')
|
|
if(toggleState === 1){
|
|
el.attr('muted','muted')
|
|
}else{
|
|
if(monitorMutes[monitorId] !== 1){
|
|
el.removeAttr('muted')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
dashboardSwitchCallbacks.jpegMode = toggleJpegMode
|
|
})
|