diff --git a/Config/config.properties b/Config/config.properties index da0b788..49cd969 100644 --- a/Config/config.properties +++ b/Config/config.properties @@ -10,7 +10,7 @@ AudioFile03 = pinkNoiseWav.wav AudioFile04 = 04.mp3 AudioFile05 = 05.mp3 AudioVolumeOutput = 100 -SerialPort = /dev/ttyAMA0 +SerialPort = /dev/ttyTHS1 SerialBaudRate = 9600 PanTiltID = 1 WebUsername = admin diff --git a/Html/html/index.js b/Html/html/index.js index 4a4ea2e..97425cd 100644 --- a/Html/html/index.js +++ b/Html/html/index.js @@ -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); diff --git a/config.properties b/config.properties index 8a5537c..b648323 100644 --- a/config.properties +++ b/config.properties @@ -12,7 +12,7 @@ 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 diff --git a/onnx/yolov8n.onnx b/onnx/yolo11n.onnx similarity index 53% rename from onnx/yolov8n.onnx rename to onnx/yolo11n.onnx index ade7079..cb0b371 100644 Binary files a/onnx/yolov8n.onnx and b/onnx/yolo11n.onnx differ diff --git a/onnx/yolov8m.onnx b/onnx/yolov8m.onnx deleted file mode 100644 index 1ad3394..0000000 Binary files a/onnx/yolov8m.onnx and /dev/null differ diff --git a/pom.xml b/pom.xml index 7243a9a..a4abf65 100644 --- a/pom.xml +++ b/pom.xml @@ -57,12 +57,13 @@ linux-arm64 + org.bytedeco tensorrt 8.6-1.5.10 - linux-arm64 + org.bytedeco cuda @@ -70,6 +71,19 @@ linux-arm64 + + org.bytedeco + javacpp + 1.5.11 + windows-x86_64 + + + org.bytedeco + javacpp + 1.5.11 + linux-arm64 + + com.corundumstudio.socketio diff --git a/src/main/java/Audio/AudioFileProperties.java b/src/main/java/Audio/AudioFileProperties.java index 3f41831..156a6e4 100644 --- a/src/main/java/Audio/AudioFileProperties.java +++ b/src/main/java/Audio/AudioFileProperties.java @@ -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 getFieldOrder() { + return Arrays.asList("handle", "filename", "Length", "duration"); } } diff --git a/src/main/java/Audio/AudioPlayer.java b/src/main/java/Audio/AudioPlayer.java index 8056569..97b3375 100644 --- a/src/main/java/Audio/AudioPlayer.java +++ b/src/main/java/Audio/AudioPlayer.java @@ -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 getFieldOrder() { +// return Arrays.asList("ap"); +// } +// +// +// } + } diff --git a/src/main/java/Audio/Bass.java b/src/main/java/Audio/Bass.java index 59c4862..af58651 100644 --- a/src/main/java/Audio/Bass.java +++ b/src/main/java/Audio/Bass.java @@ -2,6 +2,8 @@ package Audio; import com.sun.jna.*; +import java.util.Objects; + @SuppressWarnings("unused") public interface Bass extends Library { diff --git a/src/main/java/Audio/MultiUSBAudioPlayer.java b/src/main/java/Audio/MultiUSBAudioPlayer.java new file mode 100644 index 0000000..a9b1107 --- /dev/null +++ b/src/main/java/Audio/MultiUSBAudioPlayer.java @@ -0,0 +1,323 @@ +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 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 result = new ArrayList<>(); + for(BassDeviceInfoWithId dev : playbackdevices){ + if (dev.info.name.toLowerCase().contains(name.toLowerCase())){ + 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 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 {}", i); + } + } + 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 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; + } + } +} diff --git a/src/main/java/Camera/GrabbingTask.java b/src/main/java/Camera/GrabbingTask.java index 8f3a724..a0520e2 100644 --- a/src/main/java/Camera/GrabbingTask.java +++ b/src/main/java/Camera/GrabbingTask.java @@ -39,6 +39,7 @@ public class GrabbingTask implements Runnable { // for FPS calculation private int intendedFps = 10; + private final boolean useYolo; private final YoloDetector yolo; @SuppressWarnings("SameParameterValue") @@ -89,11 +90,12 @@ public class GrabbingTask implements Runnable { - public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber, int fps) { + public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber, int fps, boolean useYolo) { this.isGrabbing = isGrabbing; this.grabber = grabber; if (fps>0) intendedFps = fps; - yolo = new YoloDetector(); + this.useYolo = useYolo; + if (useYolo) yolo = new YoloDetector(); else yolo = null; } @@ -116,37 +118,52 @@ public class GrabbingTask implements Runnable { Frame resizedFrame = SomeCodes.CoreMatConverter.convert(resized); updateLQFrame(resizedFrame); updateLQBase64(SomeCodes.MatToBase64(resized)); - } else System.out.println("processFrame resized size is 0"); - DetectYolo(mat); + + if (useYolo){ + DetectYolo(resized); + } + } else Logger.error("processFrame resized size is 0"); resized.release(); - } else System.out.println("processFrame Mat size is 0"); + } else Logger.error("processFrame Mat size is 0"); mat.release(); } catch (Exception e){ - Logger.error("Error processing frame: "+e.getMessage()); + if (SomeCodes.ValidString(e.getMessage())) { + if (!e.getMessage().startsWith("unknown exception")) { + Logger.error("Error processing frame: "+e.getMessage()); + e.printStackTrace(); + } + } + } } else { - System.out.println("processFrame have null frame"); + Logger.warn("processFrame have null frame"); updateMessage("processFrame have null frame"); } } private void DetectYolo(Mat mat){ - if (mat!=null && mat.cols()>0 && mat.rows()>0){ - //System.out.println("DetectYolo mat cols = "+mat.cols()+", rows = "+mat.rows()); - try{ - Mat[] processed = yolo.Detect(mat); - Mat yolomat = yolo.Process(mat, processed[0], processed[1]); - Frame yoloFrame = SomeCodes.CoreMatConverter.convert(yolomat); - updateYoloFrame(yoloFrame); - updateYoloBase64(SomeCodes.MatToBase64(yolomat)); + 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"); + } - } catch (Exception e){ - System.out.println("error processing YOLO, Message : "+e.getMessage()); - updateYoloFrame(null); - updateYoloBase64(""); - } - } else System.out.println("DetectYolo mat is null"); } @@ -173,11 +190,14 @@ public class GrabbingTask implements Runnable { Thread.yield(); Frame frame = grabber.grab(); if (framecount0){ - Logger.info("CUDA enabled devices found: " + cudacount); - opencv_core.printCudaDeviceInfo(0); - } else { - Logger.info("No CUDA enabled devices found"); - } + public RtspGrabber(String ip, String path, boolean useYolo) { + this.useYolo = useYolo; + this.rtspUrl = "rtsp://" + ip + path; Logger.info("RtspGrabber created with url: " + rtspUrl); } @@ -146,7 +142,7 @@ public class RtspGrabber { @NotNull private GrabbingTask getGrabbingTask() { - GrabbingTask tt = new GrabbingTask(isGrabbing, grabber,10); + GrabbingTask tt = new GrabbingTask(isGrabbing, grabber,10, useYolo); tt.setOnMessageUpdate(Logger::info); tt.setOnHQFrameUpdate(value -> { if (value!=null){ diff --git a/src/main/java/Camera/YoloDetector.java b/src/main/java/Camera/YoloDetector.java index 24ccba9..c17d6e7 100644 --- a/src/main/java/Camera/YoloDetector.java +++ b/src/main/java/Camera/YoloDetector.java @@ -7,6 +7,7 @@ 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; @@ -26,18 +27,20 @@ public class YoloDetector { // Non-maximum suppression threshold private final float nms_threshold = 0.4f; + public YoloDetector() { NetLoaded = false; net = null; classes = null; - String onnxfile = SomeCodes.ExtractResource("/yolov8n.onnx", SomeCodes.currentDirectory); + String onnxfile = SomeCodes.ExtractResource("/yolo11n.onnx", SomeCodes.currentDirectory); String namesfile = SomeCodes.ExtractResource("/coco.names", SomeCodes.currentDirectory); if (SomeCodes.ValidFile(onnxfile)){ if (SomeCodes.ValidFile(namesfile)){ net = Dnn.readNetFromONNX(onnxfile); net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV); + //net.setPreferableBackend(Dnn.DNN_BACKEND_INFERENCE_ENGINE); net.setPreferableTarget(Dnn.DNN_TARGET_CPU); - + //net.setPreferableTarget(Dnn.DNN_TARGET_NPU); classes = new ArrayList<>(); if (namesfile!=null){ @@ -47,72 +50,87 @@ public class YoloDetector { classes.add(line); } } catch (Exception e){ - System.out.println("Error: reading names file"); + Logger.error("reading names file, Exception : ",e.getMessage()); } } if (!net.empty()){ if (!classes.isEmpty()){ NetLoaded = true; - } else System.out.println("Error: names file is empty"); - } else System.out.println("Error: net is empty"); - } else System.out.println("Error: names file not found"); - } else System.out.println("Error: onnx file not found"); + } else Logger.error("names file is empty"); + } else Logger.error("net is empty"); + } else Logger.error("names file not found"); + } else Logger.error("onnx file not found"); } + // Source : https://blog.csdn.net/taoli188/article/details/134720614 public Mat[] Detect(Mat frame){ - 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 = true; + 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 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)); + Mat predict = net.forward(); + Mat mask = predict.reshape(0,1).reshape(0, predict.size(1)); - return new Mat[]{predict,mask}; - } else { - System.out.println("Error: Net not loaded"); + 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]; } + } public Mat Process(Mat frame, Mat predict, Mat mask){ - 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()]; + 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;i0 && port<65536; } @@ -124,46 +132,33 @@ public class SomeCodes { } } - public static String MatToBase64(Mat mat){ - if (mat!=null){ - if (mat.cols()>0 && mat.rows()>0){ - byte[] mob = new byte[mat.cols()*mat.rows()*mat.channels()]; - opencv_imgcodecs.imencode(".jpg", mat, mob); - return base64encoder.encodeToString(mob); - } - } - return ""; - } - public static String MatToBase64(org.opencv.core.Mat mat){ if (mat!=null){ if (mat.cols()>0 && mat.rows()>0){ - MatOfByte mob = new MatOfByte(); - Imgcodecs.imencode(".jpg", mat, mob); - String base64 = base64encoder.encodeToString(mob.toArray()); - mob.release(); - return base64; + try{ + MatOfByte mob = new MatOfByte(); + Imgcodecs.imencode(".jpg", mat, mob); + String base64 = base64encoder.encodeToString(mob.toArray()); + mob.release(); + return base64; + } catch (Exception e){ + Logger.error("Error converting Mat to Base64: "+e.getMessage()); + } } } 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 && frame.imageWidth>0 && frame.imageHeight>0){ - org.opencv.core.Mat converted = CoreMatConverter.convert(frame); - if (converted!=null && converted.cols()>0 && converted.rows()>0){ - //System.out.println("FrameToBase64 use converted Mat, cols: "+converted.cols()+", rows: "+converted.rows()); - return MatToBase64(converted); - } - Mat xx = CoreMatConverter.convertToMat(frame); - if (xx!=null && xx.cols()>0 && xx.rows()>0){ - //System.out.println("FrameToBase64 use xx Mat, cols: "+xx.cols()+", rows: "+xx.rows()); - return MatToBase64(xx); + 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 ""; + + return null; } diff --git a/src/main/java/SBC/JetsonOrinPins.java b/src/main/java/SBC/JetsonOrinPins.java index 04af4ca..facb89a 100644 --- a/src/main/java/SBC/JetsonOrinPins.java +++ b/src/main/java/SBC/JetsonOrinPins.java @@ -1,31 +1,31 @@ package SBC; /** - * Source : ... + * Source : ... */ public enum JetsonOrinPins { - Pin07(7,"MCLK05",106), + Pin07(7,"AUDIO_MCLK",144), Pin11(11,"UART1_RTS",112), - Pin12(12,"I2S2_CLK",50), - Pin13(13,"GPIO32",108), - Pin15(15,"GPIO27",85), - Pin16(16,"GPIO8",9), - Pin18(18,"GPIO35",43), - Pin19(19,"SPI1_MOSI",135), - Pin21(21,"SPI1_MISO",134), - Pin22(22,"GPIO17",96), - Pin23(23,"SPI1_SCK",133), - Pin24(24,"SPI1_CS0",136), - Pin25(25,"SPI1_CS1",137), - Pin29(29,"CAN0_RX",1), - Pin31(31,"CAN0_TX",0), - Pin32(32,"GPIO9",8), - Pin33(33,"CAN1_TX",2), - Pin35(35,"I2S_FS",53), + 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,"CAN1_RX",3), - Pin38(38,"I2S_SDIN",52), - Pin40(40,"I2S_SDOUT",51); + 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; diff --git a/src/main/java/SBC/LibGpioD.java b/src/main/java/SBC/LibGpioD.java new file mode 100644 index 0000000..f9184c2 --- /dev/null +++ b/src/main/java/SBC/LibGpioD.java @@ -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); +} diff --git a/src/main/java/SBC/PCF8574.java b/src/main/java/SBC/PCF8574.java index 9d991c9..9ef8665 100644 --- a/src/main/java/SBC/PCF8574.java +++ b/src/main/java/SBC/PCF8574.java @@ -2,10 +2,11 @@ package SBC; import lombok.Getter; + @SuppressWarnings("unused") public class PCF8574 extends I2C_Device{ - private byte data = 0x00; + private Byte data = 0; private final @Getter String[] pinNames = new String[8]; /** @@ -92,8 +93,10 @@ public class PCF8574 extends I2C_Device{ public boolean SetPin(int pin){ if (pin<0 || pin>7) return false; if (super.isOpened()){ - byte temp = (byte) (data | (1<0; + synchronized (data){ + data = (byte) (data | (1<0; + } } return false; } @@ -120,8 +123,10 @@ public class PCF8574 extends I2C_Device{ public boolean ClearPin(int pin){ if (pin<0 || pin>7) return false; if (super.isOpened()){ - byte temp = (byte) (data & ~(1<0; + synchronized (data){ + data = (byte) (data & ~(1<0; + } } return false; } diff --git a/src/main/java/SBC/SystemInformation.java b/src/main/java/SBC/SystemInformation.java index d5d045f..ed05346 100644 --- a/src/main/java/SBC/SystemInformation.java +++ b/src/main/java/SBC/SystemInformation.java @@ -32,7 +32,7 @@ public class SystemInformation { File ff = new File("/proc/net/dev"); if (ff.isFile() && ff.canRead()){ List 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){ diff --git a/src/main/java/id/co/gtc/Main.java b/src/main/java/id/co/gtc/Main.java index ce72913..277c6c7 100644 --- a/src/main/java/id/co/gtc/Main.java +++ b/src/main/java/id/co/gtc/Main.java @@ -1,9 +1,6 @@ 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.VapixProtocol; @@ -12,6 +9,7 @@ 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; @@ -24,11 +22,20 @@ 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 + private static final boolean use_Yolo = true; + private static RtspGrabber rtspGrabber; + + private static PanTiltController panTiltController; private static VapixProtocol vapixProtocol; private static Timer timer; private static int cpuTemperature; @@ -52,7 +59,11 @@ public class Main { public static void main(String[] args) { System.setProperty("jna.debug_load", "false"); Runtime.getRuntime().addShutdownHook(new Thread(() -> { - if (audioPlayer!=null) audioPlayer.Unload(); + if (use_multiusb_audio) { + if (multiUSBAudioPlayer != null) multiUSBAudioPlayer.Unload(); + } else { + if (audioPlayer != null) audioPlayer.Unload(); + } if (webServer!=null) webServer.Stop(); if (rtspGrabber!=null) rtspGrabber.Stop(); if (panTiltController!=null) panTiltController.Close(); @@ -77,10 +88,11 @@ public class Main { if (pcf8574!=null){ pcf8574.Close(); } + Logger.info("Application Stopped"); })); - System.out.println("Current Directory : "+currentDirectory); + Logger.info("Current Directory : "+currentDirectory); //init_gpio(); @@ -91,7 +103,13 @@ public class Main { 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(); @@ -105,28 +123,76 @@ public class Main { Logger.info("I2C Bus opened"); pcf8574 = new PCF8574(i2c_bus.getI2c_handle(), 0x27); if (pcf8574.Open_Slave()){ - System.out.println("PCF8574 opened"); + 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"); +// 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 { - System.out.println("Failed to open PCF8574"); + Logger.error("Failed to open PCF8574"); } } else { - System.out.println("Failed to open I2C Bus"); + Logger.error("Failed to open I2C Bus"); } - } else System.out.println("PCF8574 not supported on this platform"); + } else Logger.error("PCF8574 not supported on this platform"); } - @Deprecated + // Untuk test libgpiod + // use for jetpack 6.x @SuppressWarnings("unused") private static void init_gpio(){ + LibGpioD gpio; + Pointer openPointer; + // Source : https://jetsonhacks.com/nvidia-jetson-orin-nano-gpio-header-pinout/ + int gpio_MOSI = 135; + int gpio_MISO = 134; + if (Platform.isLinux()){ + gpio = LibGpioD.Instance; + openPointer = gpio.gpiod_chip_open(LibGpioD.CHIP_NAME); + if (openPointer!=null){ + Logger.info("GPIO Chip opened : {}", LibGpioD.CHIP_NAME); + Pointer miso = gpio.gpiod_line_get(openPointer, gpio_MISO); + if (miso!=null){ + Logger.info("GPIO Line MISO opened : {}", gpio_MISO); + if (gpio.gpiod_line_request_input(miso, "MISO")!=0){ + Logger.error("Failed to set MISO as input"); + } else { + Logger.info("MISO opened"); + Logger.info("MISO value : {}", gpio.gpiod_line_get_value(miso)); + } + gpio.gpiod_line_release(miso); + Logger.info("GPIO Line MISO released : {}", gpio_MISO); + } else Logger.error("Failed to open GPIO Line : {}", gpio_MISO); + Pointer mosi = gpio.gpiod_line_get(openPointer, gpio_MOSI); + if (mosi!=null){ + Logger.info("GPIO Line MOSI opened : {}", gpio_MOSI); + if (gpio.gpiod_line_request_output(mosi, "MOSI", 0)!=0){ + Logger.error("Failed to set MOSI as output"); + } else { + Logger.info("MOSI opened"); + int result = gpio.gpiod_line_set_value(mosi, 1); + if (result!=0){ + Logger.error("Failed to set MOSI value : {}", result); + } else Logger.info("Success set MOSI value : 1"); + } + gpio.gpiod_line_release(mosi); + Logger.info("GPIO Line MOSI released : {}", gpio_MOSI); + } else Logger.error("Failed to open GPIO Line : {}", gpio_MOSI); + gpio.gpiod_chip_close(openPointer); + Logger.info("GPIO Chip closed : {}", LibGpioD.CHIP_NAME); + } else Logger.error("Failed to open GPIO Chip : {}", LibGpioD.CHIP_NAME); + } else Logger.info("GPIO not supported on this platform"); + } + + + // use for jetpack 4.x and 5.x + @SuppressWarnings("unused") + private static void init_gpio_sysfs(){ if (Platform.isLinux()){ if (GPIO.HaveGPIO()){ gpioExecutor = Executors.newVirtualThreadPerTaskExecutor(); @@ -141,7 +207,7 @@ public class Main { GPIO.SetValue(LedPanTilt,false); GPIO.SetValue(Max485Direction,false); } - } else System.out.println("GPIO not supported on this platform"); + } else Logger.info("GPIO not supported on this platform"); } @@ -169,11 +235,11 @@ public class Main { if (Max485Direction!=null){ GPIO.SetValue(Max485Direction, isTransmit); } else if (pcf8574!=null && pcf8574.isOpened()){ - if (isTransmit){ - pcf8574.SetPin("Max485 Direction"); - } else { - pcf8574.ClearPin("Max485 Direction"); - } +// if (isTransmit){ +// pcf8574.SetPin("Max485 Direction"); +// } else { +// pcf8574.ClearPin("Max485 Direction"); +// } } } @@ -182,7 +248,7 @@ public class Main { if (LedPanTilt!=null){ Blink(LedPanTilt); } else if (pcf8574!=null && pcf8574.isOpened()){ - Blink("Led Pan Tilt"); + Blink(1); } } @@ -190,7 +256,7 @@ public class Main { if (LedWeb!=null){ Blink(LedWeb); } else if (pcf8574!=null && pcf8574.isOpened()){ - Blink("Led Web"); + Blink(3); } } @@ -198,38 +264,47 @@ public class Main { if (LedIpCamera!=null){ Blink(LedIpCamera); } else if (pcf8574!=null && pcf8574.isOpened()){ - Blink("Led IP Camera"); + 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){ - pcf8574.SetPin("Amplifier Power"); + Logger.info("PCF8574 Amplifier Power ON"); + pcf8574.SetPin(6); + pcf8574.SetPin(5); + pcf8574.SetPin(4); } else { - pcf8574.ClearPin("Amplifier Power"); + Logger.info("PCF8574 Amplifier Power OFF"); + pcf8574.ClearPin(6); + pcf8574.ClearPin(5); + pcf8574.ClearPin(4); } } } - private static void Blink(String pinName){ + private static void Blink(int pin){ if (pcf8574!=null && pcf8574.isOpened()){ if (gpioExecutor!=null){ gpioExecutor.submit(()->{ - pcf8574.SetPin(pinName); + pcf8574.SetPin(pin); try { Thread.sleep(20); } catch (InterruptedException ignored) { } - pcf8574.ClearPin(pinName); + pcf8574.ClearPin(pin); }); } } } + + private static void Blink(JetsonOrinPins pin){ if (pin!=null){ if (gpioExecutor!=null){ @@ -322,15 +397,15 @@ public class Main { private static void init_Vapix(){ Properties config = SomeCodes.LoadProperties("config.properties"); - System.out.println("Saved Configuration for Camera"); + 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"); - System.out.println("Camera IP : "+ip); - System.out.println("Camera Port : "+port); - System.out.println("Camera Username : "+username); - System.out.println("Camera Password : "+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)){ @@ -356,27 +431,7 @@ public class Main { } else Logger.error( "Camera IP is not valid string"); } - private static void test_pantiltcontroller(){ - System.out.println("Pan Tilt Controller Test"); - panTiltController.PanLeft((byte)0x20); - System.out.println("Pan Left"); - Sleep(2000); - panTiltController.PanRight((byte)0x20); - System.out.println("Pan Right"); - Sleep(2000); - panTiltController.StopMovement(); - System.out.println("Stop Movement"); - panTiltController.TiltUp((byte)0x20); - System.out.println("Tilt Up"); - Sleep(2000); - panTiltController.TiltDown((byte)0x20); - System.out.println("Tilt Down"); - Sleep(2000); - panTiltController.StopMovement(); - System.out.println("Stop Movement"); - panTiltController.GoToPreset((byte)0); - System.out.println("Go To Preset 0"); - } + private static void init_pantiltcontroller() { Properties config = SomeCodes.LoadProperties("config.properties"); @@ -391,7 +446,7 @@ public class Main { if (ValidInteger(baudrate)){ if (ValidInteger(PanTiltID)){ panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID)); - if (panTiltController.isOpen()) test_pantiltcontroller(); + //if (panTiltController.isOpen()) test_pantiltcontroller(); } } else Logger.error("Invalid PTZ Baudrate"); } else Logger.error("Invalid PTZ Port"); @@ -402,21 +457,42 @@ public class Main { // check if really activated useOpenCL = opencv_core.useOpenCL(); Logger.info("OpenCL available={}, activated={}", haveOpenCL, useOpenCL); + int cudacount = opencv_core.getCudaEnabledDeviceCount(); + if (cudacount>0){ + Logger.info("CUDA enabled devices found: " + cudacount); + opencv_core.printCudaDeviceInfo(0); + } else { + Logger.info("No CUDA enabled devices found"); + } Properties config = SomeCodes.LoadProperties("config.properties"); String targetip = config.getProperty("Camera_ip"); String rtsppath = config.getProperty("Camera_Rtsp_path"); - System.out.println("Camera IP : "+targetip); - System.out.println("Camera Rtsp Path : "+rtsppath); + Logger.info("Camera IP : "+targetip); + Logger.info("Camera Rtsp Path : "+rtsppath); rtspGrabber = null; if (ValidString(targetip)){ if (ValidString(rtsppath)){ if (IpIsReachable(targetip)){ Logger.info("Camera IP : "+targetip+" is reachable"); - rtspGrabber = new RtspGrabber(targetip, rtsppath); + rtspGrabber = new RtspGrabber(targetip, rtsppath, use_Yolo); rtspGrabber.Start(true, 1920, 1080); - } else System.out.println("Camera IP : "+targetip+" is not reachable"); - } else System.out.println("Camera Path : "+rtsppath+" is not valid string"); - } else System.out.println("Camera IP : "+targetip+" is not valid string"); + } 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() { @@ -494,10 +570,18 @@ public class Main { return new WebsocketReply("STOP MOVEMENT", ""); // Audio Related Commands case "MUTE": - if (audioPlayer!=null) audioPlayer.Mute(); + if (use_multiusb_audio){ + if (multiUSBAudioPlayer!=null) multiUSBAudioPlayer.Mute(); + } else { + if (audioPlayer!=null) audioPlayer.Mute(); + } return new WebsocketReply("MUTE", ""); case "UNMUTE": - if (audioPlayer!=null) 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; @@ -507,11 +591,20 @@ public class Main { if (volume>100) volume = 100; } if (volume>=0){ - if (audioPlayer!=null) 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!=null ? audioPlayer.getPlaybackvolume() : 0; + 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)){ @@ -520,25 +613,45 @@ 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){ @@ -551,29 +664,43 @@ public class Main { 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 (zoomvapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom(); - if (vapixProtocol.Zoom(1, zoom)){ + if (vapixProtocol!=null){ + if (vapixProtocol.PTZEnabled()){ + if (ValidInteger(command.data)){ + int zoom = Integer.parseInt(command.data); + if (zoomvapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom(); 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.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){ - return switch (command.data) { - case "YOLO" -> - 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()); - case "HQ" -> - new WebsocketReply("GET BASE64", "data:image/jpeg;base64," + rtspGrabber.getLastYoloBase64(), rtspGrabber.HQStreamingStatus()); - default -> new WebsocketReply("GET BASE64", "RTSP Grabber not initialized"); - }; + if (use_Yolo){ + 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()); + case "YOLO" -> + 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){