First working Janus build
This commit is contained in:
parent
701045393c
commit
3a9c16aeea
|
@ -321,7 +321,7 @@ if(NOT ZM_NO_CURL)
|
||||||
find_package(CURL)
|
find_package(CURL)
|
||||||
if(CURL_FOUND)
|
if(CURL_FOUND)
|
||||||
set(HAVE_LIBCURL 1)
|
set(HAVE_LIBCURL 1)
|
||||||
#list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES})
|
list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES})
|
||||||
include_directories(${CURL_INCLUDE_DIRS})
|
include_directories(${CURL_INCLUDE_DIRS})
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
|
set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
|
||||||
check_include_file("curl/curl.h" HAVE_CURL_CURL_H)
|
check_include_file("curl/curl.h" HAVE_CURL_CURL_H)
|
||||||
|
|
|
@ -455,6 +455,7 @@ CREATE TABLE `Monitors` (
|
||||||
`Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor',
|
`Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor',
|
||||||
`Enabled` tinyint(3) unsigned NOT NULL default '1',
|
`Enabled` tinyint(3) unsigned NOT NULL default '1',
|
||||||
`DecodingEnabled` tinyint(3) unsigned NOT NULL default '1',
|
`DecodingEnabled` tinyint(3) unsigned NOT NULL default '1',
|
||||||
|
`JanusEnabled` BOOLEAN NOT NULL default false,
|
||||||
`LinkedMonitors` varchar(255),
|
`LinkedMonitors` varchar(255),
|
||||||
`Triggers` set('X10') NOT NULL default '',
|
`Triggers` set('X10') NOT NULL default '',
|
||||||
`EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '',
|
`EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
--
|
||||||
|
-- Update Monitors table to have JanusEnabled
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT 'Checking for JanusEnabled in Monitors';
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE table_name = 'Monitors'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
AND column_name = 'JanusEnabled'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column JanusEnabled already exists in Monitors'",
|
||||||
|
"ALTER TABLE `Monitors` ADD COLUMN `JanusEnabled` BOOLEAN NOT NULL default false AFTER `DecodingEnabled`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -77,7 +77,7 @@ struct Namespace namespaces[] =
|
||||||
// This is the official SQL (and ordering of the fields) to load a Monitor.
|
// This is the official SQL (and ordering of the fields) to load a Monitor.
|
||||||
// It will be used whereever a Monitor dbrow is needed. WHERE conditions can be appended
|
// It will be used whereever a Monitor dbrow is needed. WHERE conditions can be appended
|
||||||
std::string load_monitor_sql =
|
std::string load_monitor_sql =
|
||||||
"SELECT `Id`, `Name`, `ServerId`, `StorageId`, `Type`, `Function`+0, `Enabled`, `DecodingEnabled`, "
|
"SELECT `Id`, `Name`, `ServerId`, `StorageId`, `Type`, `Function`+0, `Enabled`, `DecodingEnabled`, `JanusEnabled`,"
|
||||||
"`LinkedMonitors`, `EventStartCommand`, `EventEndCommand`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`,"
|
"`LinkedMonitors`, `EventStartCommand`, `EventEndCommand`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`,"
|
||||||
"`Device`, `Channel`, `Format`, `V4LMultiBuffer`, `V4LCapturesPerFrame`, " // V4L Settings
|
"`Device`, `Channel`, `Format`, `V4LMultiBuffer`, `V4LCapturesPerFrame`, " // V4L Settings
|
||||||
"`Protocol`, `Method`, `Options`, `User`, `Pass`, `Host`, `Port`, `Path`, `SecondPath`, `Width`, `Height`, `Colours`, `Palette`, `Orientation`+0, `Deinterlacing`, "
|
"`Protocol`, `Method`, `Options`, `User`, `Pass`, `Host`, `Port`, `Path`, `SecondPath`, `Width`, `Height`, `Colours`, `Palette`, `Orientation`+0, `Deinterlacing`, "
|
||||||
|
@ -306,6 +306,7 @@ Monitor::Monitor()
|
||||||
function(NONE),
|
function(NONE),
|
||||||
enabled(false),
|
enabled(false),
|
||||||
decoding_enabled(false),
|
decoding_enabled(false),
|
||||||
|
janus_enabled(false),
|
||||||
//protocol
|
//protocol
|
||||||
//method
|
//method
|
||||||
//options
|
//options
|
||||||
|
@ -446,7 +447,7 @@ Monitor::Monitor()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
std::string load_monitor_sql =
|
std::string load_monitor_sql =
|
||||||
"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, DecodingEnabled, LinkedMonitors, `EventStartCommand`, `EventEndCommand`, "
|
"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, DecodingEnabled, JanusEnabled, LinkedMonitors, `EventStartCommand`, `EventEndCommand`, "
|
||||||
"AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS,"
|
"AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS,"
|
||||||
"Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings
|
"Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings
|
||||||
"Protocol, Method, Options, User, Pass, Host, Port, Path, SecondPath, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, "
|
"Protocol, Method, Options, User, Pass, Host, Port, Path, SecondPath, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, "
|
||||||
|
@ -487,7 +488,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
|
||||||
} else if ( ! strcmp(dbrow[col], "Libvlc") ) {
|
} else if ( ! strcmp(dbrow[col], "Libvlc") ) {
|
||||||
type = LIBVLC;
|
type = LIBVLC;
|
||||||
} else if ( ! strcmp(dbrow[col], "cURL") ) {
|
} else if ( ! strcmp(dbrow[col], "cURL") ) {
|
||||||
type = CURL;
|
type = LIBCURL;
|
||||||
} else if ( ! strcmp(dbrow[col], "VNC") ) {
|
} else if ( ! strcmp(dbrow[col], "VNC") ) {
|
||||||
type = VNC;
|
type = VNC;
|
||||||
} else {
|
} else {
|
||||||
|
@ -499,6 +500,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
|
||||||
enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
|
enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
|
||||||
decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
|
decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
|
||||||
// See below after save_jpegs for a recalculation of decoding_enabled
|
// See below after save_jpegs for a recalculation of decoding_enabled
|
||||||
|
janus_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++;
|
||||||
|
|
||||||
ReloadLinkedMonitors(dbrow[col]); col++;
|
ReloadLinkedMonitors(dbrow[col]); col++;
|
||||||
event_start_command = dbrow[col] ? dbrow[col] : ""; col++;
|
event_start_command = dbrow[col] ? dbrow[col] : ""; col++;
|
||||||
|
@ -859,7 +861,7 @@ void Monitor::LoadCamera() {
|
||||||
#endif // HAVE_LIBVLC
|
#endif // HAVE_LIBVLC
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CURL: {
|
case LIBCURL: {
|
||||||
#if HAVE_LIBCURL
|
#if HAVE_LIBCURL
|
||||||
camera = zm::make_unique<cURLCamera>(this,
|
camera = zm::make_unique<cURLCamera>(this,
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
|
@ -1074,44 +1076,55 @@ bool Monitor::connect() {
|
||||||
usedsubpixorder = camera->SubpixelOrder(); // Used in CheckSignal
|
usedsubpixorder = camera->SubpixelOrder(); // Used in CheckSignal
|
||||||
shared_data->valid = true;
|
shared_data->valid = true;
|
||||||
|
|
||||||
//ONVIF Setup
|
|
||||||
#ifdef WITH_GSOAP
|
#ifdef WITH_GSOAP
|
||||||
ONVIF_Trigger_State = FALSE;
|
//ONVIF Setup
|
||||||
if (onvif_event_listener) { //Temporarily using this option to enable the feature
|
ONVIF_Trigger_State = FALSE;
|
||||||
Debug(1, "Starting ONVIF");
|
if (onvif_event_listener) { //Temporarily using this option to enable the feature
|
||||||
ONVIF_Healthy = FALSE;
|
Debug(1, "Starting ONVIF");
|
||||||
if (onvif_options.find("closes_event") != std::string::npos) { //Option to indicate that ONVIF will send a close event message
|
ONVIF_Healthy = FALSE;
|
||||||
ONVIF_Closes_Event = TRUE;
|
if (onvif_options.find("closes_event") != std::string::npos) { //Option to indicate that ONVIF will send a close event message
|
||||||
}
|
ONVIF_Closes_Event = TRUE;
|
||||||
tev__PullMessages.Timeout = "PT600S";
|
|
||||||
tev__PullMessages.MessageLimit = 100;
|
|
||||||
soap = soap_new();
|
|
||||||
soap->connect_timeout = 5;
|
|
||||||
soap->recv_timeout = 5;
|
|
||||||
soap->send_timeout = 5;
|
|
||||||
soap_register_plugin(soap, soap_wsse);
|
|
||||||
proxyEvent = PullPointSubscriptionBindingProxy(soap);
|
|
||||||
std::string full_url = onvif_url + "/Events";
|
|
||||||
proxyEvent.soap_endpoint = full_url.c_str();
|
|
||||||
set_credentials(soap);
|
|
||||||
Debug(1, "ONVIF Endpoint: %s", proxyEvent.soap_endpoint);
|
|
||||||
if (proxyEvent.CreatePullPointSubscription(&request, response) != SOAP_OK) {
|
|
||||||
Warning("Couldn't create subscription!");
|
|
||||||
} else {
|
|
||||||
//Empty the stored messages
|
|
||||||
set_credentials(soap);
|
|
||||||
if (proxyEvent.PullMessages(response.SubscriptionReference.Address, NULL, &tev__PullMessages, tev__PullMessagesResponse) != SOAP_OK) {
|
|
||||||
Warning("Couldn't do initial event pull! %s", response.SubscriptionReference.Address);
|
|
||||||
} else {
|
|
||||||
Debug(1, "Good Initial ONVIF Pull");
|
|
||||||
ONVIF_Healthy = TRUE;
|
|
||||||
}
|
}
|
||||||
|
tev__PullMessages.Timeout = "PT600S";
|
||||||
|
tev__PullMessages.MessageLimit = 100;
|
||||||
|
soap = soap_new();
|
||||||
|
soap->connect_timeout = 5;
|
||||||
|
soap->recv_timeout = 5;
|
||||||
|
soap->send_timeout = 5;
|
||||||
|
soap_register_plugin(soap, soap_wsse);
|
||||||
|
proxyEvent = PullPointSubscriptionBindingProxy(soap);
|
||||||
|
std::string full_url = onvif_url + "/Events";
|
||||||
|
proxyEvent.soap_endpoint = full_url.c_str();
|
||||||
|
set_credentials(soap);
|
||||||
|
Debug(1, "ONVIF Endpoint: %s", proxyEvent.soap_endpoint);
|
||||||
|
if (proxyEvent.CreatePullPointSubscription(&request, response) != SOAP_OK) {
|
||||||
|
Warning("Couldn't create subscription!");
|
||||||
|
} else {
|
||||||
|
//Empty the stored messages
|
||||||
|
set_credentials(soap);
|
||||||
|
if (proxyEvent.PullMessages(response.SubscriptionReference.Address, NULL, &tev__PullMessages, tev__PullMessagesResponse) != SOAP_OK) {
|
||||||
|
Warning("Couldn't do initial event pull! %s", response.SubscriptionReference.Address);
|
||||||
|
} else {
|
||||||
|
Debug(1, "Good Initial ONVIF Pull");
|
||||||
|
ONVIF_Healthy = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Debug(1, "Not Starting ONVIF");
|
||||||
}
|
}
|
||||||
} else {
|
//End ONVIF Setup
|
||||||
Debug(1, "Not Starting ONVIF");
|
|
||||||
}
|
|
||||||
//End ONVIF Setup
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//janus setup.
|
||||||
|
if (janus_enabled) {
|
||||||
|
add_to_janus();
|
||||||
|
}
|
||||||
|
//ifdef janus, and if url contains rtsp
|
||||||
|
//look for username and password
|
||||||
|
//make the initial call, scrape id, then connect to plugin
|
||||||
|
//add stream using the same id
|
||||||
|
|
||||||
|
|
||||||
} else if (!shared_data->valid) {
|
} else if (!shared_data->valid) {
|
||||||
Error("Shared data not initialised by capture daemon for monitor %s", name.c_str());
|
Error("Shared data not initialised by capture daemon for monitor %s", name.c_str());
|
||||||
return false;
|
return false;
|
||||||
|
@ -3189,6 +3202,10 @@ int Monitor::Close() {
|
||||||
soap = nullptr;
|
soap = nullptr;
|
||||||
} //End ONVIF
|
} //End ONVIF
|
||||||
#endif
|
#endif
|
||||||
|
//Janus Teardown
|
||||||
|
if (janus_enabled && (purpose == CAPTURE)) {
|
||||||
|
remove_from_janus();
|
||||||
|
}
|
||||||
|
|
||||||
packetqueue.clear();
|
packetqueue.clear();
|
||||||
if (audio_fifo) {
|
if (audio_fifo) {
|
||||||
|
@ -3325,3 +3342,120 @@ int SOAP_ENV__Fault(struct soap *soap, char *faultcode, char *faultstring, char
|
||||||
return soap_send_empty_response(soap, SOAP_OK);
|
return soap_send_empty_response(soap, SOAP_OK);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
size_t Monitor::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Monitor::add_to_janus() {
|
||||||
|
//TODO clean this up, add error checking, etc
|
||||||
|
std::string response;
|
||||||
|
std::string endpoint = "127.0.0.1:8088/janus/";
|
||||||
|
std::string postData = "{\"janus\" : \"create\", \"transaction\" : \"randomString\"}";
|
||||||
|
std::string rtsp_username;
|
||||||
|
std::string rtsp_password;
|
||||||
|
std::string rtsp_path = "rtsp://";
|
||||||
|
std::size_t pos;
|
||||||
|
std::size_t pos2;
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
|
||||||
|
//parse username and password
|
||||||
|
pos = path.find(":", 7);
|
||||||
|
rtsp_username = path.substr(7, pos-7);
|
||||||
|
|
||||||
|
pos2 = path.find("@", pos);
|
||||||
|
rtsp_password = path.substr(pos+1, pos2 - pos - 1);
|
||||||
|
rtsp_path += path.substr(pos2 + 1);
|
||||||
|
|
||||||
|
//Start Janus API init. Need to get a session_id and handle_id
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
pos = response.find("\"id\": ");
|
||||||
|
std::string janus_id = response.substr(pos + 6, 16);
|
||||||
|
response = "";
|
||||||
|
endpoint += janus_id;
|
||||||
|
postData = "{\"janus\" : \"attach\", \"plugin\" : \"janus.plugin.streaming\", \"transaction\" : \"randomString\"}";
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
pos = response.find("\"id\": ");
|
||||||
|
std::string handle_id = response.substr(pos + 6, 16);
|
||||||
|
endpoint += "/";
|
||||||
|
endpoint += handle_id;
|
||||||
|
|
||||||
|
//Assemble our actual request
|
||||||
|
postData = "{\"janus\" : \"message\", \"transaction\" : \"randomString\", \"body\" : {";
|
||||||
|
postData += "\"request\" : \"create\", \"admin_key\" : \"supersecret\", \"type\" : \"rtsp\", ";
|
||||||
|
postData += "\"url\" : \"";
|
||||||
|
postData += rtsp_path;
|
||||||
|
postData += "\", \"rtsp_user\" : \"";
|
||||||
|
postData += rtsp_username;
|
||||||
|
postData += "\", \"rtsp_pwd\" : \"";
|
||||||
|
postData += rtsp_password;
|
||||||
|
postData += "\", \"id\" : ";
|
||||||
|
postData += std::to_string(id);
|
||||||
|
postData += ", \"video\" : true}}";
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
Warning(response.c_str());
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
}
|
||||||
|
int Monitor::remove_from_janus() {
|
||||||
|
//TODO clean this up, add error checking, etc
|
||||||
|
std::string response;
|
||||||
|
std::string endpoint = "127.0.0.1:8088/janus/";
|
||||||
|
std::string postData = "{\"janus\" : \"create\", \"transaction\" : \"randomString\"}";
|
||||||
|
std::size_t pos;
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
|
||||||
|
|
||||||
|
//Start Janus API init. Need to get a session_id and handle_id
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
pos = response.find("\"id\": ");
|
||||||
|
std::string janus_id = response.substr(pos + 6, 16);
|
||||||
|
response = "";
|
||||||
|
endpoint += janus_id;
|
||||||
|
postData = "{\"janus\" : \"attach\", \"plugin\" : \"janus.plugin.streaming\", \"transaction\" : \"randomString\"}";
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
pos = response.find("\"id\": ");
|
||||||
|
std::string handle_id = response.substr(pos + 6, 16);
|
||||||
|
endpoint += "/";
|
||||||
|
endpoint += handle_id;
|
||||||
|
|
||||||
|
//Assemble our actual request
|
||||||
|
postData = "{\"janus\" : \"message\", \"transaction\" : \"randomString\", \"body\" : {";
|
||||||
|
postData += "\"request\" : \"destroy\", \"admin_key\" : \"supersecret\", \"id\" : ";
|
||||||
|
postData += std::to_string(id);
|
||||||
|
postData += "}}";
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
Warning(response.c_str());
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#ifdef WITH_GSOAP
|
#ifdef WITH_GSOAP
|
||||||
#include "soapPullPointSubscriptionBindingProxy.h"
|
#include "soapPullPointSubscriptionBindingProxy.h"
|
||||||
|
@ -47,6 +48,7 @@ class Group;
|
||||||
#define MOTION_CAUSE "Motion"
|
#define MOTION_CAUSE "Motion"
|
||||||
#define LINKED_CAUSE "Linked"
|
#define LINKED_CAUSE "Linked"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is the main class for monitors. Each monitor is associated
|
// This is the main class for monitors. Each monitor is associated
|
||||||
// with a camera and is effectively a collector for events.
|
// with a camera and is effectively a collector for events.
|
||||||
|
@ -76,7 +78,7 @@ public:
|
||||||
FILE,
|
FILE,
|
||||||
FFMPEG,
|
FFMPEG,
|
||||||
LIBVLC,
|
LIBVLC,
|
||||||
CURL,
|
LIBCURL,
|
||||||
NVSOCKET,
|
NVSOCKET,
|
||||||
VNC,
|
VNC,
|
||||||
} CameraType;
|
} CameraType;
|
||||||
|
@ -266,6 +268,7 @@ protected:
|
||||||
Function function; // What the monitor is doing
|
Function function; // What the monitor is doing
|
||||||
bool enabled; // Whether the monitor is enabled or asleep
|
bool enabled; // Whether the monitor is enabled or asleep
|
||||||
bool decoding_enabled; // Whether the monitor will decode h264/h265 packets
|
bool decoding_enabled; // Whether the monitor will decode h264/h265 packets
|
||||||
|
bool janus_enabled; // Whether we set the h264/h265 stream up on janus
|
||||||
|
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
std::string method;
|
std::string method;
|
||||||
|
@ -445,6 +448,13 @@ protected:
|
||||||
void set_credentials(struct soap *soap);
|
void set_credentials(struct soap *soap);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//curl stuff for Janus
|
||||||
|
CURL *curl;
|
||||||
|
//helper class for CURL
|
||||||
|
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
|
||||||
|
int add_to_janus();
|
||||||
|
int remove_from_janus();
|
||||||
|
|
||||||
// Used in check signal
|
// Used in check signal
|
||||||
uint8_t red_val;
|
uint8_t red_val;
|
||||||
uint8_t green_val;
|
uint8_t green_val;
|
||||||
|
|
|
@ -69,6 +69,16 @@ if ( !canEdit('Monitors') ) return;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="form-group" id="FunctionJanusEnabled">
|
||||||
|
<label for="newJanusEnabled"><?php echo translate('Janus Enabled') ?></label>
|
||||||
|
<input type="checkbox" name="newJanusEnabled" id="newJanusEnabled" value="1"/>
|
||||||
|
<?php
|
||||||
|
if ( isset($OLANG['FUNCTION_JANUS_ENABLED']) ) {
|
||||||
|
echo '<div class="form-text">'.$OLANG['FUNCTION_JANUS_ENABLED']['Help'].'</div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|
|
@ -55,6 +55,7 @@ class Monitor extends ZM_Object {
|
||||||
'Function' => 'Mocord',
|
'Function' => 'Mocord',
|
||||||
'Enabled' => array('type'=>'boolean','default'=>1),
|
'Enabled' => array('type'=>'boolean','default'=>1),
|
||||||
'DecodingEnabled' => array('type'=>'boolean','default'=>1),
|
'DecodingEnabled' => array('type'=>'boolean','default'=>1),
|
||||||
|
'JanusEnabled' => array('type'=>'boolean','default'=>0),
|
||||||
'LinkedMonitors' => array('type'=>'set', 'default'=>null),
|
'LinkedMonitors' => array('type'=>'set', 'default'=>null),
|
||||||
'Triggers' => array('type'=>'set','default'=>''),
|
'Triggers' => array('type'=>'set','default'=>''),
|
||||||
'EventStartCommand' => '',
|
'EventStartCommand' => '',
|
||||||
|
|
|
@ -2094,6 +2094,8 @@ function getStreamHTML($monitor, $options = array()) {
|
||||||
'format' => ZM_MPEG_LIVE_FORMAT
|
'format' => ZM_MPEG_LIVE_FORMAT
|
||||||
) );
|
) );
|
||||||
return getVideoStreamHTML( 'liveStream'.$monitor->Id(), $streamSrc, $options['width'], $options['height'], ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
|
return getVideoStreamHTML( 'liveStream'.$monitor->Id(), $streamSrc, $options['width'], $options['height'], ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
|
||||||
|
} else if ( $monitor->JanusEnabled() ) {
|
||||||
|
return '<video id="liveStream'.$monitor->Id().'" width="'.$options['width'].'"autoplay muted playsinline=""></video>';
|
||||||
} else if ( $options['mode'] == 'stream' and canStream() ) {
|
} else if ( $options['mode'] == 'stream' and canStream() ) {
|
||||||
$options['mode'] = 'jpeg';
|
$options['mode'] = 'jpeg';
|
||||||
$streamSrc = $monitor->getStreamSrc($options);
|
$streamSrc = $monitor->getStreamSrc($options);
|
||||||
|
|
|
@ -5,6 +5,7 @@ function MonitorStream(monitorData) {
|
||||||
this.auth_relay = auth_relay;
|
this.auth_relay = auth_relay;
|
||||||
this.auth_hash = auth_hash;
|
this.auth_hash = auth_hash;
|
||||||
this.url = monitorData.url;
|
this.url = monitorData.url;
|
||||||
|
this.janusEnabled = monitorData.janusEnabled;
|
||||||
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;
|
||||||
|
@ -86,6 +87,71 @@ function MonitorStream(monitorData) {
|
||||||
console.log(stream);
|
console.log(stream);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.janusEnabled) {
|
||||||
|
var id = parseInt(this.id);
|
||||||
|
var opaqueId = "streamingtest-"+Janus.randomString(12);
|
||||||
|
var server = "http://zm-dev:8088/janus";
|
||||||
|
Janus.init({debug: "all", callback: function() {
|
||||||
|
janus = new Janus({
|
||||||
|
server: server,
|
||||||
|
success: function() {
|
||||||
|
janus.attach({
|
||||||
|
plugin: "janus.plugin.streaming",
|
||||||
|
opaqueId: opaqueId,
|
||||||
|
success: function(pluginHandle) {
|
||||||
|
streaming = pluginHandle;
|
||||||
|
var body = { "request": "watch", "id": id };
|
||||||
|
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) {
|
||||||
|
var status = result["status"];
|
||||||
|
}
|
||||||
|
} else if(msg["error"] !== undefined && msg["error"] !== null) {
|
||||||
|
alert(msg["error"]);
|
||||||
|
stopStream();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(jsep !== undefined && jsep !== null) {
|
||||||
|
Janus.debug("Handling SDP as well...");
|
||||||
|
Janus.debug(jsep);
|
||||||
|
// Offer from the plugin, let's answer
|
||||||
|
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"};
|
||||||
|
streaming.send({"message": body, "jsep": jsep});
|
||||||
|
},
|
||||||
|
error: function(error) {
|
||||||
|
Janus.error("WebRTC error:", error);
|
||||||
|
alert("WebRTC error... " + JSON.stringify(error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, //onmessage function
|
||||||
|
onremotestream: function(ourstream) {
|
||||||
|
Janus.debug(" ::: Got a remote track :::");
|
||||||
|
Janus.debug(ourstream);
|
||||||
|
Janus.attachMediaStream(stream, ourstream);
|
||||||
|
stream.play()
|
||||||
|
}
|
||||||
|
});// attach
|
||||||
|
} //Success functio
|
||||||
|
}); //new Janus
|
||||||
|
}}); //janus.init callback
|
||||||
|
return;
|
||||||
|
}
|
||||||
src = stream.src.replace(/mode=single/i, 'mode=jpeg');
|
src = stream.src.replace(/mode=single/i, 'mode=jpeg');
|
||||||
if ( -1 == src.search('connkey') ) {
|
if ( -1 == src.search('connkey') ) {
|
||||||
src += '&connkey='+this.connKey;
|
src += '&connkey='+this.connKey;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1174,6 +1174,11 @@ $OLANG = array(
|
||||||
optionally choose to not decode the H264/H265 packets. This will drastically reduce cpu use
|
optionally choose to not decode the H264/H265 packets. This will drastically reduce cpu use
|
||||||
but will make live view unavailable for this monitor.'
|
but will make live view unavailable for this monitor.'
|
||||||
),
|
),
|
||||||
|
'FUNCTION_JANUS_ENABLED' => array(
|
||||||
|
'Help' => '
|
||||||
|
Attempt to use Janus streaming server for h264/h265 live view. Experimental, but allows
|
||||||
|
for significantly better performance.'
|
||||||
|
),
|
||||||
'ImageBufferCount' => array(
|
'ImageBufferCount' => array(
|
||||||
'Help' => '
|
'Help' => '
|
||||||
Number of raw images available in /dev/shm. Currently should be set in the 3-5 range. Used for live viewing.'
|
Number of raw images available in /dev/shm. Currently should be set in the 3-5 range. Used for live viewing.'
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
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
|
||||||
|
@ -300,20 +306,43 @@ 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++ ) {
|
||||||
monitors[i] = new MonitorStream(monitorData[i]);
|
if (monitorData[i].janusEnabled) {
|
||||||
|
initJanus = true;
|
||||||
// Start the fps and status updates. give a random delay so that we don't assault the server
|
janusMonitors.push(monitorData[i]);
|
||||||
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
}
|
||||||
console.log("delay: " + delay);
|
}
|
||||||
monitors[i].start(delay);
|
if (initJanus) {
|
||||||
|
server = "http://zm-dev:8088/janus";
|
||||||
var interval = monitors[i].refresh;
|
opaqueId = "streamingtest-"+Janus.randomString(12);
|
||||||
if ( monitors[i].type == 'WebSite' && interval > 0 ) {
|
Janus.init({debug: "all", callback: function() {
|
||||||
setInterval(reloadWebSite, interval*1000, i);
|
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]);
|
||||||
|
|
||||||
|
// Start the fps and status updates. give a random delay so that we don't assault the server
|
||||||
|
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
||||||
|
console.log("delay: " + delay);
|
||||||
|
monitors[i].start(delay);
|
||||||
|
|
||||||
|
var interval = monitors[i].refresh;
|
||||||
|
if ( monitors[i].type == 'WebSite' && interval > 0 ) {
|
||||||
|
setInterval(reloadWebSite, interval*1000, i);
|
||||||
|
}
|
||||||
|
monitors[i].setup_onclick();
|
||||||
}
|
}
|
||||||
monitors[i].setup_onclick();
|
|
||||||
}
|
}
|
||||||
selectLayout('#zmMontageLayout');
|
selectLayout('#zmMontageLayout');
|
||||||
}
|
}
|
||||||
|
@ -322,5 +351,61 @@ function watchFullscreen() {
|
||||||
const content = document.getElementById('content');
|
const content = document.getElementById('content');
|
||||||
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) {
|
||||||
|
var status = result["status"];
|
||||||
|
}
|
||||||
|
} else if(msg["error"] !== undefined && msg["error"] !== null) {
|
||||||
|
alert(msg["error"]);
|
||||||
|
stopStream();
|
||||||
|
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);
|
||||||
|
alert("WebRTC error... " + JSON.stringify(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);
|
||||||
|
|
|
@ -24,6 +24,7 @@ monitorData[monitorData.length] = {
|
||||||
'connKey': <?php echo $monitor->connKey() ?>,
|
'connKey': <?php echo $monitor->connKey() ?>,
|
||||||
'width': <?php echo $monitor->ViewWidth() ?>,
|
'width': <?php echo $monitor->ViewWidth() ?>,
|
||||||
'height':<?php echo $monitor->ViewHeight() ?>,
|
'height':<?php echo $monitor->ViewHeight() ?>,
|
||||||
|
'janusEnabled':<?php echo $monitor->JanusEnabled() ?>,
|
||||||
'url': '<?php echo $monitor->UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
'url': '<?php echo $monitor->UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>',
|
||||||
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $monitor->Id() ?>' );},
|
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $monitor->Id() ?>' );},
|
||||||
'type': '<?php echo $monitor->Type() ?>',
|
'type': '<?php echo $monitor->Type() ?>',
|
||||||
|
|
|
@ -66,6 +66,7 @@ monitorData[monitorData.length] = {
|
||||||
'id': <?php echo $m->Id() ?>,
|
'id': <?php echo $m->Id() ?>,
|
||||||
'width': <?php echo $m->ViewWidth() ?>,
|
'width': <?php echo $m->ViewWidth() ?>,
|
||||||
'height':<?php echo $m->ViewHeight() ?>,
|
'height':<?php echo $m->ViewHeight() ?>,
|
||||||
|
'janusEnabled':<?php echo $m->JanusEnabled() ?>,
|
||||||
'url': '<?php echo $m->UrlToIndex() ?>',
|
'url': '<?php echo $m->UrlToIndex() ?>',
|
||||||
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $m->Id() ?>' );},
|
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $m->Id() ?>' );},
|
||||||
'type': '<?php echo $m->Type() ?>',
|
'type': '<?php echo $m->Type() ?>',
|
||||||
|
|
|
@ -574,6 +574,16 @@ if (count($available_monitor_ids)) {
|
||||||
if ( isset($OLANG['FUNCTION_DECODING_ENABLED']) ) {
|
if ( isset($OLANG['FUNCTION_DECODING_ENABLED']) ) {
|
||||||
echo '<div class="form-text">'.$OLANG['FUNCTION_DECODING_ENABLED']['Help'].'</div>';
|
echo '<div class="form-text">'.$OLANG['FUNCTION_DECODING_ENABLED']['Help'].'</div>';
|
||||||
}
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="FunctionJanusEnabled">
|
||||||
|
<td class="text-right pr-3"><?php echo translate('Janus Live Stream') ?></td>
|
||||||
|
<td><input type="checkbox" name="newMonitor[JanusEnabled]" value="1"<?php echo $monitor->JanusEnabled() ? ' checked="checked"' : '' ?>/>
|
||||||
|
<?php
|
||||||
|
if ( isset($OLANG['FUNCTION_JANUS_ENABLED']) ) {
|
||||||
|
echo '<div class="form-text">'.$OLANG['FUNCTION_JANUS_ENABLED']['Help'].'</div>';
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -325,5 +325,7 @@ foreach (array_reverse($zones) as $zone) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webrtc-adapter/8.1.0/adapter.min.js"></script>
|
||||||
|
<script src="<?php echo cache_bust('js/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() ?>
|
||||||
|
|
Loading…
Reference in New Issue