Merge pull request #3409 from jp-bennett/master

Refactor Montage view js -- Janus in MonitorStream
This commit is contained in:
Isaac Connor 2022-01-17 15:14:43 -05:00 committed by GitHub
commit eab29babea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 3755 deletions

View File

@ -3,8 +3,8 @@
[Unit] [Unit]
Description=ZoneMinder CCTV recording and security system Description=ZoneMinder CCTV recording and security system
After=network.target mysqld.service httpd.service After=network.target mysqld.service httpd.service janus.service
Requires=mysqld.service httpd.service Requires=mysqld.service httpd.service janus.service
[Service] [Service]
User=@WEB_USER@ User=@WEB_USER@

View File

@ -1100,12 +1100,13 @@ bool Monitor::connect() {
set_credentials(soap); set_credentials(soap);
Debug(1, "ONVIF Endpoint: %s", proxyEvent.soap_endpoint); Debug(1, "ONVIF Endpoint: %s", proxyEvent.soap_endpoint);
if (proxyEvent.CreatePullPointSubscription(&request, response) != SOAP_OK) { if (proxyEvent.CreatePullPointSubscription(&request, response) != SOAP_OK) {
Warning("Couldn't create subscription!"); Error("Couldn't create subscription! %s, %s", soap_fault_string(soap), soap_fault_detail(soap));
} else { } else {
//Empty the stored messages //Empty the stored messages
set_credentials(soap); set_credentials(soap);
if (proxyEvent.PullMessages(response.SubscriptionReference.Address, NULL, &tev__PullMessages, tev__PullMessagesResponse) != SOAP_OK) { if ((proxyEvent.PullMessages(response.SubscriptionReference.Address, NULL, &tev__PullMessages, tev__PullMessagesResponse) != SOAP_OK) &&
Warning("Couldn't do initial event pull! %s", response.SubscriptionReference.Address); ( soap->error != SOAP_EOF)) { //SOAP_EOF could indicate no messages to pull.
Error("Couldn't do initial event pull! Error %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
} else { } else {
Debug(1, "Good Initial ONVIF Pull"); Debug(1, "Good Initial ONVIF Pull");
ONVIF_Healthy = TRUE; ONVIF_Healthy = TRUE;
@ -1119,10 +1120,12 @@ bool Monitor::connect() {
#if HAVE_LIBCURL //janus setup. Depends on libcurl. #if HAVE_LIBCURL //janus setup. Depends on libcurl.
if (janus_enabled && (path.find("rtsp://") != std::string::npos)) { if (janus_enabled && (path.find("rtsp://") != std::string::npos)) {
if (add_to_janus() != 0) {
if (add_to_janus() != 0) { if (add_to_janus() != 0) {
Warning("Failed to add monitor stream to Janus!"); Warning("Failed to add monitor stream to Janus!");
} }
} }
}
#endif #endif
} else if (!shared_data->valid) { } else if (!shared_data->valid) {
@ -1794,8 +1797,10 @@ bool Monitor::Poll() {
set_credentials(soap); set_credentials(soap);
int result = proxyEvent.PullMessages(response.SubscriptionReference.Address, NULL, &tev__PullMessages, tev__PullMessagesResponse); int result = proxyEvent.PullMessages(response.SubscriptionReference.Address, NULL, &tev__PullMessages, tev__PullMessagesResponse);
if (result != SOAP_OK) { if (result != SOAP_OK) {
if (result != -1) //Ignore the timeout error if (result != SOAP_EOF) { //Ignore the timeout error
Warning("Failed to get ONVIF messages! %i", result); Error("Failed to get ONVIF messages! %s", soap_fault_string(soap));
ONVIF_Healthy = FALSE;
}
} else { } else {
Debug(1, "Got Good Response! %i", result); Debug(1, "Got Good Response! %i", result);
for (auto msg : tev__PullMessagesResponse.wsnt__NotificationMessage) { for (auto msg : tev__PullMessagesResponse.wsnt__NotificationMessage) {
@ -1814,6 +1819,7 @@ bool Monitor::Poll() {
if (!ONVIF_Trigger_State) { if (!ONVIF_Trigger_State) {
Debug(1,"Triggered Event"); Debug(1,"Triggered Event");
ONVIF_Trigger_State = TRUE; ONVIF_Trigger_State = TRUE;
std::this_thread::sleep_for (std::chrono::seconds(1)); //thread sleep
} }
} else { } else {
Debug(1, "Triggered off ONVIF"); Debug(1, "Triggered off ONVIF");
@ -1826,6 +1832,8 @@ bool Monitor::Poll() {
} }
} }
} }
} else {
std::this_thread::sleep_for (std::chrono::seconds(1)); //thread sleep to avoid the busy loop.
} }
#endif #endif
return TRUE; return TRUE;
@ -2111,7 +2119,10 @@ bool Monitor::Analyse() {
if (state == ALARM) { if (state == ALARM) {
last_alarm_count = analysis_image_count; last_alarm_count = analysis_image_count;
} // This is needed so post_event_count counts after last alarmed frames while in ALARM not single alarmed frames while ALERT } // This is needed so post_event_count counts after last alarmed frames while in ALARM not single alarmed frames while ALERT
} else if (!score and (snap->score == 0)) { // snap->score means -1 which means didn't do motion detection so don't do state transition
// snap->score -1 means didn't do motion detection so don't do state transition
// In Nodect, we may still have a triggered event, so need this code to run to end the event.
} else if (!score and ((snap->score == 0) or (function == NODECT))) {
Debug(1, "!score %s", State_Strings[state].c_str()); Debug(1, "!score %s", State_Strings[state].c_str());
alert_to_alarm_frame_count = alarm_frame_count; // load same value configured for alarm_frame_count alert_to_alarm_frame_count = alarm_frame_count; // load same value configured for alarm_frame_count

View File

@ -1,3 +1,5 @@
var janus = null;
var streaming = [];
function MonitorStream(monitorData) { function MonitorStream(monitorData) {
this.id = monitorData.id; this.id = monitorData.id;
@ -8,6 +10,7 @@ function MonitorStream(monitorData) {
this.url_to_zms = monitorData.url_to_zms; this.url_to_zms = monitorData.url_to_zms;
this.width = monitorData.width; this.width = monitorData.width;
this.height = monitorData.height; this.height = monitorData.height;
this.janusEnabled = monitorData.janusEnabled;
this.scale = 100; this.scale = 100;
this.status = null; this.status = null;
this.alarmState = STATE_IDLE; this.alarmState = STATE_IDLE;
@ -80,6 +83,17 @@ function MonitorStream(monitorData) {
const stream = this.getElement(); const stream = this.getElement();
if (!stream) return; if (!stream) return;
if (this.janusEnabled) {
var id = parseInt(this.id);
var server = "http://" + window.location.hostname + ":8088/janus";
if (janus == null) {
Janus.init({debug: "all", callback: function() {
janus = new Janus({server: server}); //new Janus
}});
}
attachVideo(id);
return;
}
if (!stream.src) { if (!stream.src) {
// Website Monitors won't have an img tag // Website Monitors won't have an img tag
console.log('No src for #liveStream'+this.id); console.log('No src for #liveStream'+this.id);
@ -287,3 +301,68 @@ function MonitorStream(monitorData) {
this.streamCmdReq(this.streamCmdParms); this.streamCmdReq(this.streamCmdParms);
}; };
} // end function MonitorStream } // end function MonitorStream
async function attachVideo(id) {
await waitUntil(() => janus.isConnected() )
janus.attach({
plugin: "janus.plugin.streaming",
opaqueId: "streamingtest-"+Janus.randomString(12),
success: function(pluginHandle) {
streaming[id] = pluginHandle;
var body = { "request": "watch", "id": id};
streaming[id].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"];
Janus.debug(status);
}
} else if(msg["error"] !== undefined && msg["error"] !== null) {
return;
}
if(jsep !== undefined && jsep !== null) {
Janus.debug("Handling SDP as well...");
Janus.debug(jsep);
// Offer from the plugin, let's answer
streaming[id].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"};
streaming[id].send({"message": body, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
}
});
}
}, //onmessage function
onremotestream: function(ourstream) {
Janus.debug(" ::: Got a remote track :::");
Janus.debug(ourstream);
Janus.attachMediaStream(document.getElementById("liveStream" + id), ourstream);
}
}); // janus.attach
} //function attachVideo
const waitUntil = (condition) => {
return new Promise((resolve) => {
let interval = setInterval(() => {
if (!condition()) {
return;
}
clearInterval(interval);
resolve();
}, 100);
});
}

File diff suppressed because it is too large Load Diff

View File

@ -193,5 +193,5 @@ xhtmlHeaders(__FILE__, translate('CycleWatch'));
</div> </div>
</div> </div>
<script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script> <script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script>
<script src="<?php echo cache_bust('js/janus.js') ?>"></script> <script src="/javascript/janus/janus.js"></script>
<?php xhtmlFooter() ?> <?php xhtmlFooter() ?>

View File

@ -1,9 +1,3 @@
var server;
var janus = null;
var opaqueId;
var globalCount = 0;
var streamingList = [];
var janusMonitors = [];
/** /**
* called when the layoutControl select element is changed, or the page * called when the layoutControl select element is changed, or the page
* is rendered * is rendered
@ -306,30 +300,7 @@ function initPage() {
$j("#flipMontageHeader").slideToggle("fast"); $j("#flipMontageHeader").slideToggle("fast");
$j("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up'); $j("#hdrbutton").toggleClass('glyphicon-menu-down').toggleClass('glyphicon-menu-up');
} }
var initJanus = false;
//var streamingMonitors = [];
for ( var i = 0, length = monitorData.length; i < length; i++ ) { for ( var i = 0, length = monitorData.length; i < length; i++ ) {
if (monitorData[i].janusEnabled) {
initJanus = true;
janusMonitors.push(monitorData[i]);
}
}
if (initJanus) {
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() {
for ( var i = 0, length = janusMonitors.length; i < length; i++ ) {
attachVideo(janus, i);
}
}
});
}});
}
for ( var i = 0, length = monitorData.length; i < length; i++ ) {
if (!monitorData[i].janusEnabled) {
monitors[i] = new MonitorStream(monitorData[i]); monitors[i] = new MonitorStream(monitorData[i]);
// Start the fps and status updates. give a random delay so that we don't assault the server // Start the fps and status updates. give a random delay so that we don't assault the server
@ -343,7 +314,6 @@ function initPage() {
} }
monitors[i].setup_onclick(); monitors[i].setup_onclick();
} }
}
selectLayout('#zmMontageLayout'); selectLayout('#zmMontageLayout');
} }
@ -352,58 +322,5 @@ function watchFullscreen() {
openFullscreen(content); openFullscreen(content);
} }
function attachVideo(janus, i) {
janus.attach({
plugin: "janus.plugin.streaming",
opaqueId: "streamingtest-"+Janus.randomString(12),
success: function(pluginHandle) {
janusMonitors[i].streaming = pluginHandle;
var body = {"request": "watch", "id": parseInt(janusMonitors[i].id)};
janusMonitors[i].streaming.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) {
const status = result["status"];
console.log(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
janusMonitors[i].streaming.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"};
janusMonitors[i].streaming.send({"message": body, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
}
});
}
}, //onmessage function
onremotestream: function(ourstream) {
Janus.debug(" ::: Got a remote track :::");
Janus.debug(ourstream);
Janus.attachMediaStream(document.getElementById("liveStream" + janusMonitors[i].id), ourstream);
document.getElementById("liveStream" + janusMonitors[i].id).play();
}
});// attach
}
// Kick everything off // Kick everything off
$j(document).ready(initPage); $j(document).ready(initPage);

View File

@ -326,6 +326,6 @@ foreach (array_reverse($zones) as $zone) {
</div> </div>
</div> </div>
<script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script> <script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script>
<script src="<?php echo cache_bust('js/janus.js') ?>"></script> <script src="/javascript/janus/janus.js"></script>
<script src="<?php echo cache_bust('js/MonitorStream.js') ?>"></script> <script src="<?php echo cache_bust('js/MonitorStream.js') ?>"></script>
<?php xhtmlFooter() ?> <?php xhtmlFooter() ?>

View File

@ -412,5 +412,5 @@ if ( ZM_WEB_SOUND_ON_ALARM ) {
</div> </div>
</div> </div>
<script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script> <script src="<?php echo cache_bust('js/adapter.min.js') ?>"></script>
<script src="<?php echo cache_bust('js/janus.js') ?>"></script> <script src="/javascript/janus/janus.js"></script>
<?php xhtmlFooter() ?> <?php xhtmlFooter() ?>