Compare commits

...

9 Commits

Author SHA1 Message Date
a1b6ec54ab Patch 17/03/2025 2025-03-17 13:35:05 +07:00
123a89eec9 Patch 04/03/2025 2025-03-04 12:25:02 +07:00
e1d129fa07 Kirim ke Bandara 27/02/2025 2025-02-27 15:11:56 +07:00
5f8d1946c0 YOLODetector is working (25/02/2025) 2025-02-25 13:56:57 +07:00
ce5c8d5946 Change SBC to Jetson Orin 2025-02-25 07:35:38 +07:00
21e8ab1e82 Change SBC to Jetson Orin 2024-12-03 15:59:18 +07:00
ea891d2744 GPIO checked for Raspberry Pi 5B 2024-12-03 15:22:44 +07:00
f2d560049f Changes by Monika DV 2024-11-28 15:00:37 +07:00
f515f829cf GPIO control.
Bug fix.
2024-11-15 11:22:16 +07:00
35 changed files with 2764 additions and 470 deletions

View File

@@ -4,6 +4,7 @@
<inspection_tool class="ExtractMethodRecommender" enabled="true" level="WARNING" enabled_by_default="true">
<option name="minLength" value="745" />
</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">
<option name="ignoredUrls">
<list>
@@ -35,6 +36,7 @@
</list>
</option>
</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="RedundantCast" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">

1
.idea/misc.xml generated
View File

@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">

View File

@@ -4,13 +4,14 @@ Camera_port = 80
Camera_user = root
Camera_password = password
Camera_Rtsp_path = /axis-media/media.amp
#Camera_Rtsp_path = /video1
AudioFile01 = elangWav.wav
AudioFile02 = gunshotsWav.wav
AudioFile03 = pinkNoiseWav.wav
AudioFile04 = 04.mp3
AudioFile05 = 05.mp3
AudioVolumeOutput = 100
SerialPort = /dev/ttyAMA0
SerialPort = /dev/ttyTHS1
SerialBaudRate = 9600
PanTiltID = 1
WebUsername = admin

View File

@@ -30,11 +30,11 @@
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<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 class="nav-item pad-menu">
<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>
</li>
</ul>
@@ -108,7 +108,7 @@
<br>
<div class="row">
<div class="col-3 ">
<p>Pan Speed</p>
<p class="text-dash">Pan Speed</p>
<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="pan2" class="btn btn-outline-dark btn-sm" value="32" onclick="set_pan_speed(32)">2</button>
@@ -134,8 +134,8 @@
</a>
</div>
<div class="col">
<a>
<i id="btn_center" class="btn-nav-center fa-solid fa-circle"></i>
<a onmousedown="send_stop_movement()">
<i id="btn_center" class="btn-nav-center fa-solid fa-circle" title="Stop Movement"></i>
</a>
</div>
<div class="col">
@@ -156,7 +156,7 @@
</div>
</div>
<div class="col-3">
<p>Tilt Speed</p>
<p class="text-dash">Tilt Speed</p>
<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="tilt2" class="btn btn-outline-dark btn-sm" value="32" onclick="set_tilt_speed(32)">2</button>
@@ -166,14 +166,14 @@
</div>
</div>
<div>
<p class="text-center">Zoom</p>
<p class="text-center text-dash">Zoom</p>
<div class="row">
<div class="col-10">
<input id="zoom" type="range" class="form-range" min="1" max="10909" oninput="this.nextElementSibling.value = this.value">
<output class="output"></output>
</div>
<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>
@@ -250,7 +250,7 @@
</div>
<br>
<div>
<label for="customRange" class="form-label">Volume</label>
<label for="customRange" class="form-label text-dash">Volume</label>
<div class="row">
<div class="col-10 pad-bar">
@@ -276,7 +276,7 @@
<!-- SECTION 3 -->
<div class="container-fluid footer1 outside">
<p>2024 Copyright &copy; Galva Technologies. All rights reserved.</p>
<p class="footer">2024 Copyright &copy; Galva Technologies. All rights reserved.</p>
</div>
</body>
</html>

View File

@@ -692,11 +692,12 @@ function process_command(dx){
* @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.end0_TX && systeminfo.end0_TX.length>0) $('#ethernet_TX').html(systeminfo.end0_TX);
if (systeminfo.end0_RX && systeminfo.end0_RX.length>0) $('#ethernet_RX').html(systeminfo.end0_RX);
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);

7
Html/html/public/js/socket.io.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -833,7 +833,6 @@ input.checkbox{
justify-content: center;
gap: 10px;
}
/* Style the labels (Off and On) */
.toggle-label {
@@ -911,3 +910,433 @@ select {
.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;
}
}

View File

@@ -28,11 +28,11 @@
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<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 class="nav-item pad-menu">
<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>
</li>
</ul>
@@ -46,7 +46,7 @@
<div class="container">
<div class="card card-shadow">
<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 class="card-body bg-gray">
<!-- PRESET 1-->
@@ -55,7 +55,7 @@
<p>Preset 1</p>
</div>
<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 2</option>
</select>
@@ -67,7 +67,7 @@
<p>Preset 2</p>
</div>
<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 2</option>
</select>
@@ -79,7 +79,7 @@
<p>Preset 3</p>
</div>
<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 2</option>
</select>
@@ -91,7 +91,7 @@
<p>Preset 4</p>
</div>
<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 2</option>
</select>
@@ -103,7 +103,7 @@
<p>Preset 5</p>
</div>
<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 2</option>
</select>
@@ -112,7 +112,7 @@
<div class="row mt-2">
<div class="col-6"></div>
<div class="col-6">
<button id="save_audio" 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>
@@ -120,7 +120,7 @@
<div class="card mt-5 card-shadow">
<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 class="card-body bg-gray">
<form action="/setting/uploadaudiofile" method="post" enctype="multipart/form-data">
@@ -129,10 +129,10 @@
<p> Upload audio files</p>
</div>
<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4">
<input class="form-control" type="file" name="file" required title="Select Audio File">
<input class="form-control text-input" type="file" name="file" required title="Select Audio File">
</div>
<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>
</form>
@@ -142,7 +142,7 @@
<div class="card mt-5 card-shadow">
<div class="card-header bg-secondary text-light ">
<h5 class="text-center">Camera</h5>
<h5 class="text-center setting-title">Camera</h5>
</div>
<div class="card-body bg-gray">
<div class="row mt-2">
@@ -150,7 +150,7 @@
<p>IP Address</p>
</div>
<div class="col-6">
<input id="setting_ip" name="ip" class="form-control" title="IP Address">
<input id="setting_ip" name="ip" class="form-control text-input" title="IP Address">
</div>
</div>
<div class="row mt-2">
@@ -158,7 +158,7 @@
<p>Port</p>
</div>
<div class="col-6">
<input id="setting_port" name="port" class="form-control" title="Port">
<input id="setting_port" name="port" class="form-control text-input" title="Port">
</div>
</div>
@@ -167,7 +167,7 @@
<p>Username</p>
</div>
<div class="col-6">
<input id="setting_username" name="username" class="form-control" title="Username">
<input id="setting_username" name="username" class="form-control text-input" title="Username">
</div>
</div>
@@ -177,7 +177,7 @@
</div>
<div class="col-6">
<div class="input-group">
<input type="password" id="setting_password" name="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()">
<i class="fa-solid fa-eye" id="icon_camera"></i>
</span>
@@ -187,7 +187,7 @@
<div class="row mt-2">
<div class="col-6"></div>
<div class="col-6">
<button id="save_camera" 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>
@@ -195,7 +195,7 @@
<div class="card mt-5 card-shadow">
<div class="card-header bg-secondary text-light">
<h5 class="text-center">Login</h5>
<h5 class="text-center setting-title">Login</h5>
</div>
<div class="card-body bg-gray">
<div class="row mt-2">
@@ -203,7 +203,7 @@
<p>Username</p>
</div>
<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 class="row mt-2">
@@ -212,7 +212,7 @@
</div>
<div class="col-6">
<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()">
<i class="fa-solid fa-eye" id="icon_password"></i>
</span>
@@ -225,7 +225,7 @@
</div>
<div class="col-6">
<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()">
<i class="fa-solid fa-eye" id="icon_confirm"></i>
</span>
@@ -235,7 +235,7 @@
<div class="row mt-2">
<div class="col-6"></div>
<div class="col-6">
<button id="save_login" 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>
@@ -245,7 +245,7 @@
<!-- SECTION 3 -->
<div class="container-fluid footer1 outside">
<p>2024 Copyright &copy; Galva Technologies. All rights reserved.</p>
<p class="footer">2024 Copyright &copy; Galva Technologies. All rights reserved.</p>
</div>
</body>
</html>

View File

@@ -2,17 +2,18 @@
AudioFile01=elangWav.wav
AudioFile02=gunshotsWav.wav
AudioFile03=pinkNoiseWav.wav
AudioFile04=
AudioFile04=null
AudioFile05=null
AudioVolumeOutput=100
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_port=80
Camera_user=root
PanTiltID=1
SerialBaudRate=9600
SerialPort=/dev/ttyAMA0
SerialPort=/dev/ttyTHS1
WebHost=0.0.0.0
WebPassword=bandara
WebPort=8080

80
onnx/coco.names Normal file
View 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

Binary file not shown.

231
pom.xml
View File

@@ -15,195 +15,78 @@
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.11</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.8</version>
<exclusions>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>leptonica</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>leptonica-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>artoolkitplus</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>artoolkitplus-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>libdc1394</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>libdc1394-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>libfreenect</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>libfreenect-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>libfreenect2</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>libfreenect2-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>flycapture</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>flycapture-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>librealsense</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>librealsense-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>librealsense2</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>librealsense2-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>videoinput</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>videoinput-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>tesseract</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>tesseract-platform</artifactId>
</exclusion>
<!-- platform dibuangin semua, kemudian tambah sendiri linux-arm64, windows-x86_64, linux-x86_64 -->
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>openblas-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>opencv-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>flandmark</artifactId>
</exclusion>
<exclusion>
<groupId>org.bytedeco</groupId>
<artifactId>flandmark-platform</artifactId>
</exclusion>
</exclusions>
<artifactId>opencv</artifactId>
<version>4.10.0-1.5.11</version>
<classifier>windows-x86_64</classifier>
</dependency>
<!-- manual tambah untuk platform windows-x86_64 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.6.0-1.5.8</version>
<classifier>windows-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.8</version>
<classifier>windows-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.21-1.5.8</version>
<classifier>windows-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>5.1.2-1.5.8</version>
<classifier>windows-x86_64</classifier>
</dependency>
<!-- manual tambah untuk platform linux-arm64-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.6.0-1.5.8</version>
<classifier>linux-arm64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.8</version>
<classifier>linux-arm64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.21-1.5.8</version>
<version>4.10.0-1.5.11</version>
<classifier>linux-arm64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>5.1.2-1.5.8</version>
<classifier>linux-arm64</classifier>
</dependency>
<!-- manual tambah untuk platform linux-x86_64
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.9.0-1.5.10</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.10</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.26-1.5.10</version>
<classifier>linux-x86_64</classifier>
<version>7.1-1.5.11</version>
<classifier>windows-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.1.1-1.5.10</version>
<classifier>linux-x86_64</classifier>
<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>
@@ -212,7 +95,7 @@
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version> 6.3.0</version>
<version> 6.4.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
@@ -227,7 +110,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>

View File

@@ -1,14 +1,33 @@
package Audio;
public class AudioFileProperties {
public final int handle;
public final String filename;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
public class AudioFileProperties extends Structure {
public int handle;
public String filename;
public long Length;
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.filename = filename;
this.Length = length;
this.duration = duration;
write();
}
protected List<String> getFieldOrder() {
return Arrays.asList("handle", "filename", "Length", "duration");
}
}

View File

@@ -193,9 +193,9 @@ public class AudioPlayer {
int handle = bass.BASS_StreamCreateFile(false, ff.getAbsolutePath(), 0, 0,0);
if (handle!=0){
Logger.info("Audio file {} opened successfully", ff.getName());
AudioFileProperties prop = new AudioFileProperties(handle, ff.getName());
prop.Length = bass.BASS_ChannelGetLength(handle, Bass.BASS_POS_BYTE);
prop.duration = bass.BASS_ChannelBytes2Seconds(handle, prop.Length);
long Length = bass.BASS_ChannelGetLength(handle, Bass.BASS_POS_BYTE);
double duration = bass.BASS_ChannelBytes2Seconds(handle, Length);
AudioFileProperties prop = new AudioFileProperties(handle, ff.getName(), Length, duration);
return prop;
} else Logger.error("Failed to open audio file {}, Error Code {}", ff.getAbsolutePath(), bass.BASS_ErrorGetCode());
} else Logger.info("AudioPlayer not initialized");
@@ -217,8 +217,39 @@ public class AudioPlayer {
} else Logger.info("Audio file {} closed successfully", prop.filename);
} 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
@@ -226,23 +257,23 @@ public class AudioPlayer {
* @param event PlaybackEvent object to handle playback event
*/
public void PlayAudioFile(AudioFileProperties prop, boolean looping, PlaybackEvent event){
this.playbackEvent = null;
if (inited){
if (prop!=null){
if (bass.BASS_ChannelStart(prop.handle)){
this.playbackEvent = event;
playbackhandle = prop.handle;
// SyncProcValue spv = new SyncProcValue(prop);
// spv.write();
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 (event!=null) event.onPlaybackStart(prop);
int devfailsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_DEV_FAIL,0, (handle, channel, data, user)->{
if (event!=null) event.onPlaybackFailure(prop, "Device Failure");
}, null);
int devfailsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_DEV_FAIL,0, failproc, prop.getPointer());
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)->{
if (looping) {
if (event!=null) event.onPlaybackLooped(prop);
} else if (event!=null) event.onPlaybackFinished(prop);
}, null);
int endsync = bass.BASS_ChannelSetSync(prop.handle, Bass.BASS_SYNC_END , 0, endproc, prop.getPointer());
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 {
if (event!=null) event.onPlaybackFailure(prop, String.format("Failed to play audio file %s, Error Code %d", prop.filename, bass.BASS_ErrorGetCode()));
}
@@ -254,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");
// }
//
//
// }
}

View File

@@ -2,6 +2,8 @@ package Audio;
import com.sun.jna.*;
import java.util.Objects;
@SuppressWarnings("unused")
public interface Bass extends Library {

View 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;
}
}
}

View File

@@ -5,10 +5,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import Other.SomeCodes;
import id.co.gtc.Main;
import lombok.Getter;
import lombok.Setter;
import org.bytedeco.javacv.Frame;
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 {
@@ -23,6 +27,8 @@ public class GrabbingTask implements Runnable {
@Setter private Consumer<Frame> onLQFrameUpdate;
@Setter private Consumer<String> onHQBase64Update;
@Setter private Consumer<String> onLQBase64Update;
@Setter private Consumer<Frame> onYoloUpdate;
@Setter private Consumer<String> onYoloBase64Update;
// status of capture fps
@Getter private int CaptureFPS = 0;
@@ -33,6 +39,9 @@ public class GrabbingTask implements Runnable {
// for FPS calculation
private int intendedFps = 10;
private final YoloDetector_opencv yolo;
@SuppressWarnings("SameParameterValue")
private void updateMessage(String message) {
if (onMessageUpdate != null) {
@@ -40,9 +49,17 @@ public class GrabbingTask implements Runnable {
}
}
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) {
if (onHQBase64Update != null) {
@@ -77,6 +94,9 @@ public class GrabbingTask implements Runnable {
this.isGrabbing = isGrabbing;
this.grabber = grabber;
if (fps>0) intendedFps = fps;
if (Main.use_Yolo) {
yolo = new YoloDetector_opencv();
} else yolo = null;
}
@@ -84,14 +104,69 @@ public class GrabbingTask implements Runnable {
isGrabbing.set(false);
}
private void processFrame(Frame fr){
if (fr!=null){
updateHQFrame(fr);
updateHQBase64(SomeCodes.FrameToBase64(fr));
Frame resized = SomeCodes.ResizeFrame(fr, lowquality_width, lowquality_height);
updateLQFrame(resized);
updateLQBase64(SomeCodes.FrameToBase64(resized));
} else updateMessage("processFrame have null frame");
@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(){
@@ -102,31 +177,43 @@ public class GrabbingTask implements Runnable {
}
}
@SuppressWarnings("CallToPrintStackTrace")
@Override
public void run() {
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);
Logger.info("Grabber framerate = {}, intendedFps = {}, Skipping frames = {}", fps, intendedFps, skippedframes);
int framecount = 0;
flush_grabber();
long starttick = System.currentTimeMillis();
while (isGrabbing.get()) {
try{
Thread.yield();
Frame frame = grabber.grab();
if (framecount<Integer.MAX_VALUE) framecount++; else framecount = 0;
if (framecount % skippedframes == 0) processFrame(frame);
Mat resized = processFrame(frame);
// no need to skip frames, just process all frames
if (framecount % skippedframes == 0) {
if (Main.use_Yolo){
DetectYolo(resized);
}
}
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;
//if (xx<fps) CaptureFPS = xx;
CaptureFPS = xx;
}
//Logger.info("Elapsed time = {} ms, captureFPS = {}", elapsed, CaptureFPS);
}

View File

@@ -24,12 +24,14 @@ public class PanTiltController {
if (comports.length>0){
for (SerialPort port : comports){
Logger.info("Available Serial Port : {}", port.getSystemPortName());
if (port.getSystemPortName().equals(portname)){
if (portname.contains(port.getSystemPortName())){
Logger.info("Serial Port {} found", portname);
serialPort = port;
break;
}
}
if (serialPort!=null){
serialPort.setBaudRate(baudrate);
@@ -68,10 +70,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) {
Main.Max485Direction(true);
serialPort.writeBytes(command, command.length);
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");
}
/**
@@ -87,10 +90,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) {
Main.Max485Direction(true);
serialPort.writeBytes(command, command.length);
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");
}
/**
@@ -106,10 +110,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) {
Main.Max485Direction(true);
serialPort.writeBytes(command, command.length);
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");
}
/**
@@ -120,15 +125,16 @@ public class PanTiltController {
if (speed<0) speed = 0;
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[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) {
Main.Max485Direction(true);
serialPort.writeBytes(command, command.length);
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");
}
/**
@@ -139,7 +145,50 @@ public class PanTiltController {
if (speed<0) speed = 0;
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[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()) {

View File

@@ -17,8 +17,10 @@ public class RtspGrabber {
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;
@@ -26,6 +28,7 @@ public class RtspGrabber {
private GrabbingTask grabbingTask;
public RtspGrabber(String ip, String path) {
this.rtspUrl = "rtsp://" + ip + path;
Logger.info("RtspGrabber created with url: " + rtspUrl);
}
@@ -62,6 +65,22 @@ public class RtspGrabber {
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
@@ -143,6 +162,8 @@ public class RtspGrabber {
});
tt.setOnHQBase64Update(this::setLastHQBase64);
tt.setOnLQBase64Update(this::setLastLQBase64);
tt.setOnYoloUpdate(this::setLastYoloFrame);
tt.setOnYoloBase64Update(this::setLastYoloBase64);
return tt;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -1,45 +1,38 @@
package Other;
import com.google.gson.Gson;
import org.bytedeco.javacpp.Loader;
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.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
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.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Size;
import org.bytedeco.opencv.opencv_core.UMat;
import org.bytedeco.opencv.opencv_java;
import org.bytedeco.opencv.opencv_core.*;
import org.jetbrains.annotations.NotNull;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import org.tinylog.Logger;
import java.io.*;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.Properties;
@SuppressWarnings("unused")
public class SomeCodes {
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 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 Java2DFrameConverter frameConverter = new Java2DFrameConverter();
public static final Path logsPath = Path.of(currentDirectory, "logs");
public static final boolean haveOpenCL = opencv_core.haveOpenCL();
public static boolean useOpenCL;
private static final Base64.Encoder base64encoder = java.util.Base64.getEncoder();
@@ -48,6 +41,17 @@ public class SomeCodes {
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(){
try{
return Files.list(audioPath).map(f -> f.getFileName().toString()).toArray(String[]::new);
@@ -58,10 +62,6 @@ public class SomeCodes {
return new String[0];
}
public static String LocalDateTimeToString(LocalDateTime x){
return x.format(dtf);
}
public static String ExtractResource(String filename, String targetdirectory){
try {
File destination = new File(targetdirectory, filename);
@@ -89,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){
if (ValidString(filename)){
@@ -122,6 +116,13 @@ public class SomeCodes {
return defaultspeed;
}
public static boolean ValidIntArray(int[] xx){
if (xx!=null){
return xx.length>0;
}
return false;
}
public static boolean ValidInteger(String x){
try{
Integer.parseInt(x);
@@ -131,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){
return port>0 && port<65536;
}
@@ -144,66 +154,116 @@ public class SomeCodes {
}
}
public static boolean ValidIPV4(String ipaddress){
if (ValidString(ipaddress)){
try{
InetAddress inet = InetAddress.getByName(ipaddress);
if (inet instanceof Inet4Address){
if (inet.getHostAddress().equals(ipaddress)){
return true;
}
public static String MatToBase64(Mat mat){
if (mat!=null){
if (mat.cols()>0 && mat.rows()>0){
try{
BytePointer mob = new BytePointer();
opencv_imgcodecs.imencode(".jpg", mat, mob);
byte[] data = new byte[(int) mob.limit()];
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 "";
}
// Function ini pakai opencv, bukan javacv, jadi perlu Loader.load(opencv_java.class) di awal
// lebih optimal untuk konversi frame ke base64
public static String FrameToBase64(Frame frame){
if (frame!=null){
org.opencv.core.Mat converted = CoreMatConverter.convert(frame);
if (converted!=null){
if (!converted.empty()){
public static String MatToBase64(org.opencv.core.Mat mat){
if (mat!=null){
if (mat.cols()>0 && mat.rows()>0){
try{
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(".jpg", converted, mob);
byte[] jpgdata = mob.toArray();
Imgcodecs.imencode(".jpg", mat, mob);
String base64 = base64encoder.encodeToString(mob.toArray());
mob.release();
converted.release();
return base64encoder.encodeToString(jpgdata);
return base64;
} catch (Exception e){
Logger.error("Error converting Mat to Base64: "+e.getMessage());
}
}
}
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
@@ -247,6 +307,7 @@ public class SomeCodes {
return config.getProperty(key, null);
}
@Deprecated
public static Mat ResizeMat(Mat source, int width, int height){
Size sz = new Size(width, height);
Mat dest = new Mat();
@@ -254,7 +315,6 @@ public class SomeCodes {
UMat src = new UMat();
source.copyTo(src);
UMat dst = new UMat();
opencv_imgproc.resize(src, dst, sz);
dst.copyTo(dest);
} else {
@@ -263,11 +323,6 @@ public class SomeCodes {
return dest;
}
public static Frame ResizeFrame(Frame source, int width, int height){
Mat mat = matConverter.convertToMat(source);
Mat resized = ResizeMat(mat, width, height);
return matConverter.convert(resized);
}
/**
* check if an ip address is reachable
@@ -283,4 +338,20 @@ public class SomeCodes {
}
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;
}
}

View File

@@ -32,7 +32,7 @@ public class GPIO {
* @param pin GPIO pin number
* @return true if the pin is already exported
*/
public static boolean GpioPinExists(@NotNull RaspberryPi5BPins pin){
public static boolean GpioPinExists(@NotNull JetsonOrinPins pin){
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber);
return pinPath.toFile().isDirectory();
}
@@ -42,7 +42,7 @@ public class GPIO {
* @param pin GPIO pin number
* @return true if the pin is successfully exported
*/
public static boolean ExportPin(@NotNull RaspberryPi5BPins pin){
public static boolean ExportPin(@NotNull JetsonOrinPins pin){
try{
if (Files.isWritable(gpioExportPath)){
Files.write(gpioExportPath, String.valueOf(pin.gpionumber).getBytes());
@@ -55,12 +55,13 @@ public class GPIO {
return false;
}
/**
* Unexport the pin
* @param pin GPIO pin number
* @return true if the pin is successfully unexported
*/
public static boolean UnexportPin(@NotNull RaspberryPi5BPins pin){
public static boolean UnexportPin(@NotNull JetsonOrinPins pin){
if (Files.isWritable(gpioUnexportPath)){
try{
Files.write(gpioUnexportPath, String.valueOf(pin.gpionumber).getBytes());
@@ -80,7 +81,7 @@ public class GPIO {
* @return "in" if the pin is input, "out" if the pin is output, "unknown" if the direction is unknown
*/
@SuppressWarnings("unused")
public static String GetPinDirection(@NotNull RaspberryPi5BPins pin){
public static String GetPinDirection(@NotNull JetsonOrinPins pin){
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("direction");
if (pinPath.toFile().isFile()){
if (Files.isReadable(pinPath)){
@@ -100,7 +101,7 @@ public class GPIO {
* @param direction "in" for input, "out" for output
* @return true if the direction is successfully set
*/
public static boolean SetPinDirection(@NotNull RaspberryPi5BPins pin, String direction){
public static boolean SetPinDirection(@NotNull JetsonOrinPins pin, String direction){
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("direction");
if (pinPath.toFile().isFile()){
if (Files.isWritable(pinPath)){
@@ -126,7 +127,7 @@ public class GPIO {
* @return true if the value is successfully set
*/
@SuppressWarnings("UnusedReturnValue")
public static boolean SetValue(@NotNull RaspberryPi5BPins pin, boolean isON){
public static boolean SetValue(@NotNull JetsonOrinPins pin, boolean isON){
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("value");
if (pinPath.toFile().isFile()){
if (Files.isWritable(pinPath)){
@@ -148,7 +149,7 @@ public class GPIO {
* @return "1" if the pin value is 1, "0" if the pin value is 0, "unknown" if the value is unknown
*/
@SuppressWarnings("unused")
public static String GetValue(@NotNull RaspberryPi5BPins pin){
public static String GetValue(@NotNull JetsonOrinPins pin){
Path pinPath = gpioPath.resolve("gpio"+pin.gpionumber).resolve("value");
if (pinPath.toFile().isFile()){
if (Files.isReadable(pinPath)){

View 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;
}
}
}

View 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;
}
}

View 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 */
}

View 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;
}
}

View 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);
}

View 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);
}
}
}

View 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;
}
}

View File

@@ -1,42 +0,0 @@
package SBC;
public enum RaspberryPi5BPins {
Pin03(3,"GPIO2/SDA", 573),
Pin05(5,"GPIO3/SCL", 574),
Pin07(7,"GPIO4/GPCLK0", 575),
Pin08(8,"GPIO14/TXD", 585),
Pin10(10,"GPIO15/RXD", 586),
Pin11(11,"GPIO17", 588),
Pin12(12,"GPIO18/PCMCLK", 589),
Pin13(13,"GPIO27", 598),
Pin15(15,"GPIO22", 593),
Pin16(16,"GPIO23", 594),
Pin18(18,"GPIO24", 595),
Pin19(19,"GPIO10/MOSI", 581),
Pin21(21,"GPIO9/MISO", 580),
Pin22(22,"GPIO25", 596),
Pin23(23,"GPIO11/SCLK", 582),
Pin24(24,"GPIO8/CE0", 579),
Pin26(26,"GPIO7/CE1", 578),
Pin27(27,"GPIO0/IDSD", 587),
Pin28(28,"GPIO1/IDSC", 587),
Pin29(29,"GPIO5", 576),
Pin31(31,"GPIO6", 577),
Pin32(32,"GPIO12/PWM0", 583),
Pin33(33,"GPIO13/PWM1", 584),
Pin35(35,"GPIO19/PCMFS", 590),
Pin36(36,"GPIO16", 587),
Pin37(37,"GPIO26", 597),
Pin38(38,"GPIO20/PCMDIN", 591),
Pin40(40,"GPIO21/PCMDOUT", 592);
public final int pin;
public final String name;
public final int gpionumber;
RaspberryPi5BPins(int pin, String name, int gpionumber){
this.pin = pin;
this.name = name;
this.gpionumber = gpionumber;
}
}

View File

@@ -32,7 +32,7 @@ public class SystemInformation {
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+)");
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){

View File

@@ -36,6 +36,8 @@ public class WebServer {
this.webusername = webusername;
this.webpassword = webpassword;
app = Javalin.create(config -> {
config.useVirtualThreads = true;
config.staticFiles.add("/html");
config.router.apiBuilder(()-> path("setting", () ->{
get(ctx -> ctx.json(SettingInfo.getInstance()));
@@ -267,12 +269,14 @@ public class WebServer {
connectedWebsocketClients.clear();
app.stop();
Logger.info("Web server stopped");
socketServer.stop();
socketIOClients.forEach((key, client) -> client.disconnect());
socketIOClients.clear();
socketServer.stop();
Logger.info("SocketIO server stopped");
} catch (JavalinException e){
Logger.error("Web server failed to stop: {}", e.getMessage());
e.printStackTrace();
}
}

View File

@@ -1,16 +1,15 @@
package id.co.gtc;
import Audio.AudioFileProperties;
import Audio.AudioPlayer;
import Audio.Bass;
import Audio.PlaybackEvent;
import Audio.*;
import Camera.PanTiltController;
import Camera.RtspGrabber;
import Camera.RtspGrabber_opencv;
import Camera.VapixProtocol;
import Other.SomeCodes;
import SBC.*;
import Web.*;
import com.google.gson.JsonObject;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import org.bytedeco.opencv.global.opencv_core;
import org.tinylog.Logger;
@@ -23,11 +22,21 @@ import java.util.concurrent.Executors;
import static Other.SomeCodes.*;
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 WebServer webServer;
private static RtspGrabber rtspGrabber;
private static PanTiltController panTiltController;
private static AudioFileProperties audioFileProperties;
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;
@@ -37,24 +46,57 @@ public class Main {
private static NetworkTransmitReceiveInfo[] previousNetworkInfo;
private static final Map<String, String> networkTX = new HashMap<>();
private static final Map<String, String> networkRX = new HashMap<>();
private static RaspberryPi5BPins AmplifierPower = null;
private static RaspberryPi5BPins LedWeb = null;
private static RaspberryPi5BPins LedIpCamera = null;
private static RaspberryPi5BPins LedPanTilt = null;
private static RaspberryPi5BPins Max485Direction = null;
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
public static void main(String[] args) {
System.setProperty("jna.debug_load", "false");
System.out.println("BirdStrikeSoetta "+Version);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (audioPlayer!=null) audioPlayer.Unload();
if (webServer!=null) webServer.Stop();
if (rtspGrabber!=null) rtspGrabber.Stop();
if (panTiltController!=null) panTiltController.Close();
if (vapixProtocol!=null) vapixProtocol.Close();
if (timer!=null) timer.cancel();
if (gpioExecutor!=null) gpioExecutor.shutdown();
if (use_multiusb_audio) {
if (multiUSBAudioPlayer != null) {
multiUSBAudioPlayer.Unload();
Logger.info("MultiUSB Audio Unloaded");
}
} 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));
}
@@ -70,36 +112,135 @@ public class Main {
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");
}));
init_gpio();
Logger.info("Current Directory : "+currentDirectory);
//init_gpio();
init_pcf8574();
init_system_monitoring();
init_properties();
init_audiofiles();
init_Vapix();
init_audio();
if (use_multiusb_audio) {
Logger.info("Using MultiUSB Audio");
init_multiusb_audio();
} else {
Logger.info("Using USB Audio");
init_audio();
}
init_pantiltcontroller();
init_webserver();
init_rtspgrabber();
}
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(){
if (GPIO.HaveGPIO()){
gpioExecutor = Executors.newVirtualThreadPerTaskExecutor();
AmplifierPower = InitializePin(RaspberryPi5BPins.Pin13, true);
LedWeb = InitializePin(RaspberryPi5BPins.Pin15, true);
LedIpCamera = InitializePin(RaspberryPi5BPins.Pin19, true);
LedPanTilt = InitializePin(RaspberryPi5BPins.Pin21, true);
Max485Direction = InitializePin(RaspberryPi5BPins.Pin23, true);
}
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 RaspberryPi5BPins InitializePin(RaspberryPi5BPins pin, boolean isOutput){
private static JetsonOrinPins InitializePin(JetsonOrinPins pin, boolean isOutput){
boolean exported = false;
if (GPIO.GpioPinExists(pin)){
exported = true;
@@ -121,29 +262,80 @@ public class Main {
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(){
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(RaspberryPi5BPins pin){
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);
try {
Thread.sleep(20);
} catch (InterruptedException ignored) {
}
Sleep(20);
GPIO.SetValue(pin, false);
});
}
@@ -227,10 +419,16 @@ public class Main {
private static void init_Vapix(){
Properties config = SomeCodes.LoadProperties("config.properties");
Logger.info("Saved Configuration for Camera");
String ip = config.getProperty("Camera_ip");
String port = config.getProperty("Camera_port");
String username = config.getProperty("Camera_user");
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 (ValidPortNumber(port)){
if (ValidString(username)){
@@ -246,7 +444,7 @@ public class Main {
} else Logger.error("PTZ Disabled");
Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom());
Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom());
Blink(LedIpCamera);
Blink_LedIpCamera();
} else Logger.error("Failed to query camera");
} else Logger.error("Camera IP is not reachable");
} else Logger.error("Camera Password is not valid string");
@@ -255,15 +453,23 @@ public class Main {
} else Logger.error( "Camera IP is not valid string");
}
private static void init_pantiltcontroller() {
Properties config = SomeCodes.LoadProperties("config.properties");
String portname = config.getProperty("SerialPort");
String baudrate = config.getProperty("SerialBaudRate");
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 (ValidInteger(baudrate)){
if (ValidInteger(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 Port");
@@ -274,19 +480,64 @@ public class Main {
// check if really activated
useOpenCL = opencv_core.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");
String targetip = config.getProperty("Camera_ip");
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(rtsppath)){
if (IpIsReachable(targetip)){
Logger.info("Camera IP is reachable");
rtspGrabber = new RtspGrabber(targetip, rtsppath);
rtspGrabber.Start(true, 1920, 1080);
} else Logger.error("Camera IP is not reachable");
} else Logger.error("Camera Path is not valid string");
} else Logger.error("Camera IP is not valid string");
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(){
multiUSBAudioPlayer = new MultiUSBAudioPlayer();
multiUSBAudioPlayer.DetectOutputDevices();
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() {
@@ -309,16 +560,19 @@ public class Main {
@Override
public void onPlaybackStart(AudioFileProperties prop) {
Logger.info("Playback started for {}", prop.filename);
AmplifierControl(true);
}
@Override
public void onPlaybackFinished(AudioFileProperties prop) {
Logger.info("Playback finished for {}", prop.filename);
AmplifierControl(false);
}
@Override
public void onPlaybackFailure(AudioFileProperties prop, String reason) {
Logger.error("Playback failed for {}: {}", prop.filename, reason);
AmplifierControl(false);
}
@Override
@@ -335,36 +589,63 @@ public class Main {
@Override
public WebsocketReply onWebsocketCommand(WebsocketCommand command) {
Blink(LedWeb);
Blink_LedWeb();
byte speed;
String cmd = command.command.toUpperCase().trim();
switch (cmd){
// Pan Tilt Movement Commands
case "PAN LEFT" :
Logger.info("PAN LEFT");
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));
case "PAN RIGHT" :
Logger.info("PAN RIGHT");
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));
case "TILT UP" :
Logger.info("TILT UP");
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));
case "TILT DOWN" :
Logger.info("TILT DOWN");
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));
case "STOP MOVEMENT" :
if (panTiltController!=null) panTiltController.StopMovement();
Logger.info("STOP MOVEMENT");
if (panTiltController!=null) {
panTiltController.StopMovement();
}
return new WebsocketReply("STOP MOVEMENT", "");
// Audio Related Commands
case "MUTE":
audioPlayer.Mute();
if (use_multiusb_audio){
if (multiUSBAudioPlayer!=null) multiUSBAudioPlayer.Mute();
} else {
if (audioPlayer!=null) audioPlayer.Mute();
}
return new WebsocketReply("MUTE", "");
case "UNMUTE":
audioPlayer.Unmute();
if (use_multiusb_audio){
if (multiUSBAudioPlayer!=null) multiUSBAudioPlayer.Unmute();
} else {
if (audioPlayer!=null) audioPlayer.Unmute();
}
return new WebsocketReply("UNMUTE", "");
case "SET VOLUME" :
int volume=-1;
@@ -374,11 +655,20 @@ public class Main {
if (volume>100) volume = 100;
}
if (volume>=0){
audioPlayer.setPlaybackvolume(volume);
return new WebsocketReply("SET VOLUME", String.valueOf(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));
} else return new WebsocketReply("SET VOLUME", "Invalid Volume Value");
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));
case "PLAY AUDIO" :
if (ValidInteger(command.data)){
@@ -387,57 +677,99 @@ public class Main {
if (ValidString(filename)){
File filetoplay = new File(Path.of(currentDirectory, "audiofiles", filename).toString());
if (filetoplay.isFile()){
AudioFileProperties afp = audioPlayer.OpenAudioFile(filetoplay);
if (afp!=null){
audioFileProperties = afp;
audioPlayer.PlayAudioFile(afp, true, pe);
AmplifierControl(true);
return new WebsocketReply("PLAY AUDIO", afp.filename);
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);
if (afp!=null){
audioFileProperties = afp;
audioPlayer.PlayAudioFile(afp, true, pe);
//AmplifierControl(true);
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", String.format("AudioFile with ID %02d not found", id));
} else return new WebsocketReply("PLAY AUDIO", "Invalid Audio ID");
case "STOP AUDIO" :
if (audioFileProperties!=null){
audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file
String filename = audioFileProperties.filename;
audioFileProperties = null;
AmplifierControl(false);
return new WebsocketReply("STOP AUDIO", filename);
} else return new WebsocketReply("STOP AUDIO", "No audioFileProperties");
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){
audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file
String filename = audioFileProperties.filename;
audioFileProperties = null;
//AmplifierControl(false);
return new WebsocketReply("STOP AUDIO", filename);
} else return new WebsocketReply("STOP AUDIO", "No audioFileProperties");
}
// ZOOM Related Commands
case "GET MAX ZOOM":
if (vapixProtocol!=null){
Blink_LedIpCamera();
return new WebsocketReply("GET MAX ZOOM", String.valueOf(vapixProtocol.GetPTZMaxZoom()));
} else return new WebsocketReply("GET MAX ZOOM", "VapixProtocol not initialized");
case "GET ZOOM":
if (vapixProtocol!=null){
Blink_LedIpCamera();
return new WebsocketReply("GET ZOOM", String.valueOf(vapixProtocol.GetCurrentZoomValue()));
} else return new WebsocketReply("GET ZOOM", "VapixProtocol not initialized");
case "SET ZOOM":
if (vapixProtocol.PTZEnabled()){
if (ValidInteger(command.data)){
int zoom = Integer.parseInt(command.data);
if (zoom<vapixProtocol.GetPTZMinZoom()) zoom = vapixProtocol.GetPTZMinZoom();
if (zoom>vapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom();
if (vapixProtocol.Zoom(1, zoom)){
Blink(LedIpCamera);
return new WebsocketReply("ZOOM", String.valueOf(zoom));
} else return new WebsocketReply("ZOOM", "Failed to zoom");
} else return new WebsocketReply("ZOOM", "Invalid Zoom Value");
} else return new WebsocketReply("ZOOM", "Zoom not supported");
if (vapixProtocol!=null){
if (vapixProtocol.PTZEnabled()){
if (ValidInteger(command.data)){
int zoom = Integer.parseInt(command.data);
if (zoom<vapixProtocol.GetPTZMinZoom()) zoom = vapixProtocol.GetPTZMinZoom();
if (zoom>vapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom();
Blink_LedIpCamera();
if (vapixProtocol.Zoom(1, zoom)){
return new WebsocketReply("ZOOM", String.valueOf(zoom));
} else return new WebsocketReply("ZOOM", "Failed to zoom");
} else return new WebsocketReply("ZOOM", "Invalid Zoom Value");
} else return new WebsocketReply("ZOOM", "Zoom not supported");
}
// Live Streaming Related Commands
case "GET BASE64":
if (rtspGrabber!=null){
if (Objects.equals(command.data,"HQ"))
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus());
else
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus());
if (use_Yolo){
return switch (command.data) {
case "HQ" ->
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");
case "GET RESOLUTION":
if (vapixProtocol!=null){
int[] res = vapixProtocol.GetCurrentResolution(1);
Blink_LedIpCamera();
return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1]));
} else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized");
case "GET AUDIOFILES":