2015-09-17 19:29:36 +00:00
< ? php
2019-02-22 14:19:07 +00:00
namespace ZM ;
2018-05-15 17:45:47 +00:00
require_once ( 'database.php' );
2019-09-08 16:26:11 +00:00
require_once ( 'Object.php' );
2019-09-19 18:55:27 +00:00
require_once ( 'Control.php' );
2020-08-31 22:30:05 +00:00
require_once ( 'Group.php' );
2021-07-07 13:46:36 +00:00
require_once ( 'Manufacturer.php' );
require_once ( 'Model.php' );
require_once ( 'Server.php' );
require_once ( 'Storage.php' );
2022-04-10 22:54:01 +00:00
require_once ( 'Zone.php' );
2020-08-31 22:30:05 +00:00
2022-02-27 19:03:37 +00:00
class Monitor extends ZM_Object {
protected static $FunctionTypes = null ;
2020-08-31 22:30:05 +00:00
2022-02-27 19:03:37 +00:00
public static function getFunctionTypes () {
2021-05-28 16:29:30 +00:00
if ( ! isset ( $FunctionTypes )) {
2020-08-31 22:30:05 +00:00
$FunctionTypes = array (
'None' => translate ( 'FnNone' ),
'Monitor' => translate ( 'FnMonitor' ),
'Modect' => translate ( 'FnModect' ),
2020-09-03 22:20:51 +00:00
'Record' => translate ( 'FnRecord' ),
2020-09-03 14:40:10 +00:00
'Mocord' => translate ( 'FnMocord' ),
2020-08-31 22:30:05 +00:00
'Nodect' => translate ( 'FnNodect' )
);
}
return $FunctionTypes ;
}
2015-09-17 19:29:36 +00:00
2022-02-27 19:03:37 +00:00
protected static $CapturingOptions = null ;
public static function getCapturingOptions () {
2022-03-28 21:45:01 +00:00
if ( ! isset ( $CapturingOptions )) {
2022-02-08 16:19:36 +00:00
$CapturingOptions = array (
2021-10-17 00:35:11 +00:00
'None' => translate ( 'None' ),
'Ondemand' => translate ( 'On Demand' ),
'Always' => translate ( 'Always' ),
);
}
2022-02-08 16:19:36 +00:00
return $CapturingOptions ;
2021-10-17 00:35:11 +00:00
}
2022-02-27 19:03:37 +00:00
protected static $AnalysingOptions = null ;
public static function getAnalysingOptions () {
2022-02-08 16:19:36 +00:00
if ( ! isset ( $AnalysingOptions )) {
$AnalysingOptions = array (
2021-10-17 00:35:11 +00:00
'None' => translate ( 'None' ),
'Always' => translate ( 'Always' ),
);
}
2022-02-08 16:19:36 +00:00
return $AnalysingOptions ;
2021-10-17 00:35:11 +00:00
}
2022-03-28 21:45:01 +00:00
protected static $AnalysisSourceOptions = null ;
2022-02-27 19:03:37 +00:00
public static function getAnalysisSourceOptions () {
2022-03-28 21:45:01 +00:00
if ( ! isset ( $AnalysisSourceOptions )) {
$AnalysisSourceOptions = array (
2021-10-17 00:35:11 +00:00
'Primary' => translate ( 'Primary' ),
'Secondary' => translate ( 'Secondary' ),
);
}
2022-03-28 21:45:01 +00:00
return $AnalysisSourceOptions ;
2021-10-17 00:35:11 +00:00
}
2022-06-15 15:27:48 +00:00
protected static $AnalysisImageOptions = null ;
public static function getAnalysisImageOptions () {
if ( ! isset ( $AnalysisImageOptions )) {
$AnalysisImageOptions = array (
'FullColour' => translate ( 'Full Colour' ),
'YChannel' => translate ( 'Y-Channel (Greyscale)' ),
);
}
return $AnalysisImageOptions ;
2021-10-17 00:35:11 +00:00
}
2022-02-27 19:03:37 +00:00
protected static $RecordingOptions = null ;
public static function getRecordingOptions () {
2022-02-08 16:19:36 +00:00
if ( ! isset ( $RecordingOptions )) {
$RecordingOptions = array (
2021-10-17 00:35:11 +00:00
'None' => translate ( 'None' ),
2022-03-20 15:07:46 +00:00
'OnMotion' => translate ( 'On Motion / Trigger / etc' ),
2021-10-17 00:35:11 +00:00
'Always' => translate ( 'Always' ),
);
}
2022-02-08 16:19:36 +00:00
return $RecordingOptions ;
2021-10-17 00:35:11 +00:00
}
2022-03-28 21:45:01 +00:00
protected static $RecordingSourceOptions = null ;
2022-02-27 19:03:37 +00:00
public static function getRecordingSourceOptions () {
2022-03-28 21:45:01 +00:00
if ( ! isset ( $RecordingSourceOptions )) {
$RecordingSourceOptions = array (
2021-10-17 00:35:11 +00:00
'Primary' => translate ( 'Primary' ),
'Secondary' => translate ( 'Secondary' ),
'Both' => translate ( 'Both' ),
);
}
2022-03-28 21:45:01 +00:00
return $RecordingSourceOptions ;
}
protected static $DecodingOptions = null ;
public static function getDecodingOptions () {
if ( ! isset ( $DecodingOptions )) {
$DecodingOptions = array (
'None' => translate ( 'None' ),
'Ondemand' => translate ( 'On Demand' ),
'KeyFrames' => translate ( 'KeyFrames Only' ),
2022-05-10 18:25:34 +00:00
'KeyFrames+Ondemand' => translate ( 'Keyframes + Ondemand' ),
2022-03-28 21:45:01 +00:00
'Always' => translate ( 'Always' ),
);
}
return $DecodingOptions ;
2021-10-17 00:35:11 +00:00
}
2022-02-27 19:03:37 +00:00
protected static $Statuses = null ;
public static function getStatuses () {
2021-05-28 16:29:30 +00:00
if ( ! isset ( $Statuses )) {
$Statuses = array (
- 1 => 'Unknown' ,
0 => 'Idle' ,
1 => 'PreAlarm' ,
2 => 'Alarm' ,
3 => 'Alert' ,
4 => 'Tape'
);
}
return $Statuses ;
}
2019-09-08 16:26:11 +00:00
protected static $table = 'Monitors' ;
2018-09-15 13:52:08 +00:00
2019-12-18 17:13:00 +00:00
protected $defaults = array (
'Id' => null ,
2021-02-01 21:43:24 +00:00
'Name' => array ( 'type' => 'text' , 'filter_regexp' => '/[^\w\-\.\(\)\:\/ ]/' , 'default' => 'Monitor' ),
2019-12-18 17:13:00 +00:00
'Notes' => '' ,
'ServerId' => 0 ,
'StorageId' => 0 ,
2021-09-25 14:32:04 +00:00
'ManufacturerId' => null ,
'ModelId' => null ,
2019-12-18 17:13:00 +00:00
'Type' => 'Ffmpeg' ,
2021-10-25 20:53:42 +00:00
'Capturing' => 'Always' ,
'Analysing' => 'Always' ,
'Recording' => 'Always' ,
2022-05-30 18:28:38 +00:00
'RecordingSource' => 'Primary' ,
'AnalysisSource' => 'Primary' ,
2022-06-15 15:27:48 +00:00
'AnalysisImage' => 'FullColour' ,
2019-12-18 17:13:00 +00:00
'Enabled' => array ( 'type' => 'boolean' , 'default' => 1 ),
2022-03-28 21:45:01 +00:00
'Decoding' => 'Always' ,
2022-01-11 05:22:37 +00:00
'JanusEnabled' => array ( 'type' => 'boolean' , 'default' => 0 ),
2022-01-19 06:14:52 +00:00
'JanusAudioEnabled' => array ( 'type' => 'boolean' , 'default' => 0 ),
2022-08-09 04:45:53 +00:00
'Janus_Profile_Override' => '' ,
'Janus_Use_RTSP_Restream' => array ( 'type' => 'boolean' , 'default' => 0 ),
2022-09-10 02:01:29 +00:00
'Janus_RTSP_User' => null ,
2023-01-10 00:11:54 +00:00
'Janus_RTSP_Session_Timeout' => array ( 'type' => 'integer' , 'default' => 0 ),
2019-12-18 17:13:00 +00:00
'LinkedMonitors' => array ( 'type' => 'set' , 'default' => null ),
'Triggers' => array ( 'type' => 'set' , 'default' => '' ),
2021-11-27 00:22:07 +00:00
'EventStartCommand' => '' ,
'EventEndCommand' => '' ,
2020-05-12 19:47:00 +00:00
'ONVIF_URL' => '' ,
'ONVIF_Username' => '' ,
'ONVIF_Password' => '' ,
'ONVIF_Options' => '' ,
2022-07-23 20:08:27 +00:00
'ONVIF_Alarm_Text' => '' ,
2022-01-04 17:58:19 +00:00
'ONVIF_Event_Listener' => '0' ,
2022-01-26 04:27:11 +00:00
'use_Amcrest_API' => '0' ,
2019-12-18 17:13:00 +00:00
'Device' => '' ,
'Channel' => 0 ,
'Format' => '0' ,
'V4LMultiBuffer' => null ,
'V4LCapturesPerFrame' => 1 ,
'Protocol' => null ,
'Method' => '' ,
'Host' => null ,
'Port' => '' ,
'SubPath' => '' ,
'Path' => null ,
2021-03-03 14:55:23 +00:00
'SecondPath' => null ,
2019-12-18 17:13:00 +00:00
'Options' => null ,
'User' => null ,
'Pass' => null ,
// These are NOT NULL default 0 in the db, but 0 is not a valid value. FIXME
'Width' => null ,
'Height' => null ,
'Colours' => 4 ,
'Palette' => '0' ,
2020-05-01 19:32:26 +00:00
'Orientation' => 'ROTATE_0' ,
2019-12-18 17:13:00 +00:00
'Deinterlacing' => 0 ,
'DecoderHWAccelName' => null ,
'DecoderHWAccelDevice' => null ,
2022-09-09 15:29:32 +00:00
'SaveJPEGs' => 2 ,
'VideoWriter' => '2' ,
2019-12-18 17:13:00 +00:00
'OutputCodec' => null ,
2020-05-02 22:03:42 +00:00
'Encoder' => 'auto' ,
2019-12-18 17:13:00 +00:00
'OutputContainer' => null ,
2021-04-01 14:14:02 +00:00
'EncoderParameters' => " # Lines beginning with # are a comment \n # For changing quality, use the crf option \n # 1 is best, 51 is worst quality \n crf=23 \n " ,
2019-12-18 17:13:00 +00:00
'RecordAudio' => array ( 'type' => 'boolean' , 'default' => 0 ),
2022-02-02 22:10:05 +00:00
#'OutputSourceStream' => 'Primary',
2019-12-18 17:13:00 +00:00
'RTSPDescribe' => array ( 'type' => 'boolean' , 'default' => 0 ),
'Brightness' => - 1 ,
'Contrast' => - 1 ,
'Hue' => - 1 ,
'Colour' => - 1 ,
'EventPrefix' => 'Event-' ,
'LabelFormat' => '%N - %d/%m/%y %H:%M:%S' ,
'LabelX' => 0 ,
'LabelY' => 0 ,
2022-09-09 15:29:32 +00:00
'LabelSize' => 2 ,
2021-03-22 16:05:36 +00:00
'ImageBufferCount' => 3 ,
2021-03-26 21:02:17 +00:00
'MaxImageBufferCount' => 0 ,
2019-12-18 17:13:00 +00:00
'WarmupCount' => 0 ,
2019-12-28 15:49:42 +00:00
'PreEventCount' => 5 ,
'PostEventCount' => 5 ,
2019-12-18 17:13:00 +00:00
'StreamReplayBuffer' => 0 ,
'AlarmFrameCount' => 1 ,
'SectionLength' => 600 ,
2023-01-07 17:33:42 +00:00
'SectionLengthWarn' => true ,
2019-12-18 17:13:00 +00:00
'MinSectionLength' => 10 ,
'FrameSkip' => 0 ,
'MotionFrameSkip' => 0 ,
'AnalysisFPSLimit' => null ,
'AnalysisUpdateDelay' => 0 ,
'MaxFPS' => null ,
'AlarmMaxFPS' => null ,
'FPSReportInterval' => 100 ,
'RefBlendPerc' => 6 ,
'AlarmRefBlendPerc' => 6 ,
'Controllable' => array ( 'type' => 'boolean' , 'default' => 0 ),
'ControlId' => null ,
'ControlDevice' => null ,
'ControlAddress' => null ,
'AutoStopTimeout' => null ,
'TrackMotion' => array ( 'type' => 'boolean' , 'default' => 0 ),
'TrackDelay' => null ,
'ReturnLocation' => - 1 ,
'ReturnDelay' => null ,
2021-04-23 16:56:45 +00:00
'ModectDuringPTZ' => array ( 'type' => 'boolean' , 'default' => 0 ),
2019-12-18 17:13:00 +00:00
'DefaultRate' => 100 ,
2020-12-17 14:45:06 +00:00
'DefaultScale' => 0 ,
2019-12-18 17:13:00 +00:00
'SignalCheckPoints' => 0 ,
'SignalCheckColour' => '#0000BE' ,
2020-01-01 00:10:29 +00:00
'WebColour' => '#ff0000' ,
2021-02-02 19:24:23 +00:00
'Exif' => array ( 'type' => 'boolean' , 'default' => 0 ),
2019-12-18 17:13:00 +00:00
'Sequence' => null ,
'ZoneCount' => 0 ,
'Refresh' => null ,
'DefaultCodec' => 'auto' ,
'GroupIds' => array ( 'default' => array (), 'do_not_update' => 1 ),
2020-09-24 13:01:30 +00:00
'Latitude' => null ,
'Longitude' => null ,
2021-02-02 19:24:23 +00:00
'RTSPServer' => array ( 'type' => 'boolean' , 'default' => 0 ),
2021-02-27 17:28:59 +00:00
'RTSPStreamName' => '' ,
2021-09-08 16:52:33 +00:00
'Importance' => 'Normal' ,
2022-09-06 15:22:04 +00:00
'MQTT_Enabled' => array ( 'type' => 'boolean' , 'default' => 0 ),
2021-12-26 20:20:43 +00:00
'MQTT_Subscriptions' => '' ,
2019-12-18 17:13:00 +00:00
);
private $status_fields = array (
'Status' => null ,
'AnalysisFPS' => null ,
'CaptureFPS' => null ,
'CaptureBandwidth' => null ,
2021-04-09 23:46:25 +00:00
);
private $summary_fields = array (
2020-11-06 19:00:18 +00:00
'TotalEvents' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'TotalEventDiskSpace' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'HourEvents' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'HourEventDiskSpace' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'DayEvents' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'DayEventDiskSpace' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'WeekEvents' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'WeekEventDiskSpace' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'MonthEvents' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'MonthEventDiskSpace' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'ArchivedEvents' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
'ArchivedEventDiskSpace' => array ( 'type' => 'integer' , 'default' => null , 'do_not_update' => 1 ),
2019-12-18 17:13:00 +00:00
);
2022-09-05 22:18:23 +00:00
public function Janus_Pin () {
2022-09-28 21:41:46 +00:00
if ( ! $this -> { 'JanusEnabled' }) return '' ;
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }) )) {
$cmd = getZmuCommand ( ' --janus-pin -m ' . $this -> { 'Id' });
$output = shell_exec ( $cmd );
Debug ( " Running $cmd output: $output " );
return $output ? trim ( $output ) : $output ;
} else if ( $this -> ServerId ()) {
$result = $this -> Server () -> SendToApi ( '/monitors/' . $this -> { 'Id' } . '.json' );
$json = json_decode ( $result , true );
2022-09-28 22:36:47 +00:00
return (( isset ( $json [ 'monitor' ]) and isset ( $json [ 'monitor' ][ 'Monitor' ]) and isset ( $json [ 'monitor' ][ 'Monitor' ][ 'Janus_Pin' ])) ? $json [ 'monitor' ][ 'Monitor' ][ 'Janus_Pin' ] : '' );
2022-09-28 21:41:46 +00:00
} else {
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
}
2022-09-05 22:18:23 +00:00
}
2022-09-28 21:41:46 +00:00
2019-09-19 18:55:27 +00:00
public function Control () {
2021-08-18 14:50:45 +00:00
if ( ! property_exists ( $this , 'Control' )) {
if ( $this -> ControlId ())
2019-09-19 18:55:27 +00:00
$this -> { 'Control' } = Control :: find_one ( array ( 'Id' => $this -> { 'ControlId' }));
2016-05-05 19:30:24 +00:00
2021-08-18 14:50:45 +00:00
if ( ! ( property_exists ( $this , 'Control' ) and $this -> { 'Control' }))
2019-09-19 18:55:27 +00:00
$this -> { 'Control' } = new Control ();
}
return $this -> { 'Control' };
}
2018-04-17 17:51:20 +00:00
2016-05-05 19:30:24 +00:00
public function Server () {
2021-08-18 14:50:45 +00:00
if ( ! property_exists ( $this , 'Server' )) {
2022-09-30 13:57:21 +00:00
if ( $this -> ServerId ()) {
2020-01-11 01:15:52 +00:00
$this -> { 'Server' } = Server :: find_one ( array ( 'Id' => $this -> { 'ServerId' }));
2022-09-30 13:57:21 +00:00
if ( ! $this -> { 'Server' }) {
$this -> { 'Server' } = new Server ();
}
}
2021-08-18 14:50:45 +00:00
if ( ! property_exists ( $this , 'Server' )) {
2020-01-11 01:13:09 +00:00
$this -> { 'Server' } = new Server ();
}
}
return $this -> { 'Server' };
2016-05-05 19:30:24 +00:00
}
2019-09-19 18:55:27 +00:00
2022-08-18 09:05:18 +00:00
public function Path ( $new = null ) {
// set the new value if requested
2022-08-22 15:46:57 +00:00
if ( $new !== null ) {
2022-08-18 09:05:18 +00:00
$this -> { 'Path' } = $new ;
}
// empty value or old auth values terminate
2022-08-22 15:46:57 +00:00
if ( ! isset ( $this -> { 'Path' }) or ( $this -> { 'Path' } == '' ))
2022-09-09 15:29:32 +00:00
return '' ;
2022-08-18 09:05:18 +00:00
// extract the authentication part from the path given
$values = extract_auth_values_from_url ( $this -> { 'Path' });
// If no values for User and Pass fields are present then terminate
2022-08-22 15:46:57 +00:00
if ( count ( $values ) !== 2 ) {
2022-08-18 09:05:18 +00:00
return $this -> { 'Path' };
}
2022-08-22 15:46:57 +00:00
$old_us = isset ( $this -> { 'User' }) ? $this -> { 'User' } : '' ;
$old_ps = isset ( $this -> { 'Pass' }) ? $this -> { 'Pass' } : '' ;
2022-08-18 09:05:18 +00:00
$us = $values [ 0 ];
$ps = $values [ 1 ];
// Update the auth fields if they were empty and remove them from the path
// or if they are equal between the path and field
2022-08-22 15:46:57 +00:00
if ( ( ! $old_us && ! $old_ps ) || ( $us == $old_us && $ps == $old_ps ) ) {
$this -> { 'Path' } = str_replace ( " $us : $ps @ " , '' , $this -> { 'Path' });
2022-08-18 09:05:18 +00:00
$this -> { 'User' } = $us ;
$this -> { 'Pass' } = $ps ;
}
return $this -> { 'Path' };
}
public function User ( $new = null ) {
2022-09-09 15:29:32 +00:00
if ( $new !== null ) {
2022-08-18 09:05:18 +00:00
// no url check if the update has different value
$this -> { 'User' } = $new ;
}
2022-09-09 15:29:32 +00:00
if ( isset ( $this -> { 'User' }) and $this -> { 'User' } != '' )
2022-08-18 09:05:18 +00:00
return $this -> { 'User' };
// Only try to update from path if the field is empty
2022-09-09 15:29:32 +00:00
$values = extract_auth_values_from_url ( $this -> Path ());
$this -> { 'User' } = count ( $values ) == 2 ? $values [ 0 ] : '' ;
2022-08-18 09:05:18 +00:00
return $this -> { 'User' };
}
public function Pass ( $new = null ) {
2022-09-09 15:29:32 +00:00
if ( $new !== null ) {
2022-08-18 09:05:18 +00:00
// no url check if the update has different value
$this -> { 'Pass' } = $new ;
}
2022-09-09 15:29:32 +00:00
if ( isset ( $this -> { 'Pass' }) and $this -> { 'Pass' } != '' )
2022-08-18 09:05:18 +00:00
return $this -> { 'Pass' };
// Only try to update from path if the field is empty
2022-09-09 15:29:32 +00:00
$values = extract_auth_values_from_url ( $this -> Path ());
$this -> { 'Pass' } = count ( $values ) == 2 ? $values [ 1 ] : '' ;
2022-08-18 09:05:18 +00:00
return $this -> { 'Pass' };
}
2021-08-18 14:50:45 +00:00
public function __call ( $fn , array $args ) {
if ( count ( $args )) {
if ( is_array ( $this -> defaults [ $fn ]) and $this -> defaults [ $fn ][ 'type' ] == 'set' ) {
2021-02-01 21:43:24 +00:00
$this -> { $fn } = is_array ( $args [ 0 ]) ? implode ( ',' , $args [ 0 ]) : $args [ 0 ];
2019-09-19 18:55:27 +00:00
} else {
$this -> { $fn } = $args [ 0 ];
}
2017-06-05 19:21:27 +00:00
}
2021-08-18 14:50:45 +00:00
if ( property_exists ( $this , $fn )) {
2016-05-05 19:30:24 +00:00
return $this -> { $fn };
2021-08-18 14:50:45 +00:00
} else if ( array_key_exists ( $fn , $this -> defaults )) {
2019-09-19 18:55:27 +00:00
if ( is_array ( $this -> defaults [ $fn ]) ) {
return $this -> defaults [ $fn ][ 'default' ];
}
return $this -> defaults [ $fn ];
2021-08-18 14:50:45 +00:00
} else if ( array_key_exists ( $fn , $this -> status_fields )) {
2021-04-09 23:46:25 +00:00
$sql = 'SELECT * FROM `Monitor_Status` WHERE `MonitorId`=?' ;
2019-07-07 21:25:49 +00:00
$row = dbFetchOne ( $sql , NULL , array ( $this -> { 'Id' }));
2021-08-18 14:50:45 +00:00
if ( ! $row ) {
2020-10-14 15:32:33 +00:00
Warning ( 'Unable to load Monitor status record for Id=' . $this -> { 'Id' } . ' using ' . $sql );
2021-04-09 23:46:25 +00:00
return null ;
} else {
foreach ( $row as $k => $v ) {
2019-09-25 14:13:56 +00:00
$this -> { $k } = $v ;
}
2021-04-09 23:46:25 +00:00
}
return $this -> { $fn };
2021-08-18 14:50:45 +00:00
} else if ( array_key_exists ( $fn , $this -> summary_fields )) {
2021-04-09 23:46:25 +00:00
$sql = 'SELECT * FROM `Event_Summaries` WHERE `MonitorId`=?' ;
$row = dbFetchOne ( $sql , NULL , array ( $this -> { 'Id' }));
2021-08-18 14:50:45 +00:00
if ( ! $row ) {
2021-04-09 23:46:25 +00:00
Warning ( 'Unable to load Event Summary record for Id=' . $this -> { 'Id' } . ' using ' . $sql );
return null ;
2016-06-20 16:41:14 +00:00
} else {
2019-07-07 21:25:49 +00:00
foreach ( $row as $k => $v ) {
$this -> { $k } = $v ;
}
2016-06-20 16:41:14 +00:00
}
2019-07-07 21:25:49 +00:00
return $this -> { $fn };
} else {
$backTrace = debug_backtrace ();
$file = $backTrace [ 1 ][ 'file' ];
$line = $backTrace [ 1 ][ 'line' ];
2019-09-19 18:55:27 +00:00
Warning ( " Unknown function call Monitor-> $fn from $file : $line " );
2016-06-14 16:38:17 +00:00
}
2016-05-05 19:30:24 +00:00
}
2017-02-28 02:48:08 +00:00
2018-07-09 16:09:29 +00:00
public function getStreamSrc ( $args , $querySep = '&' ) {
2018-11-29 19:26:30 +00:00
$streamSrc = $this -> Server () -> UrlToZMS (
2018-07-09 16:09:29 +00:00
ZM_MIN_STREAMING_PORT ?
ZM_MIN_STREAMING_PORT + $this -> { 'Id' } :
null );
2015-09-17 19:29:36 +00:00
2017-02-28 02:48:08 +00:00
$args [ 'monitor' ] = $this -> { 'Id' };
2015-09-17 19:29:36 +00:00
2021-08-18 14:50:45 +00:00
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
2018-06-25 18:50:54 +00:00
$args [ 'auth' ] = generateAuthHash ( ZM_AUTH_HASH_IPS );
2017-02-28 02:48:08 +00:00
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
2023-02-15 18:46:34 +00:00
$args [ 'user' ] = isset ( $_SESSION [ 'username' ]) ? $_SESSION [ 'username' ] : '' ;
2023-02-14 22:04:32 +00:00
$args [ 'pass' ] = isset ( $_SESSION [ 'password' ]) ? $_SESSION [ 'password' ] : '' ;
2017-02-28 02:48:08 +00:00
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$args [ 'user' ] = $_SESSION [ 'username' ];
2016-05-05 19:30:24 +00:00
}
}
2021-08-18 14:50:45 +00:00
if ( ZM_RAND_STREAM ) {
2017-02-28 02:48:08 +00:00
$args [ 'rand' ] = time ();
2016-05-05 19:30:24 +00:00
}
2020-08-24 18:35:59 +00:00
# zms doesn't support width & height, so if no scale is set, default it
2021-08-18 14:50:45 +00:00
if ( ! isset ( $args [ 'scale' ])) {
if ( isset ( $args [ 'width' ]) and intval ( $args [ 'width' ])) {
2020-08-24 18:35:59 +00:00
$args [ 'scale' ] = intval (( 100 * intval ( $args [ 'width' ])) / $this -> ViewWidth ());
2021-08-18 14:50:45 +00:00
} else if ( isset ( $args [ 'height' ]) and intval ( $args [ 'height' ])) {
2020-08-24 18:35:59 +00:00
$args [ 'scale' ] = intval (( 100 * intval ( $args [ 'height' ])) / $this -> ViewHeight ());
2020-07-13 18:50:21 +00:00
}
}
2022-04-10 21:28:38 +00:00
if ( $args [ 'scale' ] <= 0 ) {
$args [ 'scale' ] = 100 ;
}
2021-08-18 14:50:45 +00:00
if ( isset ( $args [ 'width' ]))
2020-08-27 14:29:50 +00:00
unset ( $args [ 'width' ]);
2021-08-18 14:50:45 +00:00
if ( isset ( $args [ 'height' ]))
2020-08-27 14:29:50 +00:00
unset ( $args [ 'height' ]);
2015-09-17 19:29:36 +00:00
2019-03-21 18:14:15 +00:00
$streamSrc .= '?' . http_build_query ( $args , '' , $querySep );
2015-09-17 19:29:36 +00:00
2018-07-09 16:09:29 +00:00
return $streamSrc ;
2016-05-05 19:30:24 +00:00
} // end function getStreamSrc
2016-06-14 16:38:17 +00:00
2019-10-29 21:39:12 +00:00
public function isPortrait () {
return $this -> ViewWidth () > $this -> ViewHeight ();
}
public function isLandscape () {
return $this -> ViewWidth () < $this -> ViewHeight ();
}
public function ViewWidth ( $new = null ) {
2021-08-18 14:50:45 +00:00
if ( $new )
2017-10-27 01:56:10 +00:00
$this -> { 'Width' } = $new ;
2019-11-29 18:56:02 +00:00
$field = ( $this -> Orientation () == 'ROTATE_90' or $this -> Orientation () == 'ROTATE_270' ) ? 'Height' : 'Width' ;
2021-08-18 14:50:45 +00:00
if ( property_exists ( $this , $field ))
2018-05-05 16:49:00 +00:00
return $this -> { $field };
2019-12-07 16:45:32 +00:00
return $this -> defaults [ $field ];
2018-05-05 16:49:00 +00:00
} // end function Width
2016-06-14 16:38:17 +00:00
2019-10-29 21:39:12 +00:00
public function ViewHeight ( $new = null ) {
2021-08-18 14:50:45 +00:00
if ( $new )
2017-10-27 01:56:10 +00:00
$this -> { 'Height' } = $new ;
2018-05-05 16:49:00 +00:00
2019-11-29 18:56:02 +00:00
$field = ( $this -> Orientation () == 'ROTATE_90' or $this -> Orientation () == 'ROTATE_270' ) ? 'Width' : 'Height' ;
2021-08-18 14:50:45 +00:00
if ( property_exists ( $this , $field ))
2018-05-05 16:49:00 +00:00
return $this -> { $field };
2019-12-07 16:45:32 +00:00
return $this -> defaults [ $field ];
2018-05-05 16:49:00 +00:00
} // end function Height
2016-06-14 16:38:17 +00:00
2019-02-10 00:41:54 +00:00
public function SignalCheckColour ( $new = null ) {
$field = 'SignalCheckColour' ;
if ( $new ) {
$this -> { $field } = $new ;
}
// Validate that it's a valid colour (we seem to allow color names, not just hex).
// This also helps prevent XSS.
2021-08-18 14:50:45 +00:00
if ( property_exists ( $this , $field ) && preg_match ( '/^[#0-9a-zA-Z]+$/' , $this -> { $field })) {
2019-02-10 00:41:54 +00:00
return $this -> { $field };
}
2019-12-07 16:45:32 +00:00
return $this -> defaults [ $field ];
2019-02-10 00:41:54 +00:00
} // end function SignalCheckColour
2021-08-18 14:50:45 +00:00
public static function find ( $parameters = array (), $options = array ()) {
2019-09-08 16:26:11 +00:00
return ZM_Object :: _find ( get_class (), $parameters , $options );
2016-05-05 19:30:24 +00:00
}
2017-12-22 15:12:34 +00:00
2021-08-18 14:50:45 +00:00
public static function find_one ( $parameters = array (), $options = array ()) {
2019-09-08 16:26:11 +00:00
return ZM_Object :: _find_one ( get_class (), $parameters , $options );
}
2017-11-05 16:54:00 +00:00
2021-08-18 14:50:45 +00:00
function zmcControl ( $mode = false ) {
if ( ! ( property_exists ( $this , 'Id' ) and $this -> { 'Id' })) {
2019-09-23 16:39:24 +00:00
Warning ( 'Attempt to control a monitor with no Id' );
2019-09-19 18:55:27 +00:00
return ;
}
2021-08-18 14:50:45 +00:00
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }) )) {
if ( $this -> Type () == 'Local' ) {
2017-10-24 00:00:59 +00:00
$zmcArgs = '-d ' . $this -> { 'Device' };
} else {
$zmcArgs = '-m ' . $this -> { 'Id' };
}
2021-08-18 14:50:45 +00:00
if ( $mode == 'stop' ) {
2018-06-11 20:34:23 +00:00
daemonControl ( 'stop' , 'zmc' , $zmcArgs );
2023-02-16 18:57:42 +00:00
} else if ( $mode == 'reload' ) {
daemonControl ( 'reload' , 'zmc' , $zmcArgs );
2017-10-24 00:00:59 +00:00
} else {
2021-08-18 14:50:45 +00:00
if ( $mode == 'restart' ) {
2018-06-11 20:34:23 +00:00
daemonControl ( 'stop' , 'zmc' , $zmcArgs );
2017-10-24 00:00:59 +00:00
}
2022-02-02 22:08:01 +00:00
if ( $this -> { 'Capturing' } != 'None' ) {
2018-06-11 20:34:23 +00:00
daemonControl ( 'start' , 'zmc' , $zmcArgs );
2018-01-18 20:38:48 +00:00
}
2017-10-24 00:00:59 +00:00
}
2021-08-18 14:50:45 +00:00
} else if ( $this -> ServerId ()) {
2022-09-28 21:41:46 +00:00
$result = $this -> Server () -> SendToApi ( '/monitors/daemonControl/' . $this -> { 'Id' } . '/' . $mode . '/zmc.json' );
2018-06-11 20:34:23 +00:00
} else {
2019-09-23 16:39:24 +00:00
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
2017-10-24 00:00:59 +00:00
}
} // end function zmcControl
2018-01-18 20:38:48 +00:00
2021-08-18 14:50:45 +00:00
public function GroupIds ( $new = '' ) {
if ( $new != '' ) {
if ( ! is_array ( $new )) {
2018-04-25 13:27:43 +00:00
$this -> { 'GroupIds' } = array ( $new );
} else {
$this -> { 'GroupIds' } = $new ;
}
}
2021-08-18 14:50:45 +00:00
if ( ! property_exists ( $this , 'GroupIds' )) {
if ( property_exists ( $this , 'Id' ) and $this -> { 'Id' }) {
$this -> { 'GroupIds' } = dbFetchAll ( 'SELECT `GroupId` FROM `Groups_Monitors` WHERE `MonitorId`=?' , 'GroupId' , array ( $this -> { 'Id' }));
if ( ! $this -> { 'GroupIds' })
2018-04-25 13:27:43 +00:00
$this -> { 'GroupIds' } = array ();
2018-02-27 19:19:20 +00:00
} else {
2018-03-23 20:34:46 +00:00
$this -> { 'GroupIds' } = array ();
2018-02-27 19:19:20 +00:00
}
}
return $this -> { 'GroupIds' };
}
2019-09-19 18:55:27 +00:00
2018-03-20 19:18:07 +00:00
public function delete () {
2021-08-18 14:50:45 +00:00
if ( ! $this -> { 'Id' }) {
Warning ( 'Attempt to delete a monitor without id.' );
2019-11-02 14:12:43 +00:00
return ;
}
2018-03-20 19:18:07 +00:00
$this -> zmcControl ( 'stop' );
// If fast deletes are on, then zmaudit will clean everything else up later
// If fast deletes are off and there are lots of events then this step may
// well time out before completing, in which case zmaudit will still tidy up
2021-08-18 14:50:45 +00:00
if ( ! ZM_OPT_FAST_DELETE ) {
2018-03-21 18:32:54 +00:00
$markEids = dbFetchAll ( 'SELECT Id FROM Events WHERE MonitorId=?' , 'Id' , array ( $this -> { 'Id' }));
2019-09-19 18:55:27 +00:00
foreach ( $markEids as $markEid )
2018-03-21 18:32:54 +00:00
deleteEvent ( $markEid );
2018-03-20 19:18:07 +00:00
2021-08-18 14:50:45 +00:00
if ( $this -> { 'Name' })
2019-11-02 14:12:43 +00:00
deletePath ( ZM_DIR_EVENTS . '/' . basename ( $this -> { 'Name' }));
2018-03-20 19:18:07 +00:00
deletePath ( ZM_DIR_EVENTS . '/' . $this -> { 'Id' });
$Storage = $this -> Storage ();
2021-08-18 14:50:45 +00:00
if ( $Storage -> Path () != ZM_DIR_EVENTS ) {
if ( $this -> { 'Name' })
2019-11-02 14:12:43 +00:00
deletePath ( $Storage -> Path () . '/' . basename ( $this -> { 'Name' }));
2018-03-20 19:18:07 +00:00
deletePath ( $Storage -> Path () . '/' . $this -> { 'Id' });
}
2019-09-19 18:55:27 +00:00
} // end if !ZM_OPT_FAST_DELETE
2018-03-20 19:18:07 +00:00
// This is the important stuff
dbQuery ( 'DELETE FROM Zones WHERE MonitorId = ?' , array ( $this -> { 'Id' }));
if ( ZM_OPT_X10 )
dbQuery ( 'DELETE FROM TriggersX10 WHERE MonitorId=?' , array ( $this -> { 'Id' }));
2021-04-09 23:46:25 +00:00
dbQuery ( 'DELETE FROM Monitor_Status WHERE MonitorId = ?' , array ( $this -> { 'Id' }));
dbQuery ( 'DELETE FROM Event_Summaries WHERE MonitorId = ?' , array ( $this -> { 'Id' }));
2018-03-20 19:18:07 +00:00
dbQuery ( 'DELETE FROM Monitors WHERE Id = ?' , array ( $this -> { 'Id' }));
} // end function delete
2018-03-21 18:32:54 +00:00
2019-09-19 18:55:27 +00:00
public function Storage ( $new = null ) {
2021-08-18 14:50:45 +00:00
if ( $new ) {
2018-03-21 18:32:54 +00:00
$this -> { 'Storage' } = $new ;
}
2021-08-18 14:50:45 +00:00
if ( ! ( property_exists ( $this , 'Storage' ) and $this -> { 'Storage' })) {
2020-08-24 18:35:59 +00:00
$this -> { 'Storage' } = isset ( $this -> { 'StorageId' }) ?
Storage :: find_one ( array ( 'Id' => $this -> { 'StorageId' })) :
2018-04-10 20:05:37 +00:00
new Storage ( NULL );
2021-08-18 14:50:45 +00:00
if ( ! $this -> { 'Storage' })
2018-05-24 13:54:45 +00:00
$this -> { 'Storage' } = new Storage ( NULL );
2018-03-21 18:32:54 +00:00
}
return $this -> { 'Storage' };
}
2018-05-04 13:46:46 +00:00
public function Source ( ) {
$source = '' ;
2021-08-18 14:50:45 +00:00
if ( $this -> { 'Type' } == 'Local' ) {
2018-05-04 13:46:46 +00:00
$source = $this -> { 'Device' } . ' (' . $this -> { 'Channel' } . ')' ;
2021-08-18 14:50:45 +00:00
} else if ( $this -> { 'Type' } == 'Remote' ) {
$source = preg_replace ( '/^.*@/' , '' , $this -> { 'Host' });
if ( $this -> { 'Port' } != '80' and $this -> { 'Port' } != '554' ) {
2018-05-04 13:46:46 +00:00
$source .= ':' . $this -> { 'Port' };
}
2021-08-18 14:50:45 +00:00
} else if ( $this -> { 'Type' } == 'VNC' ) {
2020-03-30 14:10:06 +00:00
$source = preg_replace ( '/^.*@/' , '' , $this -> { 'Host' } );
2021-08-18 14:50:45 +00:00
if ( $this -> { 'Port' } != '5900' ) {
2020-03-30 14:10:06 +00:00
$source .= ':' . $this -> { 'Port' };
}
2021-08-18 14:50:45 +00:00
} else if ( $this -> { 'Type' } == 'Ffmpeg' || $this -> { 'Type' } == 'Libvlc' || $this -> { 'Type' } == 'WebSite' ) {
$url_parts = parse_url ( $this -> { 'Path' });
if ( ZM_WEB_FILTER_SOURCE == 'Hostname' ) {
2018-11-22 15:04:33 +00:00
# Filter out everything but the hostname
2021-08-18 14:50:45 +00:00
if ( isset ( $url_parts [ 'host' ])) {
2018-09-14 18:26:45 +00:00
$source = $url_parts [ 'host' ];
} else {
$source = $this -> { 'Path' };
}
2021-08-18 14:50:45 +00:00
} else if ( ZM_WEB_FILTER_SOURCE == 'NoCredentials' ) {
2018-07-09 16:09:29 +00:00
# Filter out sensitive and common items
2018-06-20 15:12:43 +00:00
unset ( $url_parts [ 'user' ]);
unset ( $url_parts [ 'pass' ]);
#unset($url_parts['scheme']);
unset ( $url_parts [ 'query' ]);
#unset($url_parts['path']);
2021-08-18 14:50:45 +00:00
if ( isset ( $url_parts [ 'port' ]) and ( $url_parts [ 'port' ] == '80' or $url_parts [ 'port' ] == '554' ))
2018-06-20 15:12:43 +00:00
unset ( $url_parts [ 'port' ]);
$source = unparse_url ( $url_parts );
2020-08-24 18:35:59 +00:00
} else { # Don't filter anything
2018-06-20 15:12:43 +00:00
$source = $this -> { 'Path' };
}
2018-05-04 13:46:46 +00:00
}
2021-08-18 14:50:45 +00:00
if ( $source == '' ) {
2018-05-04 13:46:46 +00:00
$source = 'Monitor ' . $this -> { 'Id' };
}
return $source ;
} // end function Source
2018-09-07 20:31:11 +00:00
2019-12-13 16:50:11 +00:00
public function UrlToIndex ( $port = null ) {
return $this -> Server () -> UrlToIndex ( $port );
2018-09-14 18:26:45 +00:00
}
2018-09-07 20:31:11 +00:00
2021-11-10 19:18:58 +00:00
public function UrlToZMS ( $port = null ) {
return $this -> Server () -> UrlToZMS ( $port ) . '?mid=' . $this -> Id ();
}
2019-12-31 17:42:49 +00:00
public function sendControlCommand ( $command ) {
// command is generally a command option list like --command=blah but might be just the word quit
2019-10-08 22:07:33 +00:00
2019-12-31 17:42:49 +00:00
$options = array ();
# Convert from a command line params to an option array
2021-08-18 14:50:45 +00:00
foreach ( explode ( ' ' , $command ) as $option ) {
if ( preg_match ( '/--([^=]+)(?:=(.+))?/' , $option , $matches )) {
2019-12-31 17:42:49 +00:00
$options [ $matches [ 1 ]] = $matches [ 2 ] ? $matches [ 2 ] : 1 ;
2021-08-18 14:50:45 +00:00
} else if ( $option != '' and $option != 'quit' and $option != 'start' and $option != 'stop' ) {
2019-12-31 17:42:49 +00:00
Warning ( " Ignored command for zmcontrol $option in $command " );
}
2019-10-08 22:07:33 +00:00
}
2021-08-18 14:50:45 +00:00
if ( ! count ( $options )) {
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
2020-04-29 20:30:59 +00:00
# These are special as we now run zmcontrol as a daemon through zmdc.
$status = daemonStatus ( 'zmcontrol.pl' , array ( '--id' , $this -> { 'Id' }));
2020-10-14 14:39:25 +00:00
Debug ( " Current status $status " );
2021-08-18 14:50:45 +00:00
if ( $status or (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' })))) {
2020-04-29 20:30:59 +00:00
daemonControl ( $command , 'zmcontrol.pl' , '--id ' . $this -> { 'Id' });
return ;
}
$options [ 'command' ] = $command ;
2019-12-31 17:42:49 +00:00
} else {
2021-08-18 14:50:45 +00:00
Warning ( 'No commands to send to zmcontrol from ' . $command );
2019-12-31 17:42:49 +00:00
return false ;
}
2019-10-08 22:07:33 +00:00
}
2021-08-18 14:50:45 +00:00
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }))) {
2019-12-31 17:42:49 +00:00
# Local
2020-10-14 14:39:25 +00:00
Debug ( 'Trying to send options ' . print_r ( $options , true ));
2019-12-31 17:42:49 +00:00
$optionString = jsonEncode ( $options );
2021-08-18 14:50:45 +00:00
Debug ( 'Trying to send options ' . $optionString );
2019-12-31 17:42:49 +00:00
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
$socket = socket_create ( AF_UNIX , SOCK_STREAM , 0 );
2021-08-18 14:50:45 +00:00
if ( $socket < 0 ) {
2019-12-31 17:42:49 +00:00
Error ( 'socket_create() failed: ' . socket_strerror ( $socket ));
return false ;
2019-10-08 22:07:33 +00:00
}
2019-12-31 17:42:49 +00:00
$sockFile = ZM_PATH_SOCKS . '/zmcontrol-' . $this -> { 'Id' } . '.sock' ;
2021-08-18 14:50:45 +00:00
if ( @ socket_connect ( $socket , $sockFile )) {
if ( ! socket_write ( $socket , $optionString )) {
2019-12-31 17:42:49 +00:00
Error ( 'Can\'t write to control socket: ' . socket_strerror ( socket_last_error ( $socket )));
2020-01-05 22:30:06 +00:00
return false ;
2019-12-31 17:42:49 +00:00
}
2021-08-18 14:50:45 +00:00
} else if ( $command != 'quit' ) {
2020-09-21 15:24:17 +00:00
$command = ZM_PATH_BIN . '/zmcontrol.pl ' . $command . ' --id ' . $this -> { 'Id' };
2019-10-08 22:07:33 +00:00
2019-12-31 17:42:49 +00:00
// Can't connect so use script
$ctrlOutput = exec ( escapeshellcmd ( $command ));
}
socket_close ( $socket );
2021-08-18 14:50:45 +00:00
} else if ( $this -> ServerId ()) {
2022-09-28 21:41:46 +00:00
$result = $this -> Server () -> SendToApi ( '/monitors/daemonControl/' . $this -> { 'Id' } . '/' . $command . '/zmcontrol.pl.json' );
return $result ;
2019-10-08 22:07:33 +00:00
} else {
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
return false ;
} // end if we are on the recording server
return true ;
} // end function sendControlCommand($mid, $command)
2020-08-31 22:30:05 +00:00
function Groups ( $new = '' ) {
2021-08-18 14:50:45 +00:00
if ( $new != '' )
2020-08-31 22:30:05 +00:00
$this -> Groups = $new ;
2021-08-18 14:50:45 +00:00
if ( ! property_exists ( $this , 'Groups' )) {
2020-08-31 22:30:05 +00:00
$this -> Groups = Group :: find ( array ( 'Id' => $this -> GroupIds ()));
}
return $this -> Groups ;
}
2020-09-02 17:56:55 +00:00
function connKey ( $new = '' ) {
2021-08-18 14:50:45 +00:00
if ( $new )
2020-09-02 17:56:55 +00:00
$this -> connKey = $new ;
2021-08-18 14:50:45 +00:00
if ( ! isset ( $this -> connKey )) {
if ( ! empty ( $GLOBALS [ 'connkey' ])) {
2020-09-02 17:56:55 +00:00
$this -> connKey = $GLOBALS [ 'connkey' ];
} else {
$this -> connKey = generateConnKey ();
}
}
return $this -> connKey ;
}
2020-08-31 22:30:05 +00:00
2022-11-02 19:52:37 +00:00
function canEdit ( $u = null ) {
2020-09-18 00:56:04 +00:00
global $user ;
2022-10-19 21:48:50 +00:00
if ( $u === null or $u [ 'Id' ] == $user [ 'Id' ])
return editableMonitor ( $this -> { 'Id' });
2023-02-19 22:23:45 +00:00
$monitor_permission = Monitor_Permission :: find_one ( array ( 'UserId' => $u [ 'Id' ], 'MonitorId' => $this -> { 'Id' }));
2022-10-19 21:48:50 +00:00
if ( $monitor_permission and
( $monitor_permission -> Permission () == 'None' or $monitor_permission -> Permission () == 'View' )) {
2023-02-19 22:23:45 +00:00
Debug ( " Can't edit monitor " . $this -> { 'Id' } . " because of monitor permission " . $monitor_permission -> Permission ());
2022-10-19 21:48:50 +00:00
return false ;
}
2023-02-19 22:23:45 +00:00
$group_permissions = Group_Permission :: find ( array ( 'UserId' => $user [ 'Id' ]));
2022-10-19 21:48:50 +00:00
# If denied view in any group, then can't view it.
foreach ( $group_permissions as $permission ) {
if ( ! $permission -> canEditMonitor ( $this -> { 'Id' })) {
2023-02-19 22:23:45 +00:00
Debug ( " Can't edit monitor " . $this -> { 'Id' } . " because of group " . $permision -> Group () -> Name () . ' ' . $permision -> Permission ());
2022-10-19 21:48:50 +00:00
return false ;
}
}
return ( $u [ 'Monitors' ] == 'Edit' );
2020-09-18 00:56:04 +00:00
}
2021-03-12 14:26:23 +00:00
2022-10-19 21:48:50 +00:00
function canView ( $u = null ) {
2021-03-30 15:52:04 +00:00
global $user ;
2023-02-06 14:29:45 +00:00
if (( $u === null ) or ( $u [ 'Id' ] == $user [ 'Id' ]))
return visibleMonitor ( $this -> Id ());
2022-10-19 21:48:50 +00:00
2023-02-19 22:23:45 +00:00
$monitor_permission = Monitor_Permission :: find_one ( array ( 'UserId' => $u [ 'Id' ], 'MonitorId' => $this -> { 'Id' }));
2022-10-19 21:48:50 +00:00
if ( $monitor_permission and ( $monitor_permission -> Permission () == 'None' )) {
2023-02-19 22:23:45 +00:00
Debug ( " Can't view monitor " . $this -> { 'Id' } . " because of monitor permission " . $monitor_permission -> Permission ());
2021-08-18 14:50:45 +00:00
return false ;
2021-08-15 13:52:48 +00:00
}
2022-10-19 21:48:50 +00:00
2023-02-19 22:23:45 +00:00
$group_permissions = Group_Permission :: find ( array ( 'UserId' => $user [ 'Id' ]));
2022-10-19 21:48:50 +00:00
# If denied view in any group, then can't view it.
$group_permission_value = 'Inherit' ;
foreach ( $group_permissions as $permission ) {
$value = $pmerssion -> MonitorPermission ( $mid );
2022-10-20 13:22:37 +00:00
if ( $value == 'None' ) {
2023-02-19 22:23:45 +00:00
Debug ( " Can't view monitor " . $this -> { 'Id' } . " because of group " . $permision -> Group () -> Name () . ' ' . $permision -> Permission ());
2022-10-19 21:48:50 +00:00
return false ;
}
if ( $value == 'Edit' or $value == 'View' ) {
$group_permission_value = $value ;
2021-08-15 13:52:48 +00:00
}
}
2022-10-19 21:48:50 +00:00
if ( $group_permission_value != 'Inherit' ) return true ;
return ( $u [ 'Monitors' ] != 'None' );
} # end function canView
2021-03-30 15:52:04 +00:00
2021-04-12 19:58:46 +00:00
function AlarmCommand ( $cmd ) {
2021-08-18 14:50:45 +00:00
if (( ! defined ( 'ZM_SERVER_ID' )) or ( property_exists ( $this , 'ServerId' ) and ( ZM_SERVER_ID == $this -> { 'ServerId' }))) {
2021-04-12 19:58:46 +00:00
switch ( $cmd ) {
case 'on' : $cmd = ' -a' ; break ;
case 'off' : $cmd = ' -c' ; break ;
case 'disable' : $cmd = ' -n' ; break ;
case 'status' : $cmd = ' -s' ; break ;
default :
Warning ( " Invalid command $cmd in AlarmCommand " );
return false ;
}
$cmd = getZmuCommand ( $cmd . ' -m ' . $this -> { 'Id' });
$output = shell_exec ( $cmd );
Debug ( " Running $cmd output: $output " );
return $output ;
}
2021-08-18 14:50:45 +00:00
if ( $this -> ServerId ()) {
2022-09-28 21:41:46 +00:00
$result = $this -> Server () -> SendToApi ( '/monitors/alarm/id:' . $this -> { 'Id' } . '/command:' . $cmd . '.json' );
2021-04-12 19:58:46 +00:00
2022-09-28 21:41:46 +00:00
if ( $result === FALSE ) { /* Handle error */
Error ( 'Error sending command using ' . $url );
2021-04-12 19:58:46 +00:00
return false ;
}
2022-09-28 21:41:46 +00:00
$json = json_decode ( $result , true );
return $json [ 'status' ];
2021-04-12 19:58:46 +00:00
} // end if we are on the recording server
Error ( 'Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.' );
return false ;
}
2022-09-28 21:41:46 +00:00
2021-03-12 14:26:23 +00:00
function TriggerOn () {
2021-04-12 19:58:46 +00:00
$output = $this -> AlarmCommand ( 'on' );
2021-08-18 14:50:45 +00:00
if ( $output and preg_match ( '/Alarmed event id: (\d+)$/' , $output , $matches )) {
2021-03-12 14:26:23 +00:00
return $matches [ 1 ];
}
2021-08-18 14:50:45 +00:00
Warning ( 'No event returned from TriggerOn' );
2021-03-12 14:26:23 +00:00
}
function TriggerOff () {
2021-04-12 19:58:46 +00:00
$output = $this -> AlarmCommand ( 'off' );
2021-03-12 14:26:23 +00:00
}
2021-04-12 19:18:49 +00:00
function DisableAlarms () {
2021-04-12 19:58:46 +00:00
$output = $this -> AlarmCommand ( 'disable' );
2021-04-12 19:18:49 +00:00
}
2021-07-07 13:46:36 +00:00
function Model () {
2021-09-25 14:32:04 +00:00
if ( ! property_exists ( $this , 'Model' )) {
2022-02-07 00:06:35 +00:00
if ( property_exists ( $this , 'ModelId' ) and $this -> { 'ModelId' }) {
2021-09-25 14:32:04 +00:00
$this -> { 'Model' } = Model :: find_one ( array ( 'Id' => $this -> ModelId ()));
if ( ! $this -> { 'Model' })
$this -> { 'Model' } = new Model ();
} else {
$this -> { 'Model' } = new Model ();
}
2021-07-07 13:46:36 +00:00
}
return $this -> { 'Model' };
}
function Manufacturer () {
2021-09-25 14:32:04 +00:00
if ( ! property_exists ( $this , 'Manufacturer' )) {
2022-02-07 00:06:35 +00:00
if ( property_exists ( $this , 'ManufacturerId' ) and $this -> { 'ManufacturerId' }) {
2021-09-25 14:32:04 +00:00
$this -> { 'Manufacturer' } = Manufacturer :: find_one ( array ( 'Id' => $this -> ManufacturerId ()));
if ( ! $this -> { 'Manufacturer' })
$this -> { 'Manufacturer' } = new Manufacturer ();
} else {
$this -> { 'Manufacturer' } = new Manufacturer ();
}
2021-07-07 13:46:36 +00:00
}
return $this -> { 'Manufacturer' };
}
2022-01-20 14:47:36 +00:00
function getMonitorStateHTML () {
$html = '
< div id = " monitorStatus'. $this->Id ().' " class = " monitorStatus " >
< div id = " monitorState'. $this->Id ().' " class = " monitorState " >
< span > '.translate(' State ').' :< span id = " stateValue'. $this->Id ().' " ></ span ></ span >
< span id = " viewingFPS'. $this->Id ().' " title = " '.translate('Viewing FPS').' " >< span id = " viewingFPSValue'. $this->Id ().' " ></ span > fps </ span >
< span id = " captureFPS'. $this->Id ().' " title = " '.translate('Capturing FPS').' " >< span id = " captureFPSValue'. $this->Id ().' " ></ span > fps </ span >
' ;
2022-02-02 22:08:01 +00:00
if ( $this -> Analysing () != 'None' ) {
2022-01-20 14:47:36 +00:00
$html .= '<span id="analysisFPS' . $this -> Id () . '" title="' . translate ( 'Analysis FPS' ) . '"><span id="analysisFPSValue' . $this -> Id () . ' " ></span> fps</span>
' ;
}
$html .= '
2022-03-04 17:06:49 +00:00
< span id = " rate'. $this->Id ().' " class = " rate hidden " > '.translate(' Rate ').' : < span id = " rateValue'. $this->Id ().' " ></ span > x </ span >
< span id = " delay'. $this->Id ().' " class = " delay hidden " > '.translate(' Delay ').' : < span id = " delayValue'. $this->Id ().' " ></ span > s </ span >
< span id = " level'. $this->Id ().' " class = " buffer hidden " > '.translate(' Buffer ').' : < span id = " levelValue'. $this->Id ().' " ></ span >%</ span >
< span class = " zoom hidden " id = " zoom'. $this->Id ().' " > '. translate(' Zoom ').' : < span id = " zoomValue'. $this->Id ().' " ></ span > x </ span >
2022-01-20 14:47:36 +00:00
</ div >
</ div >
' ;
return $html ;
}
2022-04-10 21:28:38 +00:00
/* options [ 'width' ] is the desired view width not necessarily the image width requested .
* It can be % in which case we us it to set the scale
* It can be px in which case we can use it to calculate the scale
* Same width height . If both are set we should calculate the smaller resulting scale
*/
function getStreamHTML ( $options ) {
if ( isset ( $options [ 'scale' ]) and $options [ 'scale' ] != '' and $options [ 'scale' ] != 'fixed' ) {
2022-08-10 13:18:32 +00:00
if ( $options [ 'scale' ] != 'auto' && $options [ 'scale' ] != '0' ) {
2022-04-10 21:28:38 +00:00
$options [ 'width' ] = reScale ( $this -> ViewWidth (), $options [ 'scale' ]) . 'px' ;
$options [ 'height' ] = reScale ( $this -> ViewHeight (), $options [ 'scale' ]) . 'px' ;
2022-08-10 13:18:32 +00:00
} else if ( ! ( isset ( $options [ 'width' ]) or isset ( $options [ 'height' ]))) {
2022-04-10 21:28:38 +00:00
$options [ 'width' ] = '100%' ;
$options [ 'height' ] = 'auto' ;
}
} else {
$options [ 'scale' ] = 100 ;
# scale is empty or 100
# There may be a fixed width applied though, in which case we need to leave the height empty
2022-08-22 15:46:57 +00:00
if ( ! ( isset ( $options [ 'width' ]) and $options [ 'width' ]) or ( $options [ 'width' ] == 'auto' )) {
2022-04-10 21:28:38 +00:00
# Havn't specified width. If we specified height, then we should
# use a width that keeps the aspect ratio, otherwise no scaling,
# no dimensions, so assume the dimensions of the Monitor
2022-08-10 13:18:32 +00:00
if ( ! ( isset ( $options [ 'height' ]) and $options [ 'height' ])) {
2022-04-10 21:28:38 +00:00
# If we havn't specified any scale or dimensions, then we must be using CSS to scale it in a dynamic way. Can't make any assumptions.
}
} else {
2022-08-10 13:18:32 +00:00
if ( preg_match ( '/^(\d+)px$/' , $options [ 'width' ], $matches )) {
2022-04-10 21:28:38 +00:00
$scale = intval ( 100 * $matches [ 1 ] / $this -> ViewWidth ());
2022-08-10 13:18:32 +00:00
if ( $scale < $options [ 'scale' ])
2022-04-10 21:28:38 +00:00
$options [ 'scale' ] = $scale ;
2022-08-10 13:18:32 +00:00
} else if ( preg_match ( '/^(\d+)%$/' , $options [ 'width' ], $matches )) {
2022-04-10 21:28:38 +00:00
$scale = intval ( $matches [ 1 ]);
2022-08-10 13:18:32 +00:00
if ( $scale < $options [ 'scale' ])
2022-04-10 21:28:38 +00:00
$options [ 'scale' ] = $scale ;
} else {
2022-08-03 16:28:39 +00:00
$backTrace = debug_backtrace ();
2022-08-10 13:18:32 +00:00
Warning ( 'Invalid value for width: ' . $options [ 'width' ] . ' from ' . print_r ( $backTrace , true ));
2022-04-10 21:28:38 +00:00
}
}
}
2022-08-10 13:18:32 +00:00
if ( ! isset ( $options [ 'mode' ])) {
2022-04-10 21:28:38 +00:00
$options [ 'mode' ] = 'stream' ;
}
2022-08-17 19:34:39 +00:00
if ( ! isset ( $options [ 'width' ]) or $options [ 'width' ] == 'auto' )
2022-04-10 21:28:38 +00:00
$options [ 'width' ] = 0 ;
2022-08-17 19:34:39 +00:00
if ( ! isset ( $options [ 'height' ]) or $options [ 'height' ] == 'auto' )
2022-04-10 21:28:38 +00:00
$options [ 'height' ] = 0 ;
if ( ! isset ( $options [ 'maxfps' ])) {
$options [ 'maxfps' ] = ZM_WEB_VIDEO_MAXFPS ;
}
if ( $this -> StreamReplayBuffer ())
$options [ 'buffer' ] = $this -> StreamReplayBuffer ();
//Warning("width: " . $options['width'] . ' height: ' . $options['height']. ' scale: ' . $options['scale'] );
$html = '
< div id = " monitor'. $this->Id () . ' " class = " monitor " >
< div
id = " imageFeed'. $this->Id () .' "
class = " monitorStream imageFeed "
data - monitor - id = " '. $this->Id () .' "
data - width = " '. $this->ViewWidth () .' "
data - height = " '. $this->ViewHeight () .' " style = " '.
2022-04-28 19:45:35 +00:00
#(($options['width'] and ($options['width'] != '0px')) ? 'width: '.$options['width'].';' : '').
#(($options['height'] and ($options['height'] != '0px')) ? 'height: '.$options['height'].';' : '').
2022-04-10 21:28:38 +00:00
'">' ;
if ( $this -> Type () == 'WebSite' ) {
$html .= getWebSiteUrl (
'liveStream' . $this -> Id (), $this -> Path (),
( isset ( $options [ 'width' ]) ? $options [ 'width' ] : NULL ),
( isset ( $options [ 'height' ]) ? $options [ 'height' ] : NULL ),
$this -> Name ()
);
//FIXME, the width and height of the image need to be scaled.
} else if (( ZM_WEB_STREAM_METHOD == 'mpeg' ) && ZM_MPEG_LIVE_FORMAT ) {
$streamSrc = $this -> getStreamSrc ( array (
'mode' => 'mpeg' ,
'scale' => ( isset ( $options [ 'scale' ]) ? $options [ 'scale' ] : 100 ),
'bitrate' => ZM_WEB_VIDEO_BITRATE ,
'maxfps' => ZM_WEB_VIDEO_MAXFPS ,
'format' => ZM_MPEG_LIVE_FORMAT
) );
$html .= getVideoStreamHTML ( 'liveStream' . $this -> Id (), $streamSrc , $options [ 'width' ], $options [ 'height' ], ZM_MPEG_LIVE_FORMAT , $this -> Name () );
} else if ( $this -> JanusEnabled () ) {
2022-06-15 17:08:48 +00:00
$html .= '<video id="liveStream' . $this -> Id () . '" ' .
(( isset ( $options [ 'width' ]) and $options [ 'width' ] and $options [ 'width' ] != '0' ) ? 'width="' . $options [ 'width' ] . '"' : '' ) .
' autoplay muted controls playsinline=""></video>' ;
2022-04-10 21:28:38 +00:00
} else if ( $options [ 'mode' ] == 'stream' and canStream () ) {
$options [ 'mode' ] = 'jpeg' ;
$streamSrc = $this -> getStreamSrc ( $options );
$html .= getImageStreamHTML ( 'liveStream' . $this -> Id (), $streamSrc , $options [ 'width' ], $options [ 'height' ], $this -> Name ());
2022-05-30 17:35:36 +00:00
} else if ( $options [ 'mode' ] == 'single' and canStream () ) {
$streamSrc = $this -> getStreamSrc ( $options );
$html .= getImageStreamHTML ( 'liveStream' . $this -> Id (), $streamSrc , $options [ 'width' ], $options [ 'height' ], $this -> Name ());
2022-04-10 21:28:38 +00:00
} else {
if ( $options [ 'mode' ] == 'stream' ) {
Info ( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' );
}
$options [ 'mode' ] = 'single' ;
$streamSrc = $this -> getStreamSrc ( $options );
$html .= getImageStill ( 'liveStream' . $this -> Id (), $streamSrc ,
( isset ( $options [ 'width' ]) ? $options [ 'width' ] : null ),
( isset ( $options [ 'height' ]) ? $options [ 'height' ] : null ),
$this -> Name ());
}
2022-04-10 22:54:01 +00:00
2022-04-19 16:31:43 +00:00
if ( isset ( $options [ 'zones' ]) and $options [ 'zones' ]) {
2022-04-10 22:54:01 +00:00
$html .= '<svg class="zones" id="zones' . $this -> Id () . '" viewBox="0 0 ' . $this -> ViewWidth () . ' ' . $this -> ViewHeight () . '" preserveAspectRatio="none">' . PHP_EOL ;
foreach ( Zone :: find ( array ( 'MonitorId' => $this -> Id ()), array ( 'order' => 'Area DESC' )) as $zone ) {
$html .= $zone -> svg_polygon ();
} // end foreach zone
$html .= '
Sorry , your browser does not support inline SVG
</ svg >
' ;
} # end if showZones
2022-04-10 21:28:38 +00:00
$html .= PHP_EOL . '</div><!--monitorStream-->' . PHP_EOL ;
if ( isset ( $options [ 'state' ]) and $options [ 'state' ]) {
//if ((!ZM_WEB_COMPACT_MONTAGE) && ($this->Type() != 'WebSite')) {
$html .= $this -> getMonitorStateHTML ();
}
$html .= PHP_EOL . '</div>' . PHP_EOL ;
return $html ;
} // end getStreamHTML
2022-11-02 19:52:37 +00:00
public function effectivePermission ( $u = null ) {
2022-11-02 21:42:32 +00:00
if ( $u === null ) {
2022-11-02 19:52:37 +00:00
global $user ;
$u = new User ( $user );
}
$monitor_permission = $u -> Monitor_Permission ( $this -> Id ());
2022-11-02 21:42:32 +00:00
if ( $monitor_permission -> Permission () != 'Inherit' ) {
return $monitor_permission -> Permission ();
}
2022-11-02 19:52:37 +00:00
$gp_permissions = array ();
foreach ( $u -> Group_Permissions () as $gp ) {
2022-11-02 21:42:32 +00:00
if ( false === array_search ( $this -> Id (), $gp -> Group () -> MonitorIds ())) {
continue ;
}
if ( $gp -> Permission () == 'None' ) {
return $gp -> Permission ();
}
2022-11-02 19:52:37 +00:00
$gp_permissions [ $gp -> Permission ()] = 1 ;
}
if ( isset ( $gp_permissions [ 'View' ])) return 'View' ;
if ( isset ( $gp_permissions [ 'Edit' ])) return 'Edit' ;
return $u -> Monitors ();
}
2017-10-24 00:00:59 +00:00
} // end class Monitor
2015-09-17 19:29:36 +00:00
?>