var streamCmdTimer = null; var streamStatus; var alarmState = STATE_IDLE; var lastAlarmState = STATE_IDLE; var backBtn = $j('#backBtn'); var settingsBtn = $j('#settingsBtn'); var enableAlmBtn = $j('#enableAlmBtn'); var forceAlmBtn = $j('#forceAlmBtn'); var table = $j('#eventList'); var filterQuery = '&filter[Query][terms][0][attr]=MonitorId&filter[Query][terms][0][op]=%3d&filter[Query][terms][0][val]='+monitorId; var server; var janus = null; var opaqueId; var streaming2; /* This is the format of the json object sent by bootstrap-table var params = { "type":"get", "data": { "search":"some search text", "sort":"StartDateTime", "order":"asc", "offset":0, "limit":25 "filter": { "Name":"some advanced search text" "StartDateTime":"some more advanced search text" } }, "cache":true, "contentType":"application/json", "dataType":"json" }; */ // Called by bootstrap-table to retrieve zm event data function ajaxRequest(params) { // Maintain legacy behavior by statically setting these parameters var data = params.data; data.order = 'desc'; data.limit = maxDisplayEvents; data.sort = 'Id'; data.view = 'request'; data.request = 'watch'; data.mid = monitorId; if (auth_hash) data.auth = auth_hash; $j.getJSON(thisUrl, data) .done(function(data) { var rows = processRows(data.rows); params.success(rows); }) .fail(logAjaxFail); } function processRows(rows) { $j.each(rows, function(ndx, row) { var eid = row.Id; row.Delete = ''; row.Id = '' + eid + ''; row.Name = '' + row.Name + ''; row.Frames = '' + row.Frames + ''; row.AlarmFrames = '' + row.AlarmFrames + ''; row.MaxScore = '' + row.MaxScore + ''; if ( LIST_THUMBS ) row.Thumbnail = '' + row.imgHtml + ''; }); return rows; } function showEvents() { $j('#ptzControls').addClass('hidden'); $j('#events').removeClass('hidden'); if ($j('#eventsControl')) { $j('#eventsControl').addClass('hidden'); } if ($j('#controlControl')) { $j('#controlControl').removeClass('hidden'); } showMode = 'events'; } function showPtzControls() { $j('#events').addClass('hidden'); $j('#ptzControls').removeClass('hidden'); if ($j('#eventsControl')) { $j('#eventsControl').removeClass('hidden'); } if ($j('#controlControl')) { $j('#controlControl').addClass('hidden'); } showMode = 'control'; } function changeSize() { var width = $j('#width').val(); var height = $j('#height').val(); // Scale the frame monitor_frame = $j('#imageFeed'); if (!monitor_frame) { console.log('Error finding frame'); return; } if (width) monitor_frame.css('width', width); if (height) monitor_frame.css('height', height); var streamImg = document.getElementById('liveStream'+monitorData[monIdx].id); if (streamImg) { if (streamImg.nodeName == 'IMG') { let src = streamImg.src; streamImg.src = ''; src = src.replace(/width=[\.\d]+/i, 'width='+parseInt(width)); src = src.replace(/height=[\.\d]+/i, 'height='+parseInt(height)); src = src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); streamImg.src = src; } streamImg.style.width = width ? width : null; streamImg.style.height = height ? height : null; } else { console.log('Did not find liveStream'+monitorData[monIdx].id); } $j('#scale').val(''); setCookie('zmCycleScale', '', 3600); setCookie('zmCycleWidth', width, 3600); setCookie('zmCycleHeight', height, 3600); } // end function changeSize() function changeScale() { var scale = $j('#scale').val(); setCookie('zmWatchScale'+monitorId, scale, 3600); $j('#width').val('auto'); $j('#height').val('auto'); setCookie('zmCycleScale', scale, 3600); setCookie('zmCycleWidth', 'auto', 3600); setCookie('zmCycleHeight', 'auto', 3600); var newWidth; var newHeight; var autoScale; var streamImg = $j('#liveStream'+monitorId); if (!streamImg.length) { console.error('No element found for liveStream'+monitorId); } // Always turn it off, we will re-add it below. I don't know if you can add a callback multiple // times and what the consequences would be $j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active if (scale == '0' || scale == 'auto') { const newSize = scaleToFit(monitorWidth, monitorHeight, streamImg, $j('#dvrControls')); newWidth = newSize.width; newHeight = newSize.height; autoScale = newSize.autoScale; $j(window).on('resize', endOfResize); //remove resize handler when Scale to Fit is not active } else { newWidth = monitorWidth * scale / SCALE_BASE; newHeight = monitorHeight * scale / SCALE_BASE; } if (streamImg.prop('nodeName') == 'IMG') { const oldSrc = streamImg.attr('src'); streamImg.attr('src', ''); // This is so that we don't waste bandwidth and let the browser do all the scaling. if (autoScale > 100) autoScale = 100; if (scale > 100) scale = 100; const newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+((scale == 'auto' || scale == '0') ? autoScale : scale)); streamImg.css('width', newWidth+'px'); streamImg.width(newWidth); streamImg.css('height', newHeight+'px'); streamImg.height(newHeight); streamImg.attr('src', newSrc); } else { console.log("Not an IMG, can't set size"); } } // end function changeScale function setAlarmState(currentAlarmState) { alarmState = currentAlarmState; var stateClass = ''; if (alarmState == STATE_ALARM) { stateClass = 'alarm'; } else if (alarmState == STATE_ALERT) { stateClass = 'alert'; } $j('#stateValue').text(stateStrings[alarmState]); if (stateClass) { $j('#stateValue').addClass(stateClass); } else { $j('#stateValue').removeClass(); } var isAlarmed = ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ); var wasAlarmed = ( lastAlarmState == STATE_ALARM || lastAlarmState == STATE_ALERT ); var newAlarm = ( isAlarmed && !wasAlarmed ); var oldAlarm = ( !isAlarmed && wasAlarmed ); if (newAlarm) { table.bootstrapTable('refresh'); if (SOUND_ON_ALARM) { // Enable the alarm sound if (!msieVer) { $j('#alarmSound').removeClass('hidden'); } else { $j('#MediaPlayer').trigger('play'); } } if (POPUP_ON_ALARM) { window.focus(); } } if (oldAlarm) { // done with an event do a refresh table.bootstrapTable('refresh'); if (SOUND_ON_ALARM) { // Disable alarm sound if (!msieVer) { $j('#alarmSound').addClass('hidden'); } else { $j('#MediaPlayer').trigger('pause'); } } } lastAlarmState = alarmState; } // end function setAlarmState( currentAlarmState ) function streamCmdReq(data) { if (auth_hash) data.auth = auth_hash; $j.getJSON(monitorUrl + '?view=request&request=stream&connkey='+connKey, data) .done(getStreamCmdResponse) .fail(getStreamCmdError); streamCmdTimer = null; } function getStreamCmdError(text, error) { console.log(error); // Error are normally due to failed auth. reload the page. //window.location.reload(); } function getStreamCmdResponse(respObj, respText) { watchdogOk('stream'); if (streamCmdTimer) { streamCmdTimer = clearTimeout(streamCmdTimer); } if (respObj.result == 'Ok') { // The get status command can get backed up, in which case we won't be able to get the semaphore and will exit. if (respObj.status) { streamStatus = respObj.status; if ($j('#viewingFPSValue').text() != streamStatus.fps) { $j('#viewingFPSValue').text(streamStatus.fps); } if ($j('#captureFPSValue').text() != streamStatus.capturefps) { $j('#captureFPSValue').text(streamStatus.capturefps); } if ($j('#analysisFPSValue').text() != streamStatus.analysisfps) { $j('#analysisFPSValue').text(streamStatus.analysisfps); } setAlarmState(streamStatus.state); $j('#levelValue').text(streamStatus.level); var newClass = 'ok'; if (streamStatus.level > 95) { newClass = 'alarm'; } else if (streamStatus.level > 80) { newClass = 'alert'; } $j('#levelValue').removeClass(); $j('#levelValue').addClass(newClass); var delayString = secsToTime(streamStatus.delay); if (streamStatus.paused == true) { $j('#modeValue').text('Paused'); $j('#rate').addClass('hidden'); $j('#delayValue').text(delayString); $j('#delay').removeClass('hidden'); $j('#level').removeClass('hidden'); streamCmdPause(false); } else if (streamStatus.delayed == true) { $j('#modeValue').text('Replay'); $j('#rateValue').text(streamStatus.rate); $j('#rate').removeClass('hidden'); $j('#delayValue').text(delayString); $j('#delay').removeClass('hidden'); $j('#level').removeClass('hidden'); if (streamStatus.rate == 1) { streamCmdPlay(false); } else if (streamStatus.rate > 0) { if (streamStatus.rate < 1) { streamCmdSlowFwd(false); } else { streamCmdFastFwd(false); } } else { if (streamStatus.rate > -1) { streamCmdSlowRev(false); } else { streamCmdFastRev(false); } } // rate } else { $j('#modeValue').text('Live'); $j('#rate').addClass('hidden'); $j('#delay').addClass('hidden'); $j('#level').addClass('hidden'); streamCmdPlay(false); } // end if paused or delayed $j('#zoomValue').text(streamStatus.zoom); if (streamStatus.zoom == '1.0') { setButtonState('zoomOutBtn', 'unavail'); } else { setButtonState('zoomOutBtn', 'inactive'); } if (canEdit.Monitors) { if (streamStatus.enabled) { enableAlmBtn.addClass('disabled'); enableAlmBtn.prop('title', disableAlarmsStr); if (streamStatus.forced) { forceAlmBtn.addClass('disabled'); forceAlmBtn.prop('title', cancelForcedAlarmStr); } else { forceAlmBtn.removeClass('disabled'); forceAlmBtn.prop('title', forceAlarmStr); } forceAlmBtn.prop('disabled', false); } else { enableAlmBtn.removeClass('disabled'); enableAlmBtn.prop('title', enableAlarmsStr); forceAlmBtn.prop('disabled', true); } enableAlmBtn.prop('disabled', false); } // end if canEdit.Monitors if (streamStatus.auth) { auth_hash = streamStatus.auth; // Try to reload the image stream. var streamImg = $j('#liveStream'+monitorId); if (streamImg) { const oldSrc = streamImg.attr('src'); if (oldSrc) { const newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth); if (oldSrc != newSrc) { streamImg.attr('src', newSrc); table.bootstrapTable('refresh'); } } } } // end if have a new auth hash } // end if respObj.status } else { console.log("Not ok"); checkStreamForErrors('getStreamCmdResponse', respObj);//log them fetchImage($j('#imageFeed img')); } var streamCmdTimeout = statusRefreshTimeout; if (alarmState == STATE_ALARM || alarmState == STATE_ALERT) { streamCmdTimeout = streamCmdTimeout/5; } streamCmdTimer = setTimeout(streamCmdQuery, streamCmdTimeout); } function streamCmdQuery() { streamCmdReq({command: CMD_QUERY}); } function streamCmdPause(action) { setButtonState('pauseBtn', 'active'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive'); } if (action) { var data = {}; if (auth_hash) data.auth = auth_hash; data.command = CMD_PAUSE; streamCmdReq(data); } } function streamCmdPlay(action) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'active'); if (streamStatus.delayed == true) { setButtonState('stopBtn', 'inactive'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive'); } } else { setButtonState('stopBtn', 'unavail'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'unavail'); setButtonState('slowFwdBtn', 'unavail'); setButtonState('slowRevBtn', 'unavail'); setButtonState('fastRevBtn', 'unavail'); } } if (action) { streamCmdReq({command: CMD_PLAY}); } } function streamCmdStop(action) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'unavail'); setButtonState('stopBtn', 'active'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'unavail'); setButtonState('slowFwdBtn', 'unavail'); setButtonState('slowRevBtn', 'unavail'); setButtonState('fastRevBtn', 'unavail'); } if (action) { streamCmdReq({command: CMD_STOP}); } setButtonState('stopBtn', 'unavail'); setButtonState('playBtn', 'active'); } function streamCmdFastFwd(action) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive'); } if (action) { streamCmdReq({command: CMD_FASTFWD}); } } function streamCmdSlowFwd(action) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'active'); setButtonState('slowRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive'); } if (action) { streamCmdReq({command: CMD_SLOWFWD}); } setButtonState('pauseBtn', 'active'); if (monitorStreamReplayBuffer) { setButtonState('slowFwdBtn', 'inactive'); } } function streamCmdSlowRev(action) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowRevBtn', 'active'); setButtonState('fastRevBtn', 'inactive'); } if (action) { streamCmdReq({command: CMD_SLOWREV}); } setButtonState('pauseBtn', 'active'); if (monitorStreamReplayBuffer) { setButtonState('slowRevBtn', 'inactive'); } } function streamCmdFastRev(action) { setButtonState('pauseBtn', 'inactive'); setButtonState('playBtn', 'inactive'); setButtonState('stopBtn', 'inactive'); if (monitorStreamReplayBuffer) { setButtonState('fastFwdBtn', 'inactive'); setButtonState('slowFwdBtn', 'inactive'); setButtonState('slowRevBtn', 'inactive'); setButtonState('fastRevBtn', 'inactive'); } if (action) { streamCmdReq({command: CMD_FASTREV}); } } function streamCmdZoomIn(x, y) { var data = {}; data.x = x; data.y = y; data.command = CMD_ZOOMIN; streamCmdReq(data); } function streamCmdZoomOut() { streamCmdReq({command: CMD_ZOOMOUT}); } function streamCmdScale(scale) { var data = {}; data.command = CMD_SCALE; data.scale = scale; streamCmdReq(data); } function streamCmdPan(x, y) { var data = {}; data.x = x; data.y = y; data.command = CMD_PAN; streamCmdReq(data); } /* getStatusCmd is used when not streaming, since there is no persistent zms */ function getStatusCmdResponse(respObj, respText) { watchdogOk('status'); if (statusCmdTimer) { statusCmdTimer = clearTimeout(statusCmdTimer); } if (respObj.result == 'Ok') { $j('#captureFPSValue').text(respObj.monitor.FrameRate); setAlarmState(respObj.monitor.Status); } else { checkStreamForErrors('getStatusCmdResponse', respObj); } var statusCmdTimeout = statusRefreshTimeout; if (alarmState == STATE_ALARM || alarmState == STATE_ALERT) { statusCmdTimeout = statusCmdTimeout/5; } statusCmdTimer = setTimeout(statusCmdQuery, statusCmdTimeout); } function statusCmdQuery() { $j.getJSON(monitorUrl + '?view=request&request=status&entity=monitor&element[]=Status&element[]=FrameRate&id='+monitorId+'&'+auth_relay) .done(getStatusCmdResponse) .fail(logAjaxFail); statusCmdTimer = null; } function alarmCmdReq(data) { if (auth_hash) data.auth = auth_hash; $j.getJSON(monitorUrl + '?view=request&request=alarm&id='+monitorId, data) .done(getAlarmCmdResponse) .fail(function(jqxhr, textStatus, error) { if (textStatus === 'timeout') { streamCmdQuery(); } else { logAjaxFail(jqxhr, textStatus, error); } }); } function getAlarmCmdResponse(respObj, respText) { checkStreamForErrors('getAlarmCmdResponse', respObj); } function cmdDisableAlarms() { var data = {}; data.command = 'disableAlarms'; alarmCmdReq(data); } function cmdEnableAlarms() { var data = {}; data.command = 'enableAlarms'; alarmCmdReq(data); } function cmdAlarm() { if (enableAlmBtn.hasClass('disabled')) { cmdEnableAlarms(); } else { cmdDisableAlarms(); } } function cmdForceAlarm() { var data = {}; data.command = 'forceAlarm'; alarmCmdReq(data); if (window.event) window.event.preventDefault(); } function cmdCancelForcedAlarm() { var data = {}; data.command = 'cancelForcedAlarm'; alarmCmdReq(data); if (window.event) window.event.preventDefault(); return false; } function cmdForce() { if (forceAlmBtn.hasClass('disabled')) { cmdCancelForcedAlarm(); } else { cmdForceAlarm(); } } function controlReq(data) { if (auth_hash) data.auth = auth_hash; $j.getJSON(monitorUrl + '?view=request&request=control&id='+monitorId, data) .done(getControlResponse) .fail(logAjaxFail); } function getControlResponse(respObj, respText) { if (!respObj) { return; } //console.log( respText ); if (respObj.result != 'Ok') { alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message); } } function controlCmd(event) { button = event.target; console.log(event); if (event.type !='mouseup') { control = button.getAttribute('value'); } else { console.log('stop'); console.log(event); control = 'moveStop'; } xtell = button.getAttribute('data-xtell'); ytell = button.getAttribute('data-ytell'); var data = {}; if (event && (xtell || ytell)) { const target = event.target; const offset = $j(target).offset(); const width = $j(target).width(); const height = $j(target).height(); const x = event.pageX - offset.left; const y = event.pageY - offset.top; if (xtell) { let xge = parseInt((x*100)/width); if (xtell == -1) { xge = 100 - xge; } else if (xtell == 2) { xge = 2*(50 - xge); } data.xge = xge; } if (ytell) { let yge = parseInt((y*100)/height); if (ytell == -1) { yge = 100 - yge; } else if (ytell == 2) { yge = 2*(50 - yge); } data.yge = yge; } } data.control = control; controlReq(data); if (streamMode == 'single') { setTimeout(fetchImage, 1000, $j('#imageFeed img')); } } function controlCmdImage(x, y) { var data = {}; data.scale = scale; data.control = imageControlMode; data.x = x; data.y = y; controlReq(data); if (streamMode == 'single') { setTimeout(fetchImage, 1000, $j('#imageFeed img')); } } function fetchImage(streamImage) { const oldsrc = streamImage.attr('src'); streamImage.attr('src', ''); streamImage.attr('src', oldsrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ))); } function handleClick(event) { // target should be the img tag var target = $j(event.target); var width = target.width(); var height = target.height(); var scaleX = parseInt(monitorWidth / width); var scaleY = parseInt(monitorHeight / height); var pos = target.offset(); var x = parseInt((event.pageX - pos.left) * scaleX); var y = parseInt((event.pageY - pos.top) * scaleY); if (showMode == 'events' || !imageControlMode) { if ( event.shift ) { streamCmdPan(x, y); } else if (event.ctrlKey) { streamCmdZoomOut(); } else { streamCmdZoomIn(x, y); } } else { controlCmdImage(x, y); } } function appletRefresh() { if (streamStatus && (!streamStatus.paused && !streamStatus.delayed)) { var streamImg = $j('#liveStream'+monitorId); if (streamImg) { var parent = streamImg.parent(); streamImg.remove(); streamImg.append(parent); } else { console.error("Nothing found for liveStream"+monitorId); } if (appletRefreshTime) { setTimeout(appletRefresh, appletRefreshTime*1000); } } else { setTimeout(appletRefresh, 15*1000); // if we are paused or delayed check every 15 seconds if we are live yet... } } var watchdogInactive = { 'stream': false, 'status': false }; var watchdogFunctions = { 'stream': streamCmdQuery, 'status': statusCmdQuery, }; //Make sure the various refreshes are still taking effect function watchdogCheck(type) { if (watchdogInactive[type]) { console.log("Detected streamWatch of type: " + type + " stopped, restarting"); watchdogFunctions[type](); watchdogInactive[type] = false; } else { watchdogInactive[type] = true; } } function watchdogOk(type) { watchdogInactive[type] = false; } function reloadWebSite() { document.getElementById('imageFeed').innerHTML = document.getElementById('imageFeed').innerHTML; } function updatePresetLabels() { var lblNdx = $j('#ctrlPresetForm option:selected').val(); $j('#newLabel').val(labels[lblNdx]); } function getCtrlPresetModal() { $j.getJSON(monitorUrl + '?request=modal&modal=controlpreset&mid=' + monitorId) .done(function(data) { insertModalHtml('ctrlPresetModal', data.html); updatePresetLabels(); // Manage the Preset Select box $j('#preset').change(updatePresetLabels); // Manage the Save button $j('#cPresetSubmitModal').click(function(evt) { evt.preventDefault(); $j('#ctrlPresetForm').submit(); }); }) .fail(logAjaxFail); } function changeControl(e) { const input = e.target; $j.getJSON(monitorUrl+'?request=v4l2_settings&mid='+monitorId+'&'+input.name+'='+input.value) .done(function(evt) { if (evt.result == 'Ok') { evt.controls.forEach(function(control) { const element = $j('#new'+control.control.charAt(0).toUpperCase() + control.control.slice(1)); if (element.length) { element.val(control.value); element.attr('title', control.value); } else { console.err('Element not found for #new'+control.control.charAt(0).toUpperCase() + control.control.slice(1)); } }); } }) .fail(logAjaxFail); } function getSettingsModal() { $j.getJSON(monitorUrl + '?request=modal&modal=settings&mid=' + monitorId) .done(function(data) { insertModalHtml('settingsModal', data.html); // Manage the Save button $j('#settingsSubmitModal').click(function(evt) { evt.preventDefault(); $j('#settingsForm').submit(); }); $j('#newBrightness').change(changeControl); $j('#newContrast').change(changeControl); $j('#newHue').change(changeControl); $j('#newColour').change(changeControl); }) .fail(logAjaxFail); } function processClicks(event, field, value, row, $element) { if (field == 'Delete') { $j.getJSON(monitorUrl + '?request=modal&modal=delconfirm') .done(function(data) { insertModalHtml('deleteConfirm', data.html); manageDelConfirmModalBtns(); $j('#deleteConfirm').data('eid', row.Id.replace(/(<([^>]+)>)/gi, '')); $j('#deleteConfirm').modal('show'); }) .fail(logAjaxFail); } } // Manage the DELETE CONFIRMATION modal button function manageDelConfirmModalBtns() { document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) { if (!canEdit.Events) { enoperm(); return; } var eid = $j('#deleteConfirm').data('eid'); evt.preventDefault(); $j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eid) .done(function(data) { table.bootstrapTable('refresh'); $j('#deleteConfirm').modal('hide'); }) .fail(logAjaxFail); }); // Manage the CANCEL modal button document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) { $j('#deleteConfirm').modal('hide'); }); } function msieVer() { var ua = window.navigator.userAgent; var msie = ua.indexOf("MSIE "); if (msie >= 0) { // If Internet Explorer, return version number return msie; } else { // If another browser, return 0 return 0; } } function initPage() { if (canView.Control) { // Load the PTZ Preset modal into the DOM if (monitorControllable) getCtrlPresetModal(); // Load the settings modal into the DOM if (monitorType == 'Local') getSettingsModal(); } if (monitorType != 'WebSite') { if (streamMode != 'janus') { if (streamMode == 'single') { statusCmdTimer = setTimeout(statusCmdQuery, 200); setInterval(watchdogCheck, statusRefreshTimeout*2, 'status'); } else { streamCmdTimer = setTimeout(streamCmdQuery, 200); setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream'); } } if (streamMode == 'janus') { server = "http://" + window.location.hostname + ":8088/janus"; opaqueId = "streamingtest-"+Janus.randomString(12); Janus.init({debug: "all", callback: function() { janus = new Janus({ server: server, success: function() { janus.attach({ plugin: "janus.plugin.streaming", opaqueId: opaqueId, success: function(pluginHandle) { streaming2 = pluginHandle; var body = { "request": "watch", "id":monitorId }; streaming2.send({"message": body}); }, error: function(error) { Janus.error(" -- Error attaching plugin... ", error); }, onmessage: function(msg, jsep) { Janus.debug(" ::: Got a message :::"); Janus.debug(msg); var result = msg["result"]; if(result !== null && result !== undefined) { if(result["status"] !== undefined && result["status"] !== null) { var status = result["status"]; } } else if(msg["error"] !== undefined && msg["error"] !== null) { Janus.error(msg["error"]); return; } if(jsep !== undefined && jsep !== null) { Janus.debug("Handling SDP as well..."); Janus.debug(jsep); // Offer from the plugin, let's answer streaming2.createAnswer({ jsep: jsep, // We want recvonly audio/video and, if negotiated, datachannels media: { audioSend: false, videoSend: false, data: true }, success: function(jsep) { Janus.debug("Got SDP!"); Janus.debug(jsep); var body = { "request": "start"}; streaming2.send({"message": body, "jsep": jsep}); }, error: function(error) { Janus.error("WebRTC error:", error); } }); } }, //onmessage function onremotestream: function(stream) { Janus.debug(" ::: Got a remote track :::"); Janus.debug(stream); Janus.attachMediaStream(document.getElementById("liveStream" + monitorId), stream); document.getElementById("liveStream" + monitorId).play(); } });// attach } //Success functio }); //new Janus }}); //janus.init callback } else if (canStreamNative || (streamMode == 'single')) { var streamImg = $j('#imageFeed img'); if (!streamImg) streamImg = $j('#imageFeed object'); if (!streamImg) { console.error('No streamImg found for imageFeed'); } else { if (streamMode == 'single') { streamImg.click(streamImg, fetchImage); setInterval(fetchImage, imageRefreshTimeout, $j('#imageFeed img')); } else { streamImg.click(function(event) { handleClick(event); }); streamImg.on("error", function(thing) { console.log("Error loading image"); console.log(thing); setInterval(fetchImage, 100, $j('#imageFeed img')); }); } } // end if have streamImg } // streamMode native or single if (refreshApplet && appletRefreshTime) { setTimeout(appletRefresh, appletRefreshTime*1000); } if (window.history.length == 1) { $j('#closeControl').html(''); } document.querySelectorAll('select[name="scale"]').forEach(function(el) { el.onchange = window['changeScale']; }); changeScale(); document.querySelectorAll('select[name="changeRate"]').forEach(function(el) { el.onchange = window['changeRate'].bind(el, el); }); } else if (monitorRefresh > 0) { setInterval(reloadWebSite, monitorRefresh*1000); } // Manage the BACK button bindButton('#backBtn', 'click', null, function onBackClick(evt) { evt.preventDefault(); window.history.back(); }); // Don't enable the back button if there is no previous zm page to go back to backBtn.prop('disabled', !document.referrer.length); // Manage the REFRESH Button bindButton('#refreshBtn', 'click', null, function onRefreshClick(evt) { evt.preventDefault(); window.location.reload(true); }); // Manage the SETTINGS button bindButton('#settingsBtn', 'click', null, function onSettingsClick(evt) { evt.preventDefault(); $j('#settingsModal').modal('show'); }); bindButton('#cyclePlayBtn', 'click', null, cycleStart); bindButton('#cyclePauseBtn', 'click', null, cyclePause); bindButton('#cycleNextBtn', 'click', null, cycleNext); bindButton('#cyclePrevBtn', 'click', null, cyclePrev); bindButton('#cycleToggle', 'click', null, cycleToggle); bindButton('#cyclePeriod', 'change', null, cyclePeriodChange); if (cycle) { cycleStart(); } else { cyclePause(); } // Only enable the settings button for local cameras settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local'))); // Init the bootstrap-table if (monitorType != 'WebSite') table.bootstrapTable({icons: icons}); // Update table rows each time after new data is loaded table.on('post-body.bs.table', function(data) { $j('#eventList tr:contains("New Event")').addClass('recent'); }); // Take appropriate action when the user clicks on a cell table.on('click-cell.bs.table', processClicks); // Some toolbar events break the thumbnail animation, so re-init eventlistener table.on('all.bs.table', initThumbAnimation); // Update table links each time after new data is loaded table.on('post-body.bs.table', function(data) { var thumb_ndx = $j('#eventList tr th').filter(function() { return $j(this).text().trim() == 'Thumbnail'; }).index(); table.find("tr td:nth-child(" + (thumb_ndx+1) + ")").addClass('colThumbnail'); }); } // initPage function watchFullscreen() { const btn = document.getElementById('fullscreenBtn'); if (btn.firstElementChild.innerHTML=='fullscreen') { const content = document.getElementById('content'); openFullscreen(content); btn.firstElementChild.innerHTML='fullscreen_exit'; btn.setAttribute('title', translate["Exit Fullscreen"]); } else { closeFullscreen(); btn.firstElementChild.innerHTML='fullscreen'; btn.setAttribute('title', translate["Fullscreen"]); } } var intervalId; var secondsToCycle = 0; function nextCycleView() { secondsToCycle --; if (secondsToCycle<=0) { window.location.replace('?view=watch&mid='+nextMid+'&mode='+mode+'&cycle=true'); } $j('#secondsToCycle').text(secondsToCycle); } function cyclePause() { clearInterval(intervalId); $j('#cyclePauseBtn').hide(); $j('#cyclePlayBtn').show(); } function cycleStart() { secondsToCycle = $j('#cyclePeriod').val(); intervalId = setInterval(nextCycleView, 1000); $j('#cyclePauseBtn').show(); $j('#cyclePlayBtn').hide(); } function cycleNext() { monIdx ++; if (monIdx >= monitorData.length) { monIdx = 0; } if (!monitorData[monIdx]) { console.log('No monitorData for ' + monIdx); } window.location.replace('?view=watch&cycle=true&mid='+monitorData[monIdx].id+'&mode='+mode); } function cyclePrev() { monIdx --; if (monIdx < 0) { monIdx = monitorData.length - 1; } if (!monitorData[monIdx]) { console.log('No monitorData for ' + monIdx); } window.location.replace('?view=watch&cycle=true&mid='+monitorData[monIdx].id+'&mode='+mode); } function cyclePeriodChange() { const cyclePeriodSelect = $j('#cyclePeriod'); secondsToCycle = cyclePeriodSelect.val(); setCookie('zmCyclePeriod', secondsToCycle, 3600); } function cycleToggle(e) { sidebar = $j('#sidebar'); button = $j('#cycleToggle'); if (sidebar.is(":visible")) { sidebar.hide(); setCookie('zmCycleShow', false, 3600); } else { sidebar.show(); setCookie('zmCycleShow', true, 3600); } button.toggleClass('btn-secondary'); button.toggleClass('btn-primary'); } function changeRate(e) { const newvalue = $j(e).val(); if (1) { var data = {}; data.command = CMD_MAXFPS; data.maxfps = newvalue; streamCmdReq(data); } else { streamImage = $j('#liveStream'+monitorData[monIdx].id); const oldsrc = streamImage.attr('src'); streamImage.attr('src', ''); // stop streaming console.log(newvalue); if (newvalue == '0') { // Unlimited streamImage.attr('src', oldsrc.replace(/maxfps=\d+/i, 'maxfps=0.00100')); } else { streamImage.attr('src', oldsrc.replace(/maxfps=\d+/i, 'maxfps='+newvalue)); } } setCookie('zmWatchRate', newvalue, 3600); } // Kick everything off $j(document).ready(initPage);