From 6c6247cf19c42ae9c12027a5b8fe184e91858c8f Mon Sep 17 00:00:00 2001 From: frederik Date: Tue, 12 Mar 2024 13:48:47 +0100 Subject: [PATCH] with the new analysis pipeline .wav and .wav.json do not exist at the same time. make labeling work with json alone. also tweak the timing --- scripts/spectrogram.php | 200 +++++++++++++++------------------------- 1 file changed, 75 insertions(+), 125 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index 7f34c4b..806b52d 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -15,82 +15,72 @@ if(!empty($config['FREQSHIFT_RECONNECT_DELAY']) && is_numeric($config['FREQSHIFT } if(isset($_GET['ajax_csv'])) { -$RECS_DIR = $config["RECS_DIR"]; + $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); + $user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"); + $home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); + $home = trim($home); -//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/"; + $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]; + if (empty($config['RTSP_STREAM'])) { + $look_in_directory = $STREAM_DATA_DIR; + $files = scandir($look_in_directory, SCANDIR_SORT_ASCENDING); + //Extract the filename, positions 0 and 1 are the folder hierarchy '.' and '..' + $newest_file = $files[2]; + } + else { + $look_in_directory = $STREAM_DATA_DIR; -//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); - //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; + } - //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.csv files + if (stripos($stream_file_name, 'RTSP_' . $RTSP_STREAM_LISTENED_TO) !== false && stripos($stream_file_name, '.wav.json') !== false) { + //Found a match - set it as the newest file + $newest_file = $stream_file_name; + } } - - //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($look_in_directory . $newest_file . ".csv", "r")) !== FALSE) { - while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { - if($row != 1){ - $num = count($data); - for ($c=0; $c < $num; $c++) { - $exp = explode(';',$data[$c]); - echo (($exp[0]+$exp[1])/2).",".$exp[3].",".$exp[4]."\n"; - } - } - $row++; - } - fclose($handle); } + +$contents = file_get_contents($look_in_directory . $newest_file); +if ($contents !== false) { + $json = json_decode($contents); + if ($json != null) { + $datetime = DateTime::createFromFormat(DateTime::ISO8601, $json->{'timestamp'}); + $now = new DateTime(); + $interval = $now->diff($datetime); + $json->delay = $interval->format('%s'); + echo json_encode($json); + } +} + //Kill the script so no further processing or output is done die(); } @@ -212,84 +202,44 @@ function applyText(text,x,y,opacity) { CTX.fillStyle = 'hsl(280, 100%, 10%)'; } -var add =0; +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_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) - timeDiff = (d2-d1)/1000; - - // stagger Y placement if a new bird - if(split[i].split(",")[1] != lastbird || split[i].split(",")[1].length > 13) { - add+= 15; - if(add >= 60) { - add = 0; - } - - //if(parseFloat(add + document.body.querySelector('canvas').height * 0.50) > document.body.querySelector('canvas').height || parseFloat(add + document.body.querySelector('canvas').height * 0.50) <= 0) { - // add = 0; - //} - } - console.log(add) - - // Date csv file was created + relative detection time of bird + mic delay - //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 - if(x > document.body.querySelector('canvas').width - (3*avgfps)) { - setTimeout(function (split,i,x,add) { - console.log("ADD:"+add) - console.log(split[i]) - console.log("originally at "+x+", now waiting 2 sec and at "+(x-(3*avgfps))) - applyText(split[i].split(",")[1],(x - (3*avgfps)), ((document.body.querySelector('canvas').height * 0.50) + add ), split[i].split(",")[2]); - }, 2000, split, i, x, add) - } else { - applyText(split[i].split(",")[1],x, ((document.body.querySelector('canvas').height * 0.50) + add ), split[i].split(",")[2]) - } - - - lastbird = split[i].split(",")[1] + const resp = JSON.parse(this.responseText); + newest_file = resp.file_name; + console.log("delay " + resp.delay); + for (detection of resp.detections) { + console.log("detection.start " + detection.start); + secago = resp.delay - detection.start; + x = document.body.querySelector('canvas').width - (secago * avgfps); + y = (document.body.querySelector('canvas').height * 0.50) + add; + if(x > document.body.querySelector('canvas').width - (5*avgfps) && detection.common_name.length > 8) { + setTimeout(function (detection, x, y, x_org) { + console.log("originally at "+x_org+", now waiting 3 sec and at "+x); + applyText(detection.common_name, x, y, detection.confidence); + }, 3*1000, detection, x - (5*avgfps), y, x); + } else { + applyText(detection.common_name, x, y, detection.confidence); + } + // stagger Y placement + add+= 15; + if(add >= 60) { + add = 0; } - } } - } + }; xhttp.open("GET", "spectrogram.php?ajax_csv=true&newest_file="+newest_file, true); xhttp.send(); - } window.setInterval(function(){ loadDetectionIfNewExists(); -}, 500); +}, 1000); var compressor = undefined; var SOURCE;