From 8b33cee93dc5e92a5b856298f48120677a2a4c89 Mon Sep 17 00:00:00 2001 From: jaredb7 Date: Fri, 7 Apr 2023 09:46:31 +1000 Subject: [PATCH] Enhancement - Update Spectrogram page to show detection labels on RTSP streams Added in logic to handle finding the correct 'newest' detection's CSV file for the stream being listened to, the script will look in the sound card recordings location as usual, if it finds nothing there, then look in the StreamData folder for files matching the currently listened stream Updated spectrogram.sh to not execute sox if the file mentioned in analyzing now does not exist, this is just to try reduce noise in the logs Fixed my mis-spelling of RTSP again Small tweak to the Javascript responsible for drawing the labels on the spectrogram to accommodate the inclusion of RTSP_X in the streams filename --- scripts/spectrogram.php | 95 +++++++++++++++++++++++++++++++++-------- scripts/spectrogram.sh | 6 ++- 2 files changed, 82 insertions(+), 19 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index 832dd4d..65acd29 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -14,18 +14,65 @@ $RECS_DIR = $config["RECS_DIR"]; $user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"); $home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); $home = trim($home); -$files = scandir($RECS_DIR."/".date('F-Y')."/".date('d-l')."/", SCANDIR_SORT_ASCENDING); + +//Replace variables to Fix up the file paths just in case the ENV environment variables don't resolve via PHP +$RECS_DIR = str_replace("\$HOME", $home, $RECS_DIR); +$STREAM_DATA_DIR = $RECS_DIR . "/StreamData/"; + +//Try find the latest file out of the soundcard recording folder +$look_in_directory = $RECS_DIR."/".date('F-Y')."/".date('d-l')."/"; +$files = scandir($look_in_directory, SCANDIR_SORT_ASCENDING); +//Extract the filename, positions 0 and 1 are the folder hierarchy '.' and '..' $newest_file = $files[2]; +//Couldn't find under e.g /home/pi/April-2023/03-Monday/ (where USB audio streams are recorded +//look in the StreamData directory (RTSP streams are recorded here) + if (empty($files) || array_key_exists(2, $files) === false) { + $look_in_directory = $STREAM_DATA_DIR; + //Load the file in the directory + $files = scandir($look_in_directory, SCANDIR_SORT_ASCENDING); + + //Because there might be more than 1 stream, we can't really assume the file at index 2 is the latest, or even for the stream being listened to + //Read the RTSP_STREAM_TO_LIVESTREAM setting, then try to find that CSV file + if(!empty($config['RTSP_STREAM_TO_LIVESTREAM']) && is_numeric($config['RTSP_STREAM_TO_LIVESTREAM'])){ + //The stored setting of RTSP_STREAM_TO_LIVESTREAM is 0 based, but filenames are 1's based, so just add 1 to the config value + //so we can match up the stream the user is listening to with the appropriate filename + $RTSP_STREAM_LISTENED_TO = ($config['RTSP_STREAM_TO_LIVESTREAM'] + 1); + }else{ + //Setting is invalid somehow + //The stored setting of RTSP_STREAM_TO_LIVESTREAM is 0 based, but filenames are 1's based, so just add 1 to the config value + //This will be the first stream + $RTSP_STREAM_LISTENED_TO = 1; + } + + //The RTSP streams contain 'RTSP_X' in the filename, were X is the stream url index in the comma separated list of RTSP streams + //We can use this to locate the file for this stream + foreach ($files as $file_idx => $stream_file_name) { + //Skip the folder hierarchy entries + if ($stream_file_name != "." && $stream_file_name != "..") { + //See if the filename contains the correct RTSP name, also only check .wav files by excluding the csv files with the filter .wav.csv + if (stripos($stream_file_name, 'RTSP_' . $RTSP_STREAM_LISTENED_TO) !== false && stripos($stream_file_name, '.wav.csv') === false) { + //Found a match - set it as the newest file + $newest_file = $stream_file_name; + } + } + } + } + + +//If the newest file param has been supplied and it's the same as the newest file found +//then stop processing if($newest_file == $_GET['newest_file']) { die(); } +//Print out the filename echo "file,".$newest_file."\n"; +//Print out the detected birds as CSV $row = 1; -if (($handle = fopen($RECS_DIR."/".date('F-Y')."/".date('d-l')."/".$newest_file.".csv", "r")) !== FALSE) { +if (($handle = fopen($look_in_directory . $newest_file . ".csv", "r")) !== FALSE) { while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { if($row != 1){ $num = count($data); @@ -38,23 +85,25 @@ if (($handle = fopen($RECS_DIR."/".date('F-Y')."/".date('d-l')."/".$newest_file. } fclose($handle); } +//Kill the script so no further processing or output is done die(); } -$RSTP_Stream_Config = array(); +//Hold the array of RTSP steams once they are exploded +$RTSP_Stream_Config = array(); -//Load the birdnet config so we can read the RSTP setting +//Load the birdnet config so we can read the RTSP setting // Valid config data if (is_array($config) && array_key_exists('RTSP_STREAM',$config)) { if (is_null($config['RTSP_STREAM']) === false && $config['RTSP_STREAM'] !== "") { - $RSTP_Stream_Config_Data = explode(",", $config['RTSP_STREAM']); + $RTSP_Stream_Config_Data = explode(",", $config['RTSP_STREAM']); //Process the stream further //we need to able to ID it (just do this by position), get the hostname to show in the dropdown box - foreach ($RSTP_Stream_Config_Data as $stream_idx => $stream_url) { + foreach ($RTSP_Stream_Config_Data as $stream_idx => $stream_url) { //$stream_idx is the array position of the the RSP stream URL, idx of 0 is the first, 1 - second etc - $rstp_stream_url = parse_url($stream_url); - $RSTP_Stream_Config[$stream_idx] = $rstp_stream_url['host']; + $RTSP_stream_url = parse_url($stream_url); + $RTSP_Stream_Config[$stream_idx] = $RTSP_stream_url['host']; } } } @@ -159,21 +208,27 @@ function applyText(text,x,y,opacity) { var add =0; var newest_file; +var newest_file_tmp; var lastbird; function loadDetectionIfNewExists() { const xhttp = new XMLHttpRequest(); xhttp.onload = function() { // if there's a new detection that needs to be updated to the page if(this.responseText.length > 0 && !this.responseText.includes("Database")) { - + // Case insensitive match for RTSP_X + var RTSP_regex = /RTSP_[0-9]+-/i; + var RTSP_regex_match = false; var split = this.responseText.split("\n") for(var i = 1;i < split.length; i++) { if(parseInt(split[i].split(",")[0]) >= 0){ newest_file = split[0].split(",")[1] + newest_file_tmp = newest_file;//Copy the file name var so we something to work with + //Remove the string that denotes the RTSP stream from the filename to make things easier, it's not really needed + RTSP_regex_match = RTSP_regex.test(newest_file_tmp) + newest_file_tmp = newest_file_tmp.replace(RTSP_regex, "") //applyText(split[i].split(",")[1],document.body.querySelector('canvas').width - ((parseInt(split[i].split(",")[0]))*avgfps), (document.body.querySelector('canvas').height * 0.50)) - - d1 = new Date(newest_file.split("-")[0]+"/"+newest_file.split("-")[1]+"/"+newest_file.split("-")[2]+ " "+newest_file.split("-")[4].replace(".wav","")) + d1 = new Date(newest_file_tmp.split("-")[0]+"/"+newest_file_tmp.split("-")[1]+"/"+newest_file_tmp.split("-")[2]+ " "+newest_file_tmp.split("-")[4].replace(".wav","")) console.log("d1 "+d1) d2 = new Date(xhttp.getResponseHeader("Date")); console.log("d2 "+d2) @@ -193,7 +248,13 @@ function loadDetectionIfNewExists() { console.log(add) // Date csv file was created + relative detection time of bird + mic delay - secago = Math.abs(timeDiff) - split[i].split(",")[0] - 6.8; + //If we can't find the regex in the filename, then the RTSP_X string doesn't exist, unlikely to be a RTSP stream + if (RTSP_regex_match == false){ + secago = (Math.abs(timeDiff) - split[i].split(",")[0]) - 6.8; + }else{ + //half the delay for RTSP streams ~ just a rough guess + secago = (Math.abs(timeDiff) - split[i].split(",")[0]) - 4; + } x = document.body.querySelector('canvas').width - ((parseInt(secago))*avgfps); // if the text is too close to the right side of the canvas and will be cut off, wait 3 seconds before adding text @@ -361,16 +422,16 @@ h1 {
-
+