From ebb465162eb74a7fc7b40d84cfa21a8749ff4475 Mon Sep 17 00:00:00 2001 From: "Jahleel A." Date: Mon, 18 Mar 2024 01:02:41 +0000 Subject: [PATCH 1/5] Added camera connection testing on the 'IP Camera Properties' page (only supports RTSP) --- www/ajax/editip.php | 22 ++++++++++++++++--- www/ajax/ipcameracheck.php | 13 +++++------ www/lib/lang.php | 4 ++++ www/lib/lib.php | 39 +++++++++++++++++++++++---------- www/template/ajax/editip.php | 40 ++++++++++++++++++++++------------ www/template/dist/js/editip.js | 18 +++++++++++++++ www/template/main_admin.php | 1 + 7 files changed, 102 insertions(+), 35 deletions(-) create mode 100644 www/template/dist/js/editip.js diff --git a/www/ajax/editip.php b/www/ajax/editip.php index fdb641d80..c4afcd668 100644 --- a/www/ajax/editip.php +++ b/www/ajax/editip.php @@ -20,9 +20,25 @@ public function postData() $id = intval($_POST['id']); $camera = new ipCamera($id); $result = $camera->edit($_POST); - data::responseJSON($result[0], $result[1]); + $camera->checkConnection(); + data::responseJSON($result[0], array( + $result[1], + str_replace(array("%TYPE%", "%TIME%"), array("RTSP", $camera->info['connection_status']['lastTimeChecked']), + $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL) + ), json_encode($camera->info['connection_status'])); exit(); } -} - + public function postTest() + { + $id = intval($_POST['id']); + $camera = new ipCamera($id); + $camera->checkConnection(); + data::responseJSON(10, array( 1 => str_replace( //-> 10 as status to avoid the "changes saved successfully" popup + array("%TYPE%", "%TIME%"), + array("RTSP", $camera->info['connection_status']['lastTimeChecked']), + $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL) + ), json_encode($camera->info['connection_status'])); + exit(); + } +} \ No newline at end of file diff --git a/www/ajax/ipcameracheck.php b/www/ajax/ipcameracheck.php index 2de8c7dd6..e653e7dc8 100644 --- a/www/ajax/ipcameracheck.php +++ b/www/ajax/ipcameracheck.php @@ -44,13 +44,12 @@ private function initProc() $camera->checkConnection(); - $status_message = ''; - foreach($camera->info['connection_status'] as $type => $status){ - if ($status!='OK'){ - $status_message .= str_replace('%TYPE%', $type, constant('IP_ACCESS_STATUS_'.$status)).'

'; - } - }; - + $status_message = str_replace( //-> 10 as status to avoid the "changes saved successfully" popup + array("%TYPE%", "%TIME%"), + array("RTSP", $camera->info['connection_status']['lastTimeChecked']), + $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL + ); + echo $status_message; } } diff --git a/www/lib/lang.php b/www/lib/lang.php index 544da49a4..be28cb5b0 100644 --- a/www/lib/lang.php +++ b/www/lib/lang.php @@ -384,6 +384,10 @@ define('AIP_CHECK_ONVIF_SUCCESS', 'Successfull'); define('AIP_CHECK_ONVIF_ERROR', 'Unsuccessful'); define('AIP_LIMIT_ALLOWED_DEVICES', 'Could not add a camera, because exceeds the limit of the allowed devices.'); +define('AIP_TEST_CONNECTION', 'Test Connection'); +define('AIP_TEST_CONNECTION_MESSAGE', 'Test connection to IP Camera'); +define('AIP_CONNECTION_SUCCESS', 'Connection Successful using %TYPE%. Tested at %TIME%'); +define('AIP_CONNECTION_FAIL', 'Connection Unsuccessful using %TYPE%. Tested at %TIME%'); # HLS configuration define('AIP_HLS_WINDOW_SIZE', 'HLS window size'); diff --git a/www/lib/lib.php b/www/lib/lib.php index 18b3094f1..a8d269e91 100644 --- a/www/lib/lib.php +++ b/www/lib/lib.php @@ -767,19 +767,36 @@ public function getInfo($id){ $this->ptzControl = new cameraPtz($this); } } - public function checkConnection(){ + public function checkConnection() { + //FIXME: Currently only supports RTSP. MJPEG is currently untested ini_set('default_socket_timeout', 1); - #needs server to check for RTSP //// $paths['rtsp'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp']; - $paths['mjpeg'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']).':'.$this->info['portMjpeg'].$this->info['mjpeg_path']; - $paths['http'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']); - foreach($paths as $type => $path){ - $headers = @get_headers($path); - $contents = @file_get_contents($path); - if (!$headers) { $this->info['connection_status'][$type] = 'F'; continue; } - preg_match("/([0-9]{3})/", $headers[0], $response_code); - $this->info['connection_status'][$type] = ($response_code[0]=='200') ? 'OK' : $response_code[0]; + + $path = ""; + + switch(($this->info['protocol'])) { + case 'IP-RTSP': + $path = 'rtsp://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp']; + break; + case 'IP-MJPEG': + $path= 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']).':'.$this->info['portMjpeg'].$this->info['mjpeg_path']; + break; } - return $this->info['connection_status']; + + //-> '-stimeout' is measured in microseconds + $ffprobe_output = shell_exec( + "LD_LIBRARY_PATH=/usr/lib/bluecherry/ /usr/lib/bluecherry/ffprobe -stimeout 5000000 -hide_banner -show_format -show_streams -print_format json \"".$path."\""); + + $rtsp_data = json_decode($ffprobe_output, true); + + $this->info['connection_status']['lastTimeChecked'] = date("d/m/Y h:i a"); //TODO: Make date/time formatting regional + $this->info['connection_status']['success'] = array_key_exists('streams', $rtsp_data) ? count($rtsp_data['streams']) > 0 : false; + + + #needs server to check for RTSP //// $paths['rtsp'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp']; + //FIXME: Test mjpeg + //$paths['mjpeg'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']).':'.$this->info['portMjpeg'].$this->info['mjpeg_path']; + // TODO: Test http + //$paths['http'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']); } protected static function autoConfigure($driver, $info){ #auto configure known cameras include_once("ipcamlib.php"); diff --git a/www/template/ajax/editip.php b/www/template/ajax/editip.php index ad9fab615..25044f0d2 100644 --- a/www/template/ajax/editip.php +++ b/www/template/ajax/editip.php @@ -14,13 +14,27 @@
-
- - - -
-
- +
+
+ +
+
+
+ + + + + + + + +
+
+
+ +
+ +
@@ -196,18 +210,16 @@ info['debug_level']==1) ? 'checked' : ''; ?> />
-
- +
- -
+
- - - +
diff --git a/www/template/dist/js/editip.js b/www/template/dist/js/editip.js new file mode 100644 index 000000000..e3524a206 --- /dev/null +++ b/www/template/dist/js/editip.js @@ -0,0 +1,18 @@ +$(function() { + console.log("This loaded!"); +}); + +function testCameraConnection(form, msg) { + let data = JSON.parse(msg.data); + + $('#connStat').find('form').show(); + if(data.success) + $('#connStat').removeClass().addClass('alert alert-success').find('span').html(msg.msg[1]); + else + $('#connStat').removeClass().addClass('alert alert-danger').find('span').html(msg.msg[1]); +} + +function testCameraLoadingHeader(form, msg) { + $('#connStat').removeClass().addClass('alert alert-warning').find('span').html('Testing...'); + $('#connStat').find('form').hide(); +} \ No newline at end of file diff --git a/www/template/main_admin.php b/www/template/main_admin.php index a627dce78..93fa26e1f 100644 --- a/www/template/main_admin.php +++ b/www/template/main_admin.php @@ -322,6 +322,7 @@ + From ab2f4a3634c14182aaf133b232aa29e5c19886c1 Mon Sep 17 00:00:00 2001 From: Jahleel A Date: Wed, 20 Mar 2024 14:40:24 +0000 Subject: [PATCH 2/5] Update www/template/dist/js/editip.js Co-authored-by: Andriy Utkin --- www/template/dist/js/editip.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/www/template/dist/js/editip.js b/www/template/dist/js/editip.js index e3524a206..bf9e20991 100644 --- a/www/template/dist/js/editip.js +++ b/www/template/dist/js/editip.js @@ -1,7 +1,5 @@ $(function() { - console.log("This loaded!"); }); - function testCameraConnection(form, msg) { let data = JSON.parse(msg.data); From 4896efdc7d2aeac83242ebc5b784640ecae4f829 Mon Sep 17 00:00:00 2001 From: Jahleel Abraham Date: Thu, 21 Mar 2024 13:43:54 +0000 Subject: [PATCH 3/5] Added suggestions and improved flow (Remove time, Reverted MJPEG Testing, Switched to TCP) --- www/ajax/editip.php | 21 +++++++++++---------- www/lib/lang.php | 4 ++-- www/lib/lib.php | 27 +++++++++++++-------------- www/template/dist/js/editip.js | 6 +++--- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/www/ajax/editip.php b/www/ajax/editip.php index c4afcd668..7b4a6bae0 100644 --- a/www/ajax/editip.php +++ b/www/ajax/editip.php @@ -20,12 +20,13 @@ public function postData() $id = intval($_POST['id']); $camera = new ipCamera($id); $result = $camera->edit($_POST); - $camera->checkConnection(); - data::responseJSON($result[0], array( - $result[1], - str_replace(array("%TYPE%", "%TIME%"), array("RTSP", $camera->info['connection_status']['lastTimeChecked']), + $camera = new ipCamera($id); // Reinstance the object to update information + $camera->checkConnection(); // Test the connection + data::responseJSON($result[0], $result[1], array( + json_encode($camera->info['connection_status']), + str_replace("%TYPE%", str_replace("IP-", "", $camera->info['protocol']), $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL) - ), json_encode($camera->info['connection_status'])); + )); exit(); } @@ -34,11 +35,11 @@ public function postTest() $id = intval($_POST['id']); $camera = new ipCamera($id); $camera->checkConnection(); - data::responseJSON(10, array( 1 => str_replace( //-> 10 as status to avoid the "changes saved successfully" popup - array("%TYPE%", "%TIME%"), - array("RTSP", $camera->info['connection_status']['lastTimeChecked']), - $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL) - ), json_encode($camera->info['connection_status'])); + data::responseJSON(10, "", array( + json_encode($camera->info['connection_status']), + str_replace("%TYPE%", str_replace("IP-", "", $camera->info['protocol']), + $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL) + )); exit(); } } \ No newline at end of file diff --git a/www/lib/lang.php b/www/lib/lang.php index be28cb5b0..bcd029ad8 100644 --- a/www/lib/lang.php +++ b/www/lib/lang.php @@ -386,8 +386,8 @@ define('AIP_LIMIT_ALLOWED_DEVICES', 'Could not add a camera, because exceeds the limit of the allowed devices.'); define('AIP_TEST_CONNECTION', 'Test Connection'); define('AIP_TEST_CONNECTION_MESSAGE', 'Test connection to IP Camera'); -define('AIP_CONNECTION_SUCCESS', 'Connection Successful using %TYPE%. Tested at %TIME%'); -define('AIP_CONNECTION_FAIL', 'Connection Unsuccessful using %TYPE%. Tested at %TIME%'); +define('AIP_CONNECTION_SUCCESS', 'Connection Successful using %TYPE%'); +define('AIP_CONNECTION_FAIL', 'Connection Unsuccessful using %TYPE%'); # HLS configuration define('AIP_HLS_WINDOW_SIZE', 'HLS window size'); diff --git a/www/lib/lib.php b/www/lib/lib.php index a8d269e91..fc323e2ed 100644 --- a/www/lib/lib.php +++ b/www/lib/lib.php @@ -773,31 +773,29 @@ public function checkConnection() { $path = ""; - switch(($this->info['protocol'])) { + switch($this->info['protocol']) { case 'IP-RTSP': - $path = 'rtsp://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp']; - break; - case 'IP-MJPEG': - $path= 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']).':'.$this->info['portMjpeg'].$this->info['mjpeg_path']; + $path = '-rtsp_transport tcp "rtsp://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp'].'"'; break; + case 'IP-MJPEG': + //FIXME: This is the old logic for testing MJPEG. Testing for MJPEG is currently not supported by the bundled ffprobe method used for RTSP + $path = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']).':'.$this->info['portMjpeg'].$this->info['mjpeg_path']; + $headers = @get_headers($path); + if (!$headers) { $this->info['connection_status']['success'] = false; return; } + preg_match("/([0-9]{3})/", $headers[0], $response_code); + $this->info['connection_status']['success'] = ($response_code[0]=='200') ? true : false; + return; } //-> '-stimeout' is measured in microseconds $ffprobe_output = shell_exec( - "LD_LIBRARY_PATH=/usr/lib/bluecherry/ /usr/lib/bluecherry/ffprobe -stimeout 5000000 -hide_banner -show_format -show_streams -print_format json \"".$path."\""); + "/usr/lib/bluecherry/ffprobe -stimeout 5000000 -hide_banner -show_format -show_streams -print_format json ".$path); $rtsp_data = json_decode($ffprobe_output, true); - $this->info['connection_status']['lastTimeChecked'] = date("d/m/Y h:i a"); //TODO: Make date/time formatting regional $this->info['connection_status']['success'] = array_key_exists('streams', $rtsp_data) ? count($rtsp_data['streams']) > 0 : false; - - - #needs server to check for RTSP //// $paths['rtsp'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp']; - //FIXME: Test mjpeg - //$paths['mjpeg'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']).':'.$this->info['portMjpeg'].$this->info['mjpeg_path']; - // TODO: Test http - //$paths['http'] = 'http://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').((empty($this->info['ipAddrMjpeg'])) ? $this->info['ipAddr'] : $this->info['ipAddrMjpeg']); } + protected static function autoConfigure($driver, $info){ #auto configure known cameras include_once("ipcamlib.php"); $result = false; @@ -874,6 +872,7 @@ public function edit($data){ #if there were no errors, edit the camera $query = data::formQueryFromArray('update', 'Devices', $data[1], 'id', $this->info['id']); $result = data::query($query, true); + return array($result, false); } public static function create($rawData){ diff --git a/www/template/dist/js/editip.js b/www/template/dist/js/editip.js index bf9e20991..ae6f09d5a 100644 --- a/www/template/dist/js/editip.js +++ b/www/template/dist/js/editip.js @@ -1,13 +1,13 @@ $(function() { }); function testCameraConnection(form, msg) { - let data = JSON.parse(msg.data); + let data = JSON.parse(msg.data[0]); $('#connStat').find('form').show(); if(data.success) - $('#connStat').removeClass().addClass('alert alert-success').find('span').html(msg.msg[1]); + $('#connStat').removeClass().addClass('alert alert-success').find('span').html(msg.data[1]); else - $('#connStat').removeClass().addClass('alert alert-danger').find('span').html(msg.msg[1]); + $('#connStat').removeClass().addClass('alert alert-danger').find('span').html(msg.data[1]); } function testCameraLoadingHeader(form, msg) { From 7551f3de6f4730a8f17c3918cf9c3a22bf5cbd0a Mon Sep 17 00:00:00 2001 From: Jahleel Abraham Date: Thu, 21 Mar 2024 15:10:18 +0000 Subject: [PATCH 4/5] Removed last referance to 'lastTimeChecked' --- www/ajax/ipcameracheck.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/www/ajax/ipcameracheck.php b/www/ajax/ipcameracheck.php index e653e7dc8..dfb04d478 100644 --- a/www/ajax/ipcameracheck.php +++ b/www/ajax/ipcameracheck.php @@ -44,11 +44,8 @@ private function initProc() $camera->checkConnection(); - $status_message = str_replace( //-> 10 as status to avoid the "changes saved successfully" popup - array("%TYPE%", "%TIME%"), - array("RTSP", $camera->info['connection_status']['lastTimeChecked']), - $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL - ); + $status_message = str_replace("%TYPE%", str_replace("IP-", "", $camera->info['protocol']), + $camera->info['connection_status']['success'] ? AIP_CONNECTION_SUCCESS : AIP_CONNECTION_FAIL); echo $status_message; } From 18d2c3bda9d1b22797842a99d3ee697dddf26db6 Mon Sep 17 00:00:00 2001 From: "Jahleel A." Date: Thu, 21 Mar 2024 21:20:27 +0000 Subject: [PATCH 5/5] Added arguments and shell escaping --- www/lib/lib.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/www/lib/lib.php b/www/lib/lib.php index fc323e2ed..ec398bcd2 100644 --- a/www/lib/lib.php +++ b/www/lib/lib.php @@ -772,10 +772,12 @@ public function checkConnection() { ini_set('default_socket_timeout', 1); $path = ""; + $args = ""; switch($this->info['protocol']) { case 'IP-RTSP': - $path = '-rtsp_transport tcp "rtsp://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp'].'"'; + $path = 'rtsp://'.((empty($this->info['rtsp_username'])) ? '' : $this->info['rtsp_username'].':'.$this->info['rtsp_password'].'@').$this->info['ipAddr'].':'.$this->info['port'].$this->info['rtsp']; + $args = array("-rtsp_flags +prefer_tcp", "-rtsp_transport tcp", "-rtsp_transport tcp")[$this->info['rtsp_rtp_prefer_tcp']]; break; case 'IP-MJPEG': //FIXME: This is the old logic for testing MJPEG. Testing for MJPEG is currently not supported by the bundled ffprobe method used for RTSP @@ -789,7 +791,7 @@ public function checkConnection() { //-> '-stimeout' is measured in microseconds $ffprobe_output = shell_exec( - "/usr/lib/bluecherry/ffprobe -stimeout 5000000 -hide_banner -show_format -show_streams -print_format json ".$path); + "/usr/lib/bluecherry/ffprobe -stimeout 5000000 -hide_banner -show_format -show_streams -print_format json ".$args. " " . escapeshellarg($path)); $rtsp_data = json_decode($ffprobe_output, true);