Skip to content

Commit 1485a7e

Browse files
Merge pull request #4393 from IgorA100/patch-435415
Feat: Using audio motion analyzer
2 parents bb61ba7 + b7a0c1d commit 1485a7e

20 files changed

Lines changed: 3638 additions & 161 deletions

File tree

web/includes/Monitor.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,7 @@ function getMonitorStateHTML() {
10781078
$html = '
10791079
<div id="monitorStatus'.$this->Id().'" class="monitorStatus">
10801080
<div class="stream-info">
1081+
<div class="stream-info-status-track"></div>
10811082
<div class="stream-info-status"></div>
10821083
<div class="stream-info-mode"></div>
10831084
</div>
@@ -1109,6 +1110,16 @@ function getMonitorStateHTML() {
11091110
*/
11101111
function getStreamHTML($options) {
11111112
global $basename;
1113+
global $view;
1114+
1115+
$whatDisplay = (isset($_COOKIE["zmWhatDisplay"])) ? strtolower($_COOKIE["zmWhatDisplay"]) : 'default';
1116+
$dataNotDisplayVideo = 'false';
1117+
1118+
if (false !== strpos($whatDisplay, 'default')) { // Default monitor settings
1119+
if (false === (strpos(strtolower($this->WhatDisplay()), 'video'))) $dataNotDisplayVideo = 'true';
1120+
} else {
1121+
if (false === (strpos($whatDisplay, 'video'))) $dataNotDisplayVideo = 'true';
1122+
}
11121123

11131124
if (isset($options['scale']) and $options['scale'] != '' and $options['scale'] != 'fixed') {
11141125
if ($options['scale'] != 'auto' && $options['scale'] != '0') {
@@ -1175,6 +1186,7 @@ function getStreamHTML($options) {
11751186
class="monitorStream imageFeed"
11761187
data-monitor-id="'. $this->Id() .'"
11771188
data-width="'. $this->ViewWidth() .'"
1189+
data-not-display-video="'. $dataNotDisplayVideo .'"
11781190
data-height="'.$this->ViewHeight() .'" style="'.
11791191
#(($options['width'] and ($options['width'] != '0px')) ? 'width: '.$options['width'].';' : '').
11801192
#(($options['height'] and ($options['height'] != '0px')) ? 'height: '.$options['height'].';' : '').
@@ -1270,6 +1282,22 @@ class="monitorStream imageFeed"
12701282
//if ((!ZM_WEB_COMPACT_MONTAGE) && ($this->Type() != 'WebSite')) {
12711283
$html .= $this->getMonitorStateHTML();
12721284
}
1285+
$html .= '
1286+
<audio-motion id="audioVisualization'.$this->Id().'" class="audio-visualization">
1287+
'.PHP_EOL;
1288+
if ($view == 'montage') {
1289+
$html .= '
1290+
<div id="audioControlPanel'.$this->Id().'" class="audio-control-panel">
1291+
<div id="volumeControls'.$this->Id().'" class="disabled volume">
1292+
<div id="volumeSlider'.$this->Id().'" data-volume="50" data-muted="true" class="volumeSlider noUi-horizontal noUi-base noUi-round"></div>
1293+
<i id="controlMute'.$this->Id().'" class="audio-control-mute material-icons md-22"></i>
1294+
</div>
1295+
</div>
1296+
<canvas></canvas>
1297+
'.PHP_EOL;
1298+
}
1299+
$html .= '
1300+
</audio-motion>'.PHP_EOL;
12731301
$html .= PHP_EOL.'</div></div><!--.grid-stack-item-content--></div><!--.grid-stack-item-->'.PHP_EOL;
12741302
return $html;
12751303
} // end getStreamHTML

web/js/MonitorStream.js

Lines changed: 42 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function MonitorStream(monitorData) {
4545
this.server_id = monitorData.server_id;
4646
this.scale = monitorData.scale ? parseInt(monitorData.scale) : 100;
4747
this.status = {capturefps: 0, analysisfps: 0}; // json object with alarmstatus, fps etc
48+
this.whatDisplay = monitorData.whatDisplay;
4849
this.lastAlarmState = STATE_IDLE;
4950
this.statusCmdTimer = null; // timer for requests using ajax to get monitor status
5051
this.statusCmdParms = {
@@ -430,7 +431,8 @@ function MonitorStream(monitorData) {
430431

431432
//console.log('start go2rtcenabled:', this.Go2RTCEnabled, 'this.player:', this.player, 'muted', this.muted);
432433

433-
$j('#volumeControls'+this.id).hide();
434+
//$j('#volumeControls'+this.id).hide();
435+
$j('#volumeControls'+this.id).addClass('disabled');
434436
$j('#delay'+this.id).addClass('hidden');
435437

436438
if (this.Go2RTCEnabled && ((!this.player) || (-1 !== this.player.indexOf('go2rtc')))) {
@@ -640,6 +642,7 @@ function MonitorStream(monitorData) {
640642
this.handlerEventListener['killStream'] = this.streamListenerBind();
641643
this.activePlayer = 'zms';
642644
this.updateStreamInfo('ZMS MJPEG');
645+
hideAudioMotion(this.id);
643646
}; // this.start
644647

645648
this.setSrcInfoBlock = function() {
@@ -728,10 +731,14 @@ function MonitorStream(monitorData) {
728731
infoBlock.style.left = '50%';
729732
infoBlock.style.transform = 'translate(-50%, -50%)';
730733
infoBlock.style.pointerEvents = 'none';
731-
const imageFeed = document.getElementById('imageFeed'+this.id);
732-
if (imageFeed) {
733-
imageFeed.appendChild(infoBlock);
734+
let node = null;
735+
const _imageFeed = document.getElementById('imageFeed'+this.id);
736+
if (_imageFeed && _imageFeed.getAttribute('data-not-display-video') === 'true') {
737+
node = document.getElementById("audioVisualization" + this.id) || this.getElement();
738+
} else {
739+
node = this.getElement();
734740
}
741+
node.parentNode.appendChild(infoBlock);
735742
currentInfoBlock = infoBlock;
736743
}
737744
return currentInfoBlock;
@@ -806,6 +813,7 @@ function MonitorStream(monitorData) {
806813
} else {
807814
console.log("Unknown activePlayer", this.activePlayer);
808815
}
816+
if (this.audioMotion && this.audioMotion.stop) this.audioMotion.stop();
809817
this.activePlayer = '';
810818
this.started = false;
811819
};
@@ -944,6 +952,7 @@ function MonitorStream(monitorData) {
944952
}
945953
this.statusCmdTimer = setInterval(this.statusCmdQuery.bind(this), statusRefreshTimeout);
946954
}
955+
if (this.audioMotion && this.audioMotion.init) this.audioMotion.init();
947956
};
948957

949958
this.eventHandler = function(event) {
@@ -997,20 +1006,16 @@ function MonitorStream(monitorData) {
9971006
this.onplay = func;
9981007
};
9991008

1000-
10011009
this.getVolumeControls = function() {
1002-
// On Watch page slider has no ID, on Montage page it has ID
1003-
return (document.getElementById('volumeControls')) ? document.getElementById('volumeControls') : document.getElementById('volumeControls'+this.id);
1010+
return getVolumeControls(this.id);
10041011
};
10051012

10061013
this.getVolumeSlider = function() {
1007-
// On Watch page slider has no ID, on Montage page it has ID
1008-
return (document.getElementById('volumeSlider')) ? document.getElementById('volumeSlider') : document.getElementById('volumeSlider'+this.id);
1014+
return getVolumeSlider(this.id);
10091015
};
10101016

10111017
this.getIconMute = function() {
1012-
// On Watch page icon has no ID, on Montage page it has ID
1013-
return (document.getElementById('controlMute')) ? document.getElementById('controlMute') : document.getElementById('controlMute'+this.id);
1018+
return getIconMute(this.id);
10141019
};
10151020

10161021
this.getAVStream = function() {
@@ -1054,8 +1059,9 @@ function MonitorStream(monitorData) {
10541059
const volumeSlider = this.getVolumeSlider();
10551060
const audioStream = this.getAVStream();
10561061
if (!volumeSlider || !audioStream) return;
1057-
const iconMute = this.getIconMute();
1058-
$j('#volumeControls'+this.id).show();
1062+
1063+
//$j('#volumeControls'+this.id).show();
1064+
$j('#volumeControls'+this.id).removeClass('disabled');
10591065
if (!this.handlerEventListener['volumechange']) {
10601066
this.handlerEventListener['volumechange'] = manageEventListener.addEventListener(audioStream, 'volumechange',
10611067
(event) => {
@@ -1064,155 +1070,56 @@ function MonitorStream(monitorData) {
10641070
);
10651071
}
10661072
if (volumeSlider.noUiSlider) return;
1067-
const defaultVolume = (volumeSlider.getAttribute("data-volume") || 50);
1068-
1069-
noUiSlider.create(volumeSlider, {
1070-
start: [(defaultVolume) ? defaultVolume : audioStream.volume * 100],
1071-
step: 1,
1072-
//behaviour: 'unconstrained',
1073-
behaviour: 'tap',
1074-
connect: [true, false],
1075-
range: {
1076-
'min': 0,
1077-
'max': 100
1078-
},
1079-
/*tooltips: [
1080-
//true,
1081-
{ to: function(value) { return value.toFixed(0) + '%'; } }
1082-
],*/
1083-
});
1084-
volumeSlider.allowSetValue = true;
1085-
volumeSlider.noUiSlider.on('update', function onUpdateUiSlider(values, handle) {
1086-
audioStream.volume = values[0]/100;
1087-
if (values[0] > 0 && !audioStream.muted) {
1088-
iconMute.innerHTML = 'volume_up';
1089-
volumeSlider.classList.remove('noUi-mute');
1090-
} else {
1091-
iconMute.innerHTML = 'volume_off';
1092-
volumeSlider.classList.add('noUi-mute');
1093-
}
1094-
//console.log("Audio volume slider event: 'update'");
1095-
});
1096-
volumeSlider.noUiSlider.on('end', function onEndUiSlider(values, handle) {
1097-
volumeSlider.allowSetValue = true;
1098-
//console.log("Audio volume slider event: 'end'");
1099-
});
1100-
volumeSlider.noUiSlider.on('start', function onStartUiSlider(values, handle) {
1101-
volumeSlider.allowSetValue = false; // Let's prohibit changing the Value using the "Set" method, otherwise there will be lags and collapse when directly moving the slider with the mouse...
1102-
//console.log("Audio volume slider event: 'start'");
1103-
});
1104-
volumeSlider.noUiSlider.on('set', function onSetUiSlider(values, handle) {
1105-
//console.log("Audio volume slider event: 'set'");
1106-
});
1107-
volumeSlider.noUiSlider.on('slide', function onSlideUiSlider(values, handle) {
1108-
if (audioStream.volume > 0 && audioStream.muted) {
1109-
iconMute.innerHTML = 'volume_up';
1110-
audioStream.muted = false;
1111-
}
1112-
//console.log("Audio volume slider event: 'slide'");
1113-
});
11141073

1115-
if (volumeSlider.getAttribute("data-muted") !== "true") {
1116-
this.controlMute('off');
1117-
} else {
1118-
this.controlMute('on');
1119-
}
1074+
createVolumeSlider(volumeSlider, audioStream);
1075+
1076+
//if (volumeSlider.getAttribute("data-muted") !== "true") {
1077+
// this.controlMute('off');
1078+
//} else {
1079+
// this.controlMute('on');
1080+
//}
11201081
};
11211082

11221083
this.destroyVolumeSlider = function() {
1123-
$j('#volumeControls'+this.id).hide();
1084+
//$j('#volumeControls'+this.id).hide();
1085+
$j('#volumeControls'+this.id).addClass('disabled');
11241086
const volumeSlider = this.getVolumeSlider();
1087+
destroyVolumeSlider(volumeSlider);
11251088
//const iconMute = this.getIconMute();
11261089
//if (iconMute) iconMute.innerText = "";
1127-
if (volumeSlider && volumeSlider.noUiSlider) {
1128-
volumeSlider.noUiSlider.destroy();
1129-
volumeSlider.noUiSlider = null;
1130-
}
11311090
};
11321091

11331092
/*
11341093
* volume: on || off
11351094
*/
11361095
this.changeStateIconMute = function(volume) {
1137-
const volumeControls = this.getVolumeControls();
1138-
const disabled = (volumeControls) ? volumeControls.classList.contains('disabled') : false;
1139-
const iconMute = this.getIconMute();
1140-
if (!disabled && iconMute) {
1141-
iconMute.innerHTML = (volume == 'on')? 'volume_up' : 'volume_off';
1142-
}
1143-
return iconMute;
1096+
return changeStateIconMute(this.id, volume);
11441097
};
11451098

11461099
/*
11471100
* volume: on || off
11481101
*/
11491102
this.changeVolumeSlider = function(volume) {
1150-
const volumeControls = this.getVolumeControls();
1151-
//const controlMute = document.querySelector('[id ^= "controlMute'+this.id+'"]');
1152-
const volumeSlider = this.getVolumeSlider();
1153-
1154-
if (volumeSlider) {
1155-
let disabled = false;
1156-
if (volumeControls) {
1157-
disabled = volumeControls.classList.contains('disabled');
1158-
}
1159-
if (volume == 'on') {
1160-
volumeSlider.classList.remove('noUi-mute');
1161-
} else if (volume == 'off') {
1162-
volumeSlider.classList.add('noUi-mute');
1163-
}
1164-
if (volumeSlider.noUiSlider) {
1165-
(disabled) ? volumeSlider.noUiSlider.disable() : volumeSlider.noUiSlider.enable();
1166-
}
1167-
}
1168-
return volumeSlider;
1103+
return changeVolumeSlider(this.id, volume);
11691104
};
11701105

11711106
/*
11721107
* mode: switch, on, off
11731108
*/
11741109
this.controlMute = function(mode = 'switch') {
1175-
let volumeSlider = this.getVolumeSlider();
11761110
const audioStream = this.getAVStream();
1177-
const volumeControls = this.getVolumeControls();
1178-
const disabled = (volumeControls) ? volumeControls.classList.contains('disabled') : false;
1179-
1180-
if (volumeSlider && volumeSlider.noUiSlider) {
1181-
(disabled) ? volumeSlider.noUiSlider.disable() : volumeSlider.noUiSlider.enable();
1182-
}
1183-
1184-
if (disabled) {
1185-
console.log(`Volume control is disabled in controlMute for monitor ID=${this.id}`);
1186-
return;
1187-
}
1188-
if (!audioStream) {
1189-
console.log(`No audiostream! in controlMute for monitor ID=${this.id}`);
1190-
return;
1191-
}
1192-
1193-
if (mode=='switch') {
1194-
if (audioStream.muted) {
1195-
audioStream.muted = this.muted = false;
1196-
this.changeStateIconMute('on');
1197-
volumeSlider = this.changeVolumeSlider('on');
1198-
if (volumeSlider && volumeSlider.noUiSlider) {
1199-
audioStream.volume = volumeSlider.noUiSlider.get() / 100;
1111+
controlMute(this.id, mode);
1112+
if (audioStream) {
1113+
if (mode=='switch') {
1114+
if (audioStream.muted) {
1115+
this.muted = false;
1116+
} else {
1117+
this.muted = true;
12001118
}
1201-
} else {
1202-
audioStream.muted = this.muted = true;
1203-
this.changeStateIconMute('off');
1204-
this.changeVolumeSlider('off');
1205-
}
1206-
} else if (mode=='on') {
1207-
audioStream.muted = this.muted = true;
1208-
this.changeStateIconMute('off');
1209-
this.changeVolumeSlider('off');
1210-
} else if (mode=='off') {
1211-
audioStream.muted = this.muted = false;
1212-
this.changeStateIconMute('on');
1213-
volumeSlider = this.changeVolumeSlider('on');
1214-
if (volumeSlider && volumeSlider.noUiSlider) {
1215-
audioStream.volume = volumeSlider.noUiSlider.get() / 100;
1119+
} else if (mode=='on') {
1120+
this.muted = true;
1121+
} else if (mode=='off') {
1122+
this.muted = false;
12161123
}
12171124
}
12181125
};

web/lang/en_gb.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,11 @@ function zmVlang($langVarArray, $count) {
10301030
is set to "my_camera", access the stream at rtsp://ZM_HOST:20006/my_camera
10311031
',
10321032
),
1033+
'OPTIONS_WHATTODISPLAY' => array(
1034+
'Help' => '
1035+
On the Watch, Montage, Event page, you can display either a video stream, or an audio stream visualization, or both a video stream and an audio visualization.
1036+
',
1037+
),
10331038
'FUNCTION_ANALYSIS_ENABLED' => array(
10341039
'Help' => '
10351040
When to perform motion detection on the captured video.

0 commit comments

Comments
 (0)