Compare commits
16 Commits
1fe4716bab
...
jetsonOrin
| Author | SHA1 | Date | |
|---|---|---|---|
| a1b6ec54ab | |||
| 123a89eec9 | |||
| e1d129fa07 | |||
| 5f8d1946c0 | |||
| ce5c8d5946 | |||
| 21e8ab1e82 | |||
| ea891d2744 | |||
| f2d560049f | |||
| f515f829cf | |||
| f7e4ee68d6 | |||
| 0942c9936c | |||
| 10fad0e192 | |||
| 19da5914ac | |||
| d2f924f5db | |||
| 068316bb62 | |||
| f7f711d3fe |
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -4,6 +4,7 @@
|
|||||||
<inspection_tool class="ExtractMethodRecommender" enabled="true" level="WARNING" enabled_by_default="true">
|
<inspection_tool class="ExtractMethodRecommender" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
<option name="minLength" value="745" />
|
<option name="minLength" value="745" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GrazieInspection" enabled="false" level="GRAMMAR_ERROR" enabled_by_default="false" />
|
||||||
<inspection_tool class="HttpUrlsUsage" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
<inspection_tool class="HttpUrlsUsage" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
<option name="ignoredUrls">
|
<option name="ignoredUrls">
|
||||||
<list>
|
<list>
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="MethodNameSameAsClassName" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="MethodNameSameAsClassName" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="RedundantCast" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="RedundantCast" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
|
|||||||
6
.idea/jsLibraryMappings.xml
generated
6
.idea/jsLibraryMappings.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptLibraryMappings">
|
|
||||||
<file url="file://$PROJECT_DIR$" libraries="{jquery.dataTables}" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="MavenProjectsManager">
|
<component name="MavenProjectsManager">
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ Camera_port = 80
|
|||||||
Camera_user = root
|
Camera_user = root
|
||||||
Camera_password = password
|
Camera_password = password
|
||||||
Camera_Rtsp_path = /axis-media/media.amp
|
Camera_Rtsp_path = /axis-media/media.amp
|
||||||
|
#Camera_Rtsp_path = /video1
|
||||||
AudioFile01 = elangWav.wav
|
AudioFile01 = elangWav.wav
|
||||||
AudioFile02 = gunshotsWav.wav
|
AudioFile02 = gunshotsWav.wav
|
||||||
AudioFile03 = pinkNoiseWav.wav
|
AudioFile03 = pinkNoiseWav.wav
|
||||||
AudioFile04 = 04.mp3
|
AudioFile04 = 04.mp3
|
||||||
AudioFile05 = 05.mp3
|
AudioFile05 = 05.mp3
|
||||||
AudioVolumeOutput = 100
|
AudioVolumeOutput = 100
|
||||||
SerialPort = /dev/ttyUSB0
|
SerialPort = /dev/ttyTHS1
|
||||||
SerialBaudRate = 9600
|
SerialBaudRate = 9600
|
||||||
PanTiltID = 1
|
PanTiltID = 1
|
||||||
WebUsername = admin
|
WebUsername = admin
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<script src="public/js/jquery-3.7.1.min.js"></script>
|
<script src="public/js/jquery-3.7.1.min.js"></script>
|
||||||
<script src="public/js/jquery.dataTables.min.js"></script>
|
<script src="public/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="public/js/all.min.js"></script>
|
<script src="public/js/all.min.js"></script>
|
||||||
|
<script src="public/js/socket.io.min.js"></script>
|
||||||
<link rel="stylesheet" href="public/style/all.min.css">
|
<link rel="stylesheet" href="public/style/all.min.css">
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -29,50 +30,75 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav ms-auto">
|
<ul class="navbar-nav ms-auto">
|
||||||
<li class="nav-item pad-menu">
|
<li class="nav-item pad-menu">
|
||||||
<a class="nav-link" href="setting.html">Setting</a>
|
<a class="nav-link nav-setting" href="setting.html">Setting</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item pad-menu">
|
<li class="nav-item pad-menu">
|
||||||
<form action="/logout" method="get">
|
<form action="/logout" method="get">
|
||||||
<button class="btn btn-outline-light" type="submit">Logout</button>
|
<button class="btn btn-outline-light nav-logout" type="submit">Logout</button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<!--<div class="container-fluid container4">-->
|
|
||||||
<!-- <div class="row">-->
|
|
||||||
<!-- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8 border-1">-->
|
|
||||||
<!-- <h1 class="hr-lines">Bird Deterrent System</h1>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-4">-->
|
|
||||||
<!-- <div class="container">-->
|
|
||||||
<!-- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 outside-logout">-->
|
|
||||||
<!-- <form action="/logout" method="get">-->
|
|
||||||
<!-- <button class="btn btn-outline-light" type="submit">Logout</button>-->
|
|
||||||
<!-- </form>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!-- SECTION 1-->
|
|
||||||
|
|
||||||
<!-- SECTION 2 -->
|
<!-- SECTION 2 -->
|
||||||
<div class="container-fluid container3">
|
<div class="container-fluid container3 min90">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-8">
|
<div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-8">
|
||||||
<div class="outside">
|
<div class="outside">
|
||||||
<img id="camerastream" src="public/images/not-available.png" class="img-cctv class100" alt="">
|
<img id="camerastream" src="public/images/not-available.png" class="img-cctv class100" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 col-sm-6 col-md-8 col-lg-8 col-xl-8">
|
<div class="col-12 col-sm-4 col-md-4 col-lg-4 col-xl-4">
|
||||||
<p id="streaming_status">No Status</p>
|
<p id="streaming_status">No Status</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4">
|
<div class="col-12 col-sm-4 col-md-5 col-lg-5 col-xl-5">
|
||||||
<div class="form-check form-switch">
|
<div class="row">
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="quality_video" onchange="change_video_quality()">
|
<div class="col">
|
||||||
<label class="form-check-label" for="quality_video">High Quality Video</label>
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fa-solid fa-microchip icon-system"></span>
|
||||||
|
<p id="cpu_usage" class="padleft">0 %</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fa-solid fa-temperature-half icon-system"></span>
|
||||||
|
<p id="cpu_temperature" class="padleft">0 °C</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fa-solid fa-memory icon-system"></span>
|
||||||
|
<p id="ram_usage" class="padleft">0 %</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fa-solid fa-upload icon-system"></span>
|
||||||
|
<p id="ethernet_TX" class="padleft">0 B/s</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="fa-solid fa-download icon-system"></span>
|
||||||
|
<p id="ethernet_RX" class="padleft">0 B/s</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-4 col-md-3 col-lg-3 col-xl-3">
|
||||||
|
<!-- <div class="form-check form-switch">-->
|
||||||
|
<!-- <input class="form-check-input" type="checkbox" role="switch" id="quality_video" onchange="change_video_quality()">-->
|
||||||
|
<!-- <label class="form-check-label" for="quality_video">HQ</label>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div class="container align-right">
|
||||||
|
<label for="quality_video" class="toggle-label">LQ</label>
|
||||||
|
<input type="checkbox" class="toggle-switch" id="quality_video" onchange="change_video_quality()">
|
||||||
|
<label for="quality_video" class="toggle-label">HQ</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,7 +108,7 @@
|
|||||||
<br>
|
<br>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-3 ">
|
<div class="col-3 ">
|
||||||
<p>Pan Speed</p>
|
<p class="text-dash">Pan Speed</p>
|
||||||
<div class="btn-group-vertical">
|
<div class="btn-group-vertical">
|
||||||
<button id="pan1" class="btn btn-outline-dark btn-sm" value="16" onclick="set_pan_speed(16)">1</button>
|
<button id="pan1" class="btn btn-outline-dark btn-sm" value="16" onclick="set_pan_speed(16)">1</button>
|
||||||
<button id="pan2" class="btn btn-outline-dark btn-sm" value="32" onclick="set_pan_speed(32)">2</button>
|
<button id="pan2" class="btn btn-outline-dark btn-sm" value="32" onclick="set_pan_speed(32)">2</button>
|
||||||
@@ -95,7 +121,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a onmousedown="btn_up()" onmouseup="stop_movement()">
|
<a onmousedown="send_tilt_up()" onmouseup="send_stop_movement()">
|
||||||
<i class="btn-nav fa-solid fa-caret-up pad-top" title="Up"></i>
|
<i class="btn-nav fa-solid fa-caret-up pad-top" title="Up"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -103,17 +129,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a onmousedown="btn_left()" onmouseup="stop_movement()">
|
<a onmousedown="send_pan_left()" onmouseup="send_stop_movement()">
|
||||||
<i class="btn-nav fa-solid fa-caret-left pad-left" title="Left"></i>
|
<i class="btn-nav fa-solid fa-caret-left pad-left" title="Left"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a>
|
<a onmousedown="send_stop_movement()">
|
||||||
<i id="btn_center" class="btn-nav-center fa-solid fa-circle"></i>
|
<i id="btn_center" class="btn-nav-center fa-solid fa-circle" title="Stop Movement"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a onmousedown="btn_right()" onmouseup="stop_movement()">
|
<a onmousedown="send_pan_right()" onmouseup="send_stop_movement()">
|
||||||
<i class="btn-nav fa-solid fa-caret-right pad-right" title="Right"></i>
|
<i class="btn-nav fa-solid fa-caret-right pad-right" title="Right"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -121,7 +147,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a onmousedown="btn_down()" onmouseup="stop_movement()">
|
<a onmousedown="send_tilt_down()" onmouseup="send_stop_movement()">
|
||||||
<i class="i btn-nav fa-solid fa-caret-down pad-bottom" title="Down"></i>
|
<i class="i btn-nav fa-solid fa-caret-down pad-bottom" title="Down"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -130,7 +156,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<p>Tilt Speed</p>
|
<p class="text-dash">Tilt Speed</p>
|
||||||
<div class="btn-group-vertical">
|
<div class="btn-group-vertical">
|
||||||
<button id="tilt1" class="btn btn-outline-dark btn-sm" value="16" onclick="set_tilt_speed(16)">1</button>
|
<button id="tilt1" class="btn btn-outline-dark btn-sm" value="16" onclick="set_tilt_speed(16)">1</button>
|
||||||
<button id="tilt2" class="btn btn-outline-dark btn-sm" value="32" onclick="set_tilt_speed(32)">2</button>
|
<button id="tilt2" class="btn btn-outline-dark btn-sm" value="32" onclick="set_tilt_speed(32)">2</button>
|
||||||
@@ -140,14 +166,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-center">Zoom</p>
|
<p class="text-center text-dash">Zoom</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-10">
|
<div class="col-10">
|
||||||
<input id="zoom" type="range" class="form-range" min="1" max="10909" oninput="this.nextElementSibling.value = this.value">
|
<input id="zoom" type="range" class="form-range" min="1" max="10909" oninput="this.nextElementSibling.value = this.value">
|
||||||
<output class="output"></output>
|
<output class="output"></output>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<button class="btn btn-primary" onclick="set_zoom()">SET</button>
|
<button class="btn btn-primary" id="set_zoom" onclick="set_zoom()">SET</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -167,7 +193,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p> Content 1</p>
|
<p id="desc_content1"> Content 1</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -180,7 +206,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p> Content 2</p>
|
<p id="desc_content2"> Content 2</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -193,7 +219,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p> Content 3</p>
|
<p id="desc_content3"> Content 3</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -206,7 +232,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p> Content 4</p>
|
<p id="desc_content4"> Content 4</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -219,12 +245,12 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p>Content 5</p>
|
<p id="desc_content5">Content 5</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div>
|
<div>
|
||||||
<label for="customRange" class="form-label">Volume</label>
|
<label for="customRange" class="form-label text-dash">Volume</label>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-10 pad-bar">
|
<div class="col-10 pad-bar">
|
||||||
@@ -233,10 +259,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<div>
|
<div>
|
||||||
<button id="mute" class="btn-mute show" onclick="mute()" title="mute">
|
<button id="mute" class="btn-mute show" onclick="send_mute()" title="mute">
|
||||||
<i class="fa-solid fa-volume-high"></i>
|
<i class="fa-solid fa-volume-high"></i>
|
||||||
</button>
|
</button>
|
||||||
<button id="unmute" class="btn-mute hide" onclick="unmute()" title="unmute">
|
<button id="unmute" class="btn-mute hide" onclick="send_unmute()" title="unmute">
|
||||||
<i class="fa-solid fa-volume-xmark"></i>
|
<i class="fa-solid fa-volume-xmark"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,7 +276,7 @@
|
|||||||
|
|
||||||
<!-- SECTION 3 -->
|
<!-- SECTION 3 -->
|
||||||
<div class="container-fluid footer1 outside">
|
<div class="container-fluid footer1 outside">
|
||||||
<p>2024 Copyright © Galva Technologies. All rights reserved.</p>
|
<p class="footer">2024 Copyright © Galva Technologies. All rights reserved.</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -12,43 +12,90 @@ let ws;
|
|||||||
|
|
||||||
let camerastream;
|
let camerastream;
|
||||||
|
|
||||||
|
// socketio
|
||||||
|
let socketio;
|
||||||
|
|
||||||
|
let files = [null,null,null,null,null];
|
||||||
|
|
||||||
|
let getbase64handle;
|
||||||
|
let getsysteminfohandle;
|
||||||
|
|
||||||
|
let $zoom;
|
||||||
|
let $mute;
|
||||||
|
let $unmute;
|
||||||
|
|
||||||
|
window.addEventListener("unload",function (){
|
||||||
|
clearInterval(getbase64handle);
|
||||||
|
clearInterval(getsysteminfohandle);
|
||||||
|
send_stop_audio();
|
||||||
|
// wait a while
|
||||||
|
const start = Date.now();
|
||||||
|
while(Date.now()-start<200){}
|
||||||
|
ws.close();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener("load", function (){
|
||||||
|
$zoom = $('#zoom');
|
||||||
|
$mute = $('#mute');
|
||||||
|
$unmute = $('#unmute');
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
|
||||||
camerastream = document.getElementById("camerastream");
|
camerastream = document.getElementById("camerastream");
|
||||||
|
|
||||||
setInterval(function (){
|
// pilihan komunikasi, disable salah satu
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
initialize_socketio();
|
||||||
ws.send(JSON.stringify({
|
//initialize_websocket();
|
||||||
command: "GET BASE64",
|
|
||||||
data: video_quality
|
|
||||||
}));
|
|
||||||
|
|
||||||
} else update_camerastream(null);
|
// Update camera stream every 50ms / 20fps
|
||||||
},10);
|
getbase64handle = setInterval(function (){
|
||||||
|
send_get_base64();
|
||||||
|
},1000/15);
|
||||||
|
|
||||||
|
getsysteminfohandle = setInterval(function (){
|
||||||
|
send_get_system_info();
|
||||||
|
}, 5000);
|
||||||
|
set_pan_speed(32);
|
||||||
|
set_tilt_speed(32);
|
||||||
|
})
|
||||||
|
|
||||||
|
function initialize_socketio(){
|
||||||
|
socketio = io(":3001/socketio");
|
||||||
|
if (socketio){
|
||||||
|
socketio.on("connect",()=>{
|
||||||
|
console.log("Socket.io Connected to the server");
|
||||||
|
send_get_max_zoom();
|
||||||
|
send_get_volume();
|
||||||
|
send_get_zoom();
|
||||||
|
send_get_resolution();
|
||||||
|
send_get_audiofiles();
|
||||||
|
})
|
||||||
|
socketio.on("disconnect",(reason)=>{
|
||||||
|
console.log("Socket.io Disconnected from server because "+reason);
|
||||||
|
})
|
||||||
|
socketio.on("connect_error",(error)=>{
|
||||||
|
console.log("Socket.io Connection error "+error);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
socketio.on("message",(data)=>{
|
||||||
|
let dx = JSON.parse(data);
|
||||||
|
process_command(dx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize_websocket(){
|
||||||
ws = new WebSocket("/ws");
|
ws = new WebSocket("/ws");
|
||||||
|
if (ws){
|
||||||
ws.onopen = function(){
|
ws.onopen = function(){
|
||||||
console.log("Connected to the server");
|
console.log("Connected to the server");
|
||||||
|
|
||||||
// request basic parameters
|
// request basic parameters
|
||||||
ws.send(JSON.stringify({
|
send_get_max_zoom();
|
||||||
command: "GET MAX ZOOM",
|
send_get_volume();
|
||||||
data: 0
|
send_get_zoom();
|
||||||
}));
|
send_get_resolution();
|
||||||
ws.send(JSON.stringify({
|
send_get_audiofiles();
|
||||||
command: "GET VOLUME",
|
|
||||||
data: 0
|
|
||||||
}));
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "GET ZOOM",
|
|
||||||
data: 0
|
|
||||||
}));
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "GET RESOLUTION",
|
|
||||||
data: 0
|
|
||||||
}));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
ws.onmessage = function(event){
|
ws.onmessage = function(event){
|
||||||
@@ -57,71 +104,7 @@ document.addEventListener("DOMContentLoaded", function(){
|
|||||||
* @type {{reply: string, data: string|number, additional: string}} dx
|
* @type {{reply: string, data: string|number, additional: string}} dx
|
||||||
*/
|
*/
|
||||||
let dx = JSON.parse(event.data);
|
let dx = JSON.parse(event.data);
|
||||||
switch (dx.reply){
|
process_command(dx);
|
||||||
case "GET BASE64":
|
|
||||||
if (dx.data.startsWith("data:image/jpeg;base64,")){
|
|
||||||
update_camerastream(dx.data);
|
|
||||||
} else update_camerastream(null);
|
|
||||||
if (dx.additional && dx.additional.length>0){
|
|
||||||
$('#streaming_status').html(dx.additional);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "SET VOLUME":
|
|
||||||
console.log("Set Volume: "+dx.data);
|
|
||||||
break;
|
|
||||||
case "GET VOLUME":
|
|
||||||
console.log("Get Volume: "+dx.data);
|
|
||||||
$('#customRange').val(dx.data);
|
|
||||||
break;
|
|
||||||
case "GET MAX ZOOM":
|
|
||||||
console.log("Get Max Zoom: "+dx.data);
|
|
||||||
$('#zoom')
|
|
||||||
.attr("max", dx.data)
|
|
||||||
.attr("min", 1);
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "GET ZOOM":
|
|
||||||
console.log("Get Zoom: "+dx.data);
|
|
||||||
$('#zoom').val(dx.data);
|
|
||||||
break;
|
|
||||||
case "GET RESOLUTION":
|
|
||||||
console.log("Get Resolution: "+dx.data);
|
|
||||||
break;
|
|
||||||
case "PAN LEFT":
|
|
||||||
console.log("Pan Left");
|
|
||||||
break;
|
|
||||||
case "PAN RIGHT":
|
|
||||||
console.log("Pan Right");
|
|
||||||
break;
|
|
||||||
case "TILT UP":
|
|
||||||
console.log("Tilt Up");
|
|
||||||
break;
|
|
||||||
case "TILT DOWN":
|
|
||||||
console.log("Tilt Down");
|
|
||||||
break;
|
|
||||||
case "STOP MOVEMENT":
|
|
||||||
console.log("Stop Movement");
|
|
||||||
break;
|
|
||||||
case "SET ZOOM":
|
|
||||||
console.log("Set Zoom: "+dx.data);
|
|
||||||
break;
|
|
||||||
case "PLAY AUDIO":
|
|
||||||
console.log("Play Audio: "+dx.data);
|
|
||||||
if (dx.data.startsWith("Failed")){
|
|
||||||
alert(dx.data);
|
|
||||||
} else $('#status_player').html("Playing Audio "+dx.data);
|
|
||||||
break;
|
|
||||||
case "STOP AUDIO":
|
|
||||||
console.log("Stop Audio");
|
|
||||||
$('#status_player').html("Stop Playback");
|
|
||||||
break;
|
|
||||||
case 'SET VIDEO QUALITY':
|
|
||||||
console.log("Set Video Quality: "+dx.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
ws.onclose = function(){
|
ws.onclose = function(){
|
||||||
console.log("Connection closed");
|
console.log("Connection closed");
|
||||||
@@ -129,10 +112,11 @@ document.addEventListener("DOMContentLoaded", function(){
|
|||||||
ws.onerror = function(){
|
ws.onerror = function(){
|
||||||
console.log("Error in connection");
|
console.log("Error in connection");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
set_pan_speed(32);
|
|
||||||
set_tilt_speed(32);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update camera stream
|
* Update camera stream
|
||||||
@@ -150,35 +134,62 @@ function update_camerastream(value){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable play button
|
||||||
|
* @param index 1 - 5
|
||||||
|
*/
|
||||||
function play_off(index){
|
function play_off(index){
|
||||||
$('#div'+index).prop("className", "button-container div-disabled");
|
$('#div'+index).prop("className", "button-container div-disabled");
|
||||||
$('#btn_play'+index).prop("className", "btn-play1 show text-light");
|
$('#btn_play'+index)
|
||||||
|
.prop("className", "btn-play1 show text-light");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable play button
|
||||||
|
* @param index 1 - 5
|
||||||
|
*/
|
||||||
function play_on(index){
|
function play_on(index){
|
||||||
|
let content = $('#desc_content'+index).html();
|
||||||
$('#div'+index).prop("className", "button-container");
|
$('#div'+index).prop("className", "button-container");
|
||||||
$('#btn_play'+index).prop("className", "btn-play1 show");
|
$('#btn_play'+index)
|
||||||
|
.prop("className", "btn-play1 show")
|
||||||
|
.prop("title","Play "+content);
|
||||||
|
$('#btn_stop'+index)
|
||||||
|
.prop("title","Stop "+content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show play button and hide stop button
|
||||||
|
* @param index 1 - 5
|
||||||
|
*/
|
||||||
function show_play_and_hide_stop(index){
|
function show_play_and_hide_stop(index){
|
||||||
$('#btn_play'+index).prop("className", "btn-play1 show");
|
$('#btn_play'+index).prop("className", "btn-play1 show");
|
||||||
$('#btn_stop'+index).prop("className", "btn-play1 hide");
|
$('#btn_stop'+index).prop("className", "btn-play1 hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show stop button and hide play button
|
||||||
|
* @param index 1 - 5
|
||||||
|
*/
|
||||||
function show_stop_and_hide_play(index){
|
function show_stop_and_hide_play(index){
|
||||||
$('#btn_play'+index).prop("className", "btn-play1 hide");
|
$('#btn_play'+index).prop("className", "btn-play1 hide");
|
||||||
$('#btn_stop'+index).prop("className", "btn-play1 show");
|
$('#btn_stop'+index).prop("className", "btn-play1 show");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable all play buttons
|
||||||
|
*/
|
||||||
function allplay(){
|
function allplay(){
|
||||||
for (let i = 0; i < 5; i++) play_on(i+1);
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (files[i]) play_on(i+1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When play button is clicked
|
||||||
|
* @param index 1 - 5
|
||||||
|
*/
|
||||||
function play_button(index){
|
function play_button(index){
|
||||||
show_stop_and_hide_play(index);
|
show_stop_and_hide_play(index);
|
||||||
$('#status_player').html("Play");
|
$('#status_player').html("Play");
|
||||||
@@ -188,26 +199,159 @@ function play_button(index){
|
|||||||
send_play_audio(index);
|
send_play_audio(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When stop button is clicked
|
||||||
|
* @param index 1 - 5
|
||||||
|
*/
|
||||||
function stop_button(index){
|
function stop_button(index){
|
||||||
show_play_and_hide_stop(index);
|
show_play_and_hide_stop(index);
|
||||||
$('#status_player').html("Stop");
|
$('#status_player').html("Stop");
|
||||||
|
|
||||||
allplay();
|
allplay();
|
||||||
send_stop_audio();
|
send_stop_audio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function send_get_audiofiles(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET AUDIOFILES",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState===WebSocket.OPEN){
|
||||||
|
ws.send(cmd)
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_get_resolution(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET RESOLUTION",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_get_zoom(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET ZOOM",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState===WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_get_volume(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET VOLUME",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_get_max_zoom(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET MAX ZOOM",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws && ws.readyState===WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_get_system_info(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET SYSTEM INFO",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send command to stop audio
|
* Send command to stop audio
|
||||||
*/
|
*/
|
||||||
function send_stop_audio(){
|
function send_stop_audio(){
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
let cmd = JSON.stringify({
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "STOP AUDIO",
|
command: "STOP AUDIO",
|
||||||
data: 0
|
data: 0
|
||||||
}));
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
} else console.log("WebSocket is not open");
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_get_base64(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "GET BASE64",
|
||||||
|
data: video_quality
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
return;
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
return;
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
update_camerastream(null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,119 +359,198 @@ function send_stop_audio(){
|
|||||||
* @param {number} index 1 - 5
|
* @param {number} index 1 - 5
|
||||||
*/
|
*/
|
||||||
function send_play_audio(index){
|
function send_play_audio(index){
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
let cmd = JSON.stringify({
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "PLAY AUDIO",
|
command: "PLAY AUDIO",
|
||||||
data: index
|
data: index
|
||||||
}));
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
} else console.log("WebSocket is not open");
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmute(){
|
function send_unmute(){
|
||||||
$('#mute').prop("className", "btn-mute show");
|
let cmd = JSON.stringify({
|
||||||
$('#unmute').prop("className", "btn-mute hide");
|
|
||||||
console.log("unmute")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "UNMUTE",
|
command: "UNMUTE",
|
||||||
data: 0
|
data: 0
|
||||||
}));
|
});
|
||||||
} else console.log("WebSocket is not open");
|
if (ws){
|
||||||
}
|
|
||||||
function mute(){
|
|
||||||
$('#mute').prop("className", "btn-mute hide");
|
|
||||||
$('#unmute').prop("className", "btn-mute show");
|
|
||||||
|
|
||||||
console.log("mute")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
ws.send(JSON.stringify({
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_mute(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
command: "MUTE",
|
command: "MUTE",
|
||||||
data: 0
|
data: 0
|
||||||
}));
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
} else console.log("WebSocket is not open");
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_tilt_up(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "TILT UP",
|
||||||
|
data: tilt_speed
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
btn_center_off()
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
btn_center_off()
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_tilt_down(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "TILT DOWN",
|
||||||
|
data: tilt_speed
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
btn_center_off()
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
btn_center_off()
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_pan_left(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "PAN LEFT",
|
||||||
|
data: pan_speed
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
btn_center_off();
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
btn_center_off();
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_pan_right(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "PAN RIGHT",
|
||||||
|
data: pan_speed
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
btn_center_off()
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
btn_center_off()
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_stop_movement(){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "STOP MOVEMENT",
|
||||||
|
data: 0
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_set_zoom(value){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "SET ZOOM",
|
||||||
|
data: value
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_set_volume(value){
|
||||||
|
let cmd = JSON.stringify({
|
||||||
|
command: "SET VOLUME",
|
||||||
|
data: value
|
||||||
|
});
|
||||||
|
if (ws){
|
||||||
|
if (ws.readyState === WebSocket.OPEN){
|
||||||
|
ws.send(cmd);
|
||||||
|
} else console.log("WebSocket is not open");
|
||||||
|
} else if (socketio){
|
||||||
|
if (socketio.connected){
|
||||||
|
socketio.emit("message",cmd);
|
||||||
|
} else console.log("Socket.io is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function btn_center_off(){
|
function btn_center_off(){
|
||||||
$('#btn_center').prop("className", "btn-center-unactive fa-solid fa-circle");
|
$('#btn_center').prop("className", "btn-center-unactive fa-solid fa-circle");
|
||||||
}
|
}
|
||||||
|
|
||||||
function btn_up(){
|
|
||||||
console.log("btn_up")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "TILT UP",
|
|
||||||
data: tilt_speed
|
|
||||||
}));
|
|
||||||
btn_center_off()
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
|
||||||
function btn_left(){
|
|
||||||
console.log("btn_left")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "PAN LEFT",
|
|
||||||
data: pan_speed
|
|
||||||
}));
|
|
||||||
btn_center_off();
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
|
||||||
function btn_right(){
|
|
||||||
console.log("btn_right")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "PAN RIGHT",
|
|
||||||
data: pan_speed
|
|
||||||
}));
|
|
||||||
btn_center_off()
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
|
||||||
function btn_down(){
|
|
||||||
console.log("btn_down")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "TILT DOWN",
|
|
||||||
data: tilt_speed
|
|
||||||
}));
|
|
||||||
btn_center_off()
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop_movement(){
|
|
||||||
console.log("stop_movement")
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "STOP MOVEMENT",
|
|
||||||
data: 0
|
|
||||||
}));
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_zoom(){
|
function set_zoom(){
|
||||||
let zoom = document.getElementById("zoom");
|
send_set_zoom($('#zoom').val());
|
||||||
console.log("set_zoom "+zoom.value)
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "SET ZOOM",
|
|
||||||
data: zoom.value
|
|
||||||
}));
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_volumeoutput(value){
|
function set_volumeoutput(value){
|
||||||
$('#volumebarvalue').val(value);
|
$('#volumebarvalue').val(value);
|
||||||
|
send_set_volume(value);
|
||||||
console.log("set_volumeoutput "+value)
|
|
||||||
if (ws.readyState === WebSocket.OPEN){
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
command: "SET VOLUME",
|
|
||||||
data: value
|
|
||||||
}));
|
|
||||||
} else console.log("WebSocket is not open");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_pan_speed(value){
|
function set_pan_speed(value){
|
||||||
pan_speed = value;
|
pan_speed = value;
|
||||||
console.log("set_pan_speed "+value);
|
|
||||||
clearpan();
|
clearpan();
|
||||||
let classvalue = "btn btn-dark btn-sm";
|
let classvalue = "btn btn-dark btn-sm";
|
||||||
switch(pan_speed){
|
switch(pan_speed){
|
||||||
@@ -349,7 +572,6 @@ function set_pan_speed(value){
|
|||||||
|
|
||||||
function set_tilt_speed(value){
|
function set_tilt_speed(value){
|
||||||
tilt_speed = value;
|
tilt_speed = value;
|
||||||
console.log("set_tilt_speed "+value);
|
|
||||||
cleartilt();
|
cleartilt();
|
||||||
let classvalue = "btn btn-dark btn-sm";
|
let classvalue = "btn btn-dark btn-sm";
|
||||||
switch (tilt_speed){
|
switch (tilt_speed){
|
||||||
@@ -388,5 +610,149 @@ function change_video_quality(){
|
|||||||
video_quality = btn.checked?"HQ":"LQ";
|
video_quality = btn.checked?"HQ":"LQ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Command
|
||||||
|
* @param {{reply: string, data: string, additional: string}}dx
|
||||||
|
*/
|
||||||
|
function process_command(dx){
|
||||||
|
switch (dx.reply){
|
||||||
|
case "GET BASE64":
|
||||||
|
if (dx.data.startsWith("data:image/jpeg;base64,")){
|
||||||
|
update_camerastream(dx.data);
|
||||||
|
} else update_camerastream(null);
|
||||||
|
if (dx.additional && dx.additional.length>0){
|
||||||
|
let stat = JSON.parse(dx.additional);
|
||||||
|
if (Array.isArray(stat) && stat.length === 3){
|
||||||
|
$('#streaming_status').html("Streaming at "+stat[0]+"x"+stat[1]+" "+stat[2]+"fps");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "SET VOLUME":
|
||||||
|
//console.log("Set Volume: "+dx.data);
|
||||||
|
break;
|
||||||
|
case "GET VOLUME":
|
||||||
|
//console.log("Get Volume: "+dx.data);
|
||||||
|
$('#customRange').val(dx.data);
|
||||||
|
break;
|
||||||
|
case "GET MAX ZOOM":
|
||||||
|
$zoom
|
||||||
|
.prop("min", 1)
|
||||||
|
.prop("max", dx.data);
|
||||||
|
break;
|
||||||
|
case "GET ZOOM":
|
||||||
|
$zoom.val(dx.data);
|
||||||
|
break;
|
||||||
|
case "GET RESOLUTION":
|
||||||
|
//console.log("Get Resolution: "+dx.data);
|
||||||
|
break;
|
||||||
|
case "PAN LEFT":
|
||||||
|
//console.log("Pan Left");
|
||||||
|
break;
|
||||||
|
case "PAN RIGHT":
|
||||||
|
//console.log("Pan Right");
|
||||||
|
break;
|
||||||
|
case "TILT UP":
|
||||||
|
//console.log("Tilt Up");
|
||||||
|
break;
|
||||||
|
case "TILT DOWN":
|
||||||
|
//console.log("Tilt Down");
|
||||||
|
break;
|
||||||
|
case "STOP MOVEMENT":
|
||||||
|
//console.log("Stop Movement");
|
||||||
|
break;
|
||||||
|
case "SET ZOOM":
|
||||||
|
//console.log("Set Zoom: "+dx.data);
|
||||||
|
break;
|
||||||
|
case "PLAY AUDIO":
|
||||||
|
//console.log("Play Audio: "+dx.data);
|
||||||
|
if (dx.data.startsWith("Failed")){
|
||||||
|
alert(dx.data);
|
||||||
|
} else $('#status_player').html("Playing Audio "+dx.data);
|
||||||
|
break;
|
||||||
|
case "STOP AUDIO":
|
||||||
|
//console.log("Stop Audio");
|
||||||
|
document.getElementById("status_player").innerHTML = "Stop Playback";
|
||||||
|
break;
|
||||||
|
case 'SET VIDEO QUALITY':
|
||||||
|
//console.log("Set Video Quality: "+dx.data);
|
||||||
|
break;
|
||||||
|
case "MUTE":
|
||||||
|
//console.log("Mute");
|
||||||
|
$mute.prop("className", "btn-mute hide");
|
||||||
|
$unmute.prop("className", "btn-mute show");
|
||||||
|
break;
|
||||||
|
case "UNMUTE":
|
||||||
|
//console.log("Unmute");
|
||||||
|
$mute.prop("className", "btn-mute show");
|
||||||
|
$unmute.prop("className", "btn-mute hide");
|
||||||
|
break;
|
||||||
|
case "GET SYSTEM INFO":
|
||||||
|
//console.log("Get System Info: "+dx.data);
|
||||||
|
/**
|
||||||
|
* @type {{cpu_temperature: string, ram_usage: string, cpu: string, cpu0: string, cpu1: string, cpu2: string, cpu3: string}} systeminfo
|
||||||
|
*/
|
||||||
|
let systeminfo = JSON.parse(dx.data);
|
||||||
|
//console.log(systeminfo);
|
||||||
|
if (systeminfo.cpu_temperature && systeminfo.cpu_temperature.length>0) $('#cpu_temperature').html(`${systeminfo.cpu_temperature} °C`);
|
||||||
|
if (systeminfo.cpu && systeminfo.cpu.length>0) $('#cpu_usage').html(`${systeminfo.cpu} %`);
|
||||||
|
if (systeminfo.ram_usage && systeminfo.ram_usage.length>0) $('#ram_usage').html(`${systeminfo.ram_usage} %`);
|
||||||
|
if (systeminfo.enP8p1s0_TX && systeminfo.enP8p1s0_TX.length>0) $('#ethernet_TX').html(systeminfo.enP8p1s0_TX);
|
||||||
|
if (systeminfo.enP8p1s0_RX && systeminfo.enP8p1s0_RX.length>0) $('#ethernet_RX').html(systeminfo.enP8p1s0_RX);
|
||||||
|
break;
|
||||||
|
case "GET AUDIOFILES":
|
||||||
|
//console.log("Get Audio Files: "+dx.data);
|
||||||
|
let audiofiles = JSON.parse(dx.data);
|
||||||
|
if (audiofiles.preset1 && audiofiles.preset1.length>0 && audiofiles.preset1!== "null") {
|
||||||
|
files[0] = audiofiles.preset1;
|
||||||
|
$('#desc_content1').html(audiofiles.preset1);
|
||||||
|
play_on(1);
|
||||||
|
} else {
|
||||||
|
files[0] = null;
|
||||||
|
$('#desc_content1').html("");
|
||||||
|
play_off(1);
|
||||||
|
}
|
||||||
|
if (audiofiles.preset2 && audiofiles.preset2.length>0 && audiofiles.preset2!== "null") {
|
||||||
|
files[1] = audiofiles.preset2;
|
||||||
|
$('#desc_content2').html(audiofiles.preset2);
|
||||||
|
play_on(2);
|
||||||
|
} else {
|
||||||
|
files[1] = null;
|
||||||
|
$('#desc_content2').html("");
|
||||||
|
play_off(2);
|
||||||
|
}
|
||||||
|
if (audiofiles.preset3 && audiofiles.preset3.length>0 && audiofiles.preset3!== "null") {
|
||||||
|
files[2] = audiofiles.preset3;
|
||||||
|
$('#desc_content3').html(audiofiles.preset3);
|
||||||
|
play_on(3);
|
||||||
|
} else {
|
||||||
|
files[2] = null;
|
||||||
|
$('#desc_content3').html("");
|
||||||
|
play_off(3);
|
||||||
|
}
|
||||||
|
if (audiofiles.preset4 && audiofiles.preset4.length>0 && audiofiles.preset4!== "null") {
|
||||||
|
files[3] = audiofiles.preset4;
|
||||||
|
$('#desc_content4').html(audiofiles.preset4);
|
||||||
|
play_on(4);
|
||||||
|
} else {
|
||||||
|
files[3] = null;
|
||||||
|
$('#desc_content4').html("");
|
||||||
|
play_off(4);
|
||||||
|
}
|
||||||
|
if (audiofiles.preset5 && audiofiles.preset5.length>0 && audiofiles.preset5!== "null") {
|
||||||
|
files[4] = audiofiles.preset5;
|
||||||
|
$('#desc_content5').html(audiofiles.preset5);
|
||||||
|
play_on(5);
|
||||||
|
} else {
|
||||||
|
files[4] = null;
|
||||||
|
$('#desc_content5').html("");
|
||||||
|
play_off(5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 MiB After Width: | Height: | Size: 1.3 MiB |
7
Html/html/public/js/socket.io.min.js
vendored
Normal file
7
Html/html/public/js/socket.io.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@ html,body{
|
|||||||
body{
|
body{
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
background: rgb(51, 51, 51) !important;
|
||||||
}
|
}
|
||||||
/*HEADER */
|
/*HEADER */
|
||||||
*,
|
*,
|
||||||
@@ -820,3 +821,522 @@ input.checkbox{
|
|||||||
.card-shadow{
|
.card-shadow{
|
||||||
box-shadow: rgba(0, 0, 0, 0.45) 0px 25px 20px -20px;
|
box-shadow: rgba(0, 0, 0, 0.45) 0px 25px 20px -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#streaming_status{
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
/*SWITCH*/
|
||||||
|
/* Style the container to align the labels and switch */
|
||||||
|
.toggle-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
/* Style the labels (Off and On) */
|
||||||
|
|
||||||
|
.toggle-label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* Style the toggle switch (input) */
|
||||||
|
.toggle-switch {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 50px;
|
||||||
|
height: 25px;
|
||||||
|
background-color: #ccc;
|
||||||
|
border-radius: 25px;
|
||||||
|
position: relative;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Circle inside the switch */
|
||||||
|
.toggle-switch::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
/* When checked (toggle to On), change background color and move the circle */
|
||||||
|
.toggle-switch:checked {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
}
|
||||||
|
.toggle-switch:checked::before {
|
||||||
|
transform: translateX(25px);
|
||||||
|
}
|
||||||
|
.align-right{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.pass-wrong{
|
||||||
|
/*border-color: red !important;*/
|
||||||
|
box-shadow: rgba(255, 0, 0, 0.5) 0px 1px 0px, rgba(255, 0, 0, 0.5) 0px 0px 8px;
|
||||||
|
/*box-shadow: rgba(255, 0, 0, 0.5) 0px 2px 4px 0px, rgba(255, 0, 0, 0.5) 0px 2px 16px 0px;*/
|
||||||
|
}
|
||||||
|
.min90{
|
||||||
|
min-height: 80vh;
|
||||||
|
}
|
||||||
|
.container.align-right {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
-webkit-appearance: none; /* Remove default appearance in WebKit browsers */
|
||||||
|
-moz-appearance: none; /* Remove default appearance in Firefox */
|
||||||
|
appearance: none; /* Remove default appearance in other browsers */
|
||||||
|
padding-right: 30px; /* Space for the arrow */
|
||||||
|
border: 1px solid #ccc; /* Border around the select */
|
||||||
|
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zY3JlZW4vZGVmYXVsdCIgY2xhc3M9InN0b2NrdmlldyI+PHBhdGggZD0iTTEuMzgzMiwyLjU5MjUgTDIuMzEzMywxLjYwNjggTDAsMS42MDAyMyBMIDAsMiBMMi4zMzczOCwxLjYwNjggTDYuMzcwMiwzLjM4NDIiIHN0eWxlPSJzdHJva2U6IzAwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuNzgzMTtzdHJva2UtbGluZWNhcDpyb3VuZDsgc3Ryb2tlLW1vcjp1cmwoI3N0b2NrdmlldyIgc3Ryb2tlLXBhZGRpbmc6IDE3cHggIj48L3BhdGg+PC9zdmc+')
|
||||||
|
no-repeat right 10px center; /* Custom arrow icon */
|
||||||
|
background-size: 12px;
|
||||||
|
border-color: black;
|
||||||
|
border-width: 30px;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.icon-system{
|
||||||
|
margin-top: -13px;
|
||||||
|
}
|
||||||
|
.padleft{
|
||||||
|
padding-left: 3px;
|
||||||
|
}
|
||||||
|
.nav-setting{
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
.nav-logout{
|
||||||
|
font-size: 1.2em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------SET RESPONSIVE -----------------*/
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
/*Pan Tilt Speed*/
|
||||||
|
button#tilt1,
|
||||||
|
button#tilt2,
|
||||||
|
button#tilt3,
|
||||||
|
button#tilt4,
|
||||||
|
button#pan1,
|
||||||
|
button#pan2,
|
||||||
|
button#pan3,
|
||||||
|
button#pan4{
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
border-radius: .2rem;
|
||||||
|
}
|
||||||
|
/*End Pan Tilt Speed*/
|
||||||
|
/* ---- NAVIGATION ----- */
|
||||||
|
.btn-nav{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 7em;
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
.btn-nav:hover{
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.btn-nav:active{
|
||||||
|
color: dodgerblue;
|
||||||
|
}
|
||||||
|
.btn-nav-center{
|
||||||
|
font-size: 3em;
|
||||||
|
top: -12px;
|
||||||
|
color: dodgerblue;
|
||||||
|
}
|
||||||
|
.btn-center-unactive{
|
||||||
|
font-size: 2em;
|
||||||
|
color: #434343;
|
||||||
|
}
|
||||||
|
.pad-img{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.img-cctv{
|
||||||
|
box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 1.5em;
|
||||||
|
}
|
||||||
|
.btn-circle{
|
||||||
|
width: 13em;
|
||||||
|
height: 13em;
|
||||||
|
background-color: black;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
margin: 5%;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset;
|
||||||
|
}
|
||||||
|
.pad-top{
|
||||||
|
margin-top: -17px;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
|
.pad-left{
|
||||||
|
margin-top: -40px;
|
||||||
|
margin-right: -20px;
|
||||||
|
}
|
||||||
|
.pad-right{
|
||||||
|
margin-top: -40px;
|
||||||
|
margin-left: -20px;
|
||||||
|
}
|
||||||
|
.pad-bottom{
|
||||||
|
margin-top: -40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- END - NAVIGATION ----- */
|
||||||
|
/* Mute Button */
|
||||||
|
.btn-mute{
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
background-image: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#e7e7e7));
|
||||||
|
background-image: -webkit-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -moz-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -ms-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -o-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
color: black;
|
||||||
|
width: 2.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
padding: 0.2em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 3px 8px #aaa, inset 0px 2px 3px #fff;
|
||||||
|
border: solid 1px transparent;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
/* End Mute Button */
|
||||||
|
|
||||||
|
.toggle-label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* Style the toggle switch (input) */
|
||||||
|
.toggle-switch {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 55px;
|
||||||
|
height: 30px;
|
||||||
|
background-color: #ccc;
|
||||||
|
border-radius: 25px;
|
||||||
|
position: relative;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Circle inside the switch */
|
||||||
|
.toggle-switch::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
/* When checked (toggle to On), change background color and move the circle */
|
||||||
|
.toggle-switch:checked {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
}
|
||||||
|
.toggle-switch:checked::before {
|
||||||
|
transform: translateX(25px);
|
||||||
|
}
|
||||||
|
.align-right{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* End Switch */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 900px) and (max-width: 1050px) {
|
||||||
|
#streaming_status{
|
||||||
|
text-align: left;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
.padleft{
|
||||||
|
padding-left: 3px;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
.icon-system{
|
||||||
|
margin-top: -13px;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
button#tilt1,
|
||||||
|
button#tilt2,
|
||||||
|
button#tilt3,
|
||||||
|
button#tilt4,
|
||||||
|
button#pan1,
|
||||||
|
button#pan2,
|
||||||
|
button#pan3,
|
||||||
|
button#pan4{
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
border-radius: .2rem;
|
||||||
|
}
|
||||||
|
.text-dash{
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
.text-status1{
|
||||||
|
color: black;
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
/* ----- SWITCH ------ */
|
||||||
|
.toggle-label {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* Style the toggle switch (input) */
|
||||||
|
.toggle-switch {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
/*width: 50px;*/
|
||||||
|
/*height: 25px;*/
|
||||||
|
width: 75px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: #ccc;
|
||||||
|
border-radius: 25px;
|
||||||
|
position: relative;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
/* Circle inside the switch */
|
||||||
|
.toggle-switch::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
/* When checked (toggle to On), change background color and move the circle */
|
||||||
|
.toggle-switch:checked {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
}
|
||||||
|
.toggle-switch:checked::before {
|
||||||
|
transform: translateX(25px);
|
||||||
|
}
|
||||||
|
/*----- END SWITCH -----*/
|
||||||
|
|
||||||
|
/* --- Button CONTENT ---- */
|
||||||
|
.btn-play1{
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
background-image: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#e7e7e7));
|
||||||
|
background-image: -webkit-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -moz-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -ms-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -o-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
color: black;
|
||||||
|
/*width: 4.2em;*/
|
||||||
|
/*height: 4.2em;*/
|
||||||
|
width: 7em;
|
||||||
|
height: 7em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 3px 8px #aaa, inset 0px 2px 3px #fff;
|
||||||
|
border: solid 1px transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-play1:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
background: #fff;
|
||||||
|
border-top: 2px solid #ddd;
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: inset 0px 8px 48px #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-play1:active {
|
||||||
|
box-shadow: 0px 3px 8px #aaa inset, 0px 2px 3px #fff;
|
||||||
|
}
|
||||||
|
.btn-play1:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
/*color: #555;*/
|
||||||
|
color: black;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.icon1{
|
||||||
|
margin: 27%;
|
||||||
|
font-size: 4.5em;
|
||||||
|
position: absolute;
|
||||||
|
top: -9px;
|
||||||
|
left: -1px;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.icon2{
|
||||||
|
margin: 27%;
|
||||||
|
font-size: 4.5em;
|
||||||
|
position: absolute;
|
||||||
|
top: -9px;
|
||||||
|
left: 5px;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
/* --- END Button CONTENT ---- */
|
||||||
|
|
||||||
|
.btn-mute{
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
background-image: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#e7e7e7));
|
||||||
|
background-image: -webkit-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -moz-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -ms-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
background-image: -o-linear-gradient(top, #f7f7f7, #e7e7e7);
|
||||||
|
color: black;
|
||||||
|
width: 2.2em;
|
||||||
|
height: 2.2em;
|
||||||
|
padding: 0.1em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 3px 8px #aaa, inset 0px 2px 3px #fff;
|
||||||
|
border: solid 1px transparent;
|
||||||
|
font-size: 2.2em;
|
||||||
|
}
|
||||||
|
/* ---- NAVIGATION ----- */
|
||||||
|
.btn-nav{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 13em;
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
.btn-nav:hover{
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.btn-nav:active{
|
||||||
|
color: dodgerblue;
|
||||||
|
}
|
||||||
|
.btn-nav-center{
|
||||||
|
font-size: 5em;
|
||||||
|
top: -20px;
|
||||||
|
color: dodgerblue;
|
||||||
|
}
|
||||||
|
.btn-center-unactive{
|
||||||
|
font-size: 2em;
|
||||||
|
color: #434343;
|
||||||
|
}
|
||||||
|
.pad-img{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.img-cctv{
|
||||||
|
box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 1.5em;
|
||||||
|
}
|
||||||
|
.btn-circle{
|
||||||
|
width: 20em;
|
||||||
|
height: 20em;
|
||||||
|
background-color: black;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
margin: 5%;
|
||||||
|
border-radius: 70%;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset;
|
||||||
|
}
|
||||||
|
.pad-top{
|
||||||
|
margin-top: -40px;
|
||||||
|
margin-bottom: -45px;
|
||||||
|
}
|
||||||
|
.pad-left{
|
||||||
|
margin-top: -65px;
|
||||||
|
margin-right: -40px;
|
||||||
|
}
|
||||||
|
.pad-right{
|
||||||
|
margin-top: -65px;
|
||||||
|
margin-left: -40px;
|
||||||
|
}
|
||||||
|
.pad-bottom{
|
||||||
|
margin-top: -110px;
|
||||||
|
}
|
||||||
|
#set_zoom{
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
border-radius: .3rem;
|
||||||
|
}
|
||||||
|
.footer{
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
.p-title{
|
||||||
|
font-size: 3.5em !important;
|
||||||
|
}
|
||||||
|
.nav-setting{
|
||||||
|
font-size: 1.8em;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
.nav-logout{
|
||||||
|
font-size: 1.8em !important;
|
||||||
|
}
|
||||||
|
input[type="range"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 20px;
|
||||||
|
background: #ddd;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-runnable-track {
|
||||||
|
height: 20px;
|
||||||
|
background: #dddddd;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: #0d6efd;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.output{
|
||||||
|
padding-left: 20%;
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
.text-setting{
|
||||||
|
font-size: 1.7em;
|
||||||
|
}
|
||||||
|
.text-input{
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
}
|
||||||
|
#icon_confirm,
|
||||||
|
#icon_password,
|
||||||
|
#icon_camera{
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
.btn-setting{
|
||||||
|
padding: .5rem 1rem !important;
|
||||||
|
font-size: 1.1rem !important;
|
||||||
|
border-radius: .3rem !important;
|
||||||
|
}
|
||||||
|
.setting-title{
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
span.navbar-toggler-icon {
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,11 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav ms-auto">
|
<ul class="navbar-nav ms-auto">
|
||||||
<li class="nav-item pad-menu">
|
<li class="nav-item pad-menu">
|
||||||
<a class="nav-link" href="setting.html">Setting</a>
|
<a class="nav-link nav-setting" href="setting.html">Setting</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item pad-menu">
|
<li class="nav-item pad-menu">
|
||||||
<form action="/logout" method="get">
|
<form action="/logout" method="get">
|
||||||
<button class="btn btn-outline-light" type="submit">Logout</button>
|
<button class="btn btn-outline-light nav-logout" type="submit">Logout</button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -41,21 +41,21 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- SECTION 2 -->
|
<!-- SECTION 2 -->
|
||||||
<div class="container-fluid container-setting">
|
<div class="container-fluid container-setting min90">
|
||||||
|
<br>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="card mt-5 card-shadow">
|
<div class="card card-shadow">
|
||||||
<div class="card-header bg-secondary text-light">
|
<div class="card-header bg-secondary text-light">
|
||||||
<h5 class="text-md-center">Audio Files</h5>
|
<h5 class="text-md-center setting-title">Audio Files</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body bg-gray">
|
<div class="card-body bg-gray">
|
||||||
<form action="/setting/audiofile" method="post">
|
|
||||||
<!-- PRESET 1-->
|
<!-- PRESET 1-->
|
||||||
<div class="row mt--2">
|
<div class="row mt--2">
|
||||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||||
<p>Preset 1</p>
|
<p>Preset 1</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||||
<select id="preset1" class="form-control class100">
|
<select id="preset1" class="form-control text-input class100">
|
||||||
<option>Option 1</option>
|
<option>Option 1</option>
|
||||||
<option>Option 2</option>
|
<option>Option 2</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
<p>Preset 2</p>
|
<p>Preset 2</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||||
<select id="preset2" class="form-control class100">
|
<select id="preset2" class="form-control text-input class100">
|
||||||
<option>Option 1</option>
|
<option>Option 1</option>
|
||||||
<option>Option 2</option>
|
<option>Option 2</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
<p>Preset 3</p>
|
<p>Preset 3</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||||
<select id="preset3" class="form-control class100">
|
<select id="preset3" class="form-control text-input class100">
|
||||||
<option>Option 1</option>
|
<option>Option 1</option>
|
||||||
<option>Option 2</option>
|
<option>Option 2</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
<p>Preset 4</p>
|
<p>Preset 4</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||||
<select id="preset4" class="form-control class100">
|
<select id="preset4" class="form-control text-input class100">
|
||||||
<option>Option 1</option>
|
<option>Option 1</option>
|
||||||
<option>Option 2</option>
|
<option>Option 2</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
<p>Preset 5</p>
|
<p>Preset 5</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||||
<select id="preset5" class="form-control class100">
|
<select id="preset5" class="form-control text-input class100">
|
||||||
<option>Option 1</option>
|
<option>Option 1</option>
|
||||||
<option>Option 2</option>
|
<option>Option 2</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -112,16 +112,15 @@
|
|||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-6"></div>
|
<div class="col-6"></div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<button id="save_audio" type="submit" class="btn btn-primary class100" onclick="save_audio()">SAVE</button>
|
<button id="save_audio" class="btn btn-primary btn-setting class100" onclick="save_audio()">SAVE</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card mt-5 card-shadow">
|
<div class="card mt-5 card-shadow">
|
||||||
<div class="card-header bg-secondary text-light">
|
<div class="card-header bg-secondary text-light">
|
||||||
<h5 class="text-center"> Upload Audio</h5>
|
<h5 class="text-center setting-title"> Upload Audio</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body bg-gray">
|
<div class="card-body bg-gray">
|
||||||
<form action="/setting/uploadaudiofile" method="post" enctype="multipart/form-data">
|
<form action="/setting/uploadaudiofile" method="post" enctype="multipart/form-data">
|
||||||
@@ -130,10 +129,10 @@
|
|||||||
<p> Upload audio files</p>
|
<p> Upload audio files</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4">
|
<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4">
|
||||||
<input class="form-control" type="file" name="file" title="Select Audio File">
|
<input class="form-control text-input" type="file" name="file" required title="Select Audio File">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-sm-6 col-md-2 col-lg-2 col-xl-2">
|
<div class="col-6 col-sm-6 col-md-2 col-lg-2 col-xl-2">
|
||||||
<button id="uploadd_file" type="submit" class="btn btn-dark class100">Upload</button>
|
<button id="uploadd_file" type="submit" class="btn btn-setting btn-dark class100">Upload</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -143,16 +142,15 @@
|
|||||||
|
|
||||||
<div class="card mt-5 card-shadow">
|
<div class="card mt-5 card-shadow">
|
||||||
<div class="card-header bg-secondary text-light ">
|
<div class="card-header bg-secondary text-light ">
|
||||||
<h5 class="text-center">Camera</h5>
|
<h5 class="text-center setting-title">Camera</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body bg-gray">
|
<div class="card-body bg-gray">
|
||||||
<form action="/setting/camera" method="post">
|
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<p>IP Address</p>
|
<p>IP Address</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<input id="setting_ip" class="form-control" title="IP Address">
|
<input id="setting_ip" name="ip" class="form-control text-input" title="IP Address">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
@@ -160,7 +158,7 @@
|
|||||||
<p>Port</p>
|
<p>Port</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<input id="setting_port" class="form-control" title="Port">
|
<input id="setting_port" name="port" class="form-control text-input" title="Port">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -169,7 +167,7 @@
|
|||||||
<p>Username</p>
|
<p>Username</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<input id="setting_username" class="form-control" title="Username">
|
<input id="setting_username" name="username" class="form-control text-input" title="Username">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -179,7 +177,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" id="setting_password" class="form-control" title="Password">
|
<input type="password" id="setting_password" name="password" class="form-control text-input" title="Password">
|
||||||
<span class="input-group-text" onclick="cameraPassword()">
|
<span class="input-group-text" onclick="cameraPassword()">
|
||||||
<i class="fa-solid fa-eye" id="icon_camera"></i>
|
<i class="fa-solid fa-eye" id="icon_camera"></i>
|
||||||
</span>
|
</span>
|
||||||
@@ -189,25 +187,23 @@
|
|||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-6"></div>
|
<div class="col-6"></div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<button id="save_camera" type="submit" class="btn btn-primary class100" onclick="save_camera()">SAVE</button>
|
<button id="save_camera" class="btn btn-primary btn-setting class100" onclick="save_camera()">SAVE</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card mt-5 card-shadow">
|
<div class="card mt-5 card-shadow">
|
||||||
<div class="card-header bg-secondary text-light">
|
<div class="card-header bg-secondary text-light">
|
||||||
<h5 class="text-center">Login</h5>
|
<h5 class="text-center setting-title">Login</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body bg-gray">
|
<div class="card-body bg-gray">
|
||||||
<form action="/setting/weblogin" method="post">
|
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<p>Username</p>
|
<p>Username</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<input id="login_username" class="form-control" title="Username">
|
<input id="login_username" class="form-control text-input" title="Username">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
@@ -216,7 +212,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" id="edit_password" class="form-control" title="Password">
|
<input type="password" id="edit_password" class="form-control text-input" title="Password">
|
||||||
<span class="input-group-text" onclick="showPassword()">
|
<span class="input-group-text" onclick="showPassword()">
|
||||||
<i class="fa-solid fa-eye" id="icon_password"></i>
|
<i class="fa-solid fa-eye" id="icon_password"></i>
|
||||||
</span>
|
</span>
|
||||||
@@ -229,7 +225,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" id="confirm_password" class="form-control" title="Confirm Password">
|
<input type="password" id="confirm_password" class="form-control text-input" title="Confirm Password">
|
||||||
<span class="input-group-text" onclick="showConfirm()">
|
<span class="input-group-text" onclick="showConfirm()">
|
||||||
<i class="fa-solid fa-eye" id="icon_confirm"></i>
|
<i class="fa-solid fa-eye" id="icon_confirm"></i>
|
||||||
</span>
|
</span>
|
||||||
@@ -239,10 +235,9 @@
|
|||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-6"></div>
|
<div class="col-6"></div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<button id="save_login" type="submit" class="btn btn-primary class100" onclick="save_login()">SAVE</button>
|
<button id="save_login" class="btn btn-primary btn-setting class100" onclick="save_login()">SAVE</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,7 +245,7 @@
|
|||||||
|
|
||||||
<!-- SECTION 3 -->
|
<!-- SECTION 3 -->
|
||||||
<div class="container-fluid footer1 outside">
|
<div class="container-fluid footer1 outside">
|
||||||
<p>2024 Copyright © Galva Technologies. All rights reserved.</p>
|
<p class="footer">2024 Copyright © Galva Technologies. All rights reserved.</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -54,7 +54,14 @@ function fill_select(index, values){
|
|||||||
*/
|
*/
|
||||||
let preset = document.getElementById("preset"+index);
|
let preset = document.getElementById("preset"+index);
|
||||||
preset.innerHTML = "";
|
preset.innerHTML = "";
|
||||||
|
|
||||||
if (values!=null && values.length>0){
|
if (values!=null && values.length>0){
|
||||||
|
// add empty option
|
||||||
|
let option = document.createElement("option");
|
||||||
|
option.value = "";
|
||||||
|
option.innerText = "";
|
||||||
|
preset.appendChild(option);
|
||||||
|
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
const element = values[i];
|
const element = values[i];
|
||||||
let option = document.createElement("option");
|
let option = document.createElement("option");
|
||||||
@@ -109,3 +116,90 @@ function showConfirm() {
|
|||||||
icon.classList.add('fa-eye');
|
icon.classList.add('fa-eye');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function save_audio(){
|
||||||
|
let preset1 = $('#preset1').val();
|
||||||
|
let preset2 = $('#preset2').val();
|
||||||
|
let preset3 = $('#preset3').val();
|
||||||
|
let preset4 = $('#preset4').val();
|
||||||
|
let preset5 = $('#preset5').val();
|
||||||
|
|
||||||
|
if (confirm("Are you sure want to change Audio Preset ?")){
|
||||||
|
fetch("/setting/audiofile", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({preset1: preset1, preset2: preset2, preset3: preset3, preset4: preset4, preset5: preset5})
|
||||||
|
}).then(resp => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
alert("Success");
|
||||||
|
} else {
|
||||||
|
resp.text().then(text=>alert("Failed to change Audio Preset : "+text));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_camera(){
|
||||||
|
let ip = $('#setting_ip').val();
|
||||||
|
let port = $('#setting_port').val();
|
||||||
|
let username = $('#setting_username').val();
|
||||||
|
let password = $('#setting_password').val();
|
||||||
|
|
||||||
|
if (confirm("Are you sure want to change Camera Information ?")){
|
||||||
|
fetch("/setting/camera", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({ip: ip, port: port, username: username, password: password})
|
||||||
|
}).then(resp => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
alert("Success");
|
||||||
|
} else {
|
||||||
|
resp.text().then(text => {
|
||||||
|
alert("Failed to change Camera Information : "+text);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_login(){
|
||||||
|
let username = $('#login_username').val();
|
||||||
|
let password = $('#edit_password').val();
|
||||||
|
let confirmpassword = $('#confirm_password').val();
|
||||||
|
if (username.length === 0){
|
||||||
|
alert("Username cannot be empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (password.length === 0){
|
||||||
|
alert("Password cannot be empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (password !== confirmpassword){
|
||||||
|
alert("Password not match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (confirm("Are you sure want to change Web Login Information ?")){
|
||||||
|
fetch("/setting/weblogin", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({username: username, password: password})
|
||||||
|
}).then(resp => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
alert("Success");
|
||||||
|
} else {
|
||||||
|
resp.text().then(text => {
|
||||||
|
alert("Failed to change Web Login Information : "+text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,20 @@
|
|||||||
#Fri Nov 08 16:52:01 WIB 2024
|
#Mon Nov 11 16:04:42 WIB 2024
|
||||||
AudioFile01=elangWav.wav
|
AudioFile01=elangWav.wav
|
||||||
AudioFile02=gunshotsWav.wav
|
AudioFile02=gunshotsWav.wav
|
||||||
AudioFile03=pinkNoiseWav.wav
|
AudioFile03=pinkNoiseWav.wav
|
||||||
AudioFile04=04.mp3
|
AudioFile04=null
|
||||||
AudioFile05=05.mp3
|
AudioFile05=null
|
||||||
AudioVolumeOutput=100
|
AudioVolumeOutput=100
|
||||||
Camera_Rtsp_path=/axis-media/media.amp
|
Camera_Rtsp_path=/axis-media/media.amp
|
||||||
Camera_ip=192.168.10.17
|
#Camera_Rtsp_path=/video1
|
||||||
|
Camera_ip=172.17.195.51
|
||||||
Camera_password=password
|
Camera_password=password
|
||||||
Camera_port=80
|
Camera_port=80
|
||||||
Camera_user=root
|
Camera_user=root
|
||||||
PanTiltID=1
|
PanTiltID=1
|
||||||
SerialBaudRate=9600
|
SerialBaudRate=9600
|
||||||
SerialPort=/dev/ttyUSB0
|
SerialPort=/dev/ttyTHS1
|
||||||
WebHost=0.0.0.0
|
WebHost=0.0.0.0
|
||||||
WebPassword=bandara
|
WebPassword=bandara
|
||||||
WebPort=8080
|
WebPort=8080
|
||||||
WebUsername=admin
|
WebUsername=admin
|
||||||
audiofile1=
|
|
||||||
audiofile2=
|
|
||||||
audiofile3=
|
|
||||||
audiofile4=
|
|
||||||
audiofile5=
|
|
||||||
|
|||||||
80
onnx/coco.names
Normal file
80
onnx/coco.names
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
person
|
||||||
|
bicycle
|
||||||
|
car
|
||||||
|
motorbike
|
||||||
|
aeroplane
|
||||||
|
bus
|
||||||
|
train
|
||||||
|
truck
|
||||||
|
boat
|
||||||
|
traffic light
|
||||||
|
fire hydrant
|
||||||
|
stop sign
|
||||||
|
parking meter
|
||||||
|
bench
|
||||||
|
bird
|
||||||
|
cat
|
||||||
|
dog
|
||||||
|
horse
|
||||||
|
sheep
|
||||||
|
cow
|
||||||
|
elephant
|
||||||
|
bear
|
||||||
|
zebra
|
||||||
|
giraffe
|
||||||
|
backpack
|
||||||
|
umbrella
|
||||||
|
handbag
|
||||||
|
tie
|
||||||
|
suitcase
|
||||||
|
frisbee
|
||||||
|
skis
|
||||||
|
snowboard
|
||||||
|
sports ball
|
||||||
|
kite
|
||||||
|
baseball bat
|
||||||
|
baseball glove
|
||||||
|
skateboard
|
||||||
|
surfboard
|
||||||
|
tennis racket
|
||||||
|
bottle
|
||||||
|
wine glass
|
||||||
|
cup
|
||||||
|
fork
|
||||||
|
knife
|
||||||
|
spoon
|
||||||
|
bowl
|
||||||
|
banana
|
||||||
|
apple
|
||||||
|
sandwich
|
||||||
|
orange
|
||||||
|
broccoli
|
||||||
|
carrot
|
||||||
|
hot dog
|
||||||
|
pizza
|
||||||
|
donut
|
||||||
|
cake
|
||||||
|
chair
|
||||||
|
sofa
|
||||||
|
pottedplant
|
||||||
|
bed
|
||||||
|
diningtable
|
||||||
|
toilet
|
||||||
|
tvmonitor
|
||||||
|
laptop
|
||||||
|
mouse
|
||||||
|
remote
|
||||||
|
keyboard
|
||||||
|
cell phone
|
||||||
|
microwave
|
||||||
|
oven
|
||||||
|
toaster
|
||||||
|
sink
|
||||||
|
refrigerator
|
||||||
|
book
|
||||||
|
clock
|
||||||
|
vase
|
||||||
|
scissors
|
||||||
|
teddy bear
|
||||||
|
hair drier
|
||||||
|
toothbrush
|
||||||
BIN
onnx/yolov8n.onnx
Normal file
BIN
onnx/yolov8n.onnx
Normal file
Binary file not shown.
101
pom.xml
101
pom.xml
@@ -7,16 +7,95 @@
|
|||||||
<groupId>id.co.gtc</groupId>
|
<groupId>id.co.gtc</groupId>
|
||||||
<artifactId>BirdStrikeSoetta</artifactId>
|
<artifactId>BirdStrikeSoetta</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<name>Maven Repository</name>
|
||||||
|
<id>mvnrepository</id>
|
||||||
|
<url>https://mvnrepository.com/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bytedeco</groupId>
|
<groupId>org.bytedeco</groupId>
|
||||||
<artifactId>javacv-platform</artifactId>
|
<artifactId>javacv</artifactId>
|
||||||
<version>1.5.10</version>
|
<version>1.5.11</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<version>4.10.0-1.5.11</version>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<version>4.10.0-1.5.11</version>
|
||||||
|
<classifier>linux-arm64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<version>7.1-1.5.11</version>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<version>7.1-1.5.11</version>
|
||||||
|
<classifier>linux-arm64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>openblas</artifactId>
|
||||||
|
<version>0.3.28-1.5.11</version>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>openblas</artifactId>
|
||||||
|
<version>0.3.28-1.5.11</version>
|
||||||
|
<classifier>linux-arm64</classifier>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>tensorrt</artifactId>
|
||||||
|
<version>8.6-1.5.10</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>cuda</artifactId>
|
||||||
|
<version>12.6-9.5-1.5.11</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>javacpp</artifactId>
|
||||||
|
<version>1.5.11</version>
|
||||||
|
<classifier>windows-x86_64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>javacpp</artifactId>
|
||||||
|
<version>1.5.11</version>
|
||||||
|
<classifier>linux-arm64</classifier>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.corundumstudio.socketio</groupId>
|
||||||
|
<artifactId>netty-socketio</artifactId>
|
||||||
|
<version>2.0.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.javalin</groupId>
|
<groupId>io.javalin</groupId>
|
||||||
<artifactId>javalin</artifactId>
|
<artifactId>javalin</artifactId>
|
||||||
<version> 6.3.0</version>
|
<version> 6.4.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.java.dev.jna</groupId>
|
<groupId>net.java.dev.jna</groupId>
|
||||||
@@ -31,7 +110,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.34</version>
|
<version>1.18.36</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -52,6 +131,11 @@
|
|||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>2.17.2</version>
|
<version>2.17.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.11.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -60,4 +144,13 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<extensions>
|
||||||
|
<extension>
|
||||||
|
<groupId>kr.motd.maven</groupId>
|
||||||
|
<artifactId>os-maven-plugin</artifactId>
|
||||||
|
<version>1.7.0</version>
|
||||||
|
</extension>
|
||||||
|
</extensions>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,14 +1,33 @@
|
|||||||
package Audio;
|
package Audio;
|
||||||
|
|
||||||
|
|
||||||
public class AudioFileProperties {
|
import com.sun.jna.Pointer;
|
||||||
public final int handle;
|
import com.sun.jna.Structure;
|
||||||
public final String filename;
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AudioFileProperties extends Structure {
|
||||||
|
public int handle;
|
||||||
|
public String filename;
|
||||||
public long Length;
|
public long Length;
|
||||||
public double duration;
|
public double duration;
|
||||||
public AudioFileProperties(int handle, String filename){
|
|
||||||
|
public AudioFileProperties(Pointer p){
|
||||||
|
super(p);
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AudioFileProperties(int handle, String filename, long length, double duration){
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
|
this.Length = length;
|
||||||
|
this.duration = duration;
|
||||||
|
write();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("handle", "filename", "Length", "duration");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package Audio;
|
package Audio;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
|
||||||
public class AudioPlayer {
|
public class AudioPlayer {
|
||||||
Bass bass;
|
private final Bass bass;
|
||||||
int deviceid = -1;
|
private int deviceid = -1;
|
||||||
boolean inited = false;
|
@Getter private boolean inited = false;
|
||||||
|
|
||||||
int playbackhandle = 0;
|
int playbackhandle = 0;
|
||||||
float playbackvolume = 1.0f;
|
float playbackvolume = 1.0f;
|
||||||
@@ -48,13 +49,49 @@ public class AudioPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get BASS_DEVICEINFO for a device
|
||||||
|
* @param device device id
|
||||||
|
* @return BASS_DEVICEINFO object or null if failed
|
||||||
|
*/
|
||||||
|
public Bass.BASS_DEVICEINFO GetDeviceInfo(int device){
|
||||||
|
Bass.BASS_DEVICEINFO info = new Bass.BASS_DEVICEINFO();
|
||||||
|
if (bass.BASS_GetDeviceInfo(device, info)){
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Device ID with Name
|
||||||
|
* @param name device name
|
||||||
|
* @return device id, or -1 if not found
|
||||||
|
*/
|
||||||
|
public int FindDeviceIDWithName(String name){
|
||||||
|
int result = -1;
|
||||||
|
int ii = 1;
|
||||||
|
while(true){
|
||||||
|
Bass.BASS_DEVICEINFO info = new Bass.BASS_DEVICEINFO();
|
||||||
|
if (bass.BASS_GetDeviceInfo(ii, info)){
|
||||||
|
if (info.name.contains(name)){
|
||||||
|
result = ii;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ii++;
|
||||||
|
} else {
|
||||||
|
// gak ada lagi
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open Output Device
|
* Open Output Device
|
||||||
* @param device device id, starts from 1
|
* @param device device id, starts from 1
|
||||||
* @param freq output frequency
|
* @param freq output frequency
|
||||||
* @return true if success
|
* @return true if success
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedReturnValue")
|
|
||||||
public boolean OpenDevice(int device, int freq){
|
public boolean OpenDevice(int device, int freq){
|
||||||
int flag = Bass.BASS_DEVICE_REINIT | Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_MONO | Bass.BASS_DEVICE_FREQ;
|
int flag = Bass.BASS_DEVICE_REINIT | Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_MONO | Bass.BASS_DEVICE_FREQ;
|
||||||
boolean success = bass.BASS_Init(device, freq, flag);
|
boolean success = bass.BASS_Init(device, freq, flag);
|
||||||
@@ -69,7 +106,8 @@ public class AudioPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Master Volume
|
* Set Master Output Volume
|
||||||
|
* Master Output Volume related to the system volume (Alsamixer on Linux, Volume Mixer on Windows)
|
||||||
* @param value volume value, 0-100
|
* @param value volume value, 0-100
|
||||||
*/
|
*/
|
||||||
public void setMasterVolume(int value){
|
public void setMasterVolume(int value){
|
||||||
@@ -84,7 +122,8 @@ public class AudioPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Master Volume
|
* Get Master Output Volume
|
||||||
|
* Master Output Volume related to the system volume (Alsamixer on Linux, Volume Mixer on Windows)
|
||||||
* @return 0 - 100, or -1 if failed
|
* @return 0 - 100, or -1 if failed
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@@ -99,6 +138,11 @@ public class AudioPlayer {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Playback Volume
|
||||||
|
* is the volume of the currently playing audio file
|
||||||
|
* @return 0 - 100
|
||||||
|
*/
|
||||||
public int getPlaybackvolume(){
|
public int getPlaybackvolume(){
|
||||||
if (playbackvolume<0)
|
if (playbackvolume<0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -108,6 +152,11 @@ public class AudioPlayer {
|
|||||||
return (int)(playbackvolume*100);
|
return (int)(playbackvolume*100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Playback Volume
|
||||||
|
* is the volume of the currently playing audio file
|
||||||
|
* @param value 0 - 100
|
||||||
|
*/
|
||||||
public void setPlaybackvolume(int value){
|
public void setPlaybackvolume(int value){
|
||||||
if (value<0) value = 0;
|
if (value<0) value = 0;
|
||||||
if (value>100) value = 100;
|
if (value>100) value = 100;
|
||||||
@@ -119,11 +168,17 @@ public class AudioPlayer {
|
|||||||
|
|
||||||
private float lastplaybackvolume = 1.0f;
|
private float lastplaybackvolume = 1.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Playback Volume to 0
|
||||||
|
*/
|
||||||
public void Mute(){
|
public void Mute(){
|
||||||
lastplaybackvolume = playbackvolume;
|
lastplaybackvolume = playbackvolume;
|
||||||
setPlaybackvolume(0);
|
setPlaybackvolume(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Playback Volume to last volume before Mute
|
||||||
|
*/
|
||||||
public void Unmute(){
|
public void Unmute(){
|
||||||
setPlaybackvolume((int)lastplaybackvolume*100);
|
setPlaybackvolume((int)lastplaybackvolume*100);
|
||||||
}
|
}
|
||||||
@@ -138,9 +193,9 @@ public class AudioPlayer {
|
|||||||
int handle = bass.BASS_StreamCreateFile(false, ff.getAbsolutePath(), 0, 0,0);
|
int handle = bass.BASS_StreamCreateFile(false, ff.getAbsolutePath(), 0, 0,0);
|
||||||
if (handle!=0){
|
if (handle!=0){
|
||||||
Logger.info("Audio file {} opened successfully", ff.getName());
|
Logger.info("Audio file {} opened successfully", ff.getName());
|
||||||
AudioFileProperties prop = new AudioFileProperties(handle, ff.getName());
|
long Length = bass.BASS_ChannelGetLength(handle, Bass.BASS_POS_BYTE);
|
||||||
prop.Length = bass.BASS_ChannelGetLength(handle, Bass.BASS_POS_BYTE);
|
double duration = bass.BASS_ChannelBytes2Seconds(handle, Length);
|
||||||
prop.duration = bass.BASS_ChannelBytes2Seconds(handle, prop.Length);
|
AudioFileProperties prop = new AudioFileProperties(handle, ff.getName(), Length, duration);
|
||||||
return prop;
|
return prop;
|
||||||
} else Logger.error("Failed to open audio file {}, Error Code {}", ff.getAbsolutePath(), bass.BASS_ErrorGetCode());
|
} else Logger.error("Failed to open audio file {}, Error Code {}", ff.getAbsolutePath(), bass.BASS_ErrorGetCode());
|
||||||
} else Logger.info("AudioPlayer not initialized");
|
} else Logger.info("AudioPlayer not initialized");
|
||||||
@@ -162,26 +217,63 @@ public class AudioPlayer {
|
|||||||
} else Logger.info("Audio file {} closed successfully", prop.filename);
|
} else Logger.info("Audio file {} closed successfully", prop.filename);
|
||||||
} else Logger.info("AudioPlayer not initialized");
|
} else Logger.info("AudioPlayer not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlaybackEvent playbackEvent = null;
|
||||||
|
|
||||||
|
Bass.SYNCPROC endproc = (handle, channel, data, user)->{
|
||||||
|
if (user!=null){
|
||||||
|
AudioFileProperties ap = new AudioFileProperties(user);
|
||||||
|
if (playbackEvent!=null){
|
||||||
|
playbackEvent.onPlaybackFinished(ap);
|
||||||
|
} else Logger.warn("endproc playbackEvent is null");
|
||||||
|
} else Logger.warn("endproc user is null");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Bass.SYNCPROC freeproc = (handle, channel, data, user)->{
|
||||||
|
if (user!=null){
|
||||||
|
AudioFileProperties ap = new AudioFileProperties(user);
|
||||||
|
if (playbackEvent!=null){
|
||||||
|
playbackEvent.onPlaybackFinished(ap);
|
||||||
|
} else Logger.warn("freeproc playbackEvent is null");
|
||||||
|
} else Logger.warn("freeproc user is null");
|
||||||
|
};
|
||||||
|
|
||||||
|
Bass.SYNCPROC failproc = (handle, channel, data, user)->{
|
||||||
|
if (user!=null){
|
||||||
|
AudioFileProperties ap = new AudioFileProperties(user);
|
||||||
|
if (playbackEvent!=null){
|
||||||
|
playbackEvent.onPlaybackFailure(ap, "Device Failure");
|
||||||
|
} else Logger.warn("failproc playbackEvent is null");
|
||||||
|
} else Logger.warn("failproc user is null");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play Audio File
|
||||||
|
* @param prop AudioFileProperties object to play
|
||||||
|
* @param looping set true to loop the audio file
|
||||||
|
* @param event PlaybackEvent object to handle playback event
|
||||||
|
*/
|
||||||
public void PlayAudioFile(AudioFileProperties prop, boolean looping, PlaybackEvent event){
|
public void PlayAudioFile(AudioFileProperties prop, boolean looping, PlaybackEvent event){
|
||||||
|
this.playbackEvent = null;
|
||||||
if (inited){
|
if (inited){
|
||||||
if (prop!=null){
|
if (prop!=null){
|
||||||
if (bass.BASS_ChannelStart(prop.handle)){
|
if (bass.BASS_ChannelStart(prop.handle)){
|
||||||
|
this.playbackEvent = event;
|
||||||
playbackhandle = prop.handle;
|
playbackhandle = prop.handle;
|
||||||
|
// SyncProcValue spv = new SyncProcValue(prop);
|
||||||
|
// spv.write();
|
||||||
bass.BASS_ChannelSetAttribute(prop.handle, Bass.BASS_ATTRIB_VOL, playbackvolume);
|
bass.BASS_ChannelSetAttribute(prop.handle, Bass.BASS_ATTRIB_VOL, playbackvolume);
|
||||||
if (looping) bass.BASS_ChannelFlags(prop.handle, Bass.BASS_SAMPLE_LOOP, Bass.BASS_SAMPLE_LOOP);
|
if (looping) bass.BASS_ChannelFlags(prop.handle, Bass.BASS_SAMPLE_LOOP, Bass.BASS_SAMPLE_LOOP);
|
||||||
if (event!=null) event.onPlaybackStart(prop);
|
if (event!=null) event.onPlaybackStart(prop);
|
||||||
int devfailsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_DEV_FAIL,0, (handle, channel, data, user)->{
|
int devfailsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_DEV_FAIL,0, failproc, prop.getPointer());
|
||||||
if (event!=null) event.onPlaybackFailure(prop, "Device Failure");
|
|
||||||
}, null);
|
|
||||||
if (devfailsync==0) Logger.error("Failed to set Device Failure Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
if (devfailsync==0) Logger.error("Failed to set Device Failure Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
||||||
int endsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_END, 0, (handle, channel, data, user)->{
|
int endsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_END , 0, endproc, prop.getPointer());
|
||||||
if (looping) {
|
|
||||||
if (event!=null) event.onPlaybackLooped(prop);
|
|
||||||
} else if (event!=null) event.onPlaybackFinished(prop);
|
|
||||||
}, null);
|
|
||||||
if (endsync==0) Logger.error("Failed to set End Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
if (endsync==0) Logger.error("Failed to set End Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
||||||
|
int freesync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_FREE , 0, freeproc, prop.getPointer());
|
||||||
|
if (freesync==0) Logger.error("Failed to set Free Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
||||||
} else {
|
} else {
|
||||||
if (event!=null) event.onPlaybackFailure(prop, String.format("Failed to play audio file %s, Error Code %d", prop.filename, bass.BASS_ErrorGetCode()));
|
if (event!=null) event.onPlaybackFailure(prop, String.format("Failed to play audio file %s, Error Code %d", prop.filename, bass.BASS_ErrorGetCode()));
|
||||||
}
|
}
|
||||||
@@ -193,4 +285,23 @@ public class AudioPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static class SyncProcValue extends Structure{
|
||||||
|
// public AudioFileProperties ap;
|
||||||
|
// public SyncProcValue(AudioFileProperties ap){
|
||||||
|
// this.ap = ap;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public SyncProcValue(Pointer p){
|
||||||
|
// super(p);
|
||||||
|
// read();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected List<String> getFieldOrder() {
|
||||||
|
// return Arrays.asList("ap");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package Audio;
|
|||||||
|
|
||||||
import com.sun.jna.*;
|
import com.sun.jna.*;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public interface Bass extends Library {
|
public interface Bass extends Library {
|
||||||
|
|||||||
324
src/main/java/Audio/MultiUSBAudioPlayer.java
Normal file
324
src/main/java/Audio/MultiUSBAudioPlayer.java
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
package Audio;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MultiUSBAudioPlayer {
|
||||||
|
private final Bass bass;
|
||||||
|
private int[] deviceid;
|
||||||
|
@Getter
|
||||||
|
private boolean inited = false;
|
||||||
|
|
||||||
|
PlaybackHandlewithId[] playbackhandle;
|
||||||
|
float playbackvolume = 1.0f;
|
||||||
|
List<BassDeviceInfoWithId> playbackdevices = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Multi USB Audio Player
|
||||||
|
*/
|
||||||
|
public MultiUSBAudioPlayer() {
|
||||||
|
bass = Bass.Instance;
|
||||||
|
Logger.info("Bass Version = {}", Integer.toHexString(bass.BASS_GetVersion()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload Multi USB Audio Player
|
||||||
|
*/
|
||||||
|
public void Unload(){
|
||||||
|
if (inited){
|
||||||
|
if (deviceid!=null && deviceid.length>0){
|
||||||
|
for(int id: deviceid){
|
||||||
|
Logger.info("Freeing Device {}", id);
|
||||||
|
bass.BASS_SetDevice(id);
|
||||||
|
bass.BASS_Free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
deviceid = null;
|
||||||
|
inited = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect Output Devices
|
||||||
|
*/
|
||||||
|
public void DetectOutputDevices(){
|
||||||
|
Logger.info("Detecting Output Devices...");
|
||||||
|
int ii = 1;
|
||||||
|
playbackdevices.clear();
|
||||||
|
while (true){
|
||||||
|
Bass.BASS_DEVICEINFO info = new Bass.BASS_DEVICEINFO();
|
||||||
|
if (bass.BASS_GetDeviceInfo(ii, info)){
|
||||||
|
//Logger.info("Device {} = {}, flags = {}", ii, info.name, Integer.toHexString(info.flags));
|
||||||
|
playbackdevices.add(new BassDeviceInfoWithId(ii, info));
|
||||||
|
ii++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find playback devices with name
|
||||||
|
* @param name specific name
|
||||||
|
* @return array of device id
|
||||||
|
*/
|
||||||
|
public int[] FindDeviceIDWithName(String name){
|
||||||
|
if (playbackdevices!=null && !playbackdevices.isEmpty()){
|
||||||
|
List<Integer> result = new ArrayList<>();
|
||||||
|
for(BassDeviceInfoWithId dev : playbackdevices){
|
||||||
|
if (dev.info.name.toLowerCase().contains(name.toLowerCase())){
|
||||||
|
Logger.info("Found Device id={}, name={}", dev.id, dev.info.name);
|
||||||
|
result.add(dev.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.stream().mapToInt(i->i).toArray();
|
||||||
|
}
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open Devices
|
||||||
|
* @param device list of device id
|
||||||
|
* @param freq frequency
|
||||||
|
* @return true if any device is successfully initialized
|
||||||
|
*/
|
||||||
|
public boolean OpenDevice(int[] device, int freq){
|
||||||
|
if (device!=null && device.length>0){
|
||||||
|
int flag = Bass.BASS_DEVICE_REINIT | Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_MONO | Bass.BASS_DEVICE_FREQ;
|
||||||
|
|
||||||
|
List<Integer> validdevice = new ArrayList<>();
|
||||||
|
for(int i : device){
|
||||||
|
boolean result = bass.BASS_Init(i, freq, flag);
|
||||||
|
if (result){
|
||||||
|
Logger.info("Device {} initialized", i);
|
||||||
|
validdevice.add(i);
|
||||||
|
inited = true;
|
||||||
|
} else {
|
||||||
|
Logger.error("Failed to initialize device {}, errorcode={}", i, bass.BASS_ErrorGetCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceid = validdevice.stream().mapToInt(i->i).toArray();
|
||||||
|
return inited;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Master Output Volume
|
||||||
|
* Master Output Volume related to the system volume (Alsamixer on Linux, Volume Mixer on Windows)
|
||||||
|
* @param value volume value, 0-100
|
||||||
|
*/
|
||||||
|
public void setMasterVolume(int value){
|
||||||
|
if (value<0) value = 0;
|
||||||
|
if (value>100) value = 100;
|
||||||
|
if (inited){
|
||||||
|
if (deviceid!=null && deviceid.length>0){
|
||||||
|
for(int id : deviceid){
|
||||||
|
bass.BASS_SetDevice(id);
|
||||||
|
if (!bass.BASS_SetVolume(value/100.0f)){
|
||||||
|
Logger.error("Failed to set Master Volume to {}, Error Code {}", value, bass.BASS_ErrorGetCode());
|
||||||
|
} else Logger.info("Master Volume set to {}", value);
|
||||||
|
}
|
||||||
|
} else Logger.error("No device initialized");
|
||||||
|
} else Logger.info("MultiUSBAudioPlayer not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Playback Volume
|
||||||
|
* is the volume of the currently playing audio file
|
||||||
|
* @return 0 - 100
|
||||||
|
*/
|
||||||
|
public int getPlaybackvolume(){
|
||||||
|
if (playbackvolume<0)
|
||||||
|
return 0;
|
||||||
|
else if (playbackvolume>1.0f)
|
||||||
|
return 100;
|
||||||
|
else
|
||||||
|
return (int)(playbackvolume*100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Playback Volume
|
||||||
|
* is the volume of the currently playing audio file
|
||||||
|
* @param value 0 - 100
|
||||||
|
*/
|
||||||
|
public void setPlaybackvolume(int value){
|
||||||
|
if (value<0) value = 0;
|
||||||
|
if (value>100) value = 100;
|
||||||
|
playbackvolume = value/100.0f;
|
||||||
|
if (playbackhandle!=null && playbackhandle.length>0){
|
||||||
|
for(PlaybackHandlewithId ph : playbackhandle){
|
||||||
|
if (ph.handle.handle!=0){
|
||||||
|
bass.BASS_SetDevice(ph.id);
|
||||||
|
bass.BASS_ChannelSetAttribute(ph.handle.handle, Bass.BASS_ATTRIB_VOL, playbackvolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float lastplaybackvolume = 1.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Playback Volume to 0
|
||||||
|
*/
|
||||||
|
public void Mute(){
|
||||||
|
lastplaybackvolume = playbackvolume;
|
||||||
|
setPlaybackvolume(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Playback Volume to last volume before Mute
|
||||||
|
*/
|
||||||
|
public void Unmute(){
|
||||||
|
setPlaybackvolume((int)lastplaybackvolume*100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open Audio File
|
||||||
|
* @param ff audio file name to open
|
||||||
|
* @return AudioFileProperties object or null if failed
|
||||||
|
*/
|
||||||
|
public PlaybackHandlewithId[] OpenAudioFile(File ff){
|
||||||
|
if (inited){
|
||||||
|
AudioFileProperties prop;
|
||||||
|
List<PlaybackHandlewithId> phs = new ArrayList<>();
|
||||||
|
for(int id: deviceid){
|
||||||
|
bass.BASS_SetDevice(id);
|
||||||
|
int handle = bass.BASS_StreamCreateFile(false, ff.getAbsolutePath(), 0, 0,0);
|
||||||
|
if (handle!=0){
|
||||||
|
long Length = bass.BASS_ChannelGetLength(handle, Bass.BASS_POS_BYTE);
|
||||||
|
double duration = bass.BASS_ChannelBytes2Seconds(handle, Length);
|
||||||
|
prop = new AudioFileProperties(handle, ff.getName(), Length, duration);
|
||||||
|
PlaybackHandlewithId ph = new PlaybackHandlewithId(id, prop);
|
||||||
|
phs.add(ph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!phs.isEmpty()){
|
||||||
|
playbackhandle = phs.toArray(new PlaybackHandlewithId[0]);
|
||||||
|
Logger.info("Audio file {} opened successfully", ff.getName());
|
||||||
|
return playbackhandle;
|
||||||
|
} else {
|
||||||
|
Logger.error("Failed to open audio file {}, Error Code {}", ff.getName(), bass.BASS_ErrorGetCode());
|
||||||
|
}
|
||||||
|
} else Logger.info("AudioPlayer not initialized");
|
||||||
|
return new PlaybackHandlewithId[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close Audio File
|
||||||
|
* @param prop AudioFileProperties object to close
|
||||||
|
*/
|
||||||
|
public void CloseAudioFile(PlaybackHandlewithId[] prop) {
|
||||||
|
if (inited) {
|
||||||
|
if (prop != null && prop.length>0) {
|
||||||
|
for(PlaybackHandlewithId ph : prop){
|
||||||
|
if (ph.handle.handle!=0){
|
||||||
|
bass.BASS_SetDevice(ph.id);
|
||||||
|
if (!bass.BASS_ChannelFree(ph.handle.handle)){
|
||||||
|
Logger.error("Failed to close audio file {}, Error Code {}", ph.handle.filename, bass.BASS_ErrorGetCode());
|
||||||
|
} else {
|
||||||
|
Logger.info("Audio file {} closed successfully", ph.handle.filename);
|
||||||
|
}
|
||||||
|
bass.BASS_Stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else Logger.info("AudioPlayer not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaybackEvent playbackEvent = null;
|
||||||
|
|
||||||
|
Bass.SYNCPROC endproc = (handle, channel, data, user)->{
|
||||||
|
if (user!=null){
|
||||||
|
AudioFileProperties ap = new AudioFileProperties(user);
|
||||||
|
if (playbackEvent!=null){
|
||||||
|
playbackEvent.onPlaybackFinished(ap);
|
||||||
|
} else Logger.warn("endproc playbackEvent is null");
|
||||||
|
} else Logger.warn("endproc user is null");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Bass.SYNCPROC freeproc = (handle, channel, data, user)->{
|
||||||
|
if (user!=null){
|
||||||
|
AudioFileProperties ap = new AudioFileProperties(user);
|
||||||
|
if (playbackEvent!=null){
|
||||||
|
playbackEvent.onPlaybackFinished(ap);
|
||||||
|
} else Logger.warn("freeproc playbackEvent is null");
|
||||||
|
} else Logger.warn("freeproc user is null");
|
||||||
|
};
|
||||||
|
|
||||||
|
Bass.SYNCPROC failproc = (handle, channel, data, user)->{
|
||||||
|
if (user!=null){
|
||||||
|
AudioFileProperties ap = new AudioFileProperties(user);
|
||||||
|
if (playbackEvent!=null){
|
||||||
|
playbackEvent.onPlaybackFailure(ap, "Device Failure");
|
||||||
|
} else Logger.warn("failproc playbackEvent is null");
|
||||||
|
} else Logger.warn("failproc user is null");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play Audio File
|
||||||
|
* @param prop AudioFileProperties object to play
|
||||||
|
* @param looping set true to loop the audio file
|
||||||
|
* @param event PlaybackEvent object to handle playback event
|
||||||
|
*/
|
||||||
|
public void PlayAudioFile(PlaybackHandlewithId[] prop, boolean looping, PlaybackEvent event){
|
||||||
|
if (inited){
|
||||||
|
if (prop!=null && prop.length>0){
|
||||||
|
this.playbackEvent = event;
|
||||||
|
for(PlaybackHandlewithId ph : prop){
|
||||||
|
if (ph.handle.handle!=0){
|
||||||
|
bass.BASS_SetDevice(ph.id);
|
||||||
|
bass.BASS_Start();
|
||||||
|
if (bass.BASS_ChannelStart(ph.handle.handle)) {
|
||||||
|
|
||||||
|
bass.BASS_ChannelSetAttribute(ph.handle.handle, Bass.BASS_ATTRIB_VOL, playbackvolume);
|
||||||
|
if (looping) bass.BASS_ChannelFlags(ph.handle.handle, Bass.BASS_SAMPLE_LOOP, Bass.BASS_SAMPLE_LOOP);
|
||||||
|
if (event != null) event.onPlaybackStart(ph.handle);
|
||||||
|
int devfailsync = bass.BASS_ChannelSetSync(ph.handle.handle, Bass.BASS_SYNC_DEV_FAIL, 0, failproc, ph.handle.getPointer());
|
||||||
|
if (devfailsync == 0) Logger.error("Failed to set Device Failure Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
||||||
|
int endsync = bass.BASS_ChannelSetSync(ph.handle.handle, Bass.BASS_SYNC_END, 0, endproc, ph.handle.getPointer());
|
||||||
|
if (endsync == 0) Logger.error("Failed to set End Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
||||||
|
int freesync = bass.BASS_ChannelSetSync(ph.handle.handle, Bass.BASS_SYNC_FREE, 0, freeproc, ph.handle.getPointer());
|
||||||
|
if (freesync == 0) Logger.error("Failed to set Free Sync, Error Code {}", bass.BASS_ErrorGetCode());
|
||||||
|
} else {
|
||||||
|
if (event != null){
|
||||||
|
event.onPlaybackFailure(ph.handle, String.format("Failed to play audio file %s, Error Code %d", ph.handle.filename, bass.BASS_ErrorGetCode()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event!=null) event.onPlaybackFailure(null, "AudioFileProperties is null");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event!=null) event.onPlaybackFailure(null, "AudioPlayer not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlaybackHandlewithId{
|
||||||
|
public final int id;
|
||||||
|
public final AudioFileProperties handle;
|
||||||
|
public PlaybackHandlewithId(int id, AudioFileProperties handle){
|
||||||
|
this.id = id;
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BassDeviceInfoWithId{
|
||||||
|
public final int id;
|
||||||
|
public final Bass.BASS_DEVICEINFO info;
|
||||||
|
public BassDeviceInfoWithId(int id, Bass.BASS_DEVICEINFO info){
|
||||||
|
this.id = id;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,33 +5,61 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import Other.SomeCodes;
|
import Other.SomeCodes;
|
||||||
|
import id.co.gtc.Main;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.bytedeco.javacv.Frame;
|
import org.bytedeco.javacv.Frame;
|
||||||
import org.bytedeco.javacv.FrameGrabber;
|
import org.bytedeco.javacv.FrameGrabber;
|
||||||
|
import org.bytedeco.javacv.OpenCVFrameConverter;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.opencv.core.*;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
public class GrabbingTask implements Runnable {
|
public class GrabbingTask implements Runnable {
|
||||||
|
// for while loop control
|
||||||
|
private final AtomicBoolean isGrabbing;
|
||||||
|
// for grabbing frames
|
||||||
|
private final FrameGrabber grabber;
|
||||||
|
|
||||||
|
// Consumers
|
||||||
@Setter private Consumer<String> onMessageUpdate;
|
@Setter private Consumer<String> onMessageUpdate;
|
||||||
@Setter private Consumer<Frame> onHQFrameUpdate;
|
@Setter private Consumer<Frame> onHQFrameUpdate;
|
||||||
@Setter private Consumer<Frame> onLQFrameUpdate;
|
@Setter private Consumer<Frame> onLQFrameUpdate;
|
||||||
@Setter private Consumer<String> onHQBase64Update;
|
@Setter private Consumer<String> onHQBase64Update;
|
||||||
@Setter private Consumer<String> onLQBase64Update;
|
@Setter private Consumer<String> onLQBase64Update;
|
||||||
|
@Setter private Consumer<Frame> onYoloUpdate;
|
||||||
|
@Setter private Consumer<String> onYoloBase64Update;
|
||||||
|
|
||||||
private final AtomicBoolean isGrabbing;
|
// status of capture fps
|
||||||
private final FrameGrabber grabber;
|
@Getter private int CaptureFPS = 0;
|
||||||
@Getter private final int lowquality_width = 640;
|
|
||||||
@Getter private final int lowquality_height = 360;
|
@Getter @Setter private int lowquality_width = 640;
|
||||||
|
@Getter @Setter private int lowquality_height = 360;
|
||||||
|
|
||||||
|
// for FPS calculation
|
||||||
|
private int intendedFps = 10;
|
||||||
|
|
||||||
|
private final YoloDetector_opencv yolo;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private void updateMessage(String message) {
|
private void updateMessage(String message) {
|
||||||
if (onMessageUpdate != null) {
|
if (onMessageUpdate != null) {
|
||||||
onMessageUpdate.accept(message);
|
onMessageUpdate.accept(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateYoloBase64(String base64) {
|
||||||
|
if (onYoloBase64Update != null) {
|
||||||
|
onYoloBase64Update.accept(base64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateYoloFrame(Frame frame) {
|
||||||
|
if (onYoloUpdate != null) {
|
||||||
|
onYoloUpdate.accept(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateHQBase64(String base64) {
|
private void updateHQBase64(String base64) {
|
||||||
if (onHQBase64Update != null) {
|
if (onHQBase64Update != null) {
|
||||||
@@ -39,6 +67,7 @@ public class GrabbingTask implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private void updateLQBase64(String base64) {
|
private void updateLQBase64(String base64) {
|
||||||
if (onLQBase64Update != null) {
|
if (onLQBase64Update != null) {
|
||||||
onLQBase64Update.accept(base64);
|
onLQBase64Update.accept(base64);
|
||||||
@@ -61,34 +90,133 @@ public class GrabbingTask implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber) {
|
public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber, int fps) {
|
||||||
this.isGrabbing = isGrabbing;
|
this.isGrabbing = isGrabbing;
|
||||||
this.grabber = grabber;
|
this.grabber = grabber;
|
||||||
|
if (fps>0) intendedFps = fps;
|
||||||
|
if (Main.use_Yolo) {
|
||||||
|
yolo = new YoloDetector_opencv();
|
||||||
|
} else yolo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Stop(){
|
||||||
|
isGrabbing.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings({"CallToPrintStackTrace", "CatchMayIgnoreException"})
|
||||||
|
private Mat processFrame(Frame fr){
|
||||||
|
if (fr!=null && fr.image!=null && fr.imageWidth>0 && fr.imageHeight>0){
|
||||||
|
try(var converter = new OpenCVFrameConverter.ToOrgOpenCvCoreMat()){
|
||||||
|
Mat mat = converter.convert(fr);
|
||||||
|
if (mat.cols()>0 && mat.rows()>0){
|
||||||
|
updateHQFrame(fr);
|
||||||
|
updateHQBase64(SomeCodes.MatToBase64(mat));
|
||||||
|
Size lowsize = new Size(lowquality_width, lowquality_height);
|
||||||
|
Mat resized = new Mat();
|
||||||
|
|
||||||
|
Imgproc.resize(mat, resized, lowsize);
|
||||||
|
mat.release();
|
||||||
|
|
||||||
|
if (resized.cols()>0 && resized.rows()>0){
|
||||||
|
Frame resizedFrame = converter.convert(resized);
|
||||||
|
updateLQFrame(resizedFrame);
|
||||||
|
updateLQBase64(SomeCodes.MatToBase64(resized));
|
||||||
|
return resized;
|
||||||
|
} else Logger.error("processFrame resized size is 0");
|
||||||
|
} else Logger.error("processFrame Mat size is 0");
|
||||||
|
} catch (Exception e){
|
||||||
|
if (SomeCodes.ValidString(e.getMessage())) {
|
||||||
|
if (!e.getMessage().startsWith("unknown exception")) {
|
||||||
|
Logger.error("Error processing frame: "+e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// Logger.warn("processFrame have null frame");
|
||||||
|
// updateMessage("processFrame have null frame");
|
||||||
|
// }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetectYolo(Mat mat){
|
||||||
|
if (yolo!=null){
|
||||||
|
if (mat!=null && mat.cols()>0 && mat.rows()>0){
|
||||||
|
try {
|
||||||
|
// [0] = predict, [1] = mask
|
||||||
|
Mat[] processed = yolo.Detect(mat);
|
||||||
|
// gambar dalam bentuk Mat
|
||||||
|
Mat yolomat = yolo.Process(mat, processed[0], processed[1]);
|
||||||
|
// convert jadi frame
|
||||||
|
Frame yoloFrame = SomeCodes.MatToFrame(yolomat);
|
||||||
|
updateYoloFrame(yoloFrame);
|
||||||
|
updateYoloBase64(SomeCodes.MatToBase64(yolomat));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.error("error processing YOLO, Message : " + e.getMessage());
|
||||||
|
updateYoloFrame(null);
|
||||||
|
updateYoloBase64("");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else Logger.error("DetectYolo mat is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flush_grabber(){
|
||||||
|
try {
|
||||||
|
if (grabber!=null) grabber.flush();
|
||||||
|
} catch (FrameGrabber.Exception e) {
|
||||||
|
Logger.error("Error flushing grabber: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("CallToPrintStackTrace")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
isGrabbing.set(true);
|
isGrabbing.set(true);
|
||||||
|
Logger.info("Grabbing Task started");
|
||||||
|
double fps = grabber.getFrameRate();
|
||||||
|
int skippedframes = (int)(fps / intendedFps);
|
||||||
|
Logger.info("Grabber framerate = {}, intendedFps = {}, Skipping frames = {}", fps, intendedFps, skippedframes);
|
||||||
|
int framecount = 0;
|
||||||
|
flush_grabber();
|
||||||
|
long starttick = System.currentTimeMillis();
|
||||||
while (isGrabbing.get()) {
|
while (isGrabbing.get()) {
|
||||||
try {
|
try{
|
||||||
Frame fr =grabber.grab();
|
Thread.yield();
|
||||||
if (fr!=null){
|
|
||||||
updateHQFrame(fr);
|
Frame frame = grabber.grab();
|
||||||
updateHQBase64(SomeCodes.FrameToBase64(fr));
|
if (framecount<Integer.MAX_VALUE) framecount++; else framecount = 0;
|
||||||
Frame resized = SomeCodes.ResizeFrame(fr, lowquality_width, lowquality_height);
|
Mat resized = processFrame(frame);
|
||||||
updateLQFrame(resized);
|
// no need to skip frames, just process all frames
|
||||||
updateLQBase64(SomeCodes.FrameToBase64(resized));
|
if (framecount % skippedframes == 0) {
|
||||||
} else updateMessage("Grabber returned null frame");
|
if (Main.use_Yolo){
|
||||||
} catch (Exception e) {
|
DetectYolo(resized);
|
||||||
updateMessage("Error grabbing frame: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
resized.release();
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error grabbing frame: "+e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
long elapsed = System.currentTimeMillis() - starttick;
|
||||||
|
starttick = System.currentTimeMillis();
|
||||||
|
if (elapsed>0) {
|
||||||
|
int xx = (int) (1000 / elapsed);
|
||||||
|
//if (xx<fps) CaptureFPS = xx;
|
||||||
|
CaptureFPS = xx;
|
||||||
|
}
|
||||||
|
//Logger.info("Elapsed time = {} ms, captureFPS = {}", elapsed, CaptureFPS);
|
||||||
|
}
|
||||||
|
Logger.info("Grabbing Task stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package Camera;
|
package Camera;
|
||||||
|
|
||||||
import com.fazecast.jSerialComm.SerialPort;
|
import com.fazecast.jSerialComm.SerialPort;
|
||||||
|
import id.co.gtc.Main;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pan Tilt Controller
|
* Pan Tilt Controller
|
||||||
* Using PelcoD protocol
|
* Using PelcoD protocol
|
||||||
* Source : https://www.commfront.com/pages/pelco-d-protocol-tutorial
|
* Source : <a href="https://www.commfront.com/pages/pelco-d-protocol-tutorial">PelcoD Tutorial</a>
|
||||||
*/
|
*/
|
||||||
public class PanTiltController {
|
public class PanTiltController {
|
||||||
private final SerialPort serialPort;
|
private SerialPort serialPort;
|
||||||
private final byte cameraid;
|
private final byte cameraid;
|
||||||
/**
|
/**
|
||||||
* Open Pan Tilt Controller
|
* Open Pan Tilt Controller
|
||||||
@@ -17,24 +19,48 @@ public class PanTiltController {
|
|||||||
* @param baudrate baudrate used
|
* @param baudrate baudrate used
|
||||||
*/
|
*/
|
||||||
public PanTiltController(String portname, int baudrate, int cameraid){
|
public PanTiltController(String portname, int baudrate, int cameraid){
|
||||||
serialPort = SerialPort.getCommPort(portname);
|
|
||||||
serialPort.setBaudRate(baudrate);
|
|
||||||
this.cameraid = (byte)cameraid;
|
this.cameraid = (byte)cameraid;
|
||||||
|
SerialPort[] comports = SerialPort.getCommPorts();
|
||||||
|
if (comports.length>0){
|
||||||
|
for (SerialPort port : comports){
|
||||||
|
Logger.info("Available Serial Port : {}", port.getSystemPortName());
|
||||||
|
|
||||||
|
if (portname.contains(port.getSystemPortName())){
|
||||||
|
Logger.info("Serial Port {} found", portname);
|
||||||
|
serialPort = port;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (serialPort!=null){
|
||||||
|
serialPort.setBaudRate(baudrate);
|
||||||
if (serialPort.openPort()){
|
if (serialPort.openPort()){
|
||||||
Logger.info("Serial Port {} opened successfully at {}", portname, baudrate);
|
Logger.info("Serial Port {} opened successfully at {}", portname, baudrate);
|
||||||
} else {
|
} else {
|
||||||
Logger.info("Failed to open Serial Port {} at {}", portname, baudrate);
|
Logger.info("Failed to open Serial Port {} at {}", portname, baudrate);
|
||||||
}
|
}
|
||||||
|
} else Logger.info("Serial Port {} not found", portname);
|
||||||
|
} else Logger.info("No Serial Port found");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close Pan Tilt Controller
|
* Close Pan Tilt Controller
|
||||||
*/
|
*/
|
||||||
public void Close(){
|
public void Close(){
|
||||||
serialPort.closePort();
|
if (serialPort!=null) serialPort.closePort();
|
||||||
Logger.info("Serial Port closed");
|
Logger.info("Serial Port closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if Serial Port is open
|
||||||
|
* @return true if open, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isOpen(){
|
||||||
|
return serialPort != null && serialPort.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop Pan Tilt Movement
|
* Stop Pan Tilt Movement
|
||||||
*/
|
*/
|
||||||
@@ -42,7 +68,13 @@ public class PanTiltController {
|
|||||||
byte[] command = new byte[]{0, cameraid, 0, 0, 0, 0, 0};
|
byte[] command = new byte[]{0, cameraid, 0, 0, 0, 0, 0};
|
||||||
command[6] = Checksum(command); // add checksum
|
command[6] = Checksum(command); // add checksum
|
||||||
command[0] = (byte) 0xFF; // add synchronization byte
|
command[0] = (byte) 0xFF; // add synchronization byte
|
||||||
serialPort.writeBytes(command, command.length);
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("Stop movement written {}", written);
|
||||||
|
} else Logger.warn("Stop Movement failed, serial port not open");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +88,13 @@ public class PanTiltController {
|
|||||||
byte[] command = new byte[]{0, cameraid, 0, 4, speed, 0, 0};
|
byte[] command = new byte[]{0, cameraid, 0, 4, speed, 0, 0};
|
||||||
command[6] = Checksum(command); // add checksum
|
command[6] = Checksum(command); // add checksum
|
||||||
command[0] = (byte) 0xFF; // add synchronization byte
|
command[0] = (byte) 0xFF; // add synchronization byte
|
||||||
serialPort.writeBytes(command, command.length);
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("Pan Left written {} bytes", written);
|
||||||
|
} else Logger.warn("Pan Left failed, serial port not open");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,7 +108,13 @@ public class PanTiltController {
|
|||||||
byte[] command = new byte[]{0, cameraid, 0, 2, speed, 0, 0};
|
byte[] command = new byte[]{0, cameraid, 0, 2, speed, 0, 0};
|
||||||
command[6] = Checksum(command); // add checksum
|
command[6] = Checksum(command); // add checksum
|
||||||
command[0] = (byte) 0xFF; // add synchronization byte
|
command[0] = (byte) 0xFF; // add synchronization byte
|
||||||
serialPort.writeBytes(command, command.length);
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("Pan Right written {} bytes", written);
|
||||||
|
} else Logger.warn("Pan Right failed, serial port not open");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,10 +125,16 @@ public class PanTiltController {
|
|||||||
if (speed<0) speed = 0;
|
if (speed<0) speed = 0;
|
||||||
if (speed>0x3F) speed = 0x3F;
|
if (speed>0x3F) speed = 0x3F;
|
||||||
|
|
||||||
byte[] command = new byte[]{0, cameraid, 0, 8, speed, 0, 0};
|
byte[] command = new byte[]{0, cameraid, 0, 8, 0, speed, 0};
|
||||||
command[6] = Checksum(command); // add checksum
|
command[6] = Checksum(command); // add checksum
|
||||||
command[0] = (byte) 0xFF; // add synchronization byte
|
command[0] = (byte) 0xFF; // add synchronization byte
|
||||||
serialPort.writeBytes(command, command.length);
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("Tilt Up written {} bytes", written);
|
||||||
|
} else Logger.warn("Tilt Up failed, serial port not open");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,10 +145,58 @@ public class PanTiltController {
|
|||||||
if (speed<0) speed = 0;
|
if (speed<0) speed = 0;
|
||||||
if (speed>0x3F) speed = 0x3F;
|
if (speed>0x3F) speed = 0x3F;
|
||||||
|
|
||||||
byte[] command = new byte[]{0, cameraid, 0, 16, speed, 0, 0};
|
byte[] command = new byte[]{0, cameraid, 0, 16, 0, speed, 0};
|
||||||
command[6] = Checksum(command); // add checksum
|
command[6] = Checksum(command); // add checksum
|
||||||
command[0] = (byte) 0xFF; // add synchronization byte
|
command[0] = (byte) 0xFF; // add synchronization byte
|
||||||
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("Tilt Down written {} bytes", written);
|
||||||
|
} else Logger.warn("Tilt Down failed, serial port not open");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableMovementTest(){
|
||||||
|
byte[] command = new byte[]{(byte)0xFF, cameraid, 0, 7, 0, (byte)0x54, (byte)0x5c};
|
||||||
|
//command[6] = Checksum(command);
|
||||||
|
//command[0] = (byte) 0xFF;
|
||||||
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("DisableMovement test written {} bytes", written);
|
||||||
|
} else Logger.warn("DisableMovement failed, serial port not open");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableMovementTest(){
|
||||||
|
byte[] command = new byte[]{(byte)0xFF, cameraid, 0, 3, 0, (byte)0x54, (byte) 0x58};
|
||||||
|
//command[6] = Checksum(command);
|
||||||
|
//command[0] = (byte) 0xFF;
|
||||||
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
|
int written = serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
Logger.info("EnableMovement test written {} bytes", written);
|
||||||
|
} else Logger.warn("EnableMovement failed, serial port not open");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to Preset
|
||||||
|
* @param preset preset number
|
||||||
|
*/
|
||||||
|
public void GoToPreset(byte preset){
|
||||||
|
byte[] command = new byte[]{0, cameraid, 0, 15, preset, 0, 0};
|
||||||
|
command[6] = Checksum(command); // add checksum
|
||||||
|
command[0] = (byte) 0xFF; // add synchronization byte
|
||||||
|
if (isOpen()) {
|
||||||
|
Main.Max485Direction(true);
|
||||||
serialPort.writeBytes(command, command.length);
|
serialPort.writeBytes(command, command.length);
|
||||||
|
Main.Max485Direction(false);
|
||||||
|
Main.Blink_LedPanTilt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,28 +3,84 @@ import lombok.Getter;
|
|||||||
import org.bytedeco.ffmpeg.global.avutil;
|
import org.bytedeco.ffmpeg.global.avutil;
|
||||||
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
||||||
import org.bytedeco.javacv.Frame;
|
import org.bytedeco.javacv.Frame;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static Other.SomeCodes.gson;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class RtspGrabber {
|
public class RtspGrabber {
|
||||||
private final String rtspUrl;
|
private final String rtspUrl;
|
||||||
private FFmpegFrameGrabber grabber;
|
private FFmpegFrameGrabber grabber;
|
||||||
private final AtomicBoolean isGrabbing = new AtomicBoolean(false);
|
private final AtomicBoolean isGrabbing = new AtomicBoolean(false);
|
||||||
private @Getter Frame lastHQFrame = null;
|
private Frame lastHQFrame = null;
|
||||||
private @Getter Frame lastLQFrame = null;
|
private Frame lastLQFrame = null;
|
||||||
private @Getter String lastHQBase64 = null;
|
private Frame lastYoloFrame = null;
|
||||||
private @Getter String lastLQBase64 = null;
|
private String lastHQBase64 = null;
|
||||||
|
private String lastLQBase64 = null;
|
||||||
|
private String lastYoloBase64 = null;
|
||||||
private @Getter int HQWidth = 0;
|
private @Getter int HQWidth = 0;
|
||||||
private @Getter int HQHeight = 0;
|
private @Getter int HQHeight = 0;
|
||||||
private @Getter int LQWidth = 0;
|
private @Getter int LQWidth = 0;
|
||||||
private @Getter int LQHeight = 0;
|
private @Getter int LQHeight = 0;
|
||||||
|
private GrabbingTask grabbingTask;
|
||||||
|
|
||||||
public RtspGrabber(String ip, String path) {
|
public RtspGrabber(String ip, String path) {
|
||||||
|
|
||||||
this.rtspUrl = "rtsp://" + ip + path;
|
this.rtspUrl = "rtsp://" + ip + path;
|
||||||
Logger.info("RtspGrabber created with url: " + rtspUrl);
|
Logger.info("RtspGrabber created with url: " + rtspUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastHQFrame(Frame frame){
|
||||||
|
lastHQFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Frame getLastHQFrame(){
|
||||||
|
return lastHQFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastLQFrame(Frame frame){
|
||||||
|
lastLQFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Frame getLastLQFrame(){
|
||||||
|
return lastLQFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastHQBase64(String base64){
|
||||||
|
lastHQBase64 = base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized String getLastHQBase64(){
|
||||||
|
return lastHQBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastLQBase64(String base64){
|
||||||
|
lastLQBase64 = base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized String getLastLQBase64(){
|
||||||
|
return lastLQBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastYoloBase64(String base64){
|
||||||
|
lastYoloBase64 = base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized String getLastYoloBase64(){
|
||||||
|
return lastYoloBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastYoloFrame(Frame frame){
|
||||||
|
lastYoloFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Frame getLastYoloFrame(){
|
||||||
|
return lastYoloFrame;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start grabbing frames from rtsp
|
* Start grabbing frames from rtsp
|
||||||
* @param useTcp Use tcp instead of udp
|
* @param useTcp Use tcp instead of udp
|
||||||
@@ -35,21 +91,60 @@ public class RtspGrabber {
|
|||||||
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
||||||
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
|
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
|
||||||
|
|
||||||
grabber.setImageWidth(width);
|
|
||||||
grabber.setImageHeight(height);
|
|
||||||
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
|
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
|
||||||
grabber.start();
|
grabber.start();
|
||||||
|
|
||||||
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Logger.info("Grabber started");
|
Logger.info("Grabber started");
|
||||||
GrabbingTask tt = new GrabbingTask(isGrabbing, grabber);
|
GrabbingTask tt = getGrabbingTask();
|
||||||
|
grabbingTask = tt;
|
||||||
|
new Thread(tt).start();
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error starting grabber: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop grabbing frames
|
||||||
|
*/
|
||||||
|
public void Stop(){
|
||||||
|
isGrabbing.set(false);
|
||||||
|
if (grabbingTask!=null){
|
||||||
|
grabbingTask.Stop();
|
||||||
|
}
|
||||||
|
grabbingTask = null;
|
||||||
|
if (grabber!=null) {
|
||||||
|
try{
|
||||||
|
grabber.stop();
|
||||||
|
grabber.releaseUnsafe();
|
||||||
|
Logger.info("Grabber stopped");
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error stopping grabber: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grabber = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String LQStreamingStatus(){
|
||||||
|
return gson.toJson(new String[]{String.valueOf(LQWidth), String.valueOf(LQHeight) , String.valueOf(grabbingTask!=null ? grabbingTask.getCaptureFPS():"0")});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String HQStreamingStatus(){
|
||||||
|
return gson.toJson(new String[]{String.valueOf(HQWidth), String.valueOf(HQHeight) , String.valueOf(grabbingTask!=null ? grabbingTask.getCaptureFPS(): "0")});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private GrabbingTask getGrabbingTask() {
|
||||||
|
GrabbingTask tt = new GrabbingTask(isGrabbing, grabber,10);
|
||||||
tt.setOnMessageUpdate(Logger::info);
|
tt.setOnMessageUpdate(Logger::info);
|
||||||
tt.setOnHQFrameUpdate(value -> {
|
tt.setOnHQFrameUpdate(value -> {
|
||||||
if (value!=null){
|
if (value!=null){
|
||||||
if (value.imageWidth>0 && value.imageHeight>0){
|
if (value.imageWidth>0 && value.imageHeight>0){
|
||||||
lastHQFrame = value;
|
setLastHQFrame(value);
|
||||||
HQWidth = value.imageWidth;
|
HQWidth = value.imageWidth;
|
||||||
HQHeight = value.imageHeight;
|
HQHeight = value.imageHeight;
|
||||||
}
|
}
|
||||||
@@ -59,36 +154,16 @@ public class RtspGrabber {
|
|||||||
tt.setOnLQFrameUpdate(value -> {
|
tt.setOnLQFrameUpdate(value -> {
|
||||||
if (value!=null){
|
if (value!=null){
|
||||||
if (value.imageWidth>0 && value.imageHeight>0){
|
if (value.imageWidth>0 && value.imageHeight>0){
|
||||||
lastLQFrame = value;
|
setLastLQFrame(value);
|
||||||
LQWidth = value.imageWidth;
|
LQWidth = value.imageWidth;
|
||||||
LQHeight = value.imageHeight;
|
LQHeight = value.imageHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tt.setOnHQBase64Update(value -> lastHQBase64 = value);
|
tt.setOnHQBase64Update(this::setLastHQBase64);
|
||||||
tt.setOnLQBase64Update(value -> lastLQBase64 = value);
|
tt.setOnLQBase64Update(this::setLastLQBase64);
|
||||||
new Thread(tt).start();
|
tt.setOnYoloUpdate(this::setLastYoloFrame);
|
||||||
|
tt.setOnYoloBase64Update(this::setLastYoloBase64);
|
||||||
} catch (Exception e){
|
return tt;
|
||||||
Logger.error("Error starting grabber: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop grabbing frames
|
|
||||||
*/
|
|
||||||
public void Stop(){
|
|
||||||
if (grabber!=null) {
|
|
||||||
try{
|
|
||||||
isGrabbing.set(false);
|
|
||||||
grabber.stop();
|
|
||||||
Logger.info("Grabber stopped");
|
|
||||||
} catch (Exception e){
|
|
||||||
Logger.error("Error stopping grabber: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
169
src/main/java/Camera/RtspGrabber_opencv.java
Normal file
169
src/main/java/Camera/RtspGrabber_opencv.java
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package Camera;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bytedeco.ffmpeg.global.avutil;
|
||||||
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
||||||
|
import org.bytedeco.javacv.Frame;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static Other.SomeCodes.gson;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class RtspGrabber_opencv {
|
||||||
|
private final String rtspUrl;
|
||||||
|
private FFmpegFrameGrabber grabber;
|
||||||
|
private final AtomicBoolean isGrabbing = new AtomicBoolean(false);
|
||||||
|
private Frame lastHQFrame = null;
|
||||||
|
private Frame lastLQFrame = null;
|
||||||
|
private Frame lastYoloFrame = null;
|
||||||
|
private String lastHQBase64 = null;
|
||||||
|
private String lastLQBase64 = null;
|
||||||
|
private String lastYoloBase64 = null;
|
||||||
|
private @Getter int HQWidth = 0;
|
||||||
|
private @Getter int HQHeight = 0;
|
||||||
|
private @Getter int LQWidth = 0;
|
||||||
|
private @Getter int LQHeight = 0;
|
||||||
|
private GrabbingTask grabbingTask;
|
||||||
|
|
||||||
|
public RtspGrabber_opencv(String ip, String path) {
|
||||||
|
|
||||||
|
this.rtspUrl = "rtsp://" + ip + path;
|
||||||
|
Logger.info("RtspGrabber created with url: " + rtspUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastHQFrame(Frame frame){
|
||||||
|
lastHQFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Frame getLastHQFrame(){
|
||||||
|
return lastHQFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastLQFrame(Frame frame){
|
||||||
|
lastLQFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Frame getLastLQFrame(){
|
||||||
|
return lastLQFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastHQBase64(String base64){
|
||||||
|
lastHQBase64 = base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized String getLastHQBase64(){
|
||||||
|
return lastHQBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastLQBase64(String base64){
|
||||||
|
lastLQBase64 = base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized String getLastLQBase64(){
|
||||||
|
return lastLQBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastYoloBase64(String base64){
|
||||||
|
lastYoloBase64 = base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized String getLastYoloBase64(){
|
||||||
|
return lastYoloBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setLastYoloFrame(Frame frame){
|
||||||
|
lastYoloFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Frame getLastYoloFrame(){
|
||||||
|
return lastYoloFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start grabbing frames from rtsp
|
||||||
|
* @param useTcp Use tcp instead of udp
|
||||||
|
*/
|
||||||
|
public void Start(boolean useTcp, final int width, final int height){
|
||||||
|
|
||||||
|
try{
|
||||||
|
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
||||||
|
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
|
||||||
|
|
||||||
|
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
|
||||||
|
grabber.start();
|
||||||
|
|
||||||
|
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
||||||
|
|
||||||
|
Logger.info("Grabber started");
|
||||||
|
GrabbingTask tt = getGrabbingTask();
|
||||||
|
grabbingTask = tt;
|
||||||
|
new Thread(tt).start();
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error starting grabber: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop grabbing frames
|
||||||
|
*/
|
||||||
|
public void Stop(){
|
||||||
|
isGrabbing.set(false);
|
||||||
|
if (grabbingTask!=null){
|
||||||
|
grabbingTask.Stop();
|
||||||
|
}
|
||||||
|
grabbingTask = null;
|
||||||
|
if (grabber!=null) {
|
||||||
|
try{
|
||||||
|
grabber.stop();
|
||||||
|
grabber.releaseUnsafe();
|
||||||
|
Logger.info("Grabber stopped");
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error stopping grabber: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grabber = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String LQStreamingStatus(){
|
||||||
|
return gson.toJson(new String[]{String.valueOf(LQWidth), String.valueOf(LQHeight) , String.valueOf(grabbingTask!=null ? grabbingTask.getCaptureFPS():"0")});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String HQStreamingStatus(){
|
||||||
|
return gson.toJson(new String[]{String.valueOf(HQWidth), String.valueOf(HQHeight) , String.valueOf(grabbingTask!=null ? grabbingTask.getCaptureFPS(): "0")});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private GrabbingTask getGrabbingTask() {
|
||||||
|
GrabbingTask tt = new GrabbingTask(isGrabbing, grabber,5);
|
||||||
|
tt.setOnMessageUpdate(Logger::info);
|
||||||
|
tt.setOnHQFrameUpdate(value -> {
|
||||||
|
if (value!=null){
|
||||||
|
if (value.imageWidth>0 && value.imageHeight>0){
|
||||||
|
setLastHQFrame(value);
|
||||||
|
HQWidth = value.imageWidth;
|
||||||
|
HQHeight = value.imageHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tt.setOnLQFrameUpdate(value -> {
|
||||||
|
if (value!=null){
|
||||||
|
if (value.imageWidth>0 && value.imageHeight>0){
|
||||||
|
setLastLQFrame(value);
|
||||||
|
LQWidth = value.imageWidth;
|
||||||
|
LQHeight = value.imageHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tt.setOnHQBase64Update(this::setLastHQBase64);
|
||||||
|
tt.setOnLQBase64Update(this::setLastLQBase64);
|
||||||
|
tt.setOnYoloUpdate(this::setLastYoloFrame);
|
||||||
|
tt.setOnYoloBase64Update(this::setLastYoloBase64);
|
||||||
|
return tt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package Camera;
|
package Camera;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
@@ -27,7 +28,7 @@ public class VapixProtocol {
|
|||||||
private String[] ImageResolutions = new String[0];
|
private String[] ImageResolutions = new String[0];
|
||||||
private String[] ImageFormats = new String[0];
|
private String[] ImageFormats = new String[0];
|
||||||
private int CurrentZoomValue = 0;
|
private int CurrentZoomValue = 0;
|
||||||
|
@Getter private boolean successQuery = false;
|
||||||
/**
|
/**
|
||||||
* Create a new VapixProtocol object
|
* Create a new VapixProtocol object
|
||||||
* @param ip The IP address of the camera
|
* @param ip The IP address of the camera
|
||||||
@@ -83,6 +84,7 @@ public class VapixProtocol {
|
|||||||
if (ValidString(value)) ImageFormats = value.split(",");
|
if (ValidString(value)) ImageFormats = value.split(",");
|
||||||
//Logger.info("Format: "+value);
|
//Logger.info("Format: "+value);
|
||||||
}
|
}
|
||||||
|
successQuery = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
169
src/main/java/Camera/YoloDetector.java
Normal file
169
src/main/java/Camera/YoloDetector.java
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package Camera;
|
||||||
|
|
||||||
|
import Other.SomeCodes;
|
||||||
|
import id.co.gtc.Main;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import org.bytedeco.javacpp.DoublePointer;
|
||||||
|
import org.bytedeco.javacpp.FloatPointer;
|
||||||
|
import org.bytedeco.javacpp.IntPointer;
|
||||||
|
import org.bytedeco.opencv.global.opencv_core;
|
||||||
|
import org.bytedeco.opencv.global.opencv_dnn;
|
||||||
|
import org.bytedeco.opencv.global.opencv_imgproc;
|
||||||
|
import org.bytedeco.opencv.opencv_core.*;
|
||||||
|
import org.bytedeco.opencv.opencv_dnn.Net;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.bytedeco.opencv.global.opencv_core.CV_32F;
|
||||||
|
|
||||||
|
public class YoloDetector {
|
||||||
|
private Net net;
|
||||||
|
private @Getter boolean NetLoaded;
|
||||||
|
private List<String> classes ;
|
||||||
|
|
||||||
|
|
||||||
|
public YoloDetector() {
|
||||||
|
NetLoaded = false;
|
||||||
|
net = null;
|
||||||
|
classes = null;
|
||||||
|
String namesfile = SomeCodes.ExtractResource("/coco.names", SomeCodes.currentDirectory);
|
||||||
|
String netfile = SomeCodes.ExtractResource("/yolov8n.onnx", SomeCodes.currentDirectory);
|
||||||
|
if (SomeCodes.ValidFile(netfile)){
|
||||||
|
net = opencv_dnn.readNetFromONNX(netfile);
|
||||||
|
if (Main.haveCuda){
|
||||||
|
net.setPreferableBackend(opencv_dnn.DNN_BACKEND_CUDA);
|
||||||
|
net.setPreferableTarget(opencv_dnn.DNN_TARGET_CUDA_FP16);
|
||||||
|
Logger.info("Net loaded with CUDA");
|
||||||
|
} else {
|
||||||
|
net.setPreferableBackend(opencv_dnn.DNN_BACKEND_OPENCV);
|
||||||
|
net.setPreferableTarget(opencv_dnn.DNN_TARGET_CPU);
|
||||||
|
Logger.info("Net loaded with CPU");
|
||||||
|
}
|
||||||
|
} else Logger.error("net file not found");
|
||||||
|
|
||||||
|
if (net!=null){
|
||||||
|
classes = new ArrayList<>();
|
||||||
|
if (namesfile!=null){
|
||||||
|
try(BufferedReader br = new BufferedReader(new FileReader(namesfile))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
classes.add(line);
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("reading names file, Exception : ",e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!net.empty()){
|
||||||
|
if (!classes.isEmpty()){
|
||||||
|
NetLoaded = true;
|
||||||
|
} else Logger.error("names file is empty");
|
||||||
|
} else Logger.error("net is empty");
|
||||||
|
} else Logger.error("Net is not loaded");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source : https://blog.csdn.net/taoli188/article/details/134720614
|
||||||
|
public Mat[] Detect(Mat frame){
|
||||||
|
try{
|
||||||
|
if (NetLoaded){
|
||||||
|
Size inputSize = new Size(640, 640);
|
||||||
|
Scalar mean = new Scalar(0, 0, 0, 0);
|
||||||
|
double scaleFactor = 1.0f/255.0f;
|
||||||
|
boolean swapRB = true;
|
||||||
|
boolean crop = false;
|
||||||
|
|
||||||
|
//Mat blob = opencv_dnn.blobFromImage(frame, scaleFactor, inputSize, mean , swapRB, crop, CV_32F);
|
||||||
|
Mat blob = new Mat();
|
||||||
|
opencv_dnn.blobFromImage(frame, blob, scaleFactor, inputSize, mean, swapRB, crop, CV_32F);
|
||||||
|
net.setInput(blob);
|
||||||
|
|
||||||
|
Mat predict = net.forward();
|
||||||
|
Mat mask = predict.reshape(0,1).reshape(0, predict.size(1));
|
||||||
|
|
||||||
|
return new Mat[]{predict,mask};
|
||||||
|
} else {
|
||||||
|
Logger.error("Net not loaded");
|
||||||
|
return new Mat[0];
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error detecting: "+e.getMessage());
|
||||||
|
return new Mat[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("CallToPrintStackTrace")
|
||||||
|
public Mat Process(Mat frame, Mat predict, Mat mask){
|
||||||
|
try{
|
||||||
|
|
||||||
|
double width = frame.cols() / 640.0;
|
||||||
|
double height = frame.rows() / 640.0;
|
||||||
|
Rect2d[] rect2d = new Rect2d[mask.cols()];
|
||||||
|
float[] scoref = new float[mask.cols()];
|
||||||
|
int[] classid = new int[mask.cols()];
|
||||||
|
|
||||||
|
for(int i=0;i<mask.cols();i++){
|
||||||
|
double[] x = SomeCodes.getColumnValues(mask,i, new int[]{0});
|
||||||
|
double[] y = SomeCodes.getColumnValues(mask,i, new int[]{1});
|
||||||
|
double[] w = SomeCodes.getColumnValues(mask,i, new int[]{2});
|
||||||
|
double[] h = SomeCodes.getColumnValues(mask,i, new int[]{3});
|
||||||
|
rect2d[i] = new Rect2d((x[0]-w[0]/2)*width, (y[0]-h[0]/2)*height, w[0]*width, h[0]*height);
|
||||||
|
|
||||||
|
//Mat score = mask.col(i).submat(4, predict.size(1)-1,0,1) ;
|
||||||
|
Mat score = SomeCodes.getSubmat(mask,i,4,predict.size(1)-1);
|
||||||
|
// Core.MinMaxLocResult mm = Core.minMaxLoc(score);
|
||||||
|
// scoref[i] = (float)mm.maxVal;
|
||||||
|
// classid[i] = (int)mm.maxLoc.y;
|
||||||
|
|
||||||
|
DoublePointer minVal = new DoublePointer(1);
|
||||||
|
DoublePointer maxVal = new DoublePointer(1);
|
||||||
|
Point minLoc = new Point();
|
||||||
|
Point maxLoc = new Point();
|
||||||
|
opencv_core.minMaxLoc(score, minVal, maxVal, minLoc, maxLoc, null);
|
||||||
|
scoref[i] = (float)maxVal.get();
|
||||||
|
classid[i] = (int)maxLoc.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
//MatOfRect2d bboxes = new MatOfRect2d(rect2d);
|
||||||
|
Rect2dVector bboxes = new Rect2dVector(rect2d);
|
||||||
|
//MatOfFloat scores = new MatOfFloat(scoref);
|
||||||
|
FloatPointer scores = new FloatPointer(scoref);
|
||||||
|
//MatOfInt indices = new MatOfInt();
|
||||||
|
//IntVector indices = new IntVector();
|
||||||
|
IntPointer indices = new IntPointer();
|
||||||
|
// minimum confidence for detections
|
||||||
|
float confidence_threshold = 0.4f;
|
||||||
|
// Non-maximum suppression threshold
|
||||||
|
float nms_threshold = 0.4f;
|
||||||
|
|
||||||
|
opencv_dnn.NMSBoxes(bboxes, scores, confidence_threshold, nms_threshold, indices);
|
||||||
|
|
||||||
|
if (indices.limit()>0){
|
||||||
|
int[] idx = new int[(int)indices.limit()];
|
||||||
|
indices.get(idx);
|
||||||
|
for(int ii : idx){
|
||||||
|
Rect rr = new Rect(SomeCodes.toPoint(rect2d[ii].tl()), SomeCodes.toSize(rect2d[ii].size()));
|
||||||
|
opencv_imgproc.rectangle(frame,rr, Scalar.GREEN);
|
||||||
|
opencv_imgproc.putText(frame, classes.get(classid[ii])+" "+String.format("%.2f", scoref[ii]), rr.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, Scalar.RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error processing detection: "+e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
146
src/main/java/Camera/YoloDetector_opencv.java
Normal file
146
src/main/java/Camera/YoloDetector_opencv.java
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package Camera;
|
||||||
|
|
||||||
|
import Other.SomeCodes;
|
||||||
|
import id.co.gtc.Main;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.opencv.core.*;
|
||||||
|
import org.opencv.dnn.Dnn;
|
||||||
|
import org.opencv.dnn.Net;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.bytedeco.opencv.global.opencv_core.CV_32F;
|
||||||
|
|
||||||
|
public class YoloDetector_opencv {
|
||||||
|
private Net net;
|
||||||
|
private @Getter boolean NetLoaded;
|
||||||
|
private List<String> classes ;
|
||||||
|
|
||||||
|
|
||||||
|
public YoloDetector_opencv() {
|
||||||
|
NetLoaded = false;
|
||||||
|
net = null;
|
||||||
|
classes = null;
|
||||||
|
String namesfile = SomeCodes.ExtractResource("/coco.names", SomeCodes.currentDirectory);
|
||||||
|
String netfile = SomeCodes.ExtractResource("/yolov8n.onnx", SomeCodes.currentDirectory);
|
||||||
|
if (SomeCodes.ValidFile(netfile)){
|
||||||
|
net = Dnn.readNetFromONNX(netfile);
|
||||||
|
if (Main.haveCuda){
|
||||||
|
net.setPreferableBackend(Dnn.DNN_BACKEND_CUDA);
|
||||||
|
net.setPreferableTarget(Dnn.DNN_TARGET_CUDA_FP16);
|
||||||
|
Logger.info("Net loaded with CUDA");
|
||||||
|
} else {
|
||||||
|
net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV);
|
||||||
|
net.setPreferableTarget(Dnn.DNN_TARGET_CPU);
|
||||||
|
Logger.info("Net loaded with CPU");
|
||||||
|
}
|
||||||
|
} else Logger.error("net file not found");
|
||||||
|
|
||||||
|
if (net!=null){
|
||||||
|
classes = new ArrayList<>();
|
||||||
|
if (namesfile!=null){
|
||||||
|
try(BufferedReader br = new BufferedReader(new FileReader(namesfile))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
classes.add(line);
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("reading names file, Exception : ",e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!net.empty()){
|
||||||
|
if (!classes.isEmpty()){
|
||||||
|
NetLoaded = true;
|
||||||
|
} else Logger.error("names file is empty");
|
||||||
|
} else Logger.error("net is empty");
|
||||||
|
} else Logger.error("Net is not loaded");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source : https://blog.csdn.net/taoli188/article/details/134720614
|
||||||
|
public Mat[] Detect(Mat frame){
|
||||||
|
try{
|
||||||
|
if (NetLoaded){
|
||||||
|
Size inputSize = new Size(640, 640);
|
||||||
|
Scalar mean = new Scalar(0, 0, 0, 0);
|
||||||
|
float scaleFactor = 1.0f/255.0f;
|
||||||
|
boolean swapRB = true;
|
||||||
|
boolean crop = false;
|
||||||
|
|
||||||
|
Mat blob = Dnn.blobFromImage(frame, scaleFactor, inputSize, mean , swapRB, crop, CV_32F);
|
||||||
|
//Mat blob = Dnn.blobFromImage(frame, scaleFactor, inputSize);
|
||||||
|
|
||||||
|
net.setInput(blob);
|
||||||
|
|
||||||
|
Mat predict = net.forward();
|
||||||
|
Mat mask = predict.reshape(0,1).reshape(0, predict.size(1));
|
||||||
|
|
||||||
|
return new Mat[]{predict,mask};
|
||||||
|
} else {
|
||||||
|
Logger.error("Net not loaded");
|
||||||
|
return new Mat[0];
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error detecting: "+e.getMessage());
|
||||||
|
return new Mat[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("CallToPrintStackTrace")
|
||||||
|
public Mat Process(Mat frame, Mat predict, Mat mask){
|
||||||
|
try{
|
||||||
|
|
||||||
|
double width = frame.cols() / 640.0;
|
||||||
|
double height = frame.rows() / 640.0;
|
||||||
|
Rect2d[] rect2d = new Rect2d[mask.cols()];
|
||||||
|
float[] scoref = new float[mask.cols()];
|
||||||
|
int[] classid = new int[mask.cols()];
|
||||||
|
|
||||||
|
for(int i=0;i<mask.cols();i++){
|
||||||
|
double[] x = mask.col(i).get(0, 0);
|
||||||
|
double[] y = mask.col(i).get(1, 0);
|
||||||
|
double[] w = mask.col(i).get(2, 0);
|
||||||
|
double[] h = mask.col(i).get(3, 0);
|
||||||
|
rect2d[i] = new Rect2d((x[0]-w[0]/2)*width, (y[0]-h[0]/2)*height, w[0]*width, h[0]*height);
|
||||||
|
Mat score = mask.col(i).submat(4, predict.size(1)-1,0,1) ;
|
||||||
|
Core.MinMaxLocResult mm = Core.minMaxLoc(score);
|
||||||
|
scoref[i] = (float)mm.maxVal;
|
||||||
|
classid[i] = (int)mm.maxLoc.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatOfRect2d bboxes = new MatOfRect2d(rect2d);
|
||||||
|
MatOfFloat scores = new MatOfFloat(scoref);
|
||||||
|
MatOfInt indices = new MatOfInt();
|
||||||
|
// minimum confidence for detections
|
||||||
|
float confidence_threshold = 0.4f;
|
||||||
|
// Non-maximum suppression threshold
|
||||||
|
float nms_threshold = 0.4f;
|
||||||
|
Dnn.NMSBoxes(bboxes, scores, confidence_threshold, nms_threshold, indices);
|
||||||
|
|
||||||
|
if (!indices.empty()){
|
||||||
|
int[] idx = indices.toArray();
|
||||||
|
for(int ii : idx){
|
||||||
|
Rect rr = new Rect(rect2d[ii].tl(), rect2d[ii].size());
|
||||||
|
Imgproc.rectangle(frame, rr, new Scalar(0, 255, 0), 2);
|
||||||
|
Imgproc.putText(frame, classes.get(classid[ii])+" "+String.format("%.2f", scoref[ii]), rr.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar(0, 0, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error processing detection: "+e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,59 +1,65 @@
|
|||||||
package Other;
|
package Other;
|
||||||
|
|
||||||
import org.bytedeco.javacpp.Loader;
|
import com.google.gson.Gson;
|
||||||
|
import com.sun.jna.Platform;
|
||||||
|
import org.bytedeco.javacpp.BytePointer;
|
||||||
|
import org.bytedeco.javacpp.indexer.DoubleIndexer;
|
||||||
import org.bytedeco.javacv.Frame;
|
import org.bytedeco.javacv.Frame;
|
||||||
import org.bytedeco.javacv.Java2DFrameConverter;
|
|
||||||
import org.bytedeco.javacv.OpenCVFrameConverter;
|
import org.bytedeco.javacv.OpenCVFrameConverter;
|
||||||
import org.bytedeco.opencv.global.opencv_core;
|
import org.bytedeco.opencv.global.opencv_core;
|
||||||
|
import org.bytedeco.opencv.global.opencv_imgcodecs;
|
||||||
import org.bytedeco.opencv.global.opencv_imgproc;
|
import org.bytedeco.opencv.global.opencv_imgproc;
|
||||||
import org.bytedeco.opencv.opencv_core.Mat;
|
import org.bytedeco.opencv.opencv_core.*;
|
||||||
import org.bytedeco.opencv.opencv_core.Size;
|
|
||||||
import org.bytedeco.opencv.opencv_core.UMat;
|
|
||||||
import org.bytedeco.opencv.opencv_java;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.opencv.core.MatOfByte;
|
import org.opencv.core.MatOfByte;
|
||||||
import org.opencv.imgcodecs.Imgcodecs;
|
import org.opencv.imgcodecs.Imgcodecs;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.Inet4Address;
|
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class SomeCodes {
|
public class SomeCodes {
|
||||||
static{
|
static{
|
||||||
Loader.load(opencv_java.class);
|
//Loader.load(opencv_java.class);
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
LoadLinuxLibrary("/usr/local/lib/libopencv_java4100.so");
|
||||||
|
} else Logger.info("Platform is not Linux, loading standard opencv");
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static String currentDirectory = System.getProperty("user.dir");
|
public final static String currentDirectory = System.getProperty("user.dir");
|
||||||
public final static Path audioPath = Path.of(currentDirectory, "audiofiles");
|
public final static Path audioPath = Path.of(currentDirectory, "audiofiles");
|
||||||
private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
||||||
public static final OpenCVFrameConverter.ToMat matConverter = new OpenCVFrameConverter.ToMat();
|
|
||||||
public static final OpenCVFrameConverter.ToOrgOpenCvCoreMat CoreMatConverter = new OpenCVFrameConverter.ToOrgOpenCvCoreMat();
|
public static final OpenCVFrameConverter.ToOrgOpenCvCoreMat CoreMatConverter = new OpenCVFrameConverter.ToOrgOpenCvCoreMat();
|
||||||
|
|
||||||
public static final Java2DFrameConverter frameConverter = new Java2DFrameConverter();
|
|
||||||
public static final Path logsPath = Path.of(currentDirectory, "logs");
|
|
||||||
public static final boolean haveOpenCL = opencv_core.haveOpenCL();
|
public static final boolean haveOpenCL = opencv_core.haveOpenCL();
|
||||||
public static boolean useOpenCL;
|
public static boolean useOpenCL;
|
||||||
private static final Base64.Encoder base64encoder = java.util.Base64.getEncoder();
|
private static final Base64.Encoder base64encoder = java.util.Base64.getEncoder();
|
||||||
|
public static final Gson gson = new Gson();
|
||||||
|
public static final double KB_threshold = 1024.0;
|
||||||
|
public static final double MB_threshold = 1024.0 * 1024.0;
|
||||||
|
public static final double GB_threshold = 1024.0 * 1024.0 * 1024.0;
|
||||||
|
|
||||||
|
private static void LoadLinuxLibrary(String library){
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
File ff = new File(library);
|
||||||
|
if (ff.isFile()){
|
||||||
|
Logger.info("Loading library: "+library);
|
||||||
|
System.load(ff.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
public static String[] GetAudioFiles(){
|
public static String[] GetAudioFiles(){
|
||||||
try{
|
try{
|
||||||
return Files.list(audioPath).map(f -> f.getFileName().toString()).toArray(String[]::new);
|
return Files.list(audioPath).map(f -> f.getFileName().toString()).toArray(String[]::new);
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Error getting audio files: "+e.getMessage());
|
Logger.error("Error getting audio files: "+e.getMessage());
|
||||||
}
|
}
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String LocalDateTimeToString(LocalDateTime x){
|
return new String[0];
|
||||||
return x.format(dtf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String ExtractResource(String filename, String targetdirectory){
|
public static String ExtractResource(String filename, String targetdirectory){
|
||||||
@@ -83,13 +89,7 @@ public class SomeCodes {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean ValidDirectory(String path){
|
|
||||||
if (ValidString(path)){
|
|
||||||
File ff = new File(path);
|
|
||||||
return ff.isDirectory();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean ValidFile(String filename){
|
public static boolean ValidFile(String filename){
|
||||||
if (ValidString(filename)){
|
if (ValidString(filename)){
|
||||||
@@ -116,6 +116,13 @@ public class SomeCodes {
|
|||||||
return defaultspeed;
|
return defaultspeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean ValidIntArray(int[] xx){
|
||||||
|
if (xx!=null){
|
||||||
|
return xx.length>0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean ValidInteger(String x){
|
public static boolean ValidInteger(String x){
|
||||||
try{
|
try{
|
||||||
Integer.parseInt(x);
|
Integer.parseInt(x);
|
||||||
@@ -125,6 +132,15 @@ public class SomeCodes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String IntArrayToString(int[] id){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i : id){
|
||||||
|
if (!sb.isEmpty()) sb.append(",");
|
||||||
|
sb.append(i);
|
||||||
|
}
|
||||||
|
return "["+ sb +"]";
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean ValidPortNumber(int port){
|
public static boolean ValidPortNumber(int port){
|
||||||
return port>0 && port<65536;
|
return port>0 && port<65536;
|
||||||
}
|
}
|
||||||
@@ -138,71 +154,126 @@ public class SomeCodes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean ValidIPV4(String ipaddress){
|
public static String MatToBase64(Mat mat){
|
||||||
if (ValidString(ipaddress)){
|
if (mat!=null){
|
||||||
|
if (mat.cols()>0 && mat.rows()>0){
|
||||||
try{
|
try{
|
||||||
InetAddress inet = InetAddress.getByName(ipaddress);
|
BytePointer mob = new BytePointer();
|
||||||
if (inet instanceof Inet4Address){
|
opencv_imgcodecs.imencode(".jpg", mat, mob);
|
||||||
if (inet.getHostAddress().equals(ipaddress)){
|
byte[] data = new byte[(int) mob.limit()];
|
||||||
return true;
|
mob.get(data);
|
||||||
|
String base64 = base64encoder.encodeToString(data);
|
||||||
|
mob.deallocate();
|
||||||
|
return base64;
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error converting Mat to Base64: "+e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean ValidIPV6(String ipaddress){
|
|
||||||
if (ValidString(ipaddress)){
|
|
||||||
try{
|
|
||||||
InetAddress inet = InetAddress.getByName(ipaddress);
|
|
||||||
if (inet instanceof Inet6Address){
|
|
||||||
if (inet.getHostAddress().equals(ipaddress)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String GetFileName(String filepath){
|
|
||||||
if (ValidString(filepath)){
|
|
||||||
File ff = new File(filepath);
|
|
||||||
if (ff.isFile()){
|
|
||||||
return ff.getName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String MatToBase64(org.opencv.core.Mat mat){
|
||||||
// Function ini pakai opencv, bukan javacv, jadi perlu Loader.load(opencv_java.class) di awal
|
if (mat!=null){
|
||||||
// lebih optimal untuk konversi frame ke base64
|
if (mat.cols()>0 && mat.rows()>0){
|
||||||
public static String FrameToBase64(Frame frame){
|
try{
|
||||||
if (frame!=null){
|
|
||||||
org.opencv.core.Mat converted = CoreMatConverter.convert(frame);
|
|
||||||
if (converted!=null){
|
|
||||||
if (!converted.empty()){
|
|
||||||
MatOfByte mob = new MatOfByte();
|
MatOfByte mob = new MatOfByte();
|
||||||
Imgcodecs.imencode(".jpg", converted, mob);
|
Imgcodecs.imencode(".jpg", mat, mob);
|
||||||
byte[] jpgdata = mob.toArray();
|
String base64 = base64encoder.encodeToString(mob.toArray());
|
||||||
mob.release();
|
mob.release();
|
||||||
converted.release();
|
return base64;
|
||||||
return base64encoder.encodeToString(jpgdata);
|
} catch (Exception e){
|
||||||
|
Logger.error("Error converting Mat to Base64: "+e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Frame MatToFrame(Mat mat){
|
||||||
|
if (mat!=null && mat.cols()>0 && mat.rows()>0){
|
||||||
|
try{
|
||||||
|
return CoreMatConverter.convert(mat);
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error converting Mat to Frame: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Frame MatToFrame(org.opencv.core.Mat mat){
|
||||||
|
if (mat!=null && mat.cols()>0 && mat.rows()>0){
|
||||||
|
try{
|
||||||
|
return CoreMatConverter.convert(mat);
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error converting Mat to Frame: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] getColumnValues(Mat mat, int colIndex, int[] rowIndices) {
|
||||||
|
if (mat.empty()) {
|
||||||
|
throw new IllegalArgumentException("Mat is empty.");
|
||||||
|
}
|
||||||
|
if (colIndex < 0 || colIndex >= mat.cols()) {
|
||||||
|
throw new IllegalArgumentException("Column index out of range.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the column as a new Mat
|
||||||
|
Mat colMat = mat.col(colIndex);
|
||||||
|
|
||||||
|
// Create an indexer for efficient access
|
||||||
|
DoubleIndexer indexer = colMat.createIndexer();
|
||||||
|
|
||||||
|
// Extract specific row values
|
||||||
|
double[] values = new double[rowIndices.length];
|
||||||
|
for (int i = 0; i < rowIndices.length; i++) {
|
||||||
|
values[i] = indexer.get(rowIndices[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Point toPoint(Point2d p) {
|
||||||
|
return new Point((int)p.x(), (int)p.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Size toSize(Size2d s) {
|
||||||
|
return new Size((int)s.width(), (int)s.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Mat getSubmat(Mat mask, int colIndex, int startRow, int endRow) {
|
||||||
|
if (mask.empty()) {
|
||||||
|
throw new IllegalArgumentException("Mat is empty.");
|
||||||
|
}
|
||||||
|
if (colIndex < 0 || colIndex >= mask.cols()) {
|
||||||
|
throw new IllegalArgumentException("Column index out of range.");
|
||||||
|
}
|
||||||
|
if (startRow < 0 || endRow > mask.rows() || startRow >= endRow) {
|
||||||
|
throw new IllegalArgumentException("Invalid row range.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract column i
|
||||||
|
Mat colMat = mask.col(colIndex);
|
||||||
|
|
||||||
|
// Extract submatrix from row startRow to endRow
|
||||||
|
return colMat.rowRange(startRow, endRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load properties file
|
||||||
|
* @param filename properties file name
|
||||||
|
* @return Properties object loaded, or empty new Properties object if error
|
||||||
|
*/
|
||||||
public static @NotNull Properties LoadProperties(String filename){
|
public static @NotNull Properties LoadProperties(String filename){
|
||||||
try{
|
try{
|
||||||
InputStream is = new FileInputStream(filename);
|
File ff = new File(currentDirectory, filename);
|
||||||
|
InputStream is = new FileInputStream(ff);
|
||||||
Properties prop = new Properties();
|
Properties prop = new Properties();
|
||||||
prop.load(is);
|
prop.load(is);
|
||||||
return prop;
|
return prop;
|
||||||
@@ -212,9 +283,16 @@ public class SomeCodes {
|
|||||||
return new Properties();
|
return new Properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save properties file
|
||||||
|
* @param prop Properties object to save
|
||||||
|
* @param filename properties file name
|
||||||
|
* @return true if success, false otherwise
|
||||||
|
*/
|
||||||
public static boolean SaveProperties(Properties prop, String filename){
|
public static boolean SaveProperties(Properties prop, String filename){
|
||||||
try{
|
try{
|
||||||
OutputStream os = new FileOutputStream(filename);
|
File ff = new File(currentDirectory, filename);
|
||||||
|
OutputStream os = new FileOutputStream(ff);
|
||||||
prop.store(os, null);
|
prop.store(os, null);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
@@ -229,6 +307,7 @@ public class SomeCodes {
|
|||||||
return config.getProperty(key, null);
|
return config.getProperty(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Mat ResizeMat(Mat source, int width, int height){
|
public static Mat ResizeMat(Mat source, int width, int height){
|
||||||
Size sz = new Size(width, height);
|
Size sz = new Size(width, height);
|
||||||
Mat dest = new Mat();
|
Mat dest = new Mat();
|
||||||
@@ -244,9 +323,35 @@ public class SomeCodes {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Frame ResizeFrame(Frame source, int width, int height){
|
|
||||||
Mat mat = matConverter.convertToMat(source);
|
/**
|
||||||
Mat resized = ResizeMat(mat, width, height);
|
* check if an ip address is reachable
|
||||||
return matConverter.convert(resized);
|
* @param ipaddress ip address to check
|
||||||
|
* @return true if valid and reachable, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean IpIsReachable(String ipaddress){
|
||||||
|
try{
|
||||||
|
InetAddress inet = InetAddress.getByName(ipaddress);
|
||||||
|
return inet.isReachable(1000);
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error checking ip address: "+e.getMessage());
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sleep(int milliseconds){
|
||||||
|
try{
|
||||||
|
Thread.sleep(milliseconds);
|
||||||
|
} catch (Exception e){
|
||||||
|
Logger.error("Error sleeping: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GpuMat ConvertToGpuMat(Mat mat){
|
||||||
|
GpuMat gmat = new GpuMat();
|
||||||
|
gmat.upload(mat);
|
||||||
|
return gmat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/main/java/SBC/CpuInfo.java
Normal file
8
src/main/java/SBC/CpuInfo.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
public class CpuInfo {
|
||||||
|
public int processorCount;
|
||||||
|
public String revision;
|
||||||
|
public String serial;
|
||||||
|
public String model;
|
||||||
|
}
|
||||||
@@ -1,23 +1,21 @@
|
|||||||
package SBC;
|
package SBC;
|
||||||
|
|
||||||
import com.sun.jna.Platform;
|
import com.sun.jna.Platform;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class GPIO {
|
public class GPIO {
|
||||||
|
|
||||||
private static final Path gpioPath = Path.of("/sys/class/gpio");
|
public static final Path gpioPath = Path.of("/sys/class/gpio");
|
||||||
private static final Path gpioExportPath = Path.of("/sys/class/gpio/export");
|
private static final Path gpioExportPath = Path.of("/sys/class/gpio/export");
|
||||||
private static final Path gpioUnexportPath = Path.of("/sys/class/gpio/unexport");
|
private static final Path gpioUnexportPath = Path.of("/sys/class/gpio/unexport");
|
||||||
|
|
||||||
|
|
||||||
public static boolean IsRaspberry64(){
|
public static boolean HaveGPIO(){
|
||||||
if (Platform.isLinux()){
|
if (Platform.isLinux()){
|
||||||
if (Platform.isARM()){
|
|
||||||
if (Platform.is64Bit()){
|
|
||||||
if (gpioPath.toFile().isDirectory()){
|
if (gpioPath.toFile().isDirectory()){
|
||||||
if (gpioExportPath.toFile().isFile()){
|
if (gpioExportPath.toFile().isFile()){
|
||||||
if (gpioUnexportPath.toFile().isFile()){
|
if (gpioUnexportPath.toFile().isFile()){
|
||||||
@@ -25,8 +23,6 @@ public class GPIO {
|
|||||||
} else Logger.error("GPIO unexport path is not found");
|
} else Logger.error("GPIO unexport path is not found");
|
||||||
} else Logger.error("GPIO export path is not found");
|
} else Logger.error("GPIO export path is not found");
|
||||||
} else Logger.error("GPIO path is not found");
|
} else Logger.error("GPIO path is not found");
|
||||||
} else Logger.info("Device is not 64 bit");
|
|
||||||
} else Logger.info("Device is not ARM");
|
|
||||||
} else Logger.info("OS is not Linux");
|
} else Logger.info("OS is not Linux");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -36,8 +32,8 @@ public class GPIO {
|
|||||||
* @param pin GPIO pin number
|
* @param pin GPIO pin number
|
||||||
* @return true if the pin is already exported
|
* @return true if the pin is already exported
|
||||||
*/
|
*/
|
||||||
public static boolean GpioPinExists(int pin){
|
public static boolean GpioPinExists(@NotNull JetsonOrinPins pin){
|
||||||
Path pinPath = gpioPath.resolve("gpio"+pin);
|
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber);
|
||||||
return pinPath.toFile().isDirectory();
|
return pinPath.toFile().isDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,32 +42,33 @@ public class GPIO {
|
|||||||
* @param pin GPIO pin number
|
* @param pin GPIO pin number
|
||||||
* @return true if the pin is successfully exported
|
* @return true if the pin is successfully exported
|
||||||
*/
|
*/
|
||||||
public static boolean ExportPin(int pin){
|
public static boolean ExportPin(@NotNull JetsonOrinPins pin){
|
||||||
try{
|
try{
|
||||||
if (Files.isWritable(gpioExportPath)){
|
if (Files.isWritable(gpioExportPath)){
|
||||||
Files.write(gpioExportPath, String.valueOf(pin).getBytes());
|
Files.write(gpioExportPath, String.valueOf(pin.gpionumber).getBytes());
|
||||||
Logger.info("Pin "+pin+" exported");
|
Logger.info("Pin "+pin.pin+" exported");
|
||||||
return GpioPinExists(pin);
|
return GpioPinExists(pin);
|
||||||
} else Logger.error("GPIO export path is not writable");
|
} else Logger.error("GPIO export path is not writable");
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to export pin: "+pin+", Message: "+e.getMessage());
|
Logger.error("Failed to export pin: "+pin.pin+", Message: "+e.getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unexport the pin
|
* Unexport the pin
|
||||||
* @param pin GPIO pin number
|
* @param pin GPIO pin number
|
||||||
* @return true if the pin is successfully unexported
|
* @return true if the pin is successfully unexported
|
||||||
*/
|
*/
|
||||||
public static boolean UnexportPin(int pin){
|
public static boolean UnexportPin(@NotNull JetsonOrinPins pin){
|
||||||
if (Files.isWritable(gpioUnexportPath)){
|
if (Files.isWritable(gpioUnexportPath)){
|
||||||
try{
|
try{
|
||||||
Files.write(gpioUnexportPath, String.valueOf(pin).getBytes());
|
Files.write(gpioUnexportPath, String.valueOf(pin.gpionumber).getBytes());
|
||||||
Logger.info("Pin "+pin+" unexported");
|
Logger.info("Pin "+pin.pin+" unexported");
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to unexport pin: "+pin+", Message: "+e.getMessage());
|
Logger.error("Failed to unexport pin: "+pin.pin+", Message: "+e.getMessage());
|
||||||
}
|
}
|
||||||
} else Logger.error("GPIO unexport path is not writable");
|
} else Logger.error("GPIO unexport path is not writable");
|
||||||
|
|
||||||
@@ -83,17 +80,18 @@ public class GPIO {
|
|||||||
* @param pin GPIO pin number
|
* @param pin GPIO pin number
|
||||||
* @return "in" if the pin is input, "out" if the pin is output, "unknown" if the direction is unknown
|
* @return "in" if the pin is input, "out" if the pin is output, "unknown" if the direction is unknown
|
||||||
*/
|
*/
|
||||||
public static String GetPinDirection(int pin){
|
@SuppressWarnings("unused")
|
||||||
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("direction");
|
public static String GetPinDirection(@NotNull JetsonOrinPins pin){
|
||||||
|
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("direction");
|
||||||
if (pinPath.toFile().isFile()){
|
if (pinPath.toFile().isFile()){
|
||||||
if (Files.isReadable(pinPath)){
|
if (Files.isReadable(pinPath)){
|
||||||
try{
|
try{
|
||||||
return Files.readString(pinPath).trim();
|
return Files.readString(pinPath).trim();
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to read pin direction: "+pin+", Message: "+e.getMessage());
|
Logger.error("Failed to read pin direction: "+pin.pin+", Message: "+e.getMessage());
|
||||||
}
|
}
|
||||||
} else Logger.error("Pin direction file is not readable: "+pin);
|
} else Logger.error("Pin direction file is not readable: "+pin.pin);
|
||||||
} else Logger.error("Pin direction file not found: "+pin);
|
} else Logger.error("Pin direction file not found: "+pin.pin);
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,22 +101,22 @@ public class GPIO {
|
|||||||
* @param direction "in" for input, "out" for output
|
* @param direction "in" for input, "out" for output
|
||||||
* @return true if the direction is successfully set
|
* @return true if the direction is successfully set
|
||||||
*/
|
*/
|
||||||
public static boolean SetPinDirection(int pin, String direction){
|
public static boolean SetPinDirection(@NotNull JetsonOrinPins pin, String direction){
|
||||||
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("direction");
|
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("direction");
|
||||||
if (pinPath.toFile().isFile()){
|
if (pinPath.toFile().isFile()){
|
||||||
if (Files.isWritable(pinPath)){
|
if (Files.isWritable(pinPath)){
|
||||||
direction = direction.trim().toLowerCase();
|
direction = direction.trim().toLowerCase();
|
||||||
if ("in".equals(direction) || "out".equals(direction)){
|
if ("in".equals(direction) || "out".equals(direction)){
|
||||||
try{
|
try{
|
||||||
Files.write(pinPath, direction.getBytes());
|
Files.write(pinPath, direction.getBytes());
|
||||||
Logger.info("Pin "+pin+" direction set to "+direction);
|
Logger.info("Pin "+pin.pin+" direction set to "+direction);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to set pin direction: "+pin+", Message: "+e.getMessage());
|
Logger.error("Failed to set pin direction: "+pin.pin+", Message: "+e.getMessage());
|
||||||
}
|
}
|
||||||
} else Logger.error("Invalid direction: "+direction);
|
} else Logger.error("Invalid direction: "+direction);
|
||||||
} else Logger.error("Pin direction file is not writable: "+pin);
|
} else Logger.error("Pin direction file is not writable: "+pin.pin);
|
||||||
} else Logger.error("Pin direction file not found: "+pin);
|
} else Logger.error("Pin direction file not found: "+pin.pin);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,19 +126,20 @@ public class GPIO {
|
|||||||
* @param isON true to set the pin value to 1, false to set the pin value to 0
|
* @param isON true to set the pin value to 1, false to set the pin value to 0
|
||||||
* @return true if the value is successfully set
|
* @return true if the value is successfully set
|
||||||
*/
|
*/
|
||||||
public static boolean SetValue(int pin, boolean isON){
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("value");
|
public static boolean SetValue(@NotNull JetsonOrinPins pin, boolean isON){
|
||||||
|
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("value");
|
||||||
if (pinPath.toFile().isFile()){
|
if (pinPath.toFile().isFile()){
|
||||||
if (Files.isWritable(pinPath)){
|
if (Files.isWritable(pinPath)){
|
||||||
try{
|
try{
|
||||||
Files.write(pinPath, isON?"1".getBytes():"0".getBytes());
|
Files.write(pinPath, isON?"1".getBytes():"0".getBytes());
|
||||||
Logger.info("Pin "+pin+" value set to "+(isON?"1":"0"));
|
//Logger.info("Pin "+pin.pin+" value set to "+(isON?"1":"0"));
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to set pin value: "+pin+", Message: "+e.getMessage());
|
Logger.error("Failed to set pin value: "+pin.pin+", Message: "+e.getMessage());
|
||||||
}
|
}
|
||||||
} else Logger.error("Pin value file is not writable: "+pin);
|
} else Logger.error("Pin value file is not writable: "+pin.pin);
|
||||||
} else Logger.error("Pin value file not found: "+pin);
|
} else Logger.error("Pin value file not found: "+pin.pin);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,17 +148,18 @@ public class GPIO {
|
|||||||
* @param pin GPIO pin number
|
* @param pin GPIO pin number
|
||||||
* @return "1" if the pin value is 1, "0" if the pin value is 0, "unknown" if the value is unknown
|
* @return "1" if the pin value is 1, "0" if the pin value is 0, "unknown" if the value is unknown
|
||||||
*/
|
*/
|
||||||
public static String GetValue(int pin){
|
@SuppressWarnings("unused")
|
||||||
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("value");
|
public static String GetValue(@NotNull JetsonOrinPins pin){
|
||||||
|
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("value");
|
||||||
if (pinPath.toFile().isFile()){
|
if (pinPath.toFile().isFile()){
|
||||||
if (Files.isReadable(pinPath)){
|
if (Files.isReadable(pinPath)){
|
||||||
try{
|
try{
|
||||||
return Files.readString(pinPath).trim();
|
return Files.readString(pinPath).trim();
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to read pin value: "+pin+", Message: "+e.getMessage());
|
Logger.error("Failed to read pin value: "+pin.pin+", Message: "+e.getMessage());
|
||||||
}
|
}
|
||||||
} else Logger.error("Pin value file is not readable: "+pin);
|
} else Logger.error("Pin value file is not readable: "+pin.pin);
|
||||||
} else Logger.error("Pin value file not found: "+pin);
|
} else Logger.error("Pin value file not found: "+pin.pin);
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/main/java/SBC/I2C_BUS.java
Normal file
38
src/main/java/SBC/I2C_BUS.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class I2C_BUS {
|
||||||
|
private final Linux_C_lib C = Linux_C_lib.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
private @Getter boolean opened = false;
|
||||||
|
private final @Getter String i2c_name;
|
||||||
|
private @Getter int i2c_handle = -1;
|
||||||
|
|
||||||
|
public I2C_BUS(int bus_number){
|
||||||
|
this.i2c_name = "/dev/i2c-"+bus_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean Open_Bus(){
|
||||||
|
if (!opened){
|
||||||
|
final int O_RDWR = 0x00000002;
|
||||||
|
i2c_handle = C.open(i2c_name, O_RDWR);
|
||||||
|
if (i2c_handle>=0){
|
||||||
|
opened = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close_Bus(){
|
||||||
|
if (opened){
|
||||||
|
if (i2c_handle>=0){
|
||||||
|
C.close(i2c_handle);
|
||||||
|
i2c_handle = -1;
|
||||||
|
}
|
||||||
|
opened = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
147
src/main/java/SBC/I2C_Device.java
Normal file
147
src/main/java/SBC/I2C_Device.java
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class I2C_Device {
|
||||||
|
|
||||||
|
|
||||||
|
Linux_C_lib C = Linux_C_lib.INSTANCE;
|
||||||
|
private @Getter int bus_handle;
|
||||||
|
private @Getter int device_address;
|
||||||
|
private @Getter int dev_handle;
|
||||||
|
private @Getter boolean opened = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create I2C Device
|
||||||
|
* @param bus_handle I2C Bus Handle, from opening I2C_Bus
|
||||||
|
* @param device_address I2C Device Address
|
||||||
|
*/
|
||||||
|
public I2C_Device(int bus_handle, int device_address){
|
||||||
|
opened = false;
|
||||||
|
if (bus_handle<0 || device_address<0) return;
|
||||||
|
this.bus_handle = bus_handle;
|
||||||
|
this.device_address = device_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open I2C Device in Slave mode
|
||||||
|
* @return true if successfully opened
|
||||||
|
*/
|
||||||
|
public boolean Open_Slave(){
|
||||||
|
boolean sucess = false;
|
||||||
|
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SLAVE, device_address);
|
||||||
|
if (dev_handle>=0){
|
||||||
|
sucess = true;
|
||||||
|
}
|
||||||
|
opened = sucess;
|
||||||
|
return opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open I2C Device in Slave mode with Force
|
||||||
|
* @return true if successfully opened
|
||||||
|
*/
|
||||||
|
public boolean Open_SlaveForce(){
|
||||||
|
boolean sucess = false;
|
||||||
|
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SLAVE_FORCE, device_address);
|
||||||
|
if (dev_handle>=0){
|
||||||
|
C.ioctl(bus_handle,I2C_Flags.I2C_RETRIES, 3);
|
||||||
|
C.ioctl(bus_handle,I2C_Flags.I2C_TIMEOUT, 1000);
|
||||||
|
sucess = true;
|
||||||
|
}
|
||||||
|
opened = sucess;
|
||||||
|
return opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open I2C Device in Read Write mode
|
||||||
|
* @return true if successfully opened
|
||||||
|
*/
|
||||||
|
public boolean Open_RDWR(){
|
||||||
|
boolean sucess = false;
|
||||||
|
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_RDWR, device_address);
|
||||||
|
if (dev_handle>=0){
|
||||||
|
sucess = true;
|
||||||
|
}
|
||||||
|
opened = sucess;
|
||||||
|
return opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open I2C Device in SMBus mode
|
||||||
|
* @return true if successfully opened
|
||||||
|
*/
|
||||||
|
public boolean Open_SMBus(){
|
||||||
|
boolean sucess = false;
|
||||||
|
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SMBUS, device_address);
|
||||||
|
if (dev_handle>=0){
|
||||||
|
sucess = true;
|
||||||
|
}
|
||||||
|
opened = sucess;
|
||||||
|
return opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close I2C Device
|
||||||
|
*/
|
||||||
|
public void Close(){
|
||||||
|
C.close(dev_handle);
|
||||||
|
opened = false;
|
||||||
|
dev_handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Bytes to I2C Device
|
||||||
|
* @param data bytes to write
|
||||||
|
* @return number of bytes written
|
||||||
|
*/
|
||||||
|
public int WriteBytes(byte[] data){
|
||||||
|
if (bus_handle<0 || dev_handle<0 || device_address<0) return -1;
|
||||||
|
return C.write(bus_handle, data, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Byte to I2C Device
|
||||||
|
* @param register_address register address
|
||||||
|
* @param data byte to write
|
||||||
|
* @return number of bytes written
|
||||||
|
*/
|
||||||
|
public int WriteBytes(int register_address, byte data){
|
||||||
|
byte[] cmd = new byte[2];
|
||||||
|
cmd[0] = (byte) register_address;
|
||||||
|
cmd[1] = data;
|
||||||
|
return WriteBytes(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write Bytes to I2C Device
|
||||||
|
* @param register_address register address
|
||||||
|
* @param data bytes to write
|
||||||
|
* @return number of bytes written
|
||||||
|
*/
|
||||||
|
public int WriteBytes(int register_address, byte[] data){
|
||||||
|
byte[] cmd = new byte[data.length+1];
|
||||||
|
cmd[0] = (byte) register_address;
|
||||||
|
System.arraycopy(data, 0, cmd, 1, data.length);
|
||||||
|
return WriteBytes(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Bytes from I2C Device
|
||||||
|
* @param readsize number of bytes to read
|
||||||
|
* @return bytes read
|
||||||
|
*/
|
||||||
|
public byte[] ReadBytes(int readsize){
|
||||||
|
if (bus_handle<0 || dev_handle<0 || device_address<0) return null;
|
||||||
|
byte[] data = new byte[readsize];
|
||||||
|
int read = C.read(bus_handle, data, readsize);
|
||||||
|
if (read<0) return null;
|
||||||
|
if (read<readsize){
|
||||||
|
byte[] temp = new byte[read];
|
||||||
|
System.arraycopy(data, 0, temp, 0, read);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/main/java/SBC/I2C_Flags.java
Normal file
13
src/main/java/SBC/I2C_Flags.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
public class I2C_Flags {
|
||||||
|
public final static int I2C_RETRIES = 0x701; /* number of times a device address should be polled when not acknowledging */
|
||||||
|
public final static int I2C_TIMEOUT = 0x702; /* set timeout in units of 10 ms */
|
||||||
|
public final static int I2C_SLAVE = 0x703; /* Command at ioctl, means : Use this slave address */
|
||||||
|
public final static int I2C_TENBIT = 0x704; /* 0 for 7 bit addrs, != 0 for 10 bit */
|
||||||
|
public final static int I2C_FUNCS = 0x705; /* Command at ioctl, means : Get the adapter functionality */
|
||||||
|
public final static int I2C_SLAVE_FORCE = 0x706; /* Command at ioctl, means : Use this slave address, even if it is already in use by a driver! */
|
||||||
|
public final static int I2C_RDWR = 0x707; /* Command at ioctl, means : Combined R/W transfer (one stop only) */
|
||||||
|
public final static int I2C_PEC = 0x708; /* != 0 to use PEC with SMBus */
|
||||||
|
public final static int I2C_SMBUS = 0x720; /* SMBus transfer */
|
||||||
|
}
|
||||||
38
src/main/java/SBC/JetsonOrinPins.java
Normal file
38
src/main/java/SBC/JetsonOrinPins.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source : <a href="https://jetsonhacks.com/nvidia-jetson-orin-nano-gpio-header-pinout/">...</a>
|
||||||
|
*/
|
||||||
|
public enum JetsonOrinPins {
|
||||||
|
Pin07(7,"AUDIO_MCLK",144),
|
||||||
|
Pin11(11,"UART1_RTS",112),
|
||||||
|
Pin12(12,"I2S0_SCLK",50),
|
||||||
|
Pin13(13,"SPI1_SCK",122),
|
||||||
|
Pin15(15,"GPIO12",85),
|
||||||
|
Pin16(16,"SPI1_CS1",126),
|
||||||
|
Pin18(18,"SPI1_CS0",125),
|
||||||
|
Pin19(19,"SPI0_MOSI",135),
|
||||||
|
Pin21(21,"SPI0_MISO",134),
|
||||||
|
Pin22(22,"SPI1_MISO",123),
|
||||||
|
Pin23(23,"SPI0_SCK",133),
|
||||||
|
Pin24(24,"SPI0_CS0",136),
|
||||||
|
Pin25(26,"SPI0_CS1",137),
|
||||||
|
Pin29(29,"GPIO01",105),
|
||||||
|
Pin31(31,"GPIO11",106),
|
||||||
|
Pin32(32,"GPIO07",41),
|
||||||
|
Pin33(33,"GPIO13",43),
|
||||||
|
Pin35(35,"I2S0_FS",53),
|
||||||
|
Pin36(36,"UART1_CTS",113),
|
||||||
|
Pin37(37,"SPI1_MOSI",124),
|
||||||
|
Pin38(38,"I2S0_SDIN",52),
|
||||||
|
Pin40(40,"I2S0_SDOUT",51);
|
||||||
|
public final int pin;
|
||||||
|
public final String name;
|
||||||
|
public final int gpionumber;
|
||||||
|
|
||||||
|
JetsonOrinPins(int pin, String name, int gpionumber){
|
||||||
|
this.pin = pin;
|
||||||
|
this.name = name;
|
||||||
|
this.gpionumber = gpionumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/main/java/SBC/LibGpioD.java
Normal file
20
src/main/java/SBC/LibGpioD.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import com.sun.jna.Library;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
public interface LibGpioD extends Library {
|
||||||
|
String CHIP_NAME = "/dev/gpiochip0"; // First GPIO chip
|
||||||
|
LibGpioD Instance = Native.load("gpiod", LibGpioD.class);
|
||||||
|
|
||||||
|
Pointer gpiod_chip_open(String chipname);
|
||||||
|
void gpiod_chip_close(Pointer chip);
|
||||||
|
|
||||||
|
Pointer gpiod_line_get(Pointer chip, int offset);
|
||||||
|
int gpiod_line_request_output(Pointer line, String consumer, int default_val);
|
||||||
|
int gpiod_line_request_input(Pointer line, String consumer);
|
||||||
|
int gpiod_line_set_value(Pointer line, int value);
|
||||||
|
int gpiod_line_get_value(Pointer line);
|
||||||
|
void gpiod_line_release(Pointer line);
|
||||||
|
}
|
||||||
69
src/main/java/SBC/Linux_C_lib.java
Normal file
69
src/main/java/SBC/Linux_C_lib.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.NativeLong;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
public interface Linux_C_lib extends com.sun.jna.Library {
|
||||||
|
Linux_C_lib INSTANCE = (Linux_C_lib) Native.load("c", Linux_C_lib.class);
|
||||||
|
|
||||||
|
long memcpy(int[] dst, short[] src, long n);
|
||||||
|
|
||||||
|
int memcpy(int[] dst, short[] src, int n);
|
||||||
|
|
||||||
|
int pipe(int[] fds);
|
||||||
|
|
||||||
|
int tcdrain(int fd);
|
||||||
|
|
||||||
|
int fcntl(int bus_handle, int command, int args);
|
||||||
|
|
||||||
|
int ioctl(int bus_handle, int command, int args);
|
||||||
|
|
||||||
|
int ioctl(int bus_handle, int command, int... args);
|
||||||
|
|
||||||
|
int ioctl(int bus_handle, int command, Pointer args);
|
||||||
|
|
||||||
|
int open(String path, int flags);
|
||||||
|
|
||||||
|
int close(int fd);
|
||||||
|
|
||||||
|
int write(int bus_handle, byte[] buffer, int count);
|
||||||
|
|
||||||
|
int read(int bus_handle, byte[] buffer, int count);
|
||||||
|
|
||||||
|
long write(int bus_handle, byte[] buffer, long count);
|
||||||
|
|
||||||
|
long read(int bus_handle, byte[] buffer, long count);
|
||||||
|
|
||||||
|
int select(int n, int[] read, int[] write, int[] error, timeval timeout);
|
||||||
|
|
||||||
|
int poll(int[] fds, int nfds, int timeout);
|
||||||
|
|
||||||
|
int tcflush(int fd, int qs);
|
||||||
|
|
||||||
|
void perror(String msg);
|
||||||
|
|
||||||
|
int tcsendbreak(int fd, int duration);
|
||||||
|
|
||||||
|
public class timeval extends Structure {
|
||||||
|
public NativeLong tv_sec;
|
||||||
|
public NativeLong tv_usec;
|
||||||
|
|
||||||
|
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList(//
|
||||||
|
"tv_sec",//
|
||||||
|
"tv_usec"//
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public timeval(long second, long usecond) {
|
||||||
|
tv_sec = new NativeLong(second);
|
||||||
|
tv_usec = new NativeLong(usecond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/main/java/SBC/NetworkTransmitReceiveInfo.java
Normal file
84
src/main/java/SBC/NetworkTransmitReceiveInfo.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static Other.SomeCodes.ValidString;
|
||||||
|
|
||||||
|
public class NetworkTransmitReceiveInfo {
|
||||||
|
public String name;
|
||||||
|
public long bytesReceived;
|
||||||
|
public long packetsReceived;
|
||||||
|
public long errorsReceived;
|
||||||
|
public long droppedReceived;
|
||||||
|
public long fifoReceived;
|
||||||
|
public long frameReceived;
|
||||||
|
public long compressedReceived;
|
||||||
|
public long multicastReceived;
|
||||||
|
public long bytesTransmitted;
|
||||||
|
public long packetsTransmitted;
|
||||||
|
public long errorsTransmitted;
|
||||||
|
public long droppedTransmitted;
|
||||||
|
public long fifoTransmitted;
|
||||||
|
public long collsTransmitted;
|
||||||
|
public long carrierTransmitted;
|
||||||
|
public long compressedTransmitted;
|
||||||
|
public long timetick;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the download speed
|
||||||
|
* @param prev Previous NetworkTransmitReceiveInfo
|
||||||
|
* @param unit Speed unit (KB, MB, GB)
|
||||||
|
* @return Download speed in {unit}/second
|
||||||
|
*/
|
||||||
|
public double RxSpeed(NetworkTransmitReceiveInfo prev, String unit){
|
||||||
|
if (prev!=null){
|
||||||
|
if (Objects.equals(prev.name, name)){
|
||||||
|
long timeDiff = timetick - prev.timetick;
|
||||||
|
if (timeDiff>0){
|
||||||
|
long bytesDiff = bytesReceived - prev.bytesReceived;
|
||||||
|
if (ValidString(unit)) unit = unit.toUpperCase();
|
||||||
|
Double speed = ConvertToUnit(unit, timeDiff, bytesDiff);
|
||||||
|
if (speed != null) return speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Double ConvertToUnit(String unit, long timeDiff, long bytesDiff) {
|
||||||
|
if (bytesDiff>0){
|
||||||
|
double speed = ((double) bytesDiff / timeDiff) * 1000;
|
||||||
|
return switch (unit) {
|
||||||
|
case "KB" -> speed / 1024;
|
||||||
|
case "MB" -> speed / 1024 / 1024;
|
||||||
|
case "GB" -> speed / 1024 / 1024 / 1024;
|
||||||
|
default -> speed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the upload speed
|
||||||
|
* @param prev Previous NetworkTransmitReceiveInfo
|
||||||
|
* @param unit Speed unit (KB, MB, GB)
|
||||||
|
* @return Upload speed in {unit}/second
|
||||||
|
*/
|
||||||
|
public double TxSpeed(NetworkTransmitReceiveInfo prev, String unit){
|
||||||
|
if (prev!=null){
|
||||||
|
if (Objects.equals(prev.name, name)){
|
||||||
|
long timeDiff = timetick - prev.timetick;
|
||||||
|
if (timeDiff>0){
|
||||||
|
long bytesDiff = bytesTransmitted - prev.bytesTransmitted;
|
||||||
|
if (ValidString(unit)) unit = unit.toUpperCase();
|
||||||
|
Double speed = ConvertToUnit(unit, timeDiff, bytesDiff);
|
||||||
|
if (speed != null) return speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
164
src/main/java/SBC/PCF8574.java
Normal file
164
src/main/java/SBC/PCF8574.java
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class PCF8574 extends I2C_Device{
|
||||||
|
|
||||||
|
private Byte data = 0;
|
||||||
|
private final @Getter String[] pinNames = new String[8];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new PCF8574
|
||||||
|
* @param bus_number I2C Bus Number
|
||||||
|
* @param address PCF8574 Address
|
||||||
|
*/
|
||||||
|
public PCF8574(int bus_number, int address){
|
||||||
|
super(bus_number, address);
|
||||||
|
for(int i=0; i<8; i++){
|
||||||
|
pinNames[i] = i+"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set new Pin Name
|
||||||
|
* @param pin pin number, 0-7
|
||||||
|
* @param name new name
|
||||||
|
*/
|
||||||
|
public void setPinName(int pin, String name){
|
||||||
|
if (pin<0 || pin>7) return;
|
||||||
|
pinNames[pin] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Pin Name
|
||||||
|
* @param pin pin number, 0-7
|
||||||
|
* @return pin name, or null if not available
|
||||||
|
*/
|
||||||
|
public String getPinName(int pin){
|
||||||
|
if (pin<0 || pin>7) return null;
|
||||||
|
return pinNames[pin];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set All Pins High
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
public boolean AllOn(){
|
||||||
|
if (super.isOpened()){
|
||||||
|
if (super.WriteBytes(new byte[]{(byte)0xFF})>0){
|
||||||
|
data = (byte)0xFF;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set all Pins Low
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
public boolean AllOff(){
|
||||||
|
if (super.isOpened()){
|
||||||
|
if (super.WriteBytes(new byte[]{(byte)0x00})>0){
|
||||||
|
data = (byte)0x00;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Pin by Pin Name
|
||||||
|
* @param pinName pin name
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
public boolean SetPin(String pinName){
|
||||||
|
for(int i=0; i<8; i++){
|
||||||
|
if (pinNames[i].equals(pinName)){
|
||||||
|
return SetPin(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Pin High
|
||||||
|
* @param pin pin number 0-7
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
public boolean SetPin(int pin){
|
||||||
|
if (pin<0 || pin>7) return false;
|
||||||
|
if (super.isOpened()){
|
||||||
|
synchronized (data){
|
||||||
|
data = (byte) (data | (1<<pin));
|
||||||
|
return super.WriteBytes(new byte[]{data})>0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear Pin by Pin Name
|
||||||
|
* @param pinName pin name
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
public boolean ClearPin(String pinName){
|
||||||
|
for(int i=0; i<8; i++){
|
||||||
|
if (pinNames[i].equals(pinName)){
|
||||||
|
return ClearPin(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Pin Low
|
||||||
|
* @param pin pin number 0-7
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
public boolean ClearPin(int pin){
|
||||||
|
if (pin<0 || pin>7) return false;
|
||||||
|
if (super.isOpened()){
|
||||||
|
synchronized (data){
|
||||||
|
data = (byte) (data & ~(1<<pin));
|
||||||
|
return super.WriteBytes(new byte[]{data})>0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Pin by Pin Name
|
||||||
|
* @param pinName pin name
|
||||||
|
* @return 1 if high, 0 if low, -1 if error
|
||||||
|
*/
|
||||||
|
public int ReadPin(String pinName){
|
||||||
|
for(int i=0; i<8; i++){
|
||||||
|
if (pinNames[i].equals(pinName)){
|
||||||
|
return ReadPin(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read Pin
|
||||||
|
* @param pin pin to read, 0 - 7
|
||||||
|
* @return 1 if high, 0 if low, -1 if error
|
||||||
|
*/
|
||||||
|
public int ReadPin(int pin){
|
||||||
|
if (pin<0 || pin>7) return -1;
|
||||||
|
if (super.isOpened()){
|
||||||
|
byte[] buffer = super.ReadBytes(1);
|
||||||
|
byte masker = (byte) (1<<pin);
|
||||||
|
return (buffer[0] & masker) > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/main/java/SBC/ProcessorStatus.java
Normal file
45
src/main/java/SBC/ProcessorStatus.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
public class ProcessorStatus {
|
||||||
|
public String name;
|
||||||
|
public int user;
|
||||||
|
public int nice;
|
||||||
|
public int system;
|
||||||
|
public int idle;
|
||||||
|
public int iowait;
|
||||||
|
public int irq;
|
||||||
|
public int softirq;
|
||||||
|
public int steal;
|
||||||
|
public int guest;
|
||||||
|
public int guest_nice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate total CPU time
|
||||||
|
* @return Total CPU time
|
||||||
|
*/
|
||||||
|
public int total_time(){
|
||||||
|
return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate idle CPU time
|
||||||
|
* @return Idle CPU time
|
||||||
|
*/
|
||||||
|
public int idle_time(){
|
||||||
|
return idle + iowait;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate CPU usage percentage
|
||||||
|
* @param prev Previous CPU information
|
||||||
|
* @return CPU usage percentage 0 - 100
|
||||||
|
*/
|
||||||
|
public int cpu_usage(ProcessorStatus prev){
|
||||||
|
if (prev!=null){
|
||||||
|
int total_diff = total_time() - prev.total_time();
|
||||||
|
int idle_diff = idle_time() - prev.idle_time();
|
||||||
|
return (int)(100.0 * (total_diff - idle_diff) / total_diff);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/main/java/SBC/RamInformation.java
Normal file
12
src/main/java/SBC/RamInformation.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
public class RamInformation {
|
||||||
|
public int totalKB;
|
||||||
|
public int usedKB;
|
||||||
|
public int availableKB;
|
||||||
|
public int swapTotalKB;
|
||||||
|
public int swapFreeKB;
|
||||||
|
public double RamUsagePercentage(){
|
||||||
|
return (double) usedKB / totalKB * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
179
src/main/java/SBC/SystemInformation.java
Normal file
179
src/main/java/SBC/SystemInformation.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package SBC;
|
||||||
|
|
||||||
|
import com.sun.jna.Platform;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class SystemInformation {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static int getCPUTemperature() {
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
File ff = new File("/sys/class/thermal/thermal_zone0/temp");
|
||||||
|
if (ff.isFile() && ff.canRead()){
|
||||||
|
try{
|
||||||
|
String value = Files.readString(ff.toPath()).trim();
|
||||||
|
return Integer.parseInt(value) / 1000;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetworkTransmitReceiveInfo[] getNetworkTransmitReceiveInfo(){
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
File ff = new File("/proc/net/dev");
|
||||||
|
if (ff.isFile() && ff.canRead()){
|
||||||
|
List<NetworkTransmitReceiveInfo> result = new ArrayList<>();
|
||||||
|
final Pattern pattern = Pattern.compile("\\s*(.*):\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
|
||||||
|
try{
|
||||||
|
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||||
|
for (String line : lines){
|
||||||
|
Matcher m = pattern.matcher(line);
|
||||||
|
if (m.find()){
|
||||||
|
NetworkTransmitReceiveInfo info = new NetworkTransmitReceiveInfo();
|
||||||
|
info.name = m.group(1).trim();
|
||||||
|
info.bytesReceived = Long.parseLong(m.group(2));
|
||||||
|
info.packetsReceived = Long.parseLong(m.group(3));
|
||||||
|
info.errorsReceived = Long.parseLong(m.group(4));
|
||||||
|
info.droppedReceived = Long.parseLong(m.group(5));
|
||||||
|
info.fifoReceived = Long.parseLong(m.group(6));
|
||||||
|
info.frameReceived = Long.parseLong(m.group(7));
|
||||||
|
info.compressedReceived = Long.parseLong(m.group(8));
|
||||||
|
info.multicastReceived = Long.parseLong(m.group(9));
|
||||||
|
info.bytesTransmitted = Long.parseLong(m.group(10));
|
||||||
|
info.packetsTransmitted = Long.parseLong(m.group(11));
|
||||||
|
info.errorsTransmitted = Long.parseLong(m.group(12));
|
||||||
|
info.droppedTransmitted = Long.parseLong(m.group(13));
|
||||||
|
info.fifoTransmitted = Long.parseLong(m.group(14));
|
||||||
|
info.collsTransmitted = Long.parseLong(m.group(15));
|
||||||
|
info.carrierTransmitted = Long.parseLong(m.group(16));
|
||||||
|
info.compressedTransmitted = Long.parseLong(m.group(17));
|
||||||
|
info.timetick = System.currentTimeMillis();
|
||||||
|
result.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return result.toArray(new NetworkTransmitReceiveInfo[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NetworkTransmitReceiveInfo[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CpuInfo getCPUInfo(){
|
||||||
|
CpuInfo result = new CpuInfo();
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
File ff = new File("/proc/cpuinfo");
|
||||||
|
if (ff.isFile() && ff.canRead()){
|
||||||
|
final Pattern pattern = Pattern.compile( "\\s*(.*):\\s*(.*)");
|
||||||
|
try{
|
||||||
|
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||||
|
for (String line : lines){
|
||||||
|
Matcher m = pattern.matcher(line);
|
||||||
|
if (m.find()){
|
||||||
|
String key = m.group(1).trim();
|
||||||
|
String value = m.group(2).trim();
|
||||||
|
switch (key){
|
||||||
|
case "processor":
|
||||||
|
result.processorCount++;
|
||||||
|
break;
|
||||||
|
case "Revision":
|
||||||
|
result.revision = value;
|
||||||
|
break;
|
||||||
|
case "Serial":
|
||||||
|
result.serial = value;
|
||||||
|
break;
|
||||||
|
case "Model":
|
||||||
|
result.model = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProcessorStatus[] getProcStat(){
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
File ff = new File("/proc/stat");
|
||||||
|
if (ff.isFile() && ff.canRead()){
|
||||||
|
final Pattern pattern = Pattern.compile( "(cpu\\d?)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
|
||||||
|
List<ProcessorStatus> result = new ArrayList<>();
|
||||||
|
try{
|
||||||
|
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||||
|
for (String line : lines){
|
||||||
|
Matcher m = pattern.matcher(line);
|
||||||
|
if (m.find()){
|
||||||
|
ProcessorStatus info = new ProcessorStatus();
|
||||||
|
info.name = m.group(1).trim();
|
||||||
|
info.user = Integer.parseInt(m.group(2));
|
||||||
|
info.nice = Integer.parseInt(m.group(3));
|
||||||
|
info.system = Integer.parseInt(m.group(4));
|
||||||
|
info.idle = Integer.parseInt(m.group(5));
|
||||||
|
info.iowait = Integer.parseInt(m.group(6));
|
||||||
|
info.irq = Integer.parseInt(m.group(7));
|
||||||
|
info.softirq = Integer.parseInt(m.group(8));
|
||||||
|
info.steal = Integer.parseInt(m.group(9));
|
||||||
|
info.guest = Integer.parseInt(m.group(10));
|
||||||
|
info.guest_nice = Integer.parseInt(m.group(11));
|
||||||
|
result.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toArray(new ProcessorStatus[0]);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ProcessorStatus[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RamInformation getRAMInformation(){
|
||||||
|
|
||||||
|
RamInformation result = new RamInformation();
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
File ff = new File("/proc/meminfo");
|
||||||
|
if (ff.isFile() && ff.canRead()){
|
||||||
|
final Pattern pattern = Pattern.compile("(.*):\\s+(\\d+).kB");
|
||||||
|
try{
|
||||||
|
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||||
|
for (String line : lines) {
|
||||||
|
Matcher m = pattern.matcher(line);
|
||||||
|
if (m.find()){
|
||||||
|
String key = m.group(1);
|
||||||
|
int value = Integer.parseInt(m.group(2));
|
||||||
|
switch (key){
|
||||||
|
case "MemTotal":
|
||||||
|
result.totalKB = value;
|
||||||
|
break;
|
||||||
|
case "MemAvailable":
|
||||||
|
result.availableKB = value;
|
||||||
|
break;
|
||||||
|
case "SwapTotal":
|
||||||
|
result.swapTotalKB = value;
|
||||||
|
break;
|
||||||
|
case "SwapFree":
|
||||||
|
result.swapFreeKB = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
result.usedKB = result.totalKB - result.availableKB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/main/java/Web/AudioFilesInfo.java
Normal file
9
src/main/java/Web/AudioFilesInfo.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package Web;
|
||||||
|
|
||||||
|
public class AudioFilesInfo {
|
||||||
|
public String preset1;
|
||||||
|
public String preset2;
|
||||||
|
public String preset3;
|
||||||
|
public String preset4;
|
||||||
|
public String preset5;
|
||||||
|
}
|
||||||
@@ -1,17 +1,21 @@
|
|||||||
package Web;
|
package Web;
|
||||||
|
|
||||||
import Other.SomeCodes;
|
import Other.SomeCodes;
|
||||||
|
import com.corundumstudio.socketio.Configuration;
|
||||||
|
import com.corundumstudio.socketio.SocketIOClient;
|
||||||
|
import com.corundumstudio.socketio.SocketIOServer;
|
||||||
|
import com.corundumstudio.socketio.listener.ConnectListener;
|
||||||
|
import com.corundumstudio.socketio.listener.DisconnectListener;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.http.UploadedFile;
|
import io.javalin.http.UploadedFile;
|
||||||
|
import io.javalin.util.FileUtil;
|
||||||
import io.javalin.util.JavalinException;
|
import io.javalin.util.JavalinException;
|
||||||
import io.javalin.websocket.*;
|
import io.javalin.websocket.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.util.*;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static Other.SomeCodes.*;
|
import static Other.SomeCodes.*;
|
||||||
@@ -20,20 +24,30 @@ import static io.javalin.apibuilder.ApiBuilder.*;
|
|||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
@SuppressWarnings({"unused"})
|
||||||
public class WebServer {
|
public class WebServer {
|
||||||
|
private @Getter @Setter String webusername;
|
||||||
|
private @Getter @Setter String webpassword;
|
||||||
private final Javalin app;
|
private final Javalin app;
|
||||||
private final Set<WsContext> connectedWebsocketClients = ConcurrentHashMap.newKeySet();
|
private final Set<WsContext> connectedWebsocketClients = ConcurrentHashMap.newKeySet();
|
||||||
|
private final SocketIOServer socketServer;
|
||||||
|
private final Configuration socketConfig;
|
||||||
|
private final HashMap<String, SocketIOClient> socketIOClients = new HashMap<>();
|
||||||
|
|
||||||
public WebServer(WebsocketEvent event, String webusername, String webpassword){
|
public WebServer(WebsocketEvent event, String webusername, String webpassword){
|
||||||
|
this.webusername = webusername;
|
||||||
|
this.webpassword = webpassword;
|
||||||
app = Javalin.create(config -> {
|
app = Javalin.create(config -> {
|
||||||
|
config.useVirtualThreads = true;
|
||||||
|
|
||||||
config.staticFiles.add("/html");
|
config.staticFiles.add("/html");
|
||||||
config.router.apiBuilder(()-> path("setting", () ->{
|
config.router.apiBuilder(()-> path("setting", () ->{
|
||||||
get(ctx -> ctx.json(SettingInfo.getInstance()));
|
get(ctx -> ctx.json(SettingInfo.getInstance()));
|
||||||
path("audiofile",()-> post(ctx -> {
|
path("audiofile",()-> post(ctx -> {
|
||||||
Logger.info("api /setting/audiofile");
|
Logger.info("api /setting/audiofile");
|
||||||
String audiofile1 = ctx.formParam("1");
|
String audiofile1 = ctx.formParam("preset1");
|
||||||
String audiofile2 = ctx.formParam("2");
|
String audiofile2 = ctx.formParam("preset2");
|
||||||
String audiofile3 = ctx.formParam("3");
|
String audiofile3 = ctx.formParam("preset3");
|
||||||
String audiofile4 = ctx.formParam("4");
|
String audiofile4 = ctx.formParam("preset4");
|
||||||
String audiofile5 = ctx.formParam("5");
|
String audiofile5 = ctx.formParam("preset5");
|
||||||
Logger.info("audiofile1: {}", audiofile1);
|
Logger.info("audiofile1: {}", audiofile1);
|
||||||
Logger.info("audiofile2: {}", audiofile2);
|
Logger.info("audiofile2: {}", audiofile2);
|
||||||
Logger.info("audiofile3: {}", audiofile3);
|
Logger.info("audiofile3: {}", audiofile3);
|
||||||
@@ -41,41 +55,59 @@ public class WebServer {
|
|||||||
Logger.info("audiofile5: {}", audiofile5);
|
Logger.info("audiofile5: {}", audiofile5);
|
||||||
|
|
||||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||||
prop.setProperty("audiofile1", audiofile1!=null?audiofile1:"");
|
prop.setProperty("AudioFile01", audiofile1!=null?audiofile1:"");
|
||||||
prop.setProperty("audiofile2", audiofile2!=null?audiofile2:"");
|
prop.setProperty("AudioFile02", audiofile2!=null?audiofile2:"");
|
||||||
prop.setProperty("audiofile3", audiofile3!=null?audiofile3:"");
|
prop.setProperty("AudioFile03", audiofile3!=null?audiofile3:"");
|
||||||
prop.setProperty("audiofile4", audiofile4!=null?audiofile4:"");
|
prop.setProperty("AudioFile04", audiofile4!=null?audiofile4:"");
|
||||||
prop.setProperty("audiofile5", audiofile5!=null?audiofile5:"");
|
prop.setProperty("AudioFile05", audiofile5!=null?audiofile5:"");
|
||||||
if (SaveProperties(prop, "config.properties")){
|
if (SaveProperties(prop, "config.properties")){
|
||||||
Logger.info("audiofile saved");
|
Logger.info("audiofile saved");
|
||||||
ctx.status(200);
|
ctx.status(200);
|
||||||
} else {
|
} else {
|
||||||
Logger.error("Failed to save audiofile");
|
Logger.error("Failed to save audiofile");
|
||||||
ctx.status(400);
|
ctx.status(400);
|
||||||
|
ctx.result("Failed to save audiofile");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
path("uploadaudiofile", ()-> post(ctx -> {
|
path("uploadaudiofile", ()-> post(ctx -> {
|
||||||
UploadedFile file = ctx.uploadedFile("file");
|
List<UploadedFile> uploadedFileList = ctx.uploadedFiles();
|
||||||
if (file!=null){
|
int size = uploadedFileList.size();
|
||||||
try {
|
if (size>0){
|
||||||
Path targetsave = audioPath.resolve(file.filename());
|
uploadedFileList.forEach(ff ->{
|
||||||
Files.copy(file.content(), targetsave);
|
String targetsave = audioPath.resolve(ff.filename()).toString();
|
||||||
Logger.info("Uploaded file: {}, size: {} saved at {}", file.filename(),file.size(), targetsave);
|
FileUtil.streamToFile(ff.content(), targetsave);
|
||||||
} catch (Exception e){
|
Logger.info("Uploaded file: {}", targetsave);
|
||||||
Logger.error("Failed to save uploaded file: {}, Message: {}", file.filename(), e.getMessage());
|
});
|
||||||
}
|
ctx.status(200);
|
||||||
|
ctx.result("UploadedFiles: "+size);
|
||||||
|
} else {
|
||||||
|
ctx.status(400);
|
||||||
|
ctx.result("No file uploaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}));
|
}));
|
||||||
path("weblogin", ()-> post(ctx -> {
|
path("weblogin", ()-> post(ctx -> {
|
||||||
String username = ctx.formParam("username");
|
String username = ctx.formParam("username");
|
||||||
String password = ctx.formParam("password");
|
String password = ctx.formParam("password");
|
||||||
|
Logger.info("api /setting/weblogin");
|
||||||
|
Logger.info("username: {}", username);
|
||||||
|
Logger.info("password: {}", password);
|
||||||
|
|
||||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||||
prop.setProperty("WebUsername", ValidString(username)?username:"admin");
|
prop.setProperty("WebUsername", ValidString(username)?username:"admin");
|
||||||
prop.setProperty("WebPassword", ValidString(password)?password:"bandara");
|
prop.setProperty("WebPassword", ValidString(password)?password:"bandara");
|
||||||
if (SaveProperties(prop, "config.properties")){
|
if (SaveProperties(prop, "config.properties")){
|
||||||
ctx.status(200);
|
Logger.info("weblogin saved");
|
||||||
|
|
||||||
|
//ctx.status(200);
|
||||||
|
this.webusername = username;
|
||||||
|
this.webpassword = password;
|
||||||
|
ctx.redirect("/logout");
|
||||||
} else {
|
} else {
|
||||||
|
Logger.error("Failed to save weblogin");
|
||||||
ctx.status(400);
|
ctx.status(400);
|
||||||
|
ctx.result("Failed to save weblogin");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
path("camera",()-> post(ctx -> {
|
path("camera",()-> post(ctx -> {
|
||||||
@@ -83,6 +115,11 @@ public class WebServer {
|
|||||||
String camera_port = ctx.formParam("port");
|
String camera_port = ctx.formParam("port");
|
||||||
String camera_username = ctx.formParam("username");
|
String camera_username = ctx.formParam("username");
|
||||||
String camera_password = ctx.formParam("password");
|
String camera_password = ctx.formParam("password");
|
||||||
|
Logger.info("api /setting/camera");
|
||||||
|
Logger.info("camera_ip: {}", camera_ip);
|
||||||
|
Logger.info("camera_port: {}", camera_port);
|
||||||
|
Logger.info("camera_username: {}", camera_username);
|
||||||
|
Logger.info("camera_password: {}", camera_password);
|
||||||
|
|
||||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||||
prop.setProperty("Camera_ip", ValidString(camera_ip)?camera_ip:"192.168.0.4");
|
prop.setProperty("Camera_ip", ValidString(camera_ip)?camera_ip:"192.168.0.4");
|
||||||
@@ -90,9 +127,13 @@ public class WebServer {
|
|||||||
prop.setProperty("Camera_user", ValidString(camera_username)?camera_username:"root");
|
prop.setProperty("Camera_user", ValidString(camera_username)?camera_username:"root");
|
||||||
prop.setProperty("Camera_password", ValidString(camera_password)?camera_password:"password");
|
prop.setProperty("Camera_password", ValidString(camera_password)?camera_password:"password");
|
||||||
if (SaveProperties(prop, "config.properties")){
|
if (SaveProperties(prop, "config.properties")){
|
||||||
|
Logger.info("IP camera setting saved");
|
||||||
ctx.status(200);
|
ctx.status(200);
|
||||||
|
if (event!=null) event.NewCameraConfiguration();
|
||||||
} else {
|
} else {
|
||||||
|
Logger.error("Failed to save IP camera setting");
|
||||||
ctx.status(400);
|
ctx.status(400);
|
||||||
|
ctx.result("Failed to save IP camera setting");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -103,7 +144,7 @@ public class WebServer {
|
|||||||
if (ctx.sessionAttribute("username")==null) {
|
if (ctx.sessionAttribute("username")==null) {
|
||||||
// belum login
|
// belum login
|
||||||
ctx.redirect("/login.html");
|
ctx.redirect("/login.html");
|
||||||
} else if (Objects.equals(ctx.sessionAttribute("username"), webusername)){
|
} else if (Objects.equals(ctx.sessionAttribute("username"), this.webusername)){
|
||||||
// sudah login
|
// sudah login
|
||||||
ctx.redirect("/index.html");
|
ctx.redirect("/index.html");
|
||||||
} else {
|
} else {
|
||||||
@@ -127,11 +168,12 @@ public class WebServer {
|
|||||||
app.post("/login", ctx ->{
|
app.post("/login", ctx ->{
|
||||||
String username = ctx.formParam("username");
|
String username = ctx.formParam("username");
|
||||||
String password = ctx.formParam("password");
|
String password = ctx.formParam("password");
|
||||||
if (Objects.equals(username, webusername) && Objects.equals(password, webpassword)){
|
if (Objects.equals(username, this.webusername) && Objects.equals(password, this.webpassword)){
|
||||||
ctx.sessionAttribute("username", username);
|
ctx.sessionAttribute("username", username);
|
||||||
ctx.redirect("/index.html");
|
ctx.redirect("/index.html");
|
||||||
} else {
|
} else {
|
||||||
ctx.redirect("/login.html?error=Invalid username or password");
|
ctx.status(400);
|
||||||
|
ctx.redirect("/login.html");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -140,10 +182,13 @@ public class WebServer {
|
|||||||
ctx.redirect("/login.html");
|
ctx.redirect("/login.html");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
WebSocket Communication
|
||||||
|
This is temporary, later must choose either WebSocket or SocketIO
|
||||||
|
*/
|
||||||
app.ws("/ws", ws -> {
|
app.ws("/ws", ws -> {
|
||||||
ws.onConnect(connectws);
|
ws.onConnect(connectws);
|
||||||
ws.onClose(closews);
|
ws.onClose(closews);
|
||||||
//ws.onError(errorws);
|
|
||||||
ws.onMessage(ctx -> {
|
ws.onMessage(ctx -> {
|
||||||
try{
|
try{
|
||||||
//Logger.info("WebSocket message {}", ctx.message());
|
//Logger.info("WebSocket message {}", ctx.message());
|
||||||
@@ -151,13 +196,39 @@ public class WebServer {
|
|||||||
if (event!=null) {
|
if (event!=null) {
|
||||||
WebsocketReply reply = event.onWebsocketCommand(command);
|
WebsocketReply reply = event.onWebsocketCommand(command);
|
||||||
if (reply!=null) ctx.sendAsClass(reply, WebsocketReply.class);
|
if (reply!=null) ctx.sendAsClass(reply, WebsocketReply.class);
|
||||||
|
//if (reply!=null) SendtoAll(reply);
|
||||||
}
|
}
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
Logger.error("Failed to parse WebSocketCommand message: {}", e.getMessage());
|
Logger.error("Failed to parse WebSocketCommand message: {}", e.getMessage());
|
||||||
|
ctx.closeSession();
|
||||||
|
connectedWebsocketClients.remove(ctx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
SocketIO Communication
|
||||||
|
This is temporary, later must choose either WebSocket or SocketIO
|
||||||
|
*/
|
||||||
|
socketConfig = new Configuration();
|
||||||
|
socketConfig.setHostname("0.0.0.0");
|
||||||
|
socketConfig.setPort(3001);
|
||||||
|
|
||||||
|
socketServer = new SocketIOServer(socketConfig);
|
||||||
|
socketServer.addConnectListener(connectListener);
|
||||||
|
socketServer.addDisconnectListener(disconnectListener);
|
||||||
|
|
||||||
|
socketServer.addNamespace("/socketio").addEventListener("message", String.class, (client, data, ackSender) -> {
|
||||||
|
//Logger.info("SocketIO message from namespace /socketio from {}: {}", client.getRemoteAddress(), data);
|
||||||
|
WebsocketCommand command = gson.fromJson(data, WebsocketCommand.class);
|
||||||
|
if (event!=null) {
|
||||||
|
WebsocketReply reply = event.onWebsocketCommand(command);
|
||||||
|
if (reply!=null) client.sendEvent("message", gson.toJson(reply));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,7 +236,12 @@ public class WebServer {
|
|||||||
* @param obj Object to send
|
* @param obj Object to send
|
||||||
*/
|
*/
|
||||||
public void SendtoAll(Object obj){
|
public void SendtoAll(Object obj){
|
||||||
connectedWebsocketClients.forEach(wsContext -> wsContext.send(obj));
|
|
||||||
|
connectedWebsocketClients
|
||||||
|
.stream()
|
||||||
|
.filter(ws -> ws.session.isOpen())
|
||||||
|
.forEach(ws -> ws.send(obj));
|
||||||
|
socketIOClients.forEach((key, client) -> client.sendEvent("message", gson.toJson(obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,9 +251,10 @@ public class WebServer {
|
|||||||
*/
|
*/
|
||||||
public void Start(String localip, int port){
|
public void Start(String localip, int port){
|
||||||
try{
|
try{
|
||||||
connectedWebsocketClients.forEach(WsContext::closeSession);
|
|
||||||
app.start(localip, port);
|
app.start(localip, port);
|
||||||
Logger.info("Web server started at {}:{}", localip, port);
|
Logger.info("Web server started at {}:{}", localip, port);
|
||||||
|
socketServer.start();
|
||||||
|
Logger.info("SocketIO server started at {}:{}", socketConfig.getHostname(), socketConfig.getPort());
|
||||||
} catch (JavalinException e){
|
} catch (JavalinException e){
|
||||||
Logger.error("Web server failed to start: {}", e.getMessage());
|
Logger.error("Web server failed to start: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -188,25 +265,42 @@ public class WebServer {
|
|||||||
*/
|
*/
|
||||||
public void Stop(){
|
public void Stop(){
|
||||||
try{
|
try{
|
||||||
|
connectedWebsocketClients.forEach(WsContext::closeSession);
|
||||||
|
connectedWebsocketClients.clear();
|
||||||
app.stop();
|
app.stop();
|
||||||
Logger.info("Web server stopped");
|
Logger.info("Web server stopped");
|
||||||
|
socketServer.stop();
|
||||||
|
socketIOClients.forEach((key, client) -> client.disconnect());
|
||||||
|
socketIOClients.clear();
|
||||||
|
|
||||||
|
Logger.info("SocketIO server stopped");
|
||||||
} catch (JavalinException e){
|
} catch (JavalinException e){
|
||||||
Logger.error("Web server failed to stop: {}", e.getMessage());
|
Logger.error("Web server failed to stop: {}", e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WsConnectHandler connectws = ws ->{
|
WsConnectHandler connectws = ws ->{
|
||||||
Logger.info("WebSocket connected from {}", ws.host());
|
Logger.info("WebSocket connected from {}", ws.sessionId());
|
||||||
//ws.headerMap().forEach((key, value) -> Logger.info("HeaderMap {}: {}", key, value));
|
//ws.headerMap().forEach((key, value) -> Logger.info("HeaderMap {}: {}", key, value));
|
||||||
connectedWebsocketClients.add(ws);
|
connectedWebsocketClients.add(ws);
|
||||||
};
|
};
|
||||||
|
|
||||||
WsCloseHandler closews = ws ->{
|
WsCloseHandler closews = ws ->{
|
||||||
Logger.info("WebSocket closed from {}, code {}, reason {}", ws.host(), ws.status(), ws.reason());
|
Logger.info("WebSocket closed from {}, code {}, reason {}", ws.sessionId(), ws.status(), ws.reason());
|
||||||
connectedWebsocketClients.remove(ws);
|
connectedWebsocketClients.remove(ws);
|
||||||
};
|
};
|
||||||
|
|
||||||
//WsErrorHandler errorws = ws -> Logger.error("WebSocket error from {}, error {}", ws.host(), ws.error());
|
ConnectListener connectListener = client -> {
|
||||||
|
Logger.info("SocketIO connected, id {} from {}", client.getSessionId(), client.getRemoteAddress());
|
||||||
|
socketIOClients.put(client.getSessionId().toString(), client);
|
||||||
|
};
|
||||||
|
|
||||||
|
DisconnectListener disconnectListener = client -> {
|
||||||
|
Logger.info("SocketIO disconnected, id {} from {}", client.getSessionId(), client.getRemoteAddress());
|
||||||
|
socketIOClients.remove(client.getSessionId().toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ package Web;
|
|||||||
public interface WebsocketEvent {
|
public interface WebsocketEvent {
|
||||||
String onMessage(String message);
|
String onMessage(String message);
|
||||||
WebsocketReply onWebsocketCommand(WebsocketCommand command);
|
WebsocketReply onWebsocketCommand(WebsocketCommand command);
|
||||||
|
void NewCameraConfiguration();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,403 @@
|
|||||||
package id.co.gtc;
|
package id.co.gtc;
|
||||||
|
|
||||||
import Audio.AudioFileProperties;
|
import Audio.*;
|
||||||
import Audio.AudioPlayer;
|
|
||||||
import Audio.PlaybackEvent;
|
|
||||||
import Camera.PanTiltController;
|
import Camera.PanTiltController;
|
||||||
import Camera.RtspGrabber;
|
import Camera.RtspGrabber_opencv;
|
||||||
import Camera.VapixProtocol;
|
import Camera.VapixProtocol;
|
||||||
import Other.SomeCodes;
|
import Other.SomeCodes;
|
||||||
import Web.WebServer;
|
import SBC.*;
|
||||||
import Web.WebsocketCommand;
|
import Web.*;
|
||||||
import Web.WebsocketEvent;
|
import com.google.gson.JsonObject;
|
||||||
import Web.WebsocketReply;
|
import com.sun.jna.Platform;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
import org.bytedeco.opencv.global.opencv_core;
|
import org.bytedeco.opencv.global.opencv_core;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
import java.util.Properties;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import static Other.SomeCodes.*;
|
import static Other.SomeCodes.*;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
//change parameter ini untuk single audio output atau multi audio output
|
||||||
|
private static final boolean use_multiusb_audio = true;
|
||||||
|
private static MultiUSBAudioPlayer multiUSBAudioPlayer;
|
||||||
|
private static MultiUSBAudioPlayer.PlaybackHandlewithId[] playbackHandles;
|
||||||
private static AudioPlayer audioPlayer;
|
private static AudioPlayer audioPlayer;
|
||||||
private static WebServer webServer;
|
|
||||||
private static RtspGrabber rtspGrabber;
|
|
||||||
private static PanTiltController panTiltController;
|
|
||||||
private static AudioFileProperties audioFileProperties;
|
private static AudioFileProperties audioFileProperties;
|
||||||
private static VapixProtocol vapixProtocol;
|
|
||||||
|
|
||||||
|
private static WebServer webServer;
|
||||||
|
|
||||||
|
//change parameter ini untuk menggunakan Yolo atau tidak
|
||||||
|
public static final boolean use_Yolo = false;
|
||||||
|
private static RtspGrabber_opencv rtspGrabber;
|
||||||
|
public static boolean haveCuda = false;
|
||||||
|
|
||||||
|
private static PanTiltController panTiltController;
|
||||||
|
private static VapixProtocol vapixProtocol;
|
||||||
|
private static Timer timer;
|
||||||
|
private static int cpuTemperature;
|
||||||
|
private static RamInformation ramInformation;
|
||||||
|
private static ProcessorStatus[] previousCpuInfo;
|
||||||
|
private static final Map<String, Integer> cpuUsage = new HashMap<>();
|
||||||
|
private static NetworkTransmitReceiveInfo[] previousNetworkInfo;
|
||||||
|
private static final Map<String, String> networkTX = new HashMap<>();
|
||||||
|
private static final Map<String, String> networkRX = new HashMap<>();
|
||||||
|
private static JetsonOrinPins AmplifierPower = null;
|
||||||
|
private static JetsonOrinPins LedWeb = null;
|
||||||
|
private static JetsonOrinPins LedIpCamera = null;
|
||||||
|
private static JetsonOrinPins LedPanTilt = null;
|
||||||
|
private static JetsonOrinPins Max485Direction = null;
|
||||||
|
|
||||||
|
private static ExecutorService gpioExecutor = null;
|
||||||
|
|
||||||
|
private static PCF8574 pcf8574 = null;
|
||||||
|
private static final String Version = "V1.09 (17/03/2025)";
|
||||||
// Application start from here
|
// Application start from here
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
System.setProperty("jna.debug_load", "false");
|
||||||
|
System.out.println("BirdStrikeSoetta "+Version);
|
||||||
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
if (audioPlayer!=null) audioPlayer.Unload();
|
if (use_multiusb_audio) {
|
||||||
if (webServer!=null) webServer.Stop();
|
if (multiUSBAudioPlayer != null) {
|
||||||
if (rtspGrabber!=null) rtspGrabber.Stop();
|
multiUSBAudioPlayer.Unload();
|
||||||
if (panTiltController!=null) panTiltController.Close();
|
Logger.info("MultiUSB Audio Unloaded");
|
||||||
if (vapixProtocol!=null) vapixProtocol.Close();
|
}
|
||||||
|
} else {
|
||||||
|
if (audioPlayer != null) {
|
||||||
|
audioPlayer.Unload();
|
||||||
|
Logger.info("Audio Unloaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (webServer!=null) {
|
||||||
|
webServer.Stop();
|
||||||
|
Logger.info("Web Server stopped");
|
||||||
|
}
|
||||||
|
if (rtspGrabber!=null) {
|
||||||
|
rtspGrabber.Stop();
|
||||||
|
Logger.info("Rtsp Grabber stopped");
|
||||||
|
}
|
||||||
|
if (panTiltController!=null) {
|
||||||
|
panTiltController.Close();
|
||||||
|
Logger.info("Pan Tilt Controller closed");
|
||||||
|
}
|
||||||
|
if (vapixProtocol!=null) {
|
||||||
|
vapixProtocol.Close();
|
||||||
|
Logger.info("Vapix Protocol closed");
|
||||||
|
}
|
||||||
|
if (timer!=null) {
|
||||||
|
timer.cancel();
|
||||||
|
Logger.info("Timer cancelled");
|
||||||
|
}
|
||||||
|
if (gpioExecutor!=null) {
|
||||||
|
gpioExecutor.shutdown();
|
||||||
|
Logger.info("GPIO Executor shutdown");
|
||||||
|
}
|
||||||
|
if (AmplifierPower!=null) {
|
||||||
|
Logger.info("GPIO pin {} unexport : {}",AmplifierPower.pin, GPIO.UnexportPin(AmplifierPower));
|
||||||
|
}
|
||||||
|
if (LedWeb!=null) {
|
||||||
|
Logger.info("GPIO pin {} unexport : {}", LedWeb.pin,GPIO.UnexportPin(LedWeb));
|
||||||
|
}
|
||||||
|
if (LedIpCamera!=null) {
|
||||||
|
Logger.info("GPIO pin {} unexport : {}", LedIpCamera.pin, GPIO.UnexportPin(LedIpCamera));
|
||||||
|
}
|
||||||
|
if (LedPanTilt!=null) {
|
||||||
|
Logger.info("GPIO pin {} unexport : {}", LedPanTilt.pin,GPIO.UnexportPin(LedPanTilt));
|
||||||
|
}
|
||||||
|
if (Max485Direction!=null) {
|
||||||
|
Logger.info("GPIO pin {} unexport : {}", Max485Direction.pin, GPIO.UnexportPin(Max485Direction));
|
||||||
|
}
|
||||||
|
if (pcf8574!=null){
|
||||||
|
pcf8574.Close();
|
||||||
|
Logger.info("PCF8574 closed");
|
||||||
|
}
|
||||||
|
Logger.info("Application Stopped");
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
Logger.info("Current Directory : "+currentDirectory);
|
||||||
|
|
||||||
|
|
||||||
|
//init_gpio();
|
||||||
|
init_pcf8574();
|
||||||
|
init_system_monitoring();
|
||||||
|
|
||||||
init_properties();
|
init_properties();
|
||||||
init_audiofiles();
|
init_audiofiles();
|
||||||
|
|
||||||
|
init_Vapix();
|
||||||
|
if (use_multiusb_audio) {
|
||||||
|
Logger.info("Using MultiUSB Audio");
|
||||||
|
init_multiusb_audio();
|
||||||
|
} else {
|
||||||
|
Logger.info("Using USB Audio");
|
||||||
init_audio();
|
init_audio();
|
||||||
|
}
|
||||||
|
|
||||||
|
init_pantiltcontroller();
|
||||||
init_webserver();
|
init_webserver();
|
||||||
init_rtspgrabber();
|
init_rtspgrabber();
|
||||||
init_pantiltcontroller();
|
}
|
||||||
init_Vapix();
|
|
||||||
|
private static void init_pcf8574(){
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
I2C_BUS i2c_bus = new I2C_BUS(7);
|
||||||
|
if (i2c_bus.Open_Bus()){
|
||||||
|
Logger.info("I2C Bus opened");
|
||||||
|
pcf8574 = new PCF8574(i2c_bus.getI2c_handle(), 0x27);
|
||||||
|
if (pcf8574.Open_Slave()){
|
||||||
|
Logger.info("PCF8574 opened");
|
||||||
|
pcf8574.AllOff();
|
||||||
|
// pcf8574.setPinName(0, "Amplifier Power");
|
||||||
|
// pcf8574.setPinName(1, "Led Web");
|
||||||
|
// pcf8574.setPinName(2, "Led IP Camera");
|
||||||
|
// pcf8574.setPinName(3, "Led Pan Tilt");
|
||||||
|
// pcf8574.setPinName(4, "Max485 Direction");
|
||||||
|
gpioExecutor = Executors.newVirtualThreadPerTaskExecutor();
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Logger.error("Failed to open PCF8574");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.error("Failed to open I2C Bus");
|
||||||
|
}
|
||||||
|
} else Logger.error("PCF8574 not supported on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Untuk test libgpiod
|
||||||
|
// use for jetpack 6.x
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static void init_gpio(){
|
||||||
|
LibGpioD gpio;
|
||||||
|
Pointer openPointer;
|
||||||
|
// Source : https://jetsonhacks.com/nvidia-jetson-orin-nano-gpio-header-pinout/
|
||||||
|
int gpio_MOSI = 135;
|
||||||
|
int gpio_MISO = 134;
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
gpio = LibGpioD.Instance;
|
||||||
|
openPointer = gpio.gpiod_chip_open(LibGpioD.CHIP_NAME);
|
||||||
|
if (openPointer!=null){
|
||||||
|
Logger.info("GPIO Chip opened : {}", LibGpioD.CHIP_NAME);
|
||||||
|
Pointer miso = gpio.gpiod_line_get(openPointer, gpio_MISO);
|
||||||
|
if (miso!=null){
|
||||||
|
Logger.info("GPIO Line MISO opened : {}", gpio_MISO);
|
||||||
|
if (gpio.gpiod_line_request_input(miso, "MISO")!=0){
|
||||||
|
Logger.error("Failed to set MISO as input");
|
||||||
|
} else {
|
||||||
|
Logger.info("MISO opened");
|
||||||
|
Logger.info("MISO value : {}", gpio.gpiod_line_get_value(miso));
|
||||||
|
}
|
||||||
|
gpio.gpiod_line_release(miso);
|
||||||
|
Logger.info("GPIO Line MISO released : {}", gpio_MISO);
|
||||||
|
} else Logger.error("Failed to open GPIO Line : {}", gpio_MISO);
|
||||||
|
Pointer mosi = gpio.gpiod_line_get(openPointer, gpio_MOSI);
|
||||||
|
if (mosi!=null){
|
||||||
|
Logger.info("GPIO Line MOSI opened : {}", gpio_MOSI);
|
||||||
|
if (gpio.gpiod_line_request_output(mosi, "MOSI", 0)!=0){
|
||||||
|
Logger.error("Failed to set MOSI as output");
|
||||||
|
} else {
|
||||||
|
Logger.info("MOSI opened");
|
||||||
|
int result = gpio.gpiod_line_set_value(mosi, 1);
|
||||||
|
if (result!=0){
|
||||||
|
Logger.error("Failed to set MOSI value : {}", result);
|
||||||
|
} else Logger.info("Success set MOSI value : 1");
|
||||||
|
}
|
||||||
|
gpio.gpiod_line_release(mosi);
|
||||||
|
Logger.info("GPIO Line MOSI released : {}", gpio_MOSI);
|
||||||
|
} else Logger.error("Failed to open GPIO Line : {}", gpio_MOSI);
|
||||||
|
gpio.gpiod_chip_close(openPointer);
|
||||||
|
Logger.info("GPIO Chip closed : {}", LibGpioD.CHIP_NAME);
|
||||||
|
} else Logger.error("Failed to open GPIO Chip : {}", LibGpioD.CHIP_NAME);
|
||||||
|
} else Logger.info("GPIO not supported on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// use for jetpack 4.x and 5.x
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static void init_gpio_sysfs(){
|
||||||
|
if (Platform.isLinux()){
|
||||||
|
if (GPIO.HaveGPIO()){
|
||||||
|
gpioExecutor = Executors.newVirtualThreadPerTaskExecutor();
|
||||||
|
AmplifierPower = InitializePin(JetsonOrinPins.Pin13, true);
|
||||||
|
LedWeb = InitializePin(JetsonOrinPins.Pin15, true);
|
||||||
|
LedIpCamera = InitializePin(JetsonOrinPins.Pin19, true);
|
||||||
|
LedPanTilt = InitializePin(JetsonOrinPins.Pin21, true);
|
||||||
|
Max485Direction = InitializePin(JetsonOrinPins.Pin23, true);
|
||||||
|
GPIO.SetValue(AmplifierPower,false);
|
||||||
|
GPIO.SetValue(LedWeb,false);
|
||||||
|
GPIO.SetValue(LedIpCamera,false);
|
||||||
|
GPIO.SetValue(LedPanTilt,false);
|
||||||
|
GPIO.SetValue(Max485Direction,false);
|
||||||
|
}
|
||||||
|
} else Logger.info("GPIO not supported on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
|
private static JetsonOrinPins InitializePin(JetsonOrinPins pin, boolean isOutput){
|
||||||
|
boolean exported = false;
|
||||||
|
if (GPIO.GpioPinExists(pin)){
|
||||||
|
exported = true;
|
||||||
|
} else {
|
||||||
|
if (GPIO.ExportPin(pin)){
|
||||||
|
exported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exported){
|
||||||
|
if (GPIO.SetPinDirection(pin, isOutput?"out":"in")){
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dipanggil di PanTiltController, maka perlu public dan static
|
||||||
|
public static void Max485Direction(boolean isTransmit){
|
||||||
|
if (Max485Direction!=null){
|
||||||
|
GPIO.SetValue(Max485Direction, isTransmit);
|
||||||
|
} else if (pcf8574!=null && pcf8574.isOpened()){
|
||||||
|
// if (isTransmit){
|
||||||
|
// pcf8574.SetPin("Max485 Direction");
|
||||||
|
// } else {
|
||||||
|
// pcf8574.ClearPin("Max485 Direction");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dipanggil di PanTiltController, maka perlu public dan static
|
||||||
|
public static void Blink_LedPanTilt(){
|
||||||
|
if (LedPanTilt!=null){
|
||||||
|
Blink(LedPanTilt);
|
||||||
|
} else if (pcf8574!=null && pcf8574.isOpened()){
|
||||||
|
Blink(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Blink_LedWeb(){
|
||||||
|
if (LedWeb!=null){
|
||||||
|
Blink(LedWeb);
|
||||||
|
} else if (pcf8574!=null && pcf8574.isOpened()){
|
||||||
|
Blink(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Blink_LedIpCamera(){
|
||||||
|
if (LedIpCamera!=null){
|
||||||
|
Blink(LedIpCamera);
|
||||||
|
} else if (pcf8574!=null && pcf8574.isOpened()){
|
||||||
|
Blink(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AmplifierControl(boolean isON){
|
||||||
|
if (AmplifierPower!=null){
|
||||||
|
Logger.info("GPIO Amplifier Power : ",isON);
|
||||||
|
GPIO.SetValue(AmplifierPower, isON);
|
||||||
|
} else if (pcf8574!=null && pcf8574.isOpened()){
|
||||||
|
if (isON){
|
||||||
|
Logger.info("PCF8574 Amplifier Power ON");
|
||||||
|
pcf8574.SetPin(6);
|
||||||
|
pcf8574.SetPin(5);
|
||||||
|
pcf8574.SetPin(4);
|
||||||
|
} else {
|
||||||
|
Logger.info("PCF8574 Amplifier Power OFF");
|
||||||
|
pcf8574.ClearPin(6);
|
||||||
|
pcf8574.ClearPin(5);
|
||||||
|
pcf8574.ClearPin(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Blink(int pin){
|
||||||
|
if (pcf8574!=null && pcf8574.isOpened()){
|
||||||
|
if (gpioExecutor!=null){
|
||||||
|
gpioExecutor.submit(()->{
|
||||||
|
pcf8574.SetPin(pin);
|
||||||
|
Sleep(20);
|
||||||
|
pcf8574.ClearPin(pin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static void Blink(JetsonOrinPins pin){
|
||||||
|
if (pin!=null){
|
||||||
|
if (gpioExecutor!=null){
|
||||||
|
gpioExecutor.submit(()->{
|
||||||
|
GPIO.SetValue(pin, true);
|
||||||
|
Sleep(20);
|
||||||
|
GPIO.SetValue(pin, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void init_system_monitoring(){
|
||||||
|
TimerTask tt = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
cpuTemperature = SystemInformation.getCPUTemperature();
|
||||||
|
ramInformation = SystemInformation.getRAMInformation();
|
||||||
|
ProcessorStatus[] cpuinfo = SystemInformation.getProcStat();
|
||||||
|
if (cpuinfo.length>0){
|
||||||
|
if (previousCpuInfo==null || !Objects.equals(previousCpuInfo.length, cpuinfo.length)){
|
||||||
|
previousCpuInfo = cpuinfo;
|
||||||
|
} else {
|
||||||
|
for(int ii=0;ii<previousCpuInfo.length;ii++){
|
||||||
|
cpuUsage.put(cpuinfo[ii].name, cpuinfo[ii].cpu_usage(previousCpuInfo[ii]));
|
||||||
|
}
|
||||||
|
previousCpuInfo = cpuinfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NetworkTransmitReceiveInfo[] ntri = SystemInformation.getNetworkTransmitReceiveInfo();
|
||||||
|
if (ntri.length>0){
|
||||||
|
if (previousNetworkInfo==null || !Objects.equals(previousNetworkInfo.length, ntri.length)){
|
||||||
|
previousNetworkInfo = ntri;
|
||||||
|
} else {
|
||||||
|
for(int ii=0;ii<previousNetworkInfo.length;ii++){
|
||||||
|
double txspeed = ntri[ii].TxSpeed(previousNetworkInfo[ii], "B");
|
||||||
|
String txspeedstr;
|
||||||
|
if (txspeed < KB_threshold){
|
||||||
|
txspeedstr = String.format("%.0f B/s", txspeed);
|
||||||
|
} else if (txspeed < MB_threshold){
|
||||||
|
txspeedstr = String.format("%.1f KB/s", ntri[ii].TxSpeed(previousNetworkInfo[ii], "KB"));
|
||||||
|
} else if (txspeed < GB_threshold){
|
||||||
|
txspeedstr = String.format("%.1f MB/s", ntri[ii].TxSpeed(previousNetworkInfo[ii], "MB"));
|
||||||
|
} else {
|
||||||
|
txspeedstr = String.format("%.1f GB/s", ntri[ii].TxSpeed(previousNetworkInfo[ii], "GB"));
|
||||||
|
}
|
||||||
|
double rxspeed = ntri[ii].RxSpeed(previousNetworkInfo[ii], "B");
|
||||||
|
String rxspeedstr;
|
||||||
|
if (rxspeed < KB_threshold){
|
||||||
|
rxspeedstr = String.format("%.0f B/s", rxspeed);
|
||||||
|
} else if (rxspeed < MB_threshold){
|
||||||
|
rxspeedstr = String.format("%.1f KB/s", ntri[ii].RxSpeed(previousNetworkInfo[ii], "KB"));
|
||||||
|
} else if (rxspeed < GB_threshold){
|
||||||
|
rxspeedstr = String.format("%.1f MB/s", ntri[ii].RxSpeed(previousNetworkInfo[ii], "MB"));
|
||||||
|
} else {
|
||||||
|
rxspeedstr = String.format("%.1f GB/s", ntri[ii].RxSpeed(previousNetworkInfo[ii], "GB"));
|
||||||
|
}
|
||||||
|
networkTX.put(ntri[ii].name, txspeedstr);
|
||||||
|
networkRX.put(ntri[ii].name, rxspeedstr);
|
||||||
|
}
|
||||||
|
previousNetworkInfo = ntri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer = new Timer();
|
||||||
|
timer.scheduleAtFixedRate(tt, 1000, 5000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void init_properties(){
|
private static void init_properties(){
|
||||||
@@ -68,15 +419,24 @@ public class Main {
|
|||||||
|
|
||||||
private static void init_Vapix(){
|
private static void init_Vapix(){
|
||||||
Properties config = SomeCodes.LoadProperties("config.properties");
|
Properties config = SomeCodes.LoadProperties("config.properties");
|
||||||
|
Logger.info("Saved Configuration for Camera");
|
||||||
String ip = config.getProperty("Camera_ip");
|
String ip = config.getProperty("Camera_ip");
|
||||||
String port = config.getProperty("Camera_port");
|
String port = config.getProperty("Camera_port");
|
||||||
String username = config.getProperty("Camera_user");
|
String username = config.getProperty("Camera_user");
|
||||||
String password = config.getProperty("Camera_password");
|
String password = config.getProperty("Camera_password");
|
||||||
|
Logger.info("Camera IP : "+ip);
|
||||||
|
Logger.info("Camera Port : "+port);
|
||||||
|
Logger.info("Camera Username : "+username);
|
||||||
|
Logger.info("Camera Password : "+password);
|
||||||
|
|
||||||
if (ValidString(ip)){
|
if (ValidString(ip)){
|
||||||
if (ValidInteger(port)){
|
if (ValidPortNumber(port)){
|
||||||
if (ValidString(username)){
|
if (ValidString(username)){
|
||||||
if (ValidString(password)){
|
if (ValidString(password)){
|
||||||
|
if (IpIsReachable(ip)){
|
||||||
|
Logger.info("Camera IP is reachable");
|
||||||
vapixProtocol = new VapixProtocol(ip, Integer.parseInt(port), username, password);
|
vapixProtocol = new VapixProtocol(ip, Integer.parseInt(port), username, password);
|
||||||
|
if (vapixProtocol.isSuccessQuery()){
|
||||||
Logger.info("Camera Product Number: "+vapixProtocol.GetProductNumber());
|
Logger.info("Camera Product Number: "+vapixProtocol.GetProductNumber());
|
||||||
Logger.info("Camera Serial Number: "+vapixProtocol.GetSerialNumber());
|
Logger.info("Camera Serial Number: "+vapixProtocol.GetSerialNumber());
|
||||||
if (vapixProtocol.PTZEnabled()){
|
if (vapixProtocol.PTZEnabled()){
|
||||||
@@ -84,21 +444,32 @@ public class Main {
|
|||||||
} else Logger.error("PTZ Disabled");
|
} else Logger.error("PTZ Disabled");
|
||||||
Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom());
|
Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom());
|
||||||
Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom());
|
Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom());
|
||||||
} else Logger.error("Invalid Camera Password");
|
Blink_LedIpCamera();
|
||||||
} else Logger.error("Invalid Camera Username");
|
} else Logger.error("Failed to query camera");
|
||||||
} else Logger.error("Invalid Camera Port");
|
} else Logger.error("Camera IP is not reachable");
|
||||||
} else Logger.error("Invalid Camera IP");
|
} else Logger.error("Camera Password is not valid string");
|
||||||
|
} else Logger.error("Camera Username is not valid string");
|
||||||
|
} else Logger.error("Camera Port is not valid");
|
||||||
|
} else Logger.error( "Camera IP is not valid string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static void init_pantiltcontroller() {
|
private static void init_pantiltcontroller() {
|
||||||
Properties config = SomeCodes.LoadProperties("config.properties");
|
Properties config = SomeCodes.LoadProperties("config.properties");
|
||||||
String portname = config.getProperty("SerialPort");
|
String portname = config.getProperty("SerialPort");
|
||||||
String baudrate = config.getProperty("SerialBaudRate");
|
String baudrate = config.getProperty("SerialBaudRate");
|
||||||
String PanTiltID = config.getProperty("PanTiltID");
|
String PanTiltID = config.getProperty("PanTiltID");
|
||||||
|
Logger.info("Saved Configuration for Pan Tilt Controller");
|
||||||
|
Logger.info("Serial Port : "+portname);
|
||||||
|
Logger.info("Serial Baud Rate : "+baudrate);
|
||||||
|
Logger.info("Pan Tilt ID : "+PanTiltID);
|
||||||
if (ValidString(portname)){
|
if (ValidString(portname)){
|
||||||
if (ValidInteger(baudrate)){
|
if (ValidInteger(baudrate)){
|
||||||
if (ValidInteger(PanTiltID)){
|
if (ValidInteger(PanTiltID)){
|
||||||
panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID));
|
panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID));
|
||||||
|
//if (panTiltController.isOpen()) test_pantiltcontroller();
|
||||||
|
panTiltController.DisableMovementTest();
|
||||||
}
|
}
|
||||||
} else Logger.error("Invalid PTZ Baudrate");
|
} else Logger.error("Invalid PTZ Baudrate");
|
||||||
} else Logger.error("Invalid PTZ Port");
|
} else Logger.error("Invalid PTZ Port");
|
||||||
@@ -109,41 +480,99 @@ public class Main {
|
|||||||
// check if really activated
|
// check if really activated
|
||||||
useOpenCL = opencv_core.useOpenCL();
|
useOpenCL = opencv_core.useOpenCL();
|
||||||
Logger.info("OpenCL available={}, activated={}", haveOpenCL, useOpenCL);
|
Logger.info("OpenCL available={}, activated={}", haveOpenCL, useOpenCL);
|
||||||
|
haveCuda = opencv_core.getCudaEnabledDeviceCount()>0;
|
||||||
|
if (haveCuda){
|
||||||
|
Logger.info("CUDA enabled devices found: " + opencv_core.getCudaEnabledDeviceCount());
|
||||||
|
//opencv_core.printCudaDeviceInfo(0);
|
||||||
|
//Logger.info("CUDA enabled : "+opencv_core.useOptimized());
|
||||||
|
opencv_core.setUseOptimized(true);
|
||||||
|
Logger.info("CUDA enabled : "+opencv_core.useOptimized());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Logger.info("No CUDA enabled devices found");
|
||||||
|
}
|
||||||
|
// BytePointer buildinfo = opencv_core.getBuildInformation();
|
||||||
|
// if (buildinfo!=null){
|
||||||
|
// Logger.info("Opencv build information : {}", buildinfo.getString());
|
||||||
|
// } else{
|
||||||
|
// Logger.error("Failed to get OpenCV build information");
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Properties config = SomeCodes.LoadProperties("config.properties");
|
Properties config = SomeCodes.LoadProperties("config.properties");
|
||||||
String targetip = config.getProperty("Camera_ip");
|
String targetip = config.getProperty("Camera_ip");
|
||||||
String rtsppath = config.getProperty("Camera_Rtsp_path");
|
String rtsppath = config.getProperty("Camera_Rtsp_path");
|
||||||
|
int width = 1920;
|
||||||
|
int height = 1080;
|
||||||
|
|
||||||
|
// test pakai sony camera, nanti hapus
|
||||||
|
// targetip = "172.17.195.51";
|
||||||
|
// rtsppath = "/video1";
|
||||||
|
// width = 1280;
|
||||||
|
// height = 720;
|
||||||
|
Logger.info("Camera IP: {}, Rtsp Path: {}, Width: {}, Height: {}", targetip, rtsppath, width,height);
|
||||||
|
|
||||||
|
rtspGrabber = null;
|
||||||
if (ValidString(targetip)){
|
if (ValidString(targetip)){
|
||||||
if (ValidString(rtsppath)){
|
if (ValidString(rtsppath)){
|
||||||
rtspGrabber = new RtspGrabber(targetip, rtsppath);
|
if (IpIsReachable(targetip)){
|
||||||
|
Logger.info("Camera IP : "+targetip+" is reachable");
|
||||||
|
rtspGrabber = new RtspGrabber_opencv(targetip, rtsppath);
|
||||||
|
rtspGrabber.Start(true, width, height);
|
||||||
|
} else Logger.warn("Camera IP : "+targetip+" is not reachable");
|
||||||
|
} else Logger.warn("Camera Path : "+rtsppath+" is not valid string");
|
||||||
|
} else Logger.warn("Camera IP : "+targetip+" is not valid string");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void init_multiusb_audio(){
|
||||||
rtspGrabber.Start(true, 1920, 1080);
|
multiUSBAudioPlayer = new MultiUSBAudioPlayer();
|
||||||
} else Logger.error("Invalid Camera Path");
|
multiUSBAudioPlayer.DetectOutputDevices();
|
||||||
} else Logger.error("Invalid Camera IP");
|
int[] devs = multiUSBAudioPlayer.FindDeviceIDWithName("USB");
|
||||||
|
if (devs!=null && devs.length>0){
|
||||||
|
Logger.info("MultiUSB Audio Device found : {}", IntArrayToString(devs));
|
||||||
|
if (multiUSBAudioPlayer.OpenDevice(devs, 48000)){
|
||||||
|
multiUSBAudioPlayer.setMasterVolume(100);
|
||||||
|
multiUSBAudioPlayer.setPlaybackvolume(100);
|
||||||
|
Logger.info("MultiUSB Audio Device ID={} opened", IntArrayToString(devs));
|
||||||
|
} else Logger.error("Failed to open MultiUSB Audio Device ID={}", IntArrayToString(devs));
|
||||||
|
} else Logger.error("MultiUSB Audio Device not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void init_audio() {
|
private static void init_audio() {
|
||||||
audioPlayer = new AudioPlayer();
|
audioPlayer = new AudioPlayer();
|
||||||
audioPlayer.DetectOutputDevices();
|
audioPlayer.DetectOutputDevices();
|
||||||
audioPlayer.OpenDevice(1,48000);
|
int devid = audioPlayer.FindDeviceIDWithName("USB");
|
||||||
|
if (devid<1) devid = audioPlayer.FindDeviceIDWithName("Speakers");
|
||||||
|
|
||||||
|
if (devid>0){
|
||||||
|
Bass.BASS_DEVICEINFO info = audioPlayer.GetDeviceInfo(devid);
|
||||||
|
if (audioPlayer.OpenDevice(devid,48000)){
|
||||||
audioPlayer.setMasterVolume(100);
|
audioPlayer.setMasterVolume(100);
|
||||||
audioPlayer.setPlaybackvolume(100);
|
audioPlayer.setPlaybackvolume(100);
|
||||||
|
Logger.info("Audio Device ID={} opened : {}", devid, info.name);
|
||||||
|
} else Logger.error("Failed to open Audio Device ID={}", devid);
|
||||||
|
} else Logger.error("USB Audio Device not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
static PlaybackEvent pe = new PlaybackEvent() {
|
static PlaybackEvent pe = new PlaybackEvent() {
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackStart(AudioFileProperties prop) {
|
public void onPlaybackStart(AudioFileProperties prop) {
|
||||||
Logger.info("Playback started for {}", prop.filename);
|
Logger.info("Playback started for {}", prop.filename);
|
||||||
|
AmplifierControl(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackFinished(AudioFileProperties prop) {
|
public void onPlaybackFinished(AudioFileProperties prop) {
|
||||||
Logger.info("Playback finished for {}", prop.filename);
|
Logger.info("Playback finished for {}", prop.filename);
|
||||||
|
AmplifierControl(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackFailure(AudioFileProperties prop, String reason) {
|
public void onPlaybackFailure(AudioFileProperties prop, String reason) {
|
||||||
Logger.error("Playback failed for {}: {}", prop.filename, reason);
|
Logger.error("Playback failed for {}: {}", prop.filename, reason);
|
||||||
|
AmplifierControl(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -160,36 +589,63 @@ public class Main {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebsocketReply onWebsocketCommand(WebsocketCommand command) {
|
public WebsocketReply onWebsocketCommand(WebsocketCommand command) {
|
||||||
|
Blink_LedWeb();
|
||||||
byte speed;
|
byte speed;
|
||||||
String cmd = command.command.toUpperCase().trim();
|
String cmd = command.command.toUpperCase().trim();
|
||||||
switch (cmd){
|
switch (cmd){
|
||||||
// Pan Tilt Movement Commands
|
// Pan Tilt Movement Commands
|
||||||
case "PAN LEFT" :
|
case "PAN LEFT" :
|
||||||
|
Logger.info("PAN LEFT");
|
||||||
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
||||||
if (panTiltController!=null) panTiltController.PanLeft(speed);
|
if (panTiltController!=null) {
|
||||||
|
panTiltController.PanLeft(speed);
|
||||||
|
}
|
||||||
return new WebsocketReply("PAN LEFT", String.valueOf(speed));
|
return new WebsocketReply("PAN LEFT", String.valueOf(speed));
|
||||||
case "PAN RIGHT" :
|
case "PAN RIGHT" :
|
||||||
|
Logger.info("PAN RIGHT");
|
||||||
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
||||||
if (panTiltController!=null) panTiltController.PanRight(speed);
|
if (panTiltController!=null) {
|
||||||
|
panTiltController.PanRight(speed);
|
||||||
|
}
|
||||||
return new WebsocketReply("PAN RIGHT", String.valueOf(speed));
|
return new WebsocketReply("PAN RIGHT", String.valueOf(speed));
|
||||||
case "TILT UP" :
|
case "TILT UP" :
|
||||||
|
Logger.info("TILT UP");
|
||||||
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
||||||
if (panTiltController!=null) panTiltController.TiltUp(speed);
|
// kebalik
|
||||||
|
//if (panTiltController!=null) panTiltController.TiltUp(speed);
|
||||||
|
if (panTiltController!=null) {
|
||||||
|
panTiltController.TiltDown(speed);
|
||||||
|
}
|
||||||
return new WebsocketReply("TILT UP", String.valueOf(speed));
|
return new WebsocketReply("TILT UP", String.valueOf(speed));
|
||||||
case "TILT DOWN" :
|
case "TILT DOWN" :
|
||||||
|
Logger.info("TILT DOWN");
|
||||||
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
speed = GetPanTiltSpeed(command.data, (byte)0x20);
|
||||||
if (panTiltController!=null) panTiltController.TiltDown(speed);
|
// kebalik
|
||||||
|
//if (panTiltController!=null) panTiltController.TiltDown(speed);
|
||||||
|
if (panTiltController!=null) {
|
||||||
|
panTiltController.TiltUp(speed);
|
||||||
|
}
|
||||||
return new WebsocketReply("TILT DOWN", String.valueOf(speed));
|
return new WebsocketReply("TILT DOWN", String.valueOf(speed));
|
||||||
case "STOP MOVEMENT" :
|
case "STOP MOVEMENT" :
|
||||||
if (panTiltController!=null) panTiltController.StopMovement();
|
Logger.info("STOP MOVEMENT");
|
||||||
|
if (panTiltController!=null) {
|
||||||
|
panTiltController.StopMovement();
|
||||||
|
}
|
||||||
return new WebsocketReply("STOP MOVEMENT", "");
|
return new WebsocketReply("STOP MOVEMENT", "");
|
||||||
// Audio Related Commands
|
// Audio Related Commands
|
||||||
case "MUTE":
|
case "MUTE":
|
||||||
audioPlayer.Mute();
|
if (use_multiusb_audio){
|
||||||
|
if (multiUSBAudioPlayer!=null) multiUSBAudioPlayer.Mute();
|
||||||
|
} else {
|
||||||
|
if (audioPlayer!=null) audioPlayer.Mute();
|
||||||
|
}
|
||||||
return new WebsocketReply("MUTE", "");
|
return new WebsocketReply("MUTE", "");
|
||||||
case "UNMUTE":
|
case "UNMUTE":
|
||||||
audioPlayer.Unmute();
|
if (use_multiusb_audio){
|
||||||
|
if (multiUSBAudioPlayer!=null) multiUSBAudioPlayer.Unmute();
|
||||||
|
} else {
|
||||||
|
if (audioPlayer!=null) audioPlayer.Unmute();
|
||||||
|
}
|
||||||
return new WebsocketReply("UNMUTE", "");
|
return new WebsocketReply("UNMUTE", "");
|
||||||
case "SET VOLUME" :
|
case "SET VOLUME" :
|
||||||
int volume=-1;
|
int volume=-1;
|
||||||
@@ -199,11 +655,20 @@ public class Main {
|
|||||||
if (volume>100) volume = 100;
|
if (volume>100) volume = 100;
|
||||||
}
|
}
|
||||||
if (volume>=0){
|
if (volume>=0){
|
||||||
audioPlayer.setPlaybackvolume(volume);
|
if (use_multiusb_audio){
|
||||||
|
if (multiUSBAudioPlayer!=null) multiUSBAudioPlayer.setPlaybackvolume(volume);
|
||||||
|
} else{
|
||||||
|
if (audioPlayer!=null) audioPlayer.setPlaybackvolume(volume);
|
||||||
|
}
|
||||||
return new WebsocketReply("SET VOLUME", String.valueOf(volume));
|
return new WebsocketReply("SET VOLUME", String.valueOf(volume));
|
||||||
} else return new WebsocketReply("SET VOLUME", "Invalid Volume Value");
|
} else return new WebsocketReply("SET VOLUME", "Invalid Volume Value");
|
||||||
case "GET VOLUME" :
|
case "GET VOLUME" :
|
||||||
int vol = audioPlayer.getPlaybackvolume();
|
int vol = 0;
|
||||||
|
if (use_multiusb_audio){
|
||||||
|
if (multiUSBAudioPlayer!=null) vol = multiUSBAudioPlayer.getPlaybackvolume();
|
||||||
|
} else {
|
||||||
|
if (audioPlayer!=null) vol = audioPlayer.getPlaybackvolume();
|
||||||
|
}
|
||||||
return new WebsocketReply("GET VOLUME", String.valueOf(vol));
|
return new WebsocketReply("GET VOLUME", String.valueOf(vol));
|
||||||
case "PLAY AUDIO" :
|
case "PLAY AUDIO" :
|
||||||
if (ValidInteger(command.data)){
|
if (ValidInteger(command.data)){
|
||||||
@@ -212,60 +677,162 @@ public class Main {
|
|||||||
if (ValidString(filename)){
|
if (ValidString(filename)){
|
||||||
File filetoplay = new File(Path.of(currentDirectory, "audiofiles", filename).toString());
|
File filetoplay = new File(Path.of(currentDirectory, "audiofiles", filename).toString());
|
||||||
if (filetoplay.isFile()){
|
if (filetoplay.isFile()){
|
||||||
|
if (use_multiusb_audio){
|
||||||
|
MultiUSBAudioPlayer.PlaybackHandlewithId[] phs = multiUSBAudioPlayer.OpenAudioFile(filetoplay);
|
||||||
|
if (phs!=null && phs.length>0){
|
||||||
|
playbackHandles = phs;
|
||||||
|
multiUSBAudioPlayer.PlayAudioFile(phs, true, pe);
|
||||||
|
return new WebsocketReply("PLAY AUDIO", filename);
|
||||||
|
}
|
||||||
|
return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename);
|
||||||
|
} else {
|
||||||
AudioFileProperties afp = audioPlayer.OpenAudioFile(filetoplay);
|
AudioFileProperties afp = audioPlayer.OpenAudioFile(filetoplay);
|
||||||
if (afp!=null){
|
if (afp!=null){
|
||||||
audioFileProperties = afp;
|
audioFileProperties = afp;
|
||||||
audioPlayer.PlayAudioFile(afp, true, pe);
|
audioPlayer.PlayAudioFile(afp, true, pe);
|
||||||
|
//AmplifierControl(true);
|
||||||
return new WebsocketReply("PLAY AUDIO", afp.filename);
|
return new WebsocketReply("PLAY AUDIO", afp.filename);
|
||||||
} else return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename);
|
} else return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename);
|
||||||
|
}
|
||||||
|
|
||||||
} else return new WebsocketReply("PLAY AUDIO", "Audio file not found : "+filename);
|
} else return new WebsocketReply("PLAY AUDIO", "Audio file not found : "+filename);
|
||||||
} else return new WebsocketReply("PLAY AUDIO", String.format("AudioFile with ID %02d not found", id));
|
} else return new WebsocketReply("PLAY AUDIO", String.format("AudioFile with ID %02d not found", id));
|
||||||
} else return new WebsocketReply("PLAY AUDIO", "Invalid Audio ID");
|
} else return new WebsocketReply("PLAY AUDIO", "Invalid Audio ID");
|
||||||
case "STOP AUDIO" :
|
case "STOP AUDIO" :
|
||||||
|
if (use_multiusb_audio){
|
||||||
|
if (playbackHandles!=null && playbackHandles.length>0){
|
||||||
|
multiUSBAudioPlayer.CloseAudioFile(playbackHandles);
|
||||||
|
String filename = playbackHandles[0].handle.filename;
|
||||||
|
playbackHandles = null;
|
||||||
|
return new WebsocketReply("STOP AUDIO", filename);
|
||||||
|
} else return new WebsocketReply("STOP AUDIO", "No playbackHandles");
|
||||||
|
} else {
|
||||||
if (audioFileProperties!=null){
|
if (audioFileProperties!=null){
|
||||||
audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file
|
audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file
|
||||||
String filename = audioFileProperties.filename;
|
String filename = audioFileProperties.filename;
|
||||||
audioFileProperties = null;
|
audioFileProperties = null;
|
||||||
|
//AmplifierControl(false);
|
||||||
return new WebsocketReply("STOP AUDIO", filename);
|
return new WebsocketReply("STOP AUDIO", filename);
|
||||||
} else return new WebsocketReply("STOP AUDIO", "No audioFileProperties");
|
} else return new WebsocketReply("STOP AUDIO", "No audioFileProperties");
|
||||||
|
}
|
||||||
|
|
||||||
// ZOOM Related Commands
|
// ZOOM Related Commands
|
||||||
case "GET MAX ZOOM":
|
case "GET MAX ZOOM":
|
||||||
if (vapixProtocol!=null){
|
if (vapixProtocol!=null){
|
||||||
|
Blink_LedIpCamera();
|
||||||
return new WebsocketReply("GET MAX ZOOM", String.valueOf(vapixProtocol.GetPTZMaxZoom()));
|
return new WebsocketReply("GET MAX ZOOM", String.valueOf(vapixProtocol.GetPTZMaxZoom()));
|
||||||
} else return new WebsocketReply("GET MAX ZOOM", "VapixProtocol not initialized");
|
} else return new WebsocketReply("GET MAX ZOOM", "VapixProtocol not initialized");
|
||||||
case "GET ZOOM":
|
case "GET ZOOM":
|
||||||
if (vapixProtocol!=null){
|
if (vapixProtocol!=null){
|
||||||
|
Blink_LedIpCamera();
|
||||||
return new WebsocketReply("GET ZOOM", String.valueOf(vapixProtocol.GetCurrentZoomValue()));
|
return new WebsocketReply("GET ZOOM", String.valueOf(vapixProtocol.GetCurrentZoomValue()));
|
||||||
} else return new WebsocketReply("GET ZOOM", "VapixProtocol not initialized");
|
} else return new WebsocketReply("GET ZOOM", "VapixProtocol not initialized");
|
||||||
case "SET ZOOM":
|
case "SET ZOOM":
|
||||||
|
if (vapixProtocol!=null){
|
||||||
if (vapixProtocol.PTZEnabled()){
|
if (vapixProtocol.PTZEnabled()){
|
||||||
if (ValidInteger(command.data)){
|
if (ValidInteger(command.data)){
|
||||||
int zoom = Integer.parseInt(command.data);
|
int zoom = Integer.parseInt(command.data);
|
||||||
if (zoom<vapixProtocol.GetPTZMinZoom()) zoom = vapixProtocol.GetPTZMinZoom();
|
if (zoom<vapixProtocol.GetPTZMinZoom()) zoom = vapixProtocol.GetPTZMinZoom();
|
||||||
if (zoom>vapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom();
|
if (zoom>vapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom();
|
||||||
|
Blink_LedIpCamera();
|
||||||
if (vapixProtocol.Zoom(1, zoom)){
|
if (vapixProtocol.Zoom(1, zoom)){
|
||||||
return new WebsocketReply("ZOOM", String.valueOf(zoom));
|
return new WebsocketReply("ZOOM", String.valueOf(zoom));
|
||||||
} else return new WebsocketReply("ZOOM", "Failed to zoom");
|
} else return new WebsocketReply("ZOOM", "Failed to zoom");
|
||||||
} else return new WebsocketReply("ZOOM", "Invalid Zoom Value");
|
} else return new WebsocketReply("ZOOM", "Invalid Zoom Value");
|
||||||
} else return new WebsocketReply("ZOOM", "Zoom not supported");
|
} else return new WebsocketReply("ZOOM", "Zoom not supported");
|
||||||
|
}
|
||||||
|
|
||||||
// Live Streaming Related Commands
|
// Live Streaming Related Commands
|
||||||
case "GET BASE64":
|
case "GET BASE64":
|
||||||
if (rtspGrabber!=null){
|
if (rtspGrabber!=null){
|
||||||
if (Objects.equals(command.data,"HQ"))
|
if (use_Yolo){
|
||||||
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), String.format("Streaming at %dx%d", rtspGrabber.getHQWidth(), rtspGrabber.getHQHeight()));
|
return switch (command.data) {
|
||||||
else
|
case "HQ" ->
|
||||||
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), String.format("Streaming at %dx%d", rtspGrabber.getLQWidth(), rtspGrabber.getLQHeight()));
|
new WebsocketReply("GET BASE64", "data:image/jpeg;base64," + rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus());
|
||||||
|
case "YOLO" ->
|
||||||
|
new WebsocketReply("GET BASE64", "data:image/jpeg;base64," + rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus());
|
||||||
|
case "LQ" ->
|
||||||
|
new WebsocketReply("GET BASE64", "data:image/jpeg;base64," + rtspGrabber.getLastYoloBase64(), rtspGrabber.LQStreamingStatus());
|
||||||
|
default -> new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return switch (command.data) {
|
||||||
|
case "HQ" ->
|
||||||
|
new WebsocketReply("GET BASE64", "data:image/jpeg;base64," + rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus());
|
||||||
|
case "LQ" ->
|
||||||
|
new WebsocketReply("GET BASE64", "data:image/jpeg;base64," + rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus());
|
||||||
|
default -> new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
|
} else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
|
||||||
case "GET RESOLUTION":
|
case "GET RESOLUTION":
|
||||||
if (vapixProtocol!=null){
|
if (vapixProtocol!=null){
|
||||||
int[] res = vapixProtocol.GetCurrentResolution(1);
|
int[] res = vapixProtocol.GetCurrentResolution(1);
|
||||||
|
Blink_LedIpCamera();
|
||||||
return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1]));
|
return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1]));
|
||||||
} else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized");
|
} else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized");
|
||||||
|
case "GET AUDIOFILES":
|
||||||
|
AudioFilesInfo afi = new AudioFilesInfo();
|
||||||
|
afi.preset1 = GetConfigAudioFile(1);
|
||||||
|
afi.preset2 = GetConfigAudioFile(2);
|
||||||
|
afi.preset3 = GetConfigAudioFile(3);
|
||||||
|
afi.preset4 = GetConfigAudioFile(4);
|
||||||
|
afi.preset5 = GetConfigAudioFile(5);
|
||||||
|
return new WebsocketReply("GET AUDIOFILES", gson.toJson(afi));
|
||||||
|
case "GET SYSTEM INFO":
|
||||||
|
JsonObject data = new JsonObject();
|
||||||
|
data.addProperty("cpu_temperature", String.valueOf(cpuTemperature));
|
||||||
|
if (ramInformation!=null) {
|
||||||
|
data.addProperty("ram_usage", String.format("%.1f", ramInformation.RamUsagePercentage()));
|
||||||
|
}
|
||||||
|
if (!cpuUsage.isEmpty()) {
|
||||||
|
for(String key : cpuUsage.keySet()){
|
||||||
|
data.addProperty(key, String.valueOf(cpuUsage.get(key)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!networkTX.isEmpty()) {
|
||||||
|
for(String key : networkTX.keySet()){
|
||||||
|
if (key.equals("lo")) continue;
|
||||||
|
data.addProperty(key+"_TX", networkTX.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!networkRX.isEmpty()) {
|
||||||
|
for(String key : networkRX.keySet()){
|
||||||
|
if (key.equals("lo")) continue;
|
||||||
|
data.addProperty(key+"_RX", networkRX.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new WebsocketReply("GET SYSTEM INFO", data.toString());
|
||||||
default:
|
default:
|
||||||
return new WebsocketReply("UNKNOWN COMMAND", command.command);
|
return new WebsocketReply("UNKNOWN COMMAND", command.command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void NewCameraConfiguration() {
|
||||||
|
Logger.info("New Camera Configuration detected");
|
||||||
|
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||||
|
String camera_ip = prop.getProperty("Camera_ip");
|
||||||
|
String camera_port = prop.getProperty("Camera_port");
|
||||||
|
String camera_user = prop.getProperty("Camera_user");
|
||||||
|
String camera_password = prop.getProperty("Camera_password");
|
||||||
|
String camera_rtsp_path = prop.getProperty("Camera_Rtsp_path");
|
||||||
|
Logger.info("Camera Ip: "+camera_ip);
|
||||||
|
Logger.info("Camera Port: "+camera_port);
|
||||||
|
Logger.info("Camera User: "+camera_user);
|
||||||
|
Logger.info("Camera Password: "+camera_password);
|
||||||
|
Logger.info("Camera Rtsp Path: "+camera_rtsp_path);
|
||||||
|
|
||||||
|
if (rtspGrabber!=null) rtspGrabber.Stop();
|
||||||
|
init_rtspgrabber();
|
||||||
|
Logger.info("RtspGrabber recreated");
|
||||||
|
|
||||||
|
if (vapixProtocol!=null) vapixProtocol.Close();
|
||||||
|
init_Vapix();
|
||||||
|
Logger.info("VapixProtocol recreated");
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static void init_webserver() {
|
private static void init_webserver() {
|
||||||
|
|||||||
Reference in New Issue
Block a user