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
This commit is contained in:
jaredb7
2023-04-07 09:46:31 +10:00
parent bb1ac2dd70
commit 8b33cee93d
2 changed files with 82 additions and 19 deletions
+78 -17
View File
@@ -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 {
<div class="centered">
<?php
if (isset($RSTP_Stream_Config) && !empty($RSTP_Stream_Config)) {
if (isset($RTSP_Stream_Config) && !empty($RTSP_Stream_Config)) {
?>
<div style="display:inline" id="rstp_streams">
<div style="display:inline" id="RTSP_streams">
<label>RTSP Stream: </label>
<select id="rtsp_stream_select" name="RTSP Streams">
<?php
//The setting representing which livestream to stream is more than the number of RTSP streams available
//maybe the list of streams has been modified
//This isn't the ideal for this, but needed a way to fix this setting without calling the advanced setting page
if (array_key_exists($config['RTSP_STREAM_TO_LIVESTREAM'], $RSTP_Stream_Config) === false) {
if (array_key_exists($config['RTSP_STREAM_TO_LIVESTREAM'], $RTSP_Stream_Config) === false) {
$contents = file_get_contents('/etc/birdnet/birdnet.conf');
$contents2 = file_get_contents('./scripts/thisrun.txt');
$contents = preg_replace("/RTSP_STREAM_TO_LIVESTREAM=.*/", "RTSP_STREAM_TO_LIVESTREAM=\"0\"", $contents);
@@ -383,7 +444,7 @@ h1 {
}
//Print out the dropdown list for the RTSP streams
foreach ($RSTP_Stream_Config as $stream_id => $stream_host) {
foreach ($RTSP_Stream_Config as $stream_id => $stream_host) {
$isSelected = "";
//Match up the selected value saved in config so we can preselect it
if ($config['RTSP_STREAM_TO_LIVESTREAM'] == $stream_id) {
@@ -420,7 +481,7 @@ h1 {
<script>
var rtsp_stream_select = document.getElementById("rtsp_stream_select");
//When the dropdown selection is changed set the new value is settings, then restart the livestream service so it broadcasts newly selected RSTP stream
//When the dropdown selection is changed set the new value is settings, then restart the livestream service so it broadcasts newly selected RTSP stream
rtsp_stream_select.onchange = function() {
if (this.value !== 'undefined'){
// Get the audio player element