first commit

This commit is contained in:
2024-11-09 08:52:49 +07:00
commit 2450f9f42a
90 changed files with 16323 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
package Audio;
public class AudioFileProperties {
public final int handle;
public final String filename;
public long Length;
public double duration;
public AudioFileProperties(int handle, String filename){
this.handle = handle;
this.filename = filename;
}
}

View File

@@ -0,0 +1,196 @@
package Audio;
import org.tinylog.Logger;
import java.io.File;
public class AudioPlayer {
Bass bass;
int deviceid = -1;
boolean inited = false;
int playbackhandle = 0;
float playbackvolume = 1.0f;
public AudioPlayer(){
bass = Bass.Instance;
Logger.info("Bass Version = {}", Integer.toHexString(bass.BASS_GetVersion()));
}
/**
* Unload Bass
*/
public void Unload(){
if (inited){
Logger.info("Freeing Device {}", deviceid);
bass.BASS_SetDevice(deviceid);
bass.BASS_Free();
}
deviceid = -1;
inited = false;
}
/**
* Detect Output Devices
*/
public void DetectOutputDevices(){
Logger.info("Detecting Output Devices...");
int ii = 1;
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));
ii++;
} else {
break;
}
}
}
/**
* Open Output Device
* @param device device id, starts from 1
* @param freq output frequency
* @return true if success
*/
@SuppressWarnings("UnusedReturnValue")
public boolean OpenDevice(int device, int freq){
int flag = Bass.BASS_DEVICE_REINIT | Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_MONO | Bass.BASS_DEVICE_FREQ;
boolean success = bass.BASS_Init(device, freq, flag);
if (success){
Logger.info("Device {} opened successfully", device);
deviceid = device;
inited = true;
} else {
Logger.error("Failed to open device {}, Error Code {}", device, bass.BASS_ErrorGetCode());
}
return success;
}
/**
* Set Master Volume
* @param value volume value, 0-100
*/
public void setMasterVolume(int value){
if (value<0) value = 0;
if (value>100) value = 100;
if (inited){
bass.BASS_SetDevice(deviceid);
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.info("AudioPlayer not initialized");
}
/**
* Get Master Volume
* @return 0 - 100, or -1 if failed
*/
@SuppressWarnings("unused")
public int getMasterVolume(){
if (inited){
bass.BASS_SetDevice(deviceid);
float vol = bass.BASS_GetVolume();
if (vol>=0 && vol<=1){
return (int)(vol*100);
}
} else Logger.info("AudioPlayer not initialized");
return -1;
}
public int getPlaybackvolume(){
if (playbackvolume<0)
return 0;
else if (playbackvolume>1.0f)
return 100;
else
return (int)(playbackvolume*100);
}
public void setPlaybackvolume(int value){
if (value<0) value = 0;
if (value>100) value = 100;
playbackvolume = value/100.0f;
if (playbackhandle!=0){
bass.BASS_ChannelSetAttribute(playbackhandle, Bass.BASS_ATTRIB_VOL, playbackvolume);
}
}
private float lastplaybackvolume = 1.0f;
public void Mute(){
lastplaybackvolume = playbackvolume;
setPlaybackvolume(0);
}
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 AudioFileProperties OpenAudioFile(File ff){
if (inited){
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);
return prop;
} else Logger.error("Failed to open audio file {}, Error Code {}", ff.getAbsolutePath(), bass.BASS_ErrorGetCode());
} else Logger.info("AudioPlayer not initialized");
return null;
}
/**
* Close Audio File
* @param prop AudioFileProperties object to close
*/
public void CloseAudioFile(AudioFileProperties prop) {
playbackhandle = 0;
if (inited) {
if (prop != null) {
if (!bass.BASS_StreamFree(prop.handle)) {
{
Logger.error("Failed to close audio file {}, Error Code {}", prop.filename, bass.BASS_ErrorGetCode());
}
} else Logger.info("Audio file {} closed successfully", prop.filename);
} else Logger.info("AudioPlayer not initialized");
}
}
public void PlayAudioFile(AudioFileProperties prop, boolean looping, PlaybackEvent event){
if (inited){
if (prop!=null){
if (bass.BASS_ChannelStart(prop.handle)){
playbackhandle = prop.handle;
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);
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);
if (endsync==0) Logger.error("Failed to set End 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()));
}
} else {
if (event!=null) event.onPlaybackFailure(null, "AudioFileProperties is null");
}
} else {
if (event!=null) event.onPlaybackFailure(prop, "AudioPlayer not initialized");
}
}
}

View File

@@ -0,0 +1,790 @@
package Audio;
import com.sun.jna.*;
@SuppressWarnings("unused")
public interface Bass extends Library {
Bass Instance = (Bass) Native.load("bass", Bass.class);
int BASSVERSION = 0x204; // API version
String BASSVERSIONTEXT = "2.4";
// Error codes returned by BASS_ErrorGetCode
int BASS_OK = 0; // all is OK
int BASS_ERROR_MEM = 1; // memory error
int BASS_ERROR_FILEOPEN = 2; // can't open the file
int BASS_ERROR_DRIVER = 3; // can't find a free/valid driver
int BASS_ERROR_BUFLOST = 4; // the sample buffer was lost
int BASS_ERROR_HANDLE = 5; // invalid handle
int BASS_ERROR_FORMAT = 6; // unsupported sample format
int BASS_ERROR_POSITION = 7; // invalid position
int BASS_ERROR_INIT = 8; // BASS_Init has not been successfully called
int BASS_ERROR_START = 9; // BASS_Start has not been successfully called
int BASS_ERROR_SSL = 10; // SSL/HTTPS support isn't available
int BASS_ERROR_REINIT = 11; // device needs to be reinitialized
int BASS_ERROR_ALREADY = 14; // already initialized/paused/whatever
int BASS_ERROR_NOTAUDIO = 17; // file does not contain audio
int BASS_ERROR_NOCHAN = 18; // can't get a free channel
int BASS_ERROR_ILLTYPE = 19; // an illegal type was specified
int BASS_ERROR_ILLPARAM = 20; // an illegal parameter was specified
int BASS_ERROR_NO3D = 21; // no 3D support
int BASS_ERROR_NOEAX = 22; // no EAX support
int BASS_ERROR_DEVICE = 23; // illegal device number
int BASS_ERROR_NOPLAY = 24; // not playing
int BASS_ERROR_FREQ = 25; // illegal sample rate
int BASS_ERROR_NOTFILE = 27; // the stream is not a file stream
int BASS_ERROR_NOHW = 29; // no hardware voices available
int BASS_ERROR_EMPTY = 31; // the file has no sample data
int BASS_ERROR_NONET = 32; // no internet connection could be opened
int BASS_ERROR_CREATE = 33; // couldn't create the file
int BASS_ERROR_NOFX = 34; // effects are not available
int BASS_ERROR_NOTAVAIL = 37; // requested data/action is not available
int BASS_ERROR_DECODE = 38; // the channel is a "decoding channel"
int BASS_ERROR_DX = 39; // a sufficient DirectX version is not installed
int BASS_ERROR_TIMEOUT = 40; // connection timedout
int BASS_ERROR_FILEFORM = 41; // unsupported file format
int BASS_ERROR_SPEAKER = 42; // unavailable speaker
int BASS_ERROR_VERSION = 43; // invalid BASS version (used by add-ons)
int BASS_ERROR_CODEC = 44; // codec is not available/supported
int BASS_ERROR_ENDED = 45; // the channel/file has ended
int BASS_ERROR_BUSY = 46; // the device is busy
int BASS_ERROR_UNSTREAMABLE = 47; // unstreamable file
int BASS_ERROR_PROTOCOL = 48; // unsupported protocol
int BASS_ERROR_DENIED = 49; // access denied
int BASS_ERROR_UNKNOWN = -1; // some other mystery problem
int BASS_ERROR_JAVA_CLASS = 500; // object class problem
// BASS_SetConfig options
int BASS_CONFIG_BUFFER = 0;
int BASS_CONFIG_UPDATEPERIOD = 1;
int BASS_CONFIG_GVOL_SAMPLE = 4;
int BASS_CONFIG_GVOL_STREAM = 5;
int BASS_CONFIG_GVOL_MUSIC = 6;
int BASS_CONFIG_CURVE_VOL = 7;
int BASS_CONFIG_CURVE_PAN = 8;
int BASS_CONFIG_FLOATDSP = 9;
int BASS_CONFIG_3DALGORITHM = 10;
int BASS_CONFIG_NET_TIMEOUT = 11;
int BASS_CONFIG_NET_BUFFER = 12;
int BASS_CONFIG_PAUSE_NOPLAY = 13;
int BASS_CONFIG_NET_PREBUF = 15;
int BASS_CONFIG_NET_PASSIVE = 18;
int BASS_CONFIG_REC_BUFFER = 19;
int BASS_CONFIG_NET_PLAYLIST = 21;
int BASS_CONFIG_MUSIC_VIRTUAL = 22;
int BASS_CONFIG_VERIFY = 23;
int BASS_CONFIG_UPDATETHREADS = 24;
int BASS_CONFIG_DEV_BUFFER = 27;
int BASS_CONFIG_DEV_DEFAULT = 36;
int BASS_CONFIG_NET_READTIMEOUT = 37;
int BASS_CONFIG_HANDLES = 41;
int BASS_CONFIG_SRC = 43;
int BASS_CONFIG_SRC_SAMPLE = 44;
int BASS_CONFIG_ASYNCFILE_BUFFER = 45;
int BASS_CONFIG_OGG_PRESCAN = 47;
int BASS_CONFIG_DEV_NONSTOP = 50;
int BASS_CONFIG_VERIFY_NET = 52;
int BASS_CONFIG_DEV_PERIOD = 53;
int BASS_CONFIG_FLOAT = 54;
int BASS_CONFIG_NET_SEEK = 56;
int BASS_CONFIG_AM_DISABLE = 58;
int BASS_CONFIG_NET_PLAYLIST_DEPTH = 59;
int BASS_CONFIG_NET_PREBUF_WAIT = 60;
int BASS_CONFIG_ANDROID_SESSIONID = 62;
int BASS_CONFIG_ANDROID_AAUDIO = 67;
int BASS_CONFIG_SAMPLE_ONEHANDLE = 69;
int BASS_CONFIG_DEV_TIMEOUT = 70;
int BASS_CONFIG_NET_META = 71;
int BASS_CONFIG_NET_RESTRATE = 72;
int BASS_CONFIG_REC_DEFAULT = 73;
int BASS_CONFIG_NORAMP = 74;
// BASS_SetConfigPtr options
int BASS_CONFIG_NET_AGENT = 16;
int BASS_CONFIG_NET_PROXY = 17;
int BASS_CONFIG_LIBSSL = 64;
int BASS_CONFIG_FILENAME = 75;
int BASS_CONFIG_THREAD = 0x40000000; // flag: thread-specific setting
// BASS_Init flags
int BASS_DEVICE_8BITS = 1; // unused
int BASS_DEVICE_MONO = 2; // mono
int BASS_DEVICE_3D = 4; // unused
int BASS_DEVICE_16BITS = 8; // limit output to 16-bit
int BASS_DEVICE_REINIT = 128; // reinitialize
int BASS_DEVICE_LATENCY = 0x100; // unused
int BASS_DEVICE_SPEAKERS = 0x800; // force enabling of speaker assignment
int BASS_DEVICE_NOSPEAKER = 0x1000; // ignore speaker arrangement
int BASS_DEVICE_DMIX = 0x2000; // use ALSA "dmix" plugin
int BASS_DEVICE_FREQ = 0x4000; // set device sample rate
int BASS_DEVICE_STEREO = 0x8000; // limit output to stereo
int BASS_DEVICE_AUDIOTRACK = 0x20000; // use AudioTrack output
int BASS_DEVICE_DSOUND = 0x40000; // use DirectSound output
int BASS_DEVICE_SOFTWARE = 0x80000; // disable hardware/fastpath output
@Structure.FieldOrder({"name", "driver", "flags"})
class BASS_DEVICEINFO extends Structure {
public String name; // description
public String driver; // driver
public int flags;
}
// BASS_DEVICEINFO flags
int BASS_DEVICE_ENABLED = 1;
int BASS_DEVICE_DEFAULT = 2;
int BASS_DEVICE_INIT = 4;
@Structure.FieldOrder({"flags", "hwsize", "hwfree", "freesam", "free3d", "minrate", "maxrate", "eax", "minbuf", "dsver", "latency", "initflags", "speakers", "freq"})
class BASS_INFO extends Structure{
public int flags; // device capabilities (DSCAPS_xxx flags)
public int hwsize; // unused
public int hwfree; // unused
public int freesam; // unused
public int free3d; // unused
public int minrate; // unused
public int maxrate; // unused
public int eax; // unused
public int minbuf; // recommended minimum buffer length in ms
public int dsver; // DirectSound version
public int latency; // average delay (in ms) before start of playback
public int initflags; // BASS_Init "flags" parameter
public int speakers; // number of speakers available
public int freq; // current output rate
}
// Recording device info structure
@Structure.FieldOrder({"flags", "formats", "inputs", "singlein", "freq"})
class BASS_RECORDINFO extends Structure {
public int flags; // device capabilities (DSCCAPS_xxx flags)
public int formats; // supported standard formats (WAVE_FORMAT_xxx flags)
public int inputs; // number of inputs
public boolean singlein; // TRUE = only 1 input can be set at a time
public int freq; // current input rate
}
// Sample info structure
@Structure.FieldOrder({"freq", "chans", "flags", "length", "max", "origres", "chans", "mingap", "mode3d", "mindist", "maxdist", "iangle", "oangle", "outvol", "vam", "priority"})
class BASS_SAMPLE extends Structure {
public int freq; // default playback rate
public float volume; // default volume (0-1)
public float pan; // default pan (-1=left, 0=middle, 1=right)
public int flags; // BASS_SAMPLE_xxx flags
public int length; // length (in bytes)
public int max; // maximum simultaneous playbacks
public int origres; // original resolution bits
public int chans; // number of channels
public int mingap; // minimum gap (ms) between creating channels
public int mode3d; // BASS_3DMODE_xxx mode
public float mindist; // minimum distance
public float maxdist; // maximum distance
public int iangle; // angle of inside projection cone
public int oangle; // angle of outside projection cone
public float outvol; // delta-volume outside the projection cone
public int vam; // unused
public int priority; // unused
}
int BASS_SAMPLE_8BITS = 1; // 8 bit
int BASS_SAMPLE_FLOAT = 256; // 32-bit floating-point
int BASS_SAMPLE_MONO = 2; // mono
int BASS_SAMPLE_LOOP = 4; // looped
int BASS_SAMPLE_3D = 8; // 3D functionality
int BASS_SAMPLE_SOFTWARE = 16; // unused
int BASS_SAMPLE_MUTEMAX = 32; // mute at max distance (3D only)
int BASS_SAMPLE_VAM = 64; // unused
int BASS_SAMPLE_FX = 128; // unused
int BASS_SAMPLE_OVER_VOL = 0x10000; // override lowest volume
int BASS_SAMPLE_OVER_POS = 0x20000; // override longest playing
int BASS_SAMPLE_OVER_DIST = 0x30000; // override furthest from listener (3D only)
int BASS_STREAM_PRESCAN = 0x20000; // scan file for accurate seeking and length
int BASS_STREAM_AUTOFREE = 0x40000; // automatically free the stream when it stops/ends
int BASS_STREAM_RESTRATE = 0x80000; // restrict the download rate of internet file streams
int BASS_STREAM_BLOCK = 0x100000; // download/play internet file stream in small blocks
int BASS_STREAM_DECODE = 0x200000; // don't play the stream, only decode (BASS_ChannelGetData)
int BASS_STREAM_STATUS = 0x800000; // give server status info (HTTP/ICY tags) in DOWNLOADPROC
int BASS_MP3_IGNOREDELAY = 0x200; // ignore LAME/Xing/VBRI/iTunes delay & padding info
int BASS_MP3_SETPOS = BASS_STREAM_PRESCAN;
int BASS_MUSIC_FLOAT = BASS_SAMPLE_FLOAT;
int BASS_MUSIC_MONO = BASS_SAMPLE_MONO;
int BASS_MUSIC_LOOP = BASS_SAMPLE_LOOP;
int BASS_MUSIC_3D = BASS_SAMPLE_3D;
int BASS_MUSIC_FX = BASS_SAMPLE_FX;
int BASS_MUSIC_AUTOFREE = BASS_STREAM_AUTOFREE;
int BASS_MUSIC_DECODE = BASS_STREAM_DECODE;
int BASS_MUSIC_PRESCAN = BASS_STREAM_PRESCAN; // calculate playback length
int BASS_MUSIC_CALCLEN = BASS_MUSIC_PRESCAN;
int BASS_MUSIC_RAMP = 0x200; // normal ramping
int BASS_MUSIC_RAMPS = 0x400; // sensitive ramping
int BASS_MUSIC_SURROUND = 0x800; // surround sound
int BASS_MUSIC_SURROUND2 = 0x1000; // surround sound (mode 2)
int BASS_MUSIC_FT2PAN = 0x2000; // apply FastTracker 2 panning to XM files
int BASS_MUSIC_FT2MOD = 0x2000; // play .MOD as FastTracker 2 does
int BASS_MUSIC_PT1MOD = 0x4000; // play .MOD as ProTracker 1 does
int BASS_MUSIC_NONINTER = 0x10000; // non-interpolated sample mixing
int BASS_MUSIC_SINCINTER = 0x800000; // sinc interpolated sample mixing
int BASS_MUSIC_POSRESET = 0x8000; // stop all notes when moving position
int BASS_MUSIC_POSRESETEX = 0x400000; // stop all notes and reset bmp/etc when moving position
int BASS_MUSIC_STOPBACK = 0x80000; // stop the music on a backwards jump effect
int BASS_MUSIC_NOSAMPLE = 0x100000; // don't load the samples
// Speaker assignment flags
int BASS_SPEAKER_FRONT = 0x1000000; // front speakers
int BASS_SPEAKER_REAR = 0x2000000; // rear speakers
int BASS_SPEAKER_CENLFE = 0x3000000; // center & LFE speakers (5.1)
int BASS_SPEAKER_SIDE = 0x4000000; // side speakers (7.1)
static int BASS_SPEAKER_N(int n) { return n<<24; } // n'th pair of speakers (max 15)
int BASS_SPEAKER_LEFT = 0x10000000; // modifier: left
int BASS_SPEAKER_RIGHT = 0x20000000; // modifier: right
int BASS_SPEAKER_FRONTLEFT = BASS_SPEAKER_FRONT | BASS_SPEAKER_LEFT;
int BASS_SPEAKER_FRONTRIGHT = BASS_SPEAKER_FRONT | BASS_SPEAKER_RIGHT;
int BASS_SPEAKER_REARLEFT = BASS_SPEAKER_REAR | BASS_SPEAKER_LEFT;
int BASS_SPEAKER_REARRIGHT = BASS_SPEAKER_REAR | BASS_SPEAKER_RIGHT;
int BASS_SPEAKER_CENTER = BASS_SPEAKER_CENLFE | BASS_SPEAKER_LEFT;
int BASS_SPEAKER_LFE = BASS_SPEAKER_CENLFE | BASS_SPEAKER_RIGHT;
int BASS_SPEAKER_SIDELEFT = BASS_SPEAKER_SIDE | BASS_SPEAKER_LEFT;
int BASS_SPEAKER_SIDERIGHT = BASS_SPEAKER_SIDE | BASS_SPEAKER_RIGHT;
int BASS_SPEAKER_REAR2 = BASS_SPEAKER_SIDE;
int BASS_SPEAKER_REAR2LEFT = BASS_SPEAKER_SIDELEFT;
int BASS_SPEAKER_REAR2RIGHT = BASS_SPEAKER_SIDERIGHT;
int BASS_ASYNCFILE = 0x40000000; // read file asynchronously
int BASS_RECORD_PAUSE = 0x8000; // start recording paused
// Channel info structure
@Structure.FieldOrder({"freq", "chans", "flags", "ctype", "origres", "plugin", "sample", "filename"})
class BASS_CHANNELINFO extends Structure {
public int freq; // default playback rate
public int chans; // channels
public int flags;
public int ctype; // type of channel
public int origres; // original resolution
public int plugin;
public int sample;
public String filename;
}
int BASS_ORIGRES_FLOAT = 0x10000;
// BASS_CHANNELINFO types
int BASS_CTYPE_SAMPLE = 1;
int BASS_CTYPE_RECORD = 2;
int BASS_CTYPE_STREAM = 0x10000;
int BASS_CTYPE_STREAM_VORBIS = 0x10002;
int BASS_CTYPE_STREAM_OGG = 0x10002;
int BASS_CTYPE_STREAM_MP1 = 0x10003;
int BASS_CTYPE_STREAM_MP2 = 0x10004;
int BASS_CTYPE_STREAM_MP3 = 0x10005;
int BASS_CTYPE_STREAM_AIFF = 0x10006;
int BASS_CTYPE_STREAM_CA = 0x10007;
int BASS_CTYPE_STREAM_MF = 0x10008;
int BASS_CTYPE_STREAM_AM = 0x10009;
int BASS_CTYPE_STREAM_SAMPLE = 0x1000a;
int BASS_CTYPE_STREAM_DUMMY = 0x18000;
int BASS_CTYPE_STREAM_DEVICE = 0x18001;
int BASS_CTYPE_STREAM_WAV = 0x40000; // WAVE flag (LOWORD=codec)
int BASS_CTYPE_STREAM_WAV_PCM = 0x50001;
int BASS_CTYPE_STREAM_WAV_FLOAT = 0x50003;
int BASS_CTYPE_MUSIC_MOD = 0x20000;
int BASS_CTYPE_MUSIC_MTM = 0x20001;
int BASS_CTYPE_MUSIC_S3M = 0x20002;
int BASS_CTYPE_MUSIC_XM = 0x20003;
int BASS_CTYPE_MUSIC_IT = 0x20004;
int BASS_CTYPE_MUSIC_MO3 = 0x00100; // MO3 flag
@Structure.FieldOrder({"ctype", "name", "exts"})
class BASS_PLUGINFORM extends Structure {
int ctype; // channel type
String name; // format description
String exts; // file extension filter (*.ext1;*.ext2;etc...)
}
@Structure.FieldOrder({"version", "formatc", "formats"})
class BASS_PLUGININFO extends Structure {
int version; // version (same form as BASS_GetVersion)
int formatc; // number of formats
BASS_PLUGINFORM[] formats; // the array of formats
}
// 3D vector (for 3D positions/velocities/orientations)
class BASS_3DVECTOR {
BASS_3DVECTOR() {}
BASS_3DVECTOR(float _x, float _y, float _z) { x=_x; y=_y; z=_z; }
float x; // +=right, -=left
float y; // +=up, -=down
float z; // +=front, -=behind
}
// 3D channel modes
int BASS_3DMODE_NORMAL = 0; // normal 3D processing
int BASS_3DMODE_RELATIVE = 1; // position is relative to the listener
int BASS_3DMODE_OFF = 2; // no 3D processing
// software 3D mixing algorithms (used with BASS_CONFIG_3DALGORITHM)
int BASS_3DALG_DEFAULT = 0;
int BASS_3DALG_OFF = 1;
int BASS_3DALG_FULL = 2;
int BASS_3DALG_LIGHT = 3;
// BASS_SampleGetChannel flags
int BASS_SAMCHAN_NEW = 1; // get a new playback channel
int BASS_SAMCHAN_STREAM = 2; // create a stream
interface STREAMPROC extends Callback
{
int STREAMPROC(int handle, Pointer buffer, int length, Pointer user);
/* User stream callback function.
handle : The stream that needs writing
buffer : Buffer to write the samples in
length : Number of bytes to write
user : The 'user' parameter value given when calling BASS_StreamCreate
RETURN : Number of bytes written. Set the BASS_STREAMPROC_END flag to end
the stream. */
}
int BASS_STREAMPROC_END = 0x80000000; // end of user stream flag
// Special STREAMPROCs
int STREAMPROC_DUMMY = 0; // "dummy" stream
int STREAMPROC_PUSH = -1; // push stream
int STREAMPROC_DEVICE = -2; // device mix stream
int STREAMPROC_DEVICE_3D = -3; // device 3D mix stream
// BASS_StreamCreateFileUser file systems
int STREAMFILE_NOBUFFER = 0;
int STREAMFILE_BUFFER = 1;
int STREAMFILE_BUFFERPUSH = 2;
interface BASS_FILEPROCS extends Callback
{
// User file stream callback functions
void FILECLOSEPROC(Pointer user);
long FILELENPROC(Pointer user) ;
int FILEREADPROC(Pointer buffer, int length, Pointer user);
boolean FILESEEKPROC(long offset, Pointer user);
}
// BASS_StreamPutFileData options
int BASS_FILEDATA_END = 0; // end & close the file
// BASS_StreamGetFilePosition modes
int BASS_FILEPOS_CURRENT = 0;
int BASS_FILEPOS_DECODE = BASS_FILEPOS_CURRENT;
int BASS_FILEPOS_DOWNLOAD = 1;
int BASS_FILEPOS_END = 2;
int BASS_FILEPOS_START = 3;
int BASS_FILEPOS_CONNECTED = 4;
int BASS_FILEPOS_BUFFER = 5;
int BASS_FILEPOS_SOCKET = 6;
int BASS_FILEPOS_ASYNCBUF = 7;
int BASS_FILEPOS_SIZE = 8;
int BASS_FILEPOS_BUFFERING = 9;
int BASS_FILEPOS_AVAILABLE = 10;
interface DOWNLOADPROC extends Callback
{
void DOWNLOADPROC(Pointer buffer, int length, Pointer user);
/* Internet stream download callback function.
buffer : Buffer containing the downloaded data... NULL=end of download
length : Number of bytes in the buffer
user : The 'user' parameter value given when calling BASS_StreamCreateURL */
}
// BASS_ChannelSetSync types
int BASS_SYNC_POS = 0;
int BASS_SYNC_END = 2;
int BASS_SYNC_META = 4;
int BASS_SYNC_SLIDE = 5;
int BASS_SYNC_STALL = 6;
int BASS_SYNC_DOWNLOAD = 7;
int BASS_SYNC_FREE = 8;
int BASS_SYNC_SETPOS = 11;
int BASS_SYNC_MUSICPOS = 10;
int BASS_SYNC_MUSICINST = 1;
int BASS_SYNC_MUSICFX = 3;
int BASS_SYNC_OGG_CHANGE = 12;
int BASS_SYNC_DEV_FAIL = 14;
int BASS_SYNC_DEV_FORMAT = 15;
int BASS_SYNC_THREAD = 0x20000000; // flag: call sync in other thread
int BASS_SYNC_MIXTIME = 0x40000000; // flag: sync at mixtime, else at playtime
int BASS_SYNC_ONETIME = 0x80000000; // flag: sync only once, else continuously
interface SYNCPROC extends Callback
{
void SYNCPROC(int handle, int channel, int data, Pointer user);
/* Sync callback function.
handle : The sync that has occured
channel: Channel that the sync occured in
data : Additional data associated with the sync's occurance
user : The 'user' parameter given when calling BASS_ChannelSetSync */
}
interface DSPPROC extends Callback
{
void DSPPROC(int handle, int channel, Pointer buffer, int length, Pointer user);
/* DSP callback function.
handle : The DSP handle
channel: Channel that the DSP is being applied to
buffer : Buffer to apply the DSP to
length : Number of bytes in the buffer
user : The 'user' parameter given when calling BASS_ChannelSetDSP */
}
interface RECORDPROC extends Callback
{
boolean RECORDPROC(int handle, Pointer buffer, int length, Pointer user);
/* Recording callback function.
handle : The recording handle
buffer : Buffer containing the recorded sample data
length : Number of bytes
user : The 'user' parameter value given when calling BASS_RecordStart
RETURN : true = continue recording, false = stop */
}
// BASS_ChannelIsActive return values
int BASS_ACTIVE_STOPPED = 0;
int BASS_ACTIVE_PLAYING =1;
int BASS_ACTIVE_STALLED = 2;
int BASS_ACTIVE_PAUSED = 3;
int BASS_ACTIVE_PAUSED_DEVICE = 4;
// Channel attributes
int BASS_ATTRIB_FREQ = 1;
int BASS_ATTRIB_VOL = 2;
int BASS_ATTRIB_PAN = 3;
int BASS_ATTRIB_EAXMIX = 4;
int BASS_ATTRIB_NOBUFFER = 5;
int BASS_ATTRIB_VBR = 6;
int BASS_ATTRIB_CPU = 7;
int BASS_ATTRIB_SRC = 8;
int BASS_ATTRIB_NET_RESUME = 9;
int BASS_ATTRIB_SCANINFO = 10;
int BASS_ATTRIB_NORAMP = 11;
int BASS_ATTRIB_BITRATE = 12;
int BASS_ATTRIB_BUFFER = 13;
int BASS_ATTRIB_GRANULE = 14;
int BASS_ATTRIB_USER = 15;
int BASS_ATTRIB_TAIL = 16;
int BASS_ATTRIB_PUSH_LIMIT = 17;
int BASS_ATTRIB_DOWNLOADPROC = 18;
int BASS_ATTRIB_VOLDSP = 19;
int BASS_ATTRIB_VOLDSP_PRIORITY = 20;
int BASS_ATTRIB_MUSIC_AMPLIFY = 0x100;
int BASS_ATTRIB_MUSIC_PANSEP = 0x101;
int BASS_ATTRIB_MUSIC_PSCALER = 0x102;
int BASS_ATTRIB_MUSIC_BPM = 0x103;
int BASS_ATTRIB_MUSIC_SPEED = 0x104;
int BASS_ATTRIB_MUSIC_VOL_GLOBAL = 0x105;
int BASS_ATTRIB_MUSIC_VOL_CHAN = 0x200; // + channel #
int BASS_ATTRIB_MUSIC_VOL_INST = 0x300; // + instrument #
// BASS_ChannelSlideAttribute flags
int BASS_SLIDE_LOG = 0x1000000;
// BASS_ChannelGetData flags
int BASS_DATA_AVAILABLE = 0; // query how much data is buffered
int BASS_DATA_NOREMOVE = 0x10000000; // flag: don't remove data from recording buffer
int BASS_DATA_FIXED = 0x20000000; // unused
int BASS_DATA_FLOAT = 0x40000000; // flag: return floating-point sample data
int BASS_DATA_FFT256 = 0x80000000; // 256 sample FFT
int BASS_DATA_FFT512 = 0x80000001; // 512 FFT
int BASS_DATA_FFT1024 = 0x80000002; // 1024 FFT
int BASS_DATA_FFT2048 = 0x80000003; // 2048 FFT
int BASS_DATA_FFT4096 = 0x80000004; // 4096 FFT
int BASS_DATA_FFT8192 = 0x80000005; // 8192 FFT
int BASS_DATA_FFT16384 = 0x80000006; // 16384 FFT
int BASS_DATA_FFT32768 = 0x80000007; // 32768 FFT
int BASS_DATA_FFT_INDIVIDUAL = 0x10; // FFT flag: FFT for each channel, else all combined
int BASS_DATA_FFT_NOWINDOW = 0x20; // FFT flag: no Hanning window
int BASS_DATA_FFT_REMOVEDC = 0x40; // FFT flag: pre-remove DC bias
int BASS_DATA_FFT_COMPLEX = 0x80; // FFT flag: return complex data
int BASS_DATA_FFT_NYQUIST = 0x100; // FFT flag: return extra Nyquist value
// BASS_ChannelGetLevelEx flags
int BASS_LEVEL_MONO = 1; // get mono level
int BASS_LEVEL_STEREO = 2; // get stereo level
int BASS_LEVEL_RMS = 4; // get RMS levels
int BASS_LEVEL_VOLPAN = 8; // apply VOL/PAN attributes to the levels
int BASS_LEVEL_NOREMOVE = 16; // don't remove data from recording buffer
// BASS_ChannelGetTags types : what's returned
int BASS_TAG_ID3 = 0; // ID3v1 tags : TAG_ID3
int BASS_TAG_ID3V2 = 1; // ID3v2 tags : ByteBuffer
int BASS_TAG_OGG = 2; // OGG comments : String array
int BASS_TAG_HTTP = 3; // HTTP headers : String array
int BASS_TAG_ICY = 4; // ICY headers : String array
int BASS_TAG_META = 5; // ICY metadata : String
int BASS_TAG_APE = 6; // APE tags : String array
int BASS_TAG_MP4 = 7; // MP4/iTunes metadata : String array
int BASS_TAG_VENDOR = 9; // OGG encoder : String
int BASS_TAG_LYRICS3 = 10; // Lyric3v2 tag : String
int BASS_TAG_WAVEFORMAT = 14; // WAVE format : ByteBuffer containing WAVEFORMATEEX structure
int BASS_TAG_AM_NAME = 16; // Android Media codec name : String
int BASS_TAG_ID3V2_2 = 17; // ID3v2 tags (2nd block) : ByteBuffer
int BASS_TAG_AM_MIME = 18; // Android Media MIME type : String
int BASS_TAG_LOCATION = 19; // redirected URL : String
int BASS_TAG_RIFF_INFO = 0x100; // RIFF "INFO" tags : String array
int BASS_TAG_RIFF_BEXT = 0x101; // RIFF/BWF "bext" tags : TAG_BEXT
int BASS_TAG_RIFF_CART = 0x102; // RIFF/BWF "cart" tags : TAG_CART
int BASS_TAG_RIFF_DISP = 0x103; // RIFF "DISP" text tag : String
int BASS_TAG_RIFF_CUE = 0x104; // RIFF "cue " chunk : TAG_CUE structure
int BASS_TAG_RIFF_SMPL = 0x105; // RIFF "smpl" chunk : TAG_SMPL structure
int BASS_TAG_APE_BINARY = 0x1000; // + index #, binary APE tag : TAG_APE_BINARY
int BASS_TAG_MUSIC_NAME = 0x10000; // MOD music name : String
int BASS_TAG_MUSIC_MESSAGE = 0x10001; // MOD message : String
int BASS_TAG_MUSIC_ORDERS = 0x10002; // MOD order list : ByteBuffer
int BASS_TAG_MUSIC_AUTH = 0x10003; // MOD author : UTF-8 string
int BASS_TAG_MUSIC_INST = 0x10100; // + instrument #, MOD instrument name : String
int BASS_TAG_MUSIC_CHAN = 0x10200; // + channel #, MOD channel name : String
int BASS_TAG_MUSIC_SAMPLE = 0x10300; // + sample #, MOD sample name : String
int BASS_TAG_BYTEBUFFER = 0x10000000; // flag: return a ByteBuffer instead of a String or TAG_ID3
// ID3v1 tag structure
@Structure.FieldOrder({"id", "title", "artist", "album", "year", "comment", "genre", "track"})
class TAG_ID3 extends Structure {
String id;
String title;
String artist;
String album;
String year;
String comment;
byte genre;
byte track;
}
// Binary APE tag structure
@Structure.FieldOrder({"key", "data", "length"})
class TAG_APE_BINARY extends Structure {
String key;
Pointer data;
int length;
}
// BASS_ChannelGetLength/GetPosition/SetPosition modes
int BASS_POS_BYTE = 0; // byte position
int BASS_POS_MUSIC_ORDER = 1; // order.row position, MAKELONG(order,row)
int BASS_POS_OGG = 3; // OGG bitstream number
int BASS_POS_END = 0x10; // trimmed end position
int BASS_POS_LOOP = 0x11; // loop start positiom
int BASS_POS_FLUSH = 0x1000000; // flag: flush decoder/FX buffers
int BASS_POS_RESET = 0x2000000; // flag: reset user file buffers
int BASS_POS_RELATIVE = 0x4000000; // flag: seek relative to the current position
int BASS_POS_INEXACT = 0x8000000; // flag: allow seeking to inexact position
int BASS_POS_DECODE = 0x10000000; // flag: get the decoding (not playing) position
int BASS_POS_DECODETO = 0x20000000; // flag: decode to the position instead of seeking
int BASS_POS_SCAN = 0x40000000; // flag: scan to the position
// BASS_ChannelSetDevice/GetDevice option
int BASS_NODEVICE = 0x20000;
// DX8 effect types, use with BASS_ChannelSetFX
int BASS_FX_DX8_CHORUS = 0;
int BASS_FX_DX8_COMPRESSOR = 1;
int BASS_FX_DX8_DISTORTION = 2;
int BASS_FX_DX8_ECHO = 3;
int BASS_FX_DX8_FLANGER = 4;
int BASS_FX_DX8_GARGLE = 5;
int BASS_FX_DX8_I3DL2REVERB = 6;
int BASS_FX_DX8_PARAMEQ = 7;
int BASS_FX_DX8_REVERB = 8;
int BASS_FX_VOLUME = 9;
@Structure.FieldOrder({"fWetDryMix", "fDepth", "fFeedback", "fFrequency", "lWaveform", "fDelay", "lPhase"})
class BASS_DX8_CHORUS extends Structure {
float fWetDryMix;
float fDepth;
float fFeedback;
float fFrequency;
int lWaveform; // 0=triangle, 1=sine
float fDelay;
int lPhase; // BASS_DX8_PHASE_xxx
}
@Structure.FieldOrder({"fGain","fEdge","fPostEQCenterFrequency","fPostEQBandwidth","fPreLowpassCutoff"})
class BASS_DX8_DISTORTION extends Structure {
float fGain;
float fEdge;
float fPostEQCenterFrequency;
float fPostEQBandwidth;
float fPreLowpassCutoff;
}
@Structure.FieldOrder({"fWetDryMix","fFeedback","fLeftDelay","fRightDelay","lPanDelay"})
class BASS_DX8_ECHO extends Structure {
float fWetDryMix;
float fFeedback;
float fLeftDelay;
float fRightDelay;
boolean lPanDelay;
}
@Structure.FieldOrder({"fWetDryMix","fDepth","fFeedback","fFrequency","lWaveform","fDelay","lPhase"})
class BASS_DX8_FLANGER extends Structure {
float fWetDryMix;
float fDepth;
float fFeedback;
float fFrequency;
int lWaveform; // 0=triangle, 1=sine
float fDelay;
int lPhase; // BASS_DX8_PHASE_xxx
}
@Structure.FieldOrder({"fCenter","fBandwidth","fGain"})
class BASS_DX8_PARAMEQ extends Structure {
float fCenter;
float fBandwidth;
float fGain;
}
@Structure.FieldOrder({"fInGain","fReverbMix","fReverbTime","fHighFreqRTRatio"})
class BASS_DX8_REVERB extends Structure {
float fInGain;
float fReverbMix;
float fReverbTime;
float fHighFreqRTRatio;
}
int BASS_DX8_PHASE_NEG_180 = 0;
int BASS_DX8_PHASE_NEG_90 = 1;
int BASS_DX8_PHASE_ZERO = 2;
int BASS_DX8_PHASE_90 = 3;
int BASS_DX8_PHASE_180 = 4;
@Structure.FieldOrder({"fTarget","fCurrent","fTime","lCurve"})
class BASS_FX_VOLUME_PARAM extends Structure {
float fTarget;
float fCurrent;
float fTime;
int lCurve;
}
class FloatValue {
public float value;
}
boolean BASS_SetConfig(int option, int value);
int BASS_GetConfig(int option);
boolean BASS_SetConfigPtr(int option, Pointer value);
Object BASS_GetConfigPtr(int option);
int BASS_GetVersion();
int BASS_ErrorGetCode();
boolean BASS_GetDeviceInfo(int device, BASS_DEVICEINFO info);
boolean BASS_Init(int device, int freq, int flags);
boolean BASS_Free();
boolean BASS_SetDevice(int device);
int BASS_GetDevice();
boolean BASS_GetInfo(BASS_INFO info);
boolean BASS_Start();
boolean BASS_Stop();
boolean BASS_Pause();
int BASS_IsStarted();
boolean BASS_Update(int length);
float BASS_GetCPU();
boolean BASS_SetVolume(float volume);
float BASS_GetVolume();
boolean BASS_Set3DFactors(float distf, float rollf, float doppf);
boolean BASS_Get3DFactors(FloatValue distf, FloatValue rollf, FloatValue doppf);
boolean BASS_Set3DPosition(BASS_3DVECTOR pos, BASS_3DVECTOR vel, BASS_3DVECTOR front, BASS_3DVECTOR top);
boolean BASS_Get3DPosition(BASS_3DVECTOR pos, BASS_3DVECTOR vel, BASS_3DVECTOR front, BASS_3DVECTOR top);
void BASS_Apply3D();
int BASS_PluginLoad(String file, int flags);
boolean BASS_PluginFree(int handle);
boolean BASS_PluginEnable(int handle, boolean enable);
BASS_PLUGININFO BASS_PluginGetInfo(int handle);
int BASS_SampleLoad(String file, long offset, int length, int max, int flags);
int BASS_SampleLoad(Pointer file, long offset, int length, int max, int flags);
int BASS_SampleCreate(int length, int freq, int chans, int max, int flags);
boolean BASS_SampleFree(int handle);
boolean BASS_SampleSetData(int handle, Pointer buffer);
boolean BASS_SampleGetData(int handle, Pointer buffer);
boolean BASS_SampleGetInfo(int handle, BASS_SAMPLE info);
boolean BASS_SampleSetInfo(int handle, BASS_SAMPLE info);
int BASS_SampleGetChannel(int handle, boolean onlynew);
int BASS_SampleGetChannels(int handle, int[] channels);
boolean BASS_SampleStop(int handle);
int BASS_StreamCreate(int freq, int chans, int flags, STREAMPROC proc, Pointer user);
int BASS_StreamCreateFile(boolean mem, String file, long offset, long length, int flags);
int BASS_StreamCreateFile(Pointer file, long offset, long length, int flags);
int BASS_StreamCreateURL(String url, int offset, int flags, DOWNLOADPROC proc, Pointer user);
int BASS_StreamCreateFileUser(int system, int flags, BASS_FILEPROCS procs, Pointer user);
boolean BASS_StreamFree(int handle);
long BASS_StreamGetFilePosition(int handle, int mode);
int BASS_StreamPutData(int handle, Pointer buffer, int length);
int BASS_StreamPutFileData(int handle, Pointer buffer, int length);
int BASS_MusicLoad(String file, long offset, int length, int flags, int freq);
int BASS_MusicLoad(Pointer file, long offset, int length, int flags, int freq);
boolean BASS_MusicFree(int handle);
boolean BASS_RecordGetDeviceInfo(int device, BASS_DEVICEINFO info);
boolean BASS_RecordInit(int device);
boolean BASS_RecordFree();
boolean BASS_RecordSetDevice(int device);
int BASS_RecordGetDevice();
boolean BASS_RecordGetInfo(BASS_RECORDINFO info);
String BASS_RecordGetInputName(int input);
boolean BASS_RecordSetInput(int input, int flags, float volume);
int BASS_RecordGetInput(int input, FloatValue volume);
int BASS_RecordStart(int freq, int chans, int flags, RECORDPROC proc, Pointer user);
double BASS_ChannelBytes2Seconds(int handle, long pos);
long BASS_ChannelSeconds2Bytes(int handle, double pos);
int BASS_ChannelGetDevice(int handle);
boolean BASS_ChannelSetDevice(int handle, int device);
int BASS_ChannelIsActive(int handle);
boolean BASS_ChannelGetInfo(int handle, BASS_CHANNELINFO info);
Object BASS_ChannelGetTags(int handle, int tags);
long BASS_ChannelFlags(int handle, int flags, int mask);
boolean BASS_ChannelLock(int handle, boolean lock);
boolean BASS_ChannelFree(int handle);
boolean BASS_ChannelPlay(int handle, boolean restart);
boolean BASS_ChannelStart(int handle);
boolean BASS_ChannelStop(int handle);
boolean BASS_ChannelPause(int handle);
boolean BASS_ChannelUpdate(int handle, int length);
boolean BASS_ChannelSetAttribute(int handle, int attrib, float value);
boolean BASS_ChannelGetAttribute(int handle, int attrib, FloatValue value);
boolean BASS_ChannelSlideAttribute(int handle, int attrib, float value, int time);
boolean BASS_ChannelIsSliding(int handle, int attrib);
boolean BASS_ChannelSetAttributeEx(int handle, int attrib, Pointer value, int size);
boolean BASS_ChannelSetAttributeDOWNLOADPROC(int handle, DOWNLOADPROC proc, Pointer user);
int BASS_ChannelGetAttributeEx(int handle, int attrib, Pointer value, int size);
boolean BASS_ChannelSet3DAttributes(int handle, int mode, float min, float max, int iangle, int oangle, float outvol);
boolean BASS_ChannelGet3DAttributes(int handle, Integer mode, FloatValue min, FloatValue max, Integer iangle, Integer oangle, FloatValue outvol);
boolean BASS_ChannelSet3DPosition(int handle, BASS_3DVECTOR pos, BASS_3DVECTOR orient, BASS_3DVECTOR vel);
boolean BASS_ChannelGet3DPosition(int handle, BASS_3DVECTOR pos, BASS_3DVECTOR orient, BASS_3DVECTOR vel);
long BASS_ChannelGetLength(int handle, int mode);
boolean BASS_ChannelSetPosition(int handle, long pos, int mode);
long BASS_ChannelGetPosition(int handle, int mode);
int BASS_ChannelGetLevel(int handle);
boolean BASS_ChannelGetLevelEx(int handle, float[] levels, float length, int flags);
int BASS_ChannelGetData(int handle, Pointer buffer, int length);
int BASS_ChannelSetSync(int handle, int type, long param, SYNCPROC proc, Pointer user);
boolean BASS_ChannelRemoveSync(int handle, int sync);
boolean BASS_ChannelSetLink(int handle, int chan);
boolean BASS_ChannelRemoveLink(int handle, int chan);
int BASS_ChannelSetDSP(int handle, DSPPROC proc, Pointer user, int priority);
boolean BASS_ChannelRemoveDSP(int handle, int dsp);
int BASS_ChannelSetFX(int handle, int type, int priority);
boolean BASS_ChannelRemoveFX(int handle, int fx);
boolean BASS_FXSetParameters(int handle, Object params);
boolean BASS_FXGetParameters(int handle, Object params);
boolean BASS_FXSetPriority(int handle, int priority);
boolean BASS_FXReset(int handle);
// gak bisa
int BASS_StreamCreate(int freq, int chans, int flags, int proc, Pointer user);
}

View File

@@ -0,0 +1,8 @@
package Audio;
public interface PlaybackEvent {
void onPlaybackStart(AudioFileProperties prop);
void onPlaybackFinished(AudioFileProperties prop);
void onPlaybackFailure(AudioFileProperties prop, String reason);
void onPlaybackLooped(AudioFileProperties prop);
}

View File

@@ -0,0 +1,122 @@
package Camera;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import Other.SomeCodes;
import lombok.Getter;
import lombok.Setter;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.opencv.opencv_core.Mat;
public class GrabbingTask implements Runnable {
@Setter private Consumer<String> onMessageUpdate;
@Setter private Consumer<Mat> onMatUpdate;
@Setter private Consumer<Frame> onFrameUpdate;
@Setter private Consumer<String> onBase64Update;
@Setter private Consumer<String> onStreamingStatusUpdate;
private final AtomicBoolean isGrabbing;
private final FrameGrabber grabber;
@Getter private final int lowquality_width = 640;
@Getter private final int lowquality_height = 360;
@Getter @Setter private boolean HQ = false;
@Getter private int streaming_width = 0;
@Getter private int streaming_height = 0;
@Getter private int streaming_fps = 0;
AtomicBoolean streamingstatuschanged = new AtomicBoolean(false);
private void updateMessage(String message) {
if (onMessageUpdate != null) {
onMessageUpdate.accept(message);
}
}
private void updateMat(Mat value) {
if (onMatUpdate != null) {
onMatUpdate.accept(value);
}
}
private void updateBase64(String base64) {
if (onBase64Update != null) {
onBase64Update.accept(base64);
}
}
private void updateFrame(Frame frame) {
if (onFrameUpdate != null) {
onFrameUpdate.accept(frame);
}
}
private void updateStreamingStatus(String status) {
if (onStreamingStatusUpdate != null) {
onStreamingStatusUpdate.accept(status);
}
}
public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber) {
this.isGrabbing = isGrabbing;
this.grabber = grabber;
}
public String GetStreamingStatus(){
return "Streaming at " + streaming_width + "x" + streaming_height + " " + streaming_fps + "fps";
}
@Override
public void run() {
isGrabbing.set(true);
AtomicInteger framecount = new AtomicInteger(0);
TimerTask task = new TimerTask() {
@Override
public void run() {
if (streaming_fps != framecount.get()) {
streaming_fps = framecount.get();
streamingstatuschanged.set(true);
}
framecount.set(0);
if (streamingstatuschanged.get()) {
updateStreamingStatus(GetStreamingStatus());
streamingstatuschanged.set(false);
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 1000, 1000);
while (isGrabbing.get()) {
try {
//Thread.sleep(100); // 10 fps
Frame fr =grabber.grab();
if (fr!=null){
if (!HQ) fr = SomeCodes.ResizeFrame(fr, lowquality_width, lowquality_height);
updateFrame(fr);
updateBase64(SomeCodes.BufferedImageToBase64(SomeCodes.FrameToBufferedImage(fr)));
Mat mat = SomeCodes.matConverter.convert(fr);
updateMat(mat);
if (streaming_width != fr.imageWidth) {
streaming_width = fr.imageWidth;
streamingstatuschanged.set(true);
}
if (streaming_height != fr.imageHeight) {
streaming_height = fr.imageHeight;
streamingstatuschanged.set(true);
}
framecount.incrementAndGet();
} else updateMessage("Grabber returned null frame");
} catch (Exception e) {
updateMessage("Error grabbing frame: " + e.getMessage());
}
}
timer.cancel();
}
}

View File

@@ -0,0 +1,117 @@
package Camera;
import com.fazecast.jSerialComm.SerialPort;
import org.tinylog.Logger;
/**
* Pan Tilt Controller
* Using PelcoD protocol
* Source : https://www.commfront.com/pages/pelco-d-protocol-tutorial
*/
public class PanTiltController {
private final SerialPort serialPort;
private final byte cameraid;
/**
* Open Pan Tilt Controller
* @param portname serial port name used
* @param baudrate baudrate used
*/
public PanTiltController(String portname, int baudrate, int cameraid){
serialPort = SerialPort.getCommPort(portname);
serialPort.setBaudRate(baudrate);
this.cameraid = (byte)cameraid;
if (serialPort.openPort()){
Logger.info("Serial Port {} opened successfully at {}", portname, baudrate);
} else {
Logger.info("Failed to open Serial Port {} at {}", portname, baudrate);
}
}
/**
* Close Pan Tilt Controller
*/
public void Close(){
serialPort.closePort();
Logger.info("Serial Port closed");
}
/**
* Stop Pan Tilt Movement
*/
public void StopMovement(){
byte[] command = new byte[]{0, cameraid, 0, 0, 0, 0, 0};
command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte
serialPort.writeBytes(command, command.length);
}
/**
* Pan Left
* @param speed speed of movement, 0-63
*/
public void PanLeft(byte speed){
if (speed<0) speed = 0;
if (speed>0x3F) speed = 0x3F;
byte[] command = new byte[]{0, cameraid, 0, 4, speed, 0, 0};
command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte
serialPort.writeBytes(command, command.length);
}
/**
* Pan Right
* @param speed speed of movement, 0-63
*/
public void PanRight(byte speed){
if (speed<0) speed = 0;
if (speed>0x3F) speed = 0x3F;
byte[] command = new byte[]{0, cameraid, 0, 2, speed, 0, 0};
command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte
serialPort.writeBytes(command, command.length);
}
/**
* Tilt Up
* @param speed speed of movement, 0-63
*/
public void TiltUp(byte speed){
if (speed<0) speed = 0;
if (speed>0x3F) speed = 0x3F;
byte[] command = new byte[]{0, cameraid, 0, 8, speed, 0, 0};
command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte
serialPort.writeBytes(command, command.length);
}
/**
* Tilt Down
* @param speed speed of movement, 0-63
*/
public void TiltDown(byte speed){
if (speed<0) speed = 0;
if (speed>0x3F) speed = 0x3F;
byte[] command = new byte[]{0, cameraid, 0, 16, speed, 0, 0};
command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte
serialPort.writeBytes(command, command.length);
}
/**
* Sum of bytes, then modulo by 256
* @param data data to be summed
* @return checksum
*/
private byte Checksum(byte[] data){
int sum = 0;
for (byte b : data){
sum += b;
}
return (byte)(sum % 256);
}
}

View File

@@ -0,0 +1,11 @@
package Camera;
import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.opencv_core.Mat;
public interface RtspEvent {
void onMatReceived(Mat mat);
void onFrameReceived(Frame frame);
void onBase64Received(String base64);
void onStreamingStatusReceived(String status);
}

View File

@@ -0,0 +1,120 @@
package Camera;
import lombok.Getter;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.opencv_core.Mat;
import org.tinylog.Logger;
import java.util.concurrent.atomic.AtomicBoolean;
@SuppressWarnings("unused")
public class RtspGrabber {
private final String rtspUrl;
private FFmpegFrameGrabber grabber;
private final AtomicBoolean isGrabbing = new AtomicBoolean(false);
private @Getter Frame lastFrame = null;
private @Getter String lastBase64 = null;
private @Getter Mat lastMat = null;
private GrabbingTask grabbingTask = null;
public RtspGrabber(String ip, int port, String username, String password, String path) {
rtspUrl = "rtsp://" + username + ":" + password + "@" + ip + ":" + port + path;
Logger.info("RtspGrabber created with url: " + rtspUrl);
}
public RtspGrabber(String ip, String path) {
this.rtspUrl = "rtsp://" + ip + path;
Logger.info("RtspGrabber created with url: " + rtspUrl);
}
/**
* Start grabbing frames from rtsp
* @param useTcp Use tcp instead of udp
* @param event Event to be called when frame is received
*/
public void Start(boolean useTcp, final int width, final int height, RtspEvent event){
try{
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
//grabber.setImageWidth(width);
//grabber.setImageHeight(height);
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
grabber.start();
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
Logger.info("Grabber started");
GrabbingTask tt = new GrabbingTask(isGrabbing, grabber);
tt.setOnMessageUpdate(Logger::info);
tt.setOnMatUpdate(value -> {
// Kalau butuh Mat untuk diproses
lastMat = value;
if (event!=null) event.onMatReceived(value);
});
tt.setOnFrameUpdate(value -> {
// Kalau butuh Frame untuk ditampilkan
lastFrame = value;
if (event!=null) event.onFrameReceived(value);
});
tt.setOnBase64Update(value -> {
// Kalau butuh Base64 untuk dikirim ke Websocket
lastBase64 = value;
if (event!=null) event.onBase64Received(value);
});
tt.setOnStreamingStatusUpdate(value -> {
// Kalau butuh status streaming
if (event!=null) event.onStreamingStatusReceived(value);
});
new Thread(tt).start();
grabbingTask = tt;
} catch (Exception e){
Logger.error("Error starting grabber: " + e.getMessage());
}
}
/**
* Stop grabbing frames
*/
public void Stop(){
if (grabber!=null) {
try{
isGrabbing.set(false);
grabber.stop();
Logger.info("Grabber stopped");
} catch (Exception e){
Logger.error("Error stopping grabber: " + e.getMessage());
}
}
}
/**
* Check if grabber is grabbing
* @return True if grabbing
*/
public boolean IsGrabbing(){
return isGrabbing.get();
}
public void ChangeVideoQuality(boolean HQ){
if (IsGrabbing()){
if (grabbingTask!=null){
grabbingTask.setHQ(HQ);
}
}
}
public String GetStreamingStatus(){
if (grabbingTask!=null){
return grabbingTask.GetStreamingStatus();
}
return "No Status";
}
}

View File

@@ -0,0 +1,348 @@
package Camera;
import org.tinylog.Logger;
import java.awt.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static Other.SomeCodes.ValidInteger;
import static Other.SomeCodes.ValidString;
@SuppressWarnings("unused")
public class VapixProtocol {
private final String url;
private final HttpClient client;
private String parameters;
private String ProductNumberValue = "";
private String SerialNumberValue = "";
private int CameraIDValue = 0;
private int MaxZoomValue = 0;
private int MinZoomValue = 0;
private boolean PTZEnabledValue = false;
private String[] ImageResolutions = new String[0];
private String[] ImageFormats = new String[0];
private int CurrentZoomValue = 0;
/**
* Create a new VapixProtocol object
* @param ip The IP address of the camera
* @param port The HTTP port of the camera
* @param username The username to access the camera (optional)
* @param password The password to access the camera (optional)
*/
public VapixProtocol(String ip, int port, String username, String password) {
url = "http://" + ip + ":" + port+"/axis-cgi/";
String auth = username + ":" + password;
//encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
client = HttpClient.newHttpClient();
GetParameters(null);
if (ValidString(parameters)){
Pattern ProductNumber = Pattern.compile(".*ProdNbr=(.*)");
Matcher m1 = ProductNumber.matcher(parameters);
if (m1.find()) ProductNumberValue = m1.group(1);
Pattern SerialNumber = Pattern.compile(".*SerialNumber=(.*)");
Matcher m2 = SerialNumber.matcher(parameters);
if (m2.find()) SerialNumberValue = m2.group(1);
Pattern PTZCamId = Pattern.compile(".*CamId=(.*)");
Matcher m3 = PTZCamId.matcher(parameters);
if (m3.find()) {
String value = m3.group(1);
if (ValidInteger(value)) CameraIDValue = Integer.parseInt(value);
}
Pattern PTZMaxZoom = Pattern.compile(".*MaxZoom=(.*)");
Matcher m4 = PTZMaxZoom.matcher(parameters);
if (m4.find()) {
String value = m4.group(1);
if (ValidInteger(value)) MaxZoomValue = Integer.parseInt(value);
}
Pattern PTZMinZoom = Pattern.compile(".*MinZoom=(.*)");
Matcher m5 = PTZMinZoom.matcher(parameters);
if (m5.find()) {
String value = m5.group(1);
if (ValidInteger(value)) MinZoomValue = Integer.parseInt(value);
}
Pattern PTZEnabled = Pattern.compile(".*PTZ.PTZ=(.*)");
Matcher m6 = PTZEnabled.matcher(parameters);
if (m6.find()) PTZEnabledValue = m6.group(1).contains("yes");
Pattern Resolution = Pattern.compile(".*Image.Resolution=(.*)");
Matcher m7 = Resolution.matcher(parameters);
if (m7.find()) {
String value = m7.group(1);
if (ValidString(value)) ImageResolutions = value.split(",");
//Logger.info("Resolution: "+value);
}
Pattern Format = Pattern.compile(".*Image.Format=(.*)");
Matcher m8 = Format.matcher(parameters);
if (m8.find()) {
String value = m8.group(1);
if (ValidString(value)) ImageFormats = value.split(",");
//Logger.info("Format: "+value);
}
}
}
@SuppressWarnings("SameParameterValue")
private void GetParameters(String group){
String command = url+"param.cgi?action=list";
if (ValidString(group)) command+="&group="+group;
HttpRequest request = HttpRequest.newBuilder()
.uri(java.net.URI.create(command))
.build();
parameters = "";
try{
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode()==200){
parameters = response.body();
} else Logger.info("Error getting parameters: "+response.statusCode());
} catch (Exception e){
Logger.error("Error getting parameters: "+e.getMessage());
}
}
/**
* Get Product Number of the camera
* @return Product Number, or empty string if not available
*/
public String GetProductNumber(){
return ProductNumberValue;
}
/**
* Get Serial Number of the camera
* @return Serial Number, or empty string if not available
*/
public String GetSerialNumber(){
return SerialNumberValue;
}
/**
* Get PTZ Camera ID
* @return Camera ID
*/
public int GetPTZCameraID(){
return CameraIDValue;
}
/**
* Get Maximum Zoom Value
* @return Maximum Zoom Value
*/
public int GetPTZMaxZoom(){
return MaxZoomValue;
}
/**
* Get Minimum Zoom Value
* @return Minimum Zoom Value
*/
public int GetPTZMinZoom(){
return MinZoomValue;
}
/**
* Check if PTZ Control enabled for this camera
* @return true if PTZ Control enabled, false otherwise
*/
public boolean PTZEnabled() {
return PTZEnabledValue;
}
/**
* Get Available Image Resolutions
* @return array of String, in format "widthxheight"
*/
public String[] GetImageResolutions(){
return ImageResolutions;
}
/**
* Get Available Image Formats
* @return array of String, example "jpeg","mjpeg","h264","bitmap"
*/
public String[] GetImageFormats(){
return ImageFormats;
}
/**
* Close VapiX Protocol
*/
public void Close(){
if (client!=null) client.close();
}
/**
* Zoom In / Out
* @param cameraid Camera ID, get it from GetPTZCameraID()
* @param zoom Zoom value, value between GetPTZMinZoom and GetPTZMaxZoom()
* @return true if successful, false otherwise
*/
public boolean Zoom(int cameraid, int zoom){
if (zoom < MinZoomValue) zoom = MinZoomValue;
if (zoom > MaxZoomValue) zoom = MaxZoomValue;
String command = url+"com/ptz.cgi?zoom="+zoom+"&camera="+cameraid;
HttpRequest request = HttpRequest.newBuilder()
.uri(java.net.URI.create(command))
.build();
try{
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode()==200){
Logger.info("Zoom: "+response.body());
return true;
}
} catch (Exception e){
Logger.error("Error zooming: "+e.getMessage());
}
return false;
}
/**
* Get Current Zoom Value
* @return Current Zoom Value
*/
public int GetCurrentZoomValue(){
update_ptz_query_position();
return CurrentZoomValue;
}
/**
* Get Current Image Resolution
* @param cameraid Camera ID, get it from GetPTZCameraID()
* @return array of int, [0] = width, [1] = height
*/
public int[] GetCurrentResolution(int cameraid){
int[] result = new int[]{0,0};
String command = url+"imagesize.cgi?camera="+cameraid;
HttpRequest request = HttpRequest.newBuilder()
.uri(java.net.URI.create(command))
.build();
try{
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode()==200){
String values = response.body();
//Something like this:
//image width = 1920
//image height = 1080
for (String s : values.split("\n")) {
String[] parts = s.split("=");
if (parts.length==2){
String part0 = parts[0].trim();
String part1 = parts[1].trim();
if (part0.contains("width")){
if (ValidInteger(part1)) result[0] = Integer.parseInt(part1);
}
if (part0.contains("height")) {
if (ValidInteger(part1)) result[1] = Integer.parseInt(part1);
}
}
}
}
} catch (Exception e){
Logger.error("Error getting resolution: "+e.getMessage());
}
return result;
}
/**
* Set Image Resolution
* @param cameraid Camera ID, get it from GetPTZCameraID()
* @param width Width of the image
* @param height Height of the image
* @return true if successful, false otherwise
*/
public boolean SetResolution(int cameraid, int width, int height){
String resolution = width+"x"+height;
boolean supported = false;
for(String r: ImageResolutions){
if (r.equals(resolution)){
supported = true;
break;
}
}
if (supported){
String command = url+"imagesize.cgi?camera="+cameraid+"&resolution="+resolution;
HttpRequest request = HttpRequest.newBuilder()
.uri(java.net.URI.create(command))
.build();
try{
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode()==200){
Logger.info("Resolution set: "+response.body());
String values = response.body();
//Something like this:
//image width = 1920
//image height = 1080
boolean width_ok = false;
boolean height_ok = false;
for (String s : values.split("\n")) {
String[] parts = s.split("=");
if (parts.length==2){
String part0 = parts[0].trim();
String part1 = parts[1].trim();
if (part0.contains("width")){
if (ValidInteger(part1)) {
if (Integer.parseInt(part1)==width)
width_ok = true;
else Logger.error("Width failed, target: "+width+" actual: "+part1);
}
}
if (part0.contains("height")) {
if (ValidInteger(part1)) {
if (Integer.parseInt(part1)==height)
height_ok = true;
else Logger.error("Height failed, target: "+height+" actual: "+part1);
}
}
}
}
return width_ok && height_ok;
}
} catch (Exception e){
Logger.error("Error setting resolution: "+e.getMessage());
}
} else Logger.info("Resolution not supported: "+resolution);
return false;
}
private void update_ptz_query_position(){
String command = url+"com/ptz.cgi?query=position";
HttpRequest request = HttpRequest.newBuilder()
.uri(java.net.URI.create(command))
.build();
try{
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode()==200){
String values = response.body();
//Something like this:
//pan=0.0000
//tilt=0.0000
//zoom=1
//iris=5000
//focus=9574
//brightness=5000
//autofocus=on
//autoiris=off
for (String s : values.split("\n")) {
String[] parts = s.split("=");
if (parts.length==2){
if (parts[0].equals("zoom")) CurrentZoomValue = Integer.parseInt(parts[1].trim());
}
}
}
} catch (Exception e){
Logger.error("Error getting PTZ position: "+e.getMessage());
}
}
}

View File

@@ -0,0 +1,245 @@
package Other;
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_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Size;
import org.bytedeco.opencv.opencv_core.UMat;
import org.jetbrains.annotations.NotNull;
import org.tinylog.Logger;
import java.awt.image.BufferedImage;
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.Properties;
@SuppressWarnings("unused")
public class SomeCodes {
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 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;
public static String[] GetAudioFiles(){
try{
return Files.list(audioPath).map(f -> f.getFileName().toString()).toArray(String[]::new);
} catch (Exception e){
Logger.error("Error getting audio files: "+e.getMessage());
}
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);
if (destination.exists()) {
Logger.info("Resource File already exists: " + filename);
return destination.getAbsolutePath();
}
InputStream is = SomeCodes.class.getResourceAsStream(filename);
if (is!=null){
Files.copy(is, destination.toPath());
Logger.info("Resource File extracted: "+filename);
return destination.getAbsolutePath();
} else {
Logger.error("Resource File not found: "+filename);
}
} catch (Exception e){
Logger.error("Error extracting resource: "+filename+", Message : "+e.getMessage());
}
return null;
}
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)){
File ff = new File(filename);
return ff.isFile();
}
return false;
}
public static boolean ValidString(String x){
if (x!=null){
return !x.isEmpty();
}
return false;
}
public static byte GetPanTiltSpeed(String data, byte defaultspeed){
if (ValidInteger(data)){
int speed = Integer.parseInt(data);
if (speed<0) speed = 0;
if (speed>0x3F) speed = 0x3F;
return (byte)speed;
}
return defaultspeed;
}
public static boolean ValidInteger(String x){
try{
Integer.parseInt(x);
return true;
} catch (Exception e){
return false;
}
}
public static boolean ValidPortNumber(int port){
return port>0 && port<65536;
}
public static boolean ValidPortNumber(String port){
try{
int portx = Integer.parseInt(port);
return ValidPortNumber(portx);
} catch (Exception e){
return false;
}
}
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;
}
}
} 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 "";
}
public static BufferedImage FrameToBufferedImage(Frame frame){
return frameConverter.getBufferedImage(frame);
}
public static BufferedImage MatToBufferedImage(Mat mat){
return frameConverter.getBufferedImage(matConverter.convert(mat));
}
public static String BufferedImageToBase64(BufferedImage image){
if (image!=null){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
javax.imageio.ImageIO.write(image, "jpg", baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();
baos.close();
return java.util.Base64.getEncoder().encodeToString(imageInByte);
} catch (Exception e){
Logger.error("Error converting BufferedImage to Base64: "+e.getMessage());
}
}
return "";
}
public static @NotNull Properties LoadProperties(String filename){
try{
InputStream is = new FileInputStream(filename);
Properties prop = new Properties();
prop.load(is);
return prop;
} catch (Exception e){
Logger.error("Error loading properties file: "+e.getMessage());
}
return new Properties();
}
public static boolean SaveProperties(Properties prop, String filename){
try{
OutputStream os = new FileOutputStream(filename);
prop.store(os, null);
return true;
} catch (Exception e){
Logger.error("Error saving properties file: "+e.getMessage());
}
return false;
}
public static String GetConfigAudioFile(int index){
Properties config = LoadProperties("config.properties");
String key = String.format("AudioFile%02d", index);
return config.getProperty(key, null);
}
public static Mat ResizeMat(Mat source, int width, int height){
Size sz = new Size(width, height);
Mat dest = new Mat();
if (useOpenCL){
UMat src = new UMat();
source.copyTo(src);
UMat dst = new UMat();
opencv_imgproc.resize(src, dst, sz);
dst.copyTo(dest);
} else {
opencv_imgproc.resize(source, dest, sz);
}
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);
}
}

165
src/main/java/SBC/GPIO.java Normal file
View File

@@ -0,0 +1,165 @@
package SBC;
import com.sun.jna.Platform;
import org.tinylog.Logger;
import java.nio.file.Files;
import java.nio.file.Path;
@SuppressWarnings("unused")
public class GPIO {
private static final Path gpioPath = Path.of("/sys/class/gpio");
private static final Path gpioExportPath = Path.of("/sys/class/gpio/export");
private static final Path gpioUnexportPath = Path.of("/sys/class/gpio/unexport");
public static boolean IsRaspberry64(){
if (Platform.isLinux()){
if (Platform.isARM()){
if (Platform.is64Bit()){
if (gpioPath.toFile().isDirectory()){
if (gpioExportPath.toFile().isFile()){
if (gpioUnexportPath.toFile().isFile()){
return true;
} else Logger.error("GPIO unexport path is not found");
} else Logger.error("GPIO export path is not found");
} else Logger.error("GPIO path is not found");
} else Logger.info("Device is not 64 bit");
} else Logger.info("Device is not ARM");
} else Logger.info("OS is not Linux");
return false;
}
/**
* Check if the pin is already exported
* @param pin GPIO pin number
* @return true if the pin is already exported
*/
public static boolean GpioPinExists(int pin){
Path pinPath = gpioPath.resolve("gpio"+pin);
return pinPath.toFile().isDirectory();
}
/**
* Export the pin
* @param pin GPIO pin number
* @return true if the pin is successfully exported
*/
public static boolean ExportPin(int pin){
try{
if (Files.isWritable(gpioExportPath)){
Files.write(gpioExportPath, String.valueOf(pin).getBytes());
Logger.info("Pin "+pin+" exported");
return GpioPinExists(pin);
} else Logger.error("GPIO export path is not writable");
} catch (Exception e){
Logger.error("Failed to export pin: "+pin+", Message: "+e.getMessage());
}
return false;
}
/**
* Unexport the pin
* @param pin GPIO pin number
* @return true if the pin is successfully unexported
*/
public static boolean UnexportPin(int pin){
if (Files.isWritable(gpioUnexportPath)){
try{
Files.write(gpioUnexportPath, String.valueOf(pin).getBytes());
Logger.info("Pin "+pin+" unexported");
return true;
} catch (Exception e){
Logger.error("Failed to unexport pin: "+pin+", Message: "+e.getMessage());
}
} else Logger.error("GPIO unexport path is not writable");
return false;
}
/**
* Get Direction of the pin
* @param pin GPIO pin number
* @return "in" if the pin is input, "out" if the pin is output, "unknown" if the direction is unknown
*/
public static String GetPinDirection(int pin){
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("direction");
if (pinPath.toFile().isFile()){
if (Files.isReadable(pinPath)){
try{
return Files.readString(pinPath).trim();
} catch (Exception e){
Logger.error("Failed to read pin direction: "+pin+", Message: "+e.getMessage());
}
} else Logger.error("Pin direction file is not readable: "+pin);
} else Logger.error("Pin direction file not found: "+pin);
return "unknown";
}
/**
* Set the direction of the pin
* @param pin GPIO pin number
* @param direction "in" for input, "out" for output
* @return true if the direction is successfully set
*/
public static boolean SetPinDirection(int pin, String direction){
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("direction");
if (pinPath.toFile().isFile()){
if (Files.isWritable(pinPath)){
direction = direction.trim().toLowerCase();
if ("in".equals(direction) || "out".equals(direction)){
try{
Files.write(pinPath, direction.getBytes());
Logger.info("Pin "+pin+" direction set to "+direction);
return true;
} catch (Exception e){
Logger.error("Failed to set pin direction: "+pin+", Message: "+e.getMessage());
}
} else Logger.error("Invalid direction: "+direction);
} else Logger.error("Pin direction file is not writable: "+pin);
} else Logger.error("Pin direction file not found: "+pin);
return false;
}
/**
* Set the value of the output pin
* @param pin GPIO pin number
* @param isON true to set the pin value to 1, false to set the pin value to 0
* @return true if the value is successfully set
*/
public static boolean SetValue(int pin, boolean isON){
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("value");
if (pinPath.toFile().isFile()){
if (Files.isWritable(pinPath)){
try{
Files.write(pinPath, isON?"1".getBytes():"0".getBytes());
Logger.info("Pin "+pin+" value set to "+(isON?"1":"0"));
return true;
} catch (Exception e){
Logger.error("Failed to set pin value: "+pin+", Message: "+e.getMessage());
}
} else Logger.error("Pin value file is not writable: "+pin);
} else Logger.error("Pin value file not found: "+pin);
return false;
}
/**
* Get the value of the pin
* @param pin GPIO pin number
* @return "1" if the pin value is 1, "0" if the pin value is 0, "unknown" if the value is unknown
*/
public static String GetValue(int pin){
Path pinPath = gpioPath.resolve("gpio"+pin).resolve("value");
if (pinPath.toFile().isFile()){
if (Files.isReadable(pinPath)){
try{
return Files.readString(pinPath).trim();
} catch (Exception e){
Logger.error("Failed to read pin value: "+pin+", Message: "+e.getMessage());
}
} else Logger.error("Pin value file is not readable: "+pin);
} else Logger.error("Pin value file not found: "+pin);
return "unknown";
}
}

View File

@@ -0,0 +1,38 @@
package Web;
import Other.SomeCodes;
import java.util.Properties;
public class SettingInfo {
public String[] AudioFiles;
public String AudioFile1;
public String AudioFile2;
public String AudioFile3;
public String AudioFile4;
public String AudioFile5;
public String CameraIP;
public String CameraPort;
public String CameraUsername;
public String CameraPassword;
public String LoginUsername;
public String LoginPassword;
public static SettingInfo getInstance() {
SettingInfo settingInfo = new SettingInfo();
Properties prop = SomeCodes.LoadProperties("config.properties");
settingInfo.AudioFiles = SomeCodes.GetAudioFiles();
settingInfo.AudioFile1 = prop.getProperty("AudioFile01","").trim();
settingInfo.AudioFile2 = prop.getProperty("AudioFile02","").trim();
settingInfo.AudioFile3 = prop.getProperty("AudioFile03","").trim();
settingInfo.AudioFile4 = prop.getProperty("AudioFile04","").trim();
settingInfo.AudioFile5 = prop.getProperty("AudioFile05","").trim();
settingInfo.CameraIP = prop.getProperty("Camera_ip","").trim();
settingInfo.CameraPort = prop.getProperty("Camera_port","").trim();
settingInfo.CameraUsername = prop.getProperty("Camera_user","").trim();
settingInfo.CameraPassword = prop.getProperty("Camera_password","").trim();
settingInfo.LoginUsername = prop.getProperty("WebUsername","").trim();
settingInfo.LoginPassword = prop.getProperty("WebPassword","").trim();
return settingInfo;
}
}

View File

@@ -0,0 +1,214 @@
package Web;
import Other.SomeCodes;
import io.javalin.Javalin;
import io.javalin.http.UploadedFile;
import io.javalin.util.JavalinException;
import io.javalin.websocket.*;
import lombok.extern.java.Log;
import org.tinylog.Logger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static Other.SomeCodes.*;
import static io.javalin.apibuilder.ApiBuilder.*;
@SuppressWarnings({"unused"})
public class WebServer {
private final Javalin app;
private final Set<WsContext> connectedWebsocketClients = ConcurrentHashMap.newKeySet();
public WebServer(WebsocketEvent event, String webusername, String webpassword){
app = Javalin.create(config -> {
config.staticFiles.add("/html");
config.router.apiBuilder(()-> path("setting", () ->{
get(ctx -> ctx.json(SettingInfo.getInstance()));
path("audiofile",()-> post(ctx -> {
Logger.info("api /setting/audiofile");
String audiofile1 = ctx.formParam("1");
String audiofile2 = ctx.formParam("2");
String audiofile3 = ctx.formParam("3");
String audiofile4 = ctx.formParam("4");
String audiofile5 = ctx.formParam("5");
Logger.info("audiofile1: {}", audiofile1);
Logger.info("audiofile2: {}", audiofile2);
Logger.info("audiofile3: {}", audiofile3);
Logger.info("audiofile4: {}", audiofile4);
Logger.info("audiofile5: {}", audiofile5);
Properties prop = SomeCodes.LoadProperties("config.properties");
prop.setProperty("audiofile1", audiofile1!=null?audiofile1:"");
prop.setProperty("audiofile2", audiofile2!=null?audiofile2:"");
prop.setProperty("audiofile3", audiofile3!=null?audiofile3:"");
prop.setProperty("audiofile4", audiofile4!=null?audiofile4:"");
prop.setProperty("audiofile5", audiofile5!=null?audiofile5:"");
if (SaveProperties(prop, "config.properties")){
Logger.info("audiofile saved");
ctx.status(200);
} else {
Logger.error("Failed to save audiofile");
ctx.status(400);
}
}));
path("uploadaudiofile", ()-> post(ctx -> {
UploadedFile file = ctx.uploadedFile("file");
if (file!=null){
try {
Path targetsave = audioPath.resolve(file.filename());
Files.copy(file.content(), targetsave);
Logger.info("Uploaded file: {}, size: {} saved at {}", file.filename(),file.size(), targetsave);
} catch (Exception e){
Logger.error("Failed to save uploaded file: {}, Message: {}", file.filename(), e.getMessage());
}
}
}));
path("weblogin", ()-> post(ctx -> {
String username = ctx.formParam("username");
String password = ctx.formParam("password");
Properties prop = SomeCodes.LoadProperties("config.properties");
prop.setProperty("WebUsername", ValidString(username)?username:"admin");
prop.setProperty("WebPassword", ValidString(password)?password:"bandara");
if (SaveProperties(prop, "config.properties")){
ctx.status(200);
} else {
ctx.status(400);
}
}));
path("camera",()-> post(ctx -> {
String camera_ip = ctx.formParam("ip");
String camera_port = ctx.formParam("port");
String camera_username = ctx.formParam("username");
String camera_password = ctx.formParam("password");
Properties prop = SomeCodes.LoadProperties("config.properties");
prop.setProperty("Camera_ip", ValidString(camera_ip)?camera_ip:"192.168.0.4");
prop.setProperty("Camera_port", ValidString(camera_port)?camera_port:"80");
prop.setProperty("Camera_user", ValidString(camera_username)?camera_username:"root");
prop.setProperty("Camera_password", ValidString(camera_password)?camera_password:"password");
if (SaveProperties(prop, "config.properties")){
ctx.status(200);
} else {
ctx.status(400);
}
}));
}));
});
app.get("/", ctx-> {
if (ctx.sessionAttribute("username")==null) {
// belum login
ctx.redirect("/login.html");
} else if (Objects.equals(ctx.sessionAttribute("username"), webusername)){
// sudah login
ctx.redirect("/index.html");
} else {
// sudah login tapi bukan username yang benar
ctx.redirect("/login.html");
}
});
app.before("/index.html", ctx ->{
if (ctx.sessionAttribute("username")==null){
ctx.redirect("/login.html");
}
});
app.before("/setting.html", ctx ->{
if (ctx.sessionAttribute("username")==null){
ctx.redirect("/login.html");
}
});
app.post("/login", ctx ->{
String username = ctx.formParam("username");
String password = ctx.formParam("password");
if (Objects.equals(username, webusername) && Objects.equals(password, webpassword)){
ctx.sessionAttribute("username", username);
ctx.redirect("/index.html");
} else {
ctx.redirect("/login.html?error=Invalid username or password");
}
});
app.get("/logout", ctx ->{
ctx.sessionAttribute("username", null);
ctx.redirect("/login.html");
});
app.ws("/ws", ws -> {
ws.onConnect(connectws);
ws.onClose(closews);
//ws.onError(errorws);
ws.onMessage(ctx -> {
try{
//Logger.info("WebSocket message {}", ctx.message());
WebsocketCommand command = ctx.messageAsClass(WebsocketCommand.class);
if (event!=null) {
WebsocketReply reply = event.onWebsocketCommand(command);
if (reply!=null) ctx.sendAsClass(reply, WebsocketReply.class);
}
} catch (Exception e){
Logger.error("Failed to parse WebSocketCommand message: {}", e.getMessage());
}
});
});
}
/**
* Send Object message to all connected websocket clients
* @param obj Object to send
*/
public void SendtoAll(Object obj){
connectedWebsocketClients.forEach(wsContext -> wsContext.send(obj));
}
/**
* Start the web server
* @param localip Local IP address to bind
* @param port Port to bind
*/
public void Start(String localip, int port){
try{
connectedWebsocketClients.forEach(WsContext::closeSession);
app.start(localip, port);
Logger.info("Web server started at {}:{}", localip, port);
} catch (JavalinException e){
Logger.error("Web server failed to start: {}", e.getMessage());
}
}
/**
* Stop the web server
*/
public void Stop(){
try{
app.stop();
Logger.info("Web server stopped");
} catch (JavalinException e){
Logger.error("Web server failed to stop: {}", e.getMessage());
}
}
WsConnectHandler connectws = ws ->{
Logger.info("WebSocket connected from {}", ws.host());
//ws.headerMap().forEach((key, value) -> Logger.info("HeaderMap {}: {}", key, value));
connectedWebsocketClients.add(ws);
};
WsCloseHandler closews = ws ->{
Logger.info("WebSocket closed from {}, code {}, reason {}", ws.host(), ws.status(), ws.reason());
connectedWebsocketClients.remove(ws);
};
//WsErrorHandler errorws = ws -> Logger.error("WebSocket error from {}, error {}", ws.host(), ws.error());
}

View File

@@ -0,0 +1,14 @@
package Web;
public class WebsocketCommand {
public String command;
public String data;
public WebsocketCommand(){
this.command = "";
this.data = "";
}
public WebsocketCommand(String command, String data){
this.command = command;
this.data = data;
}
}

View File

@@ -0,0 +1,6 @@
package Web;
public interface WebsocketEvent {
String onMessage(String message);
WebsocketReply onWebsocketCommand(WebsocketCommand command);
}

View File

@@ -0,0 +1,10 @@
package Web;
public class WebsocketReply {
public String reply;
public String data;
public WebsocketReply(String reply, String data){
this.reply = reply;
this.data = data;
}
}

View File

@@ -0,0 +1,314 @@
package id.co.gtc;
import Audio.AudioFileProperties;
import Audio.AudioPlayer;
import Audio.PlaybackEvent;
import Camera.PanTiltController;
import Camera.RtspEvent;
import Camera.RtspGrabber;
import Camera.VapixProtocol;
import Other.SomeCodes;
import Web.WebServer;
import Web.WebsocketCommand;
import Web.WebsocketEvent;
import Web.WebsocketReply;
import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.opencv_core.Mat;
import org.tinylog.Logger;
import java.io.File;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Properties;
import static Other.SomeCodes.*;
public class Main {
private static AudioPlayer audioPlayer;
private static WebServer webServer;
private static RtspGrabber rtspGrabber;
private static PanTiltController panTiltController;
private static AudioFileProperties audioFileProperties;
private static VapixProtocol vapixProtocol;
// Application start from here
public static void main(String[] args) {
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();
}));
init_properties();
init_audiofiles();
init_audio();
init_webserver();
init_rtspgrabber();
init_pantiltcontroller();
init_Vapix();
}
private static void init_properties(){
if (ExtractResource("/tinylog.properties", currentDirectory)==null) Logger.error("Failed to extract tinylog.properties");
if (ExtractResource("/config.properties", currentDirectory)==null) Logger.error("Failed to extract config.properties");
if (ExtractResource("/simplelogger.properties", currentDirectory)==null) Logger.error("Failed to extract simplelogger.properties");
}
private static void init_audiofiles(){
if (audioPath.toFile().isDirectory()) {
Logger.info("Audio Files Directory exists : "+audioPath);
} else {
if (audioPath.toFile().mkdirs()) Logger.info("Audio Files Directory created : "+audioPath);
}
if (ExtractResource("/elangWav.wav", audioPath.toString())==null) Logger.error("Failed to extract elangWav.wav");
if (ExtractResource("/gunshotsWav.wav", audioPath.toString())==null) Logger.error("Failed to extract gunshotsWav.wav");
if (ExtractResource("/pinkNoiseWav.wav", audioPath.toString())==null) Logger.error("Failed to extract pinkNoiseWav.wav");
}
private static void init_Vapix(){
Properties config = SomeCodes.LoadProperties("config.properties");
String ip = config.getProperty("Camera_ip");
String port = config.getProperty("Camera_port");
String username = config.getProperty("Camera_user");
String password = config.getProperty("Camera_password");
if (ValidString(ip)){
if (ValidInteger(port)){
if (ValidString(username)){
if (ValidString(password)){
vapixProtocol = new VapixProtocol(ip, Integer.parseInt(port), username, password);
Logger.info("Camera Product Number: "+vapixProtocol.GetProductNumber());
Logger.info("Camera Serial Number: "+vapixProtocol.GetSerialNumber());
if (vapixProtocol.PTZEnabled()){
Logger.info("PTZ Enabled");
} else Logger.error("PTZ Disabled");
Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom());
Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom());
} else Logger.error("Invalid Camera Password");
} else Logger.error("Invalid Camera Username");
} else Logger.error("Invalid Camera Port");
} else Logger.error("Invalid Camera IP");
}
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");
if (ValidString(portname)){
if (ValidInteger(baudrate)){
if (ValidInteger(PanTiltID)){
panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID));
}
} else Logger.error("Invalid PTZ Baudrate");
} else Logger.error("Invalid PTZ Port");
}
private static void init_rtspgrabber() {
if (haveOpenCL) opencv_core.setUseOpenCL(true);
// check if really activated
useOpenCL = opencv_core.useOpenCL();
Logger.info("OpenCL available={}, activated={}", haveOpenCL, useOpenCL);
Properties config = SomeCodes.LoadProperties("config.properties");
String targetip = config.getProperty("Camera_ip");
String rtsppath = config.getProperty("Camera_Rtsp_path");
if (ValidString(targetip)){
if (ValidString(rtsppath)){
rtspGrabber = new RtspGrabber(targetip, rtsppath);
RtspEvent re = new RtspEvent() {
@Override
public void onMatReceived(Mat mat) {
//TODO : kalau butuh Mat, ambil disini
}
@Override
public void onFrameReceived(Frame frame) {
//TODO : kalau butuh Frame, ambil disini
}
@Override
public void onBase64Received(String base64) {
WebsocketReply wr = new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ base64);
webServer.SendtoAll(wr);
}
@Override
public void onStreamingStatusReceived(String status) {
WebsocketReply wr = new WebsocketReply("STREAMING STATUS", status);
webServer.SendtoAll(wr);
}
};
rtspGrabber.Start(true, 1920, 1080, re);
} else Logger.error("Invalid Camera Path");
} else Logger.error("Invalid Camera IP");
}
private static void init_audio() {
audioPlayer = new AudioPlayer();
audioPlayer.DetectOutputDevices();
audioPlayer.OpenDevice(1,48000);
audioPlayer.setMasterVolume(100);
audioPlayer.setPlaybackvolume(100);
}
static PlaybackEvent pe = new PlaybackEvent() {
@Override
public void onPlaybackStart(AudioFileProperties prop) {
Logger.info("Playback started for {}", prop.filename);
}
@Override
public void onPlaybackFinished(AudioFileProperties prop) {
Logger.info("Playback finished for {}", prop.filename);
}
@Override
public void onPlaybackFailure(AudioFileProperties prop, String reason) {
Logger.error("Playback failed for {}: {}", prop.filename, reason);
}
@Override
public void onPlaybackLooped(AudioFileProperties prop) {
Logger.info("Playback looped for {}", prop.filename);
}
};
static WebsocketEvent we = new WebsocketEvent() {
@Override
public String onMessage(String message) {
return "";
}
@Override
public WebsocketReply onWebsocketCommand(WebsocketCommand command) {
byte speed;
String cmd = command.command.toUpperCase().trim();
switch (cmd){
// Pan Tilt Movement Commands
case "PAN LEFT" :
speed = GetPanTiltSpeed(command.data, (byte)0x20);
if (panTiltController!=null) panTiltController.PanLeft(speed);
return new WebsocketReply("PAN LEFT", String.valueOf(speed));
case "PAN RIGHT" :
speed = GetPanTiltSpeed(command.data, (byte)0x20);
if (panTiltController!=null) panTiltController.PanRight(speed);
return new WebsocketReply("PAN RIGHT", String.valueOf(speed));
case "TILT UP" :
speed = GetPanTiltSpeed(command.data, (byte)0x20);
if (panTiltController!=null) panTiltController.TiltUp(speed);
return new WebsocketReply("TILT UP", String.valueOf(speed));
case "TILT DOWN" :
speed = GetPanTiltSpeed(command.data, (byte)0x20);
if (panTiltController!=null) panTiltController.TiltDown(speed);
return new WebsocketReply("TILT DOWN", String.valueOf(speed));
case "STOP MOVEMENT" :
if (panTiltController!=null) panTiltController.StopMovement();
return new WebsocketReply("STOP MOVEMENT", "");
// Audio Related Commands
case "MUTE":
audioPlayer.Mute();
return new WebsocketReply("MUTE", "");
case "UNMUTE":
audioPlayer.Unmute();
return new WebsocketReply("UNMUTE", "");
case "SET VOLUME" :
int volume=-1;
if (ValidInteger(command.data)){
volume = Integer.parseInt(command.data);
if (volume<0) volume = 0;
if (volume>100) volume = 100;
}
if (volume>=0){
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();
return new WebsocketReply("GET VOLUME", String.valueOf(vol));
case "PLAY AUDIO" :
if (ValidInteger(command.data)){
int id = Integer.parseInt(command.data);
String filename = GetConfigAudioFile(id);
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);
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", "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;
return new WebsocketReply("STOP AUDIO", filename);
} else return new WebsocketReply("STOP AUDIO", "No audioFileProperties");
// ZOOM Related Commands
case "GET MAX ZOOM":
if (vapixProtocol!=null){
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){
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)){
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 new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastBase64());
} else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
case "GET RESOLUTION":
if (vapixProtocol!=null){
int[] res = vapixProtocol.GetCurrentResolution(1);
return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1]));
} else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized");
case "SET VIDEO QUALITY":
if (Objects.equals(command.data,"HQ")){
if (rtspGrabber!=null) rtspGrabber.ChangeVideoQuality(true);
return new WebsocketReply("SET VIDEO QUALITY", "High Quality");
} else if (Objects.equals(command.data,"LQ")){
if (rtspGrabber!=null) rtspGrabber.ChangeVideoQuality(false);
return new WebsocketReply("SET VIDEO QUALITY", "Low Quality");
} else return new WebsocketReply("SET VIDEO QUALITY", "Invalid Video Quality");
case "STREAMING STATUS":
if (rtspGrabber!=null){
return new WebsocketReply("STREAMING STATUS", rtspGrabber.GetStreamingStatus());
} else return new WebsocketReply("STREAMING STATUS", "RTSP Grabber not initialized");
default:
return new WebsocketReply("UNKNOWN COMMAND", command.command);
}
}
};
private static void init_webserver() {
Properties config = SomeCodes.LoadProperties("config.properties");
String webusername = config.getProperty("WebUsername", "admin");
String webpassword = config.getProperty("WebPassword", "bandara");
String webhost = config.getProperty("WebHost","0.0.0.0");
String webport = config.getProperty("WebPort","8080");
webServer = new WebServer(we, webusername, webpassword);
webServer.Start(webhost, Integer.parseInt(webport));
}
}