diff --git a/src/Main.java b/src/Main.java index 0e913d7..faf7914 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,54 +1,93 @@ +import SBC.GpioInput; +import SBC.GpioOutput; +import SBC.NanopiDuo2; +import SIP.SIP_Request; +import SIP.SIP_Response; +import SIP.jSIPClient; +import SIP.javaSipEvents; import Webpage.WebServer; import code.common; import org.pmw.tinylog.Logger; import java.io.File; import java.text.MessageFormat; +import java.util.Properties; +import java.util.Timer; +import java.util.TimerTask; + import static code.common.currentDir; public class Main { private static jSIPClient client; private static WebServer webserver; + private static GpioInput callButton; + private static GpioInput hangupButton; + private static GpioOutput pilotLight; + private static GpioOutput networkLight; + private static GpioOutput callLight; + private static Timer timer; + private static TimerTask callLightTask; + public static void main(String[] args) { common.ExtractProperties(currentDir,"config.properties", false); + Properties config = common.LoadProperties(currentDir,"config.properties"); + + // Timer Section + timer = new Timer(); + callLightTask = new TimerTask() { + @Override + public void run() { + if (callLight!=null && callLight.isInitialized()) callLight.BlinkON(100); + } + }; // SIP Section - client = new jSIPClient(); + client = new jSIPClient(config); client.SetJavaSipEvent(new javaSipEvents() { @Override - public void Registering(jSIPClient.SIP_Request req) { + public void Registering(SIP_Request req) { Logger.info("Registering to SIP Server, Request: {}",req); + + // selama registering, blink dengan interval 500ms + callLightTask.cancel(); + timer.purge(); + timer.scheduleAtFixedRate(callLightTask, 0, 500); } @Override - public void RegisterSuccesful(jSIPClient.SIP_Response resp) { + public void RegisterSuccesful(SIP_Response resp) { Logger.info("Registered to SIP Server, Response: {}",resp); + + // setelah register berhasil, blink dengan interval 3000ms + callLightTask.cancel(); + timer.purge(); + timer.scheduleAtFixedRate(callLightTask, 0, 3000); } @Override - public void RegisterFailed(jSIPClient.SIP_Response resp) { + public void RegisterFailed(SIP_Response resp) { Logger.info("Failed to register to SIP Server, Response: {}",resp); } @Override - public void IncomingCall(jSIPClient.SIP_Request req, jSIPClient.SIP_Response resp) { + public void IncomingCall(SIP_Request req, SIP_Response resp) { Logger.info("Incoming Call, Request: {}, Response: {}",req,resp); client.AcceptIncomingCall(req); } @Override - public void RemoteHangUp(jSIPClient.SIP_Request req) { + public void RemoteHangUp(SIP_Request req) { Logger.info("Remote Hangup, Request: {}",req); client.HangUp(); } @Override - public void Ringing(jSIPClient.SIP_Response resp) { + public void Ringing(SIP_Response resp) { Logger.info("Ringing, Response: {}",resp); } @Override - public void CalleePickup(jSIPClient.SIP_Response resp) { + public void CalleePickup(SIP_Response resp) { Logger.info("Callee Pickup, Response: {}",resp); } }); @@ -56,13 +95,35 @@ public class Main { // Web Server Section - webserver = new WebServer(); + webserver = new WebServer(config); webserver.Start(); + // GPIO Section + callButton = new GpioInput(NanopiDuo2.Pin12.gpionumber); + hangupButton = new GpioInput(NanopiDuo2.Pin14.gpionumber); + pilotLight = new GpioOutput(NanopiDuo2.Pin16.gpionumber, true); + if (pilotLight.isInitialized()){ + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (pilotLight!=null && pilotLight.isInitialized()) pilotLight.BlinkON(100); + } + }, 0, 1000); + } + networkLight = new GpioOutput(NanopiDuo2.Pin18.gpionumber, true); + callLight = new GpioOutput(NanopiDuo2.Pin20.gpionumber, true); + + // Shutdown Hook Runtime.getRuntime().addShutdownHook(new Thread(() -> { Logger.info("Shutting down SIPIntercom"); if (client!=null) client.Disconnect(); if (webserver!=null) webserver.Stop(); + if (callButton!=null && callButton.isInitialized()) callButton.Close(); + if (hangupButton!=null && hangupButton.isInitialized()) hangupButton.Close(); + if (pilotLight!=null && pilotLight.isInitialized()) pilotLight.Close(); + if (networkLight!=null && networkLight.isInitialized()) networkLight.Close(); + if (callLight!=null && callLight.isInitialized()) callLight.Close(); + if (timer!=null) timer.cancel(); })); } diff --git a/src/SBC/GpioInput.java b/src/SBC/GpioInput.java new file mode 100644 index 0000000..4ac0f1f --- /dev/null +++ b/src/SBC/GpioInput.java @@ -0,0 +1,74 @@ +package SBC; + +import lombok.Getter; +import lombok.Setter; +import org.pmw.tinylog.Logger; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Consumer; + +import static code.common.*; + +@SuppressWarnings("unused") +@Getter +public class GpioInput { + private boolean initialized = false; + private int gpionumber = 0; + private String lastvalue = ""; + private Path valuePath; + private Path directionPath; + @Setter private Consumer onChange; + + private void updateValue(String value){ + if (onChange!=null){ + if (ValidString(value)){ + onChange.accept(value); + } + } + } + + /** + * Create GpioInput object + * @param gpionumber GPIO number + */ + public GpioInput(int gpionumber){ + if (gpionumber>0){ + if (HaveGPIO()){ + if (WriteFile(gpioExportPath,gpionumber)){ + valuePath = gpioPath.resolve("gpio"+gpionumber).resolve("value"); + directionPath = gpioPath.resolve("gpio"+gpionumber).resolve("direction"); + if (Files.exists(valuePath) && Files.exists(directionPath)){ + if (WriteFile(directionPath,"in")){ + this.gpionumber = gpionumber; + initialized = true; + new Thread(()->{ + while(initialized){ + try{ + Thread.sleep(10); + } catch (Exception ignored) {} + String value = ReadFile(valuePath); + if (Objects.equals(lastvalue, value)) continue; + lastvalue = value; + updateValue(value); + } + }).start(); + Logger.info("GPIO Input created: {}",gpionumber); + } else Logger.info("Failed to set direction to in: {}",gpionumber); + } else Logger.info("Failed to export GPIO: {}",gpionumber); + } else Logger.info("Failed to write export GPIO: {}",gpionumber); + } else Logger.info("Dont have GPIO path"); + } else Logger.info("Platform is not Linux"); + } + + /** + * Close Gpio Input + */ + public void Close(){ + if (initialized){ + initialized = false; + WriteFile(gpioUnexportPath,gpionumber); + } + } +} diff --git a/src/SBC/GpioOutput.java b/src/SBC/GpioOutput.java new file mode 100644 index 0000000..61ce468 --- /dev/null +++ b/src/SBC/GpioOutput.java @@ -0,0 +1,97 @@ +package SBC; + +import lombok.Getter; +import org.pmw.tinylog.Logger; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static code.common.*; + +@SuppressWarnings({"unused", "UnusedReturnValue"}) +@Getter +public class GpioOutput { + private boolean initialized = false; + private int gpionumber = 0; + private Path valuePath; + private Path directionPath; + private boolean activeHigh = true; + /** + * Create GpioInput object + * Active High : ON = 1, OFF = 0 + * Active Low : ON = 0, OFF = 1 + * @param gpionumber GPIO number + * @param activeHigh true if active high, false if active low + */ + public GpioOutput(int gpionumber,boolean activeHigh){ + if (gpionumber>0){ + if (HaveGPIO()){ + if (WriteFile(gpioExportPath,gpionumber)){ + valuePath = gpioPath.resolve("gpio"+gpionumber).resolve("value"); + directionPath = gpioPath.resolve("gpio"+gpionumber).resolve("direction"); + if (Files.exists(valuePath) && Files.exists(directionPath)){ + if (WriteFile(directionPath,"out")){ + this.activeHigh = activeHigh; + this.gpionumber = gpionumber; + initialized = true; + Logger.info("GPIO Output created: {}",gpionumber); + } else Logger.info("Failed to set direction to in: {}",gpionumber); + } else Logger.info("Failed to export GPIO: {}",gpionumber); + } else Logger.info("Failed to write export GPIO: {}",gpionumber); + } else Logger.info("Dont have GPIO path"); + } else Logger.info("Platform is not Linux"); + } + + /** + * Set GPIO Value + * @param isON true to set GPIO ON, false to set GPIO OFF + * @return true if success + */ + public boolean SetValue(boolean isON){ + if (initialized){ + return WriteFile(valuePath,activeHigh?isON?"1":"0":isON?"0":"1"); + } + return false; + } + + /** + * Set Blink ON for specific delay + * Blink ON = OFF -> ON -> OFF + * @param delay delay in milliseconds + */ + public void BlinkON(int delay){ + SetValue(false); + SetValue(true); + try { + Thread.sleep(delay); + } catch (InterruptedException ignored) { + } + SetValue(false); + } + + /** + * Set Blink OFF for specific delay + * Blink OFF = ON -> OFF -> ON + * @param delay delay in milliseconds + */ + public void BlinkOFF(int delay) { + SetValue(true); + SetValue(false); + try { + Thread.sleep(delay); + } catch (InterruptedException ignored) { + } + SetValue(true); + } + + /** + * Close Gpio Input + */ + public void Close(){ + if (initialized){ + SetValue(false); + initialized = false; + WriteFile(gpioUnexportPath,gpionumber); + } + } +} diff --git a/src/SBC/NanopiDuo2.java b/src/SBC/NanopiDuo2.java new file mode 100644 index 0000000..5ca75a0 --- /dev/null +++ b/src/SBC/NanopiDuo2.java @@ -0,0 +1,24 @@ +package SBC; + +public enum NanopiDuo2 { + Pin09(9,"IRRX",363), + Pin11(11,"PG11",203), + Pin02(2,"RX0",5), + Pin04(4,"TX0",4), + Pin08(8,"SCL",11), + Pin10(10,"SDA",12), + Pin12(12,"SPI_CS",13), + Pin14(14,"SPI_CLK",14), + Pin16(16,"SPI_MISO",16), + Pin18(18,"SPI_MOSI",15), + Pin20(20,"RX1",199), + Pin22(22,"TX1",198); + public final int pin; + public final String name; + public final int gpionumber; + NanopiDuo2(int pin, String name, int gpio) { + this.pin = pin; + this.name = name; + this.gpionumber = gpio; + } +} diff --git a/src/SBC/RaspberryPi3B.java b/src/SBC/RaspberryPi3B.java new file mode 100644 index 0000000..cc11f48 --- /dev/null +++ b/src/SBC/RaspberryPi3B.java @@ -0,0 +1,42 @@ +package SBC; + +public enum RaspberryPi3B { + Pin03(3,"GPIO2/SDA", 2), + Pin05(5,"GPIO3/SCL", 3), + Pin07(7,"GPIO4/GPCLK0", 4), + Pin08(8,"GPIO14/TXD", 14), + Pin10(10,"GPIO15/RXD", 15), + Pin11(11,"GPIO17", 17), + Pin12(12,"GPIO18/PCMCLK", 18), + Pin13(13,"GPIO27", 27), + Pin15(15,"GPIO22", 22), + Pin16(16,"GPIO23", 23), + Pin18(18,"GPIO24", 24), + Pin19(19,"GPIO10/MOSI", 10), + Pin21(21,"GPIO9/MISO", 9), + Pin22(22,"GPIO25", 25), + Pin23(23,"GPIO11/SCLK", 11), + Pin24(24,"GPIO8/CE0", 8), + Pin26(26,"GPIO7/CE1", 7), + Pin27(27,"GPIO0/IDSD", 0), + Pin28(28,"GPIO1/IDSC", 1), + Pin29(29,"GPIO5", 5), + Pin31(31,"GPIO6", 6), + Pin32(32,"GPIO12/PWM0", 12), + Pin33(33,"GPIO13/PWM1", 13), + Pin35(35,"GPIO19/PCMFS", 19), + Pin36(36,"GPIO16", 16), + Pin37(37,"GPIO26", 26), + Pin38(38,"GPIO20/PCMDIN", 20), + Pin40(40,"GPIO21/PCMDOUT", 21); + + public final int pin; + public final String name; + public final int gpionumber; + + RaspberryPi3B(int pin, String name, int gpionumber){ + this.pin = pin; + this.name = name; + this.gpionumber = gpionumber; + } +} diff --git a/src/SBC/RaspberryPi5B.java b/src/SBC/RaspberryPi5B.java new file mode 100644 index 0000000..82f381e --- /dev/null +++ b/src/SBC/RaspberryPi5B.java @@ -0,0 +1,42 @@ +package SBC; + +public enum RaspberryPi5B { + Pin03(3,"GPIO2/SDA", 573), + Pin05(5,"GPIO3/SCL", 574), + Pin07(7,"GPIO4/GPCLK0", 575), + Pin08(8,"GPIO14/TXD", 585), + Pin10(10,"GPIO15/RXD", 586), + Pin11(11,"GPIO17", 588), + Pin12(12,"GPIO18/PCMCLK", 589), + Pin13(13,"GPIO27", 598), + Pin15(15,"GPIO22", 593), + Pin16(16,"GPIO23", 594), + Pin18(18,"GPIO24", 595), + Pin19(19,"GPIO10/MOSI", 581), + Pin21(21,"GPIO9/MISO", 580), + Pin22(22,"GPIO25", 596), + Pin23(23,"GPIO11/SCLK", 582), + Pin24(24,"GPIO8/CE0", 579), + Pin26(26,"GPIO7/CE1", 578), + Pin27(27,"GPIO0/IDSD", 587), + Pin28(28,"GPIO1/IDSC", 587), + Pin29(29,"GPIO5", 576), + Pin31(31,"GPIO6", 577), + Pin32(32,"GPIO12/PWM0", 583), + Pin33(33,"GPIO13/PWM1", 584), + Pin35(35,"GPIO19/PCMFS", 590), + Pin36(36,"GPIO16", 587), + Pin37(37,"GPIO26", 597), + Pin38(38,"GPIO20/PCMDIN", 591), + Pin40(40,"GPIO21/PCMDOUT", 592); + + public final int pin; + public final String name; + public final int gpionumber; + + RaspberryPi5B(int pin, String name, int gpionumber){ + this.pin = pin; + this.name = name; + this.gpionumber = gpionumber; + } +} diff --git a/src/SIP/CustomConfig.java b/src/SIP/CustomConfig.java new file mode 100644 index 0000000..3c0af47 --- /dev/null +++ b/src/SIP/CustomConfig.java @@ -0,0 +1,291 @@ +package SIP; + +import code.common; +import org.pmw.tinylog.Logger; +import peers.Config; +import peers.media.MediaMode; +import peers.sip.syntaxencoding.SipURI; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +@SuppressWarnings("unused") +public class CustomConfig implements Config { + private InetAddress localIpAddress; + private InetAddress publicIpAddress; + private String registrar; + private String username; + private String password; + private int sip_port; + private int rtp_port; + private transient MediaMode mm; // tidak disave dan load + private SipURI outbondproxy; + private transient boolean mediadebug; // tidak disave dan load + private transient String mediafile; // tidak disave dan load + + + + /** + * Create CustomConfig + * @param registrar Server IP + * @param username username + * @param password password + */ + public CustomConfig(String registrar, String username, String password) { + this.registrar = registrar; + this.password = password; + this.username = username; + setLocalInetAddress(null); + + } + + /** + * Create CustomConfig + * @param registrar Server IP + * @param username username + * @param password password + * @param localip local ethernet to use to register. if not valid, will use default LocalHost + */ + public CustomConfig(String registrar, String username, String password, String localip) { + this.registrar = registrar; + this.password = password; + this.username = username; + SetLocalInetAddress(localip); + + } + + public CustomConfig() { + this.registrar = "192.168.5.1"; + this.username = "1002"; + this.password = "1234"; + setLocalInetAddress(null); + } + + /** + * Get Local IP Address + */ + @Override + public InetAddress getLocalInetAddress() { + return localIpAddress; + + } + + /** + * Get public IP Address used + */ + @Override + public InetAddress getPublicInetAddress() { + return publicIpAddress; + } + + /** + * Get Username to use for registering with SIP Server + */ + @Override + public String getUserPart() { + return username; + } + + /** + * Get SIP Server (registrar) + */ + @Override + public String getDomain() { + return registrar; + } + + /** + * Get Password + */ + @Override + public String getPassword() { + return password; + } + + /** + * Get Outbond Proxy used + */ + @Override + public SipURI getOutboundProxy() { + return outbondproxy; + } + + /** + * Get SIP Port . default is 5060 + */ + @Override + public int getSipPort() { + return sip_port; + } + + /** + * Get Current MediaMode + */ + @Override + public MediaMode getMediaMode() { + return mm; + } + + /** + * Not used + */ + @Override + public boolean isMediaDebug() { + return mediadebug; + } + + /** + * Get MediaFile used + */ + @Override + public String getMediaFile() { + return mediafile; + } + + /** + * Get RTP Port used + */ + @Override + public int getRtpPort() { + return rtp_port; + } + + /** + * Set Local Network Interface to use with SIP.jSIPClient + * useful when having multiple network interfaces in the machine + */ + @Override + public void setLocalInetAddress(InetAddress inetAddress) { + try { + this.localIpAddress = inetAddress == null ? InetAddress.getLocalHost() : inetAddress; + } catch (UnknownHostException e) { + Logger.error("setLocalInetAddress exception = " + e.getMessage()); + } + + } + + /** + * Set Local Network Interface to use with SIP.jSIPClient + * useful when having multiple network interfaces in the machine + * @param ipaddress IP Address of the network interface to use in the machine + */ + public void SetLocalInetAddress(String ipaddress) { + try { + InetAddress xx = InetAddress.getByName(ipaddress); + setLocalInetAddress(xx); + } catch (UnknownHostException e) { + Logger.error("SetLocalInetAddress exception = "+e.getMessage()); + } + } + + /** + * Set Public InetAddress to use with JSIPClient + * personal note : dont know if really necessary + */ + @Override + public void setPublicInetAddress(InetAddress inetAddress) { + publicIpAddress = inetAddress; + } + + /** + * Set Public IP Address to use with SIP.jSIPClient + * Personal Note : dont know if really necessary + * @param ipaddress IP Address in string + */ + public void SetPublicInetAddress(String ipaddress) { + try { + InetAddress xx = InetAddress.getByName(ipaddress); + setPublicInetAddress(xx); + } catch (UnknownHostException e) { + Logger.error("SetPublicInetAddress exception = "+e.getMessage()); + } + } + + /** + * Set Username to use for registering to SIP Server + */ + @Override + public void setUserPart(String username) { + this.username = username; + + } + + /** + * Set SIP Server (registrar) IP Address / Domain + */ + @Override + public void setDomain(String domain) { + registrar = domain; + + } + + /** + * Set Password to use for registering to SIP Server + */ + @Override + public void setPassword(String password) { + this.password = password; + + } + + /** + * Not used + */ + @Override + public void setOutboundProxy(SipURI outboundProxy) { + outbondproxy = outboundProxy; + + } + + /** + * Not used + */ + @Override + public void setSipPort(int sipPort) { + this.sip_port = common.ValidPortNumber(sipPort) ? sipPort : 5060; + + } + + /** + * Not used + */ + @Override + public void setMediaMode(MediaMode mediaMode) { + mm = mediaMode; + + } + + /** + * Not used + */ + @Override + public void setMediaDebug(boolean mediaDebug) { + mediadebug = mediaDebug; + + } + + /** + * Not used + */ + @Override + public void setMediaFile(String mediaFile) { + mediafile = mediaFile; + + } + + /** + * Not used + */ + @Override + public void setRtpPort(int rtpPort) { + rtp_port = common.ValidPortNumber(rtpPort) ? rtpPort : 49152 ; + + } + + /** + * Not used + */ + @Override + public void save() {} + +} diff --git a/src/SIP/SIP_Request.java b/src/SIP/SIP_Request.java new file mode 100644 index 0000000..c4a3a14 --- /dev/null +++ b/src/SIP/SIP_Request.java @@ -0,0 +1,37 @@ +package SIP; + +import code.common; +import lombok.Getter; +import peers.sip.syntaxencoding.SipHeaders; +import peers.sip.transport.SipRequest; + +import java.text.MessageFormat; + +public class SIP_Request{ + private @Getter + final SipRequest req; + public String To; + public String From; + public String CallID; + public String Contact; + + + public SIP_Request(SipRequest source) { + req = source; + if (req!=null) { + SipHeaders head = source.getSipHeaders(); + this.To = common.GetSIPHeaderValue(head,"To", null); + this.From = common.GetSIPHeaderValue(head, "From", null); + this.CallID = common.GetSIPHeaderValue(head, "Call-ID", null); + this.Contact = common.GetSIPHeaderValue(head, "Contact", null); + } + } + + @Override + public String toString() { + return MessageFormat.format("To:{0}\n" + + "From:{1}\n" + + "Call-ID:{2}\n" + + "Contact:{3}", To, From, CallID, Contact); + } +} diff --git a/src/SIP/SIP_Response.java b/src/SIP/SIP_Response.java new file mode 100644 index 0000000..84b84a3 --- /dev/null +++ b/src/SIP/SIP_Response.java @@ -0,0 +1,48 @@ +package SIP; + +import code.common; +import lombok.Getter; +import peers.sip.syntaxencoding.SipHeaders; +import peers.sip.transport.SipResponse; + +import java.text.MessageFormat; + +public class SIP_Response{ + public SIP_Response(SipResponse source) { + resp = source; + if (resp!=null) { + this.statusCode = source.getStatusCode(); + this.reasonPhrase = source.getReasonPhrase(); + SipHeaders head = source.getSipHeaders(); + this.To = common.GetSIPHeaderValue(head, "To", null); + this.From = common.GetSIPHeaderValue(head, "From", null); + this.CallID = common.GetSIPHeaderValue(head, "Call-ID", null); + this.Contact = common.GetSIPHeaderValue(head, "Contact", null); + this.Server = common.GetSIPHeaderValue(head, "Server", null); + this.Date = common.GetSIPHeaderValue(head, "Date", null); + } + } + private @Getter + final SipResponse resp; + + public int statusCode; + public String reasonPhrase; + public String From; + public String To; + public String CallID; + public String Server; + public String Contact; + public String Date; + + @Override + public String toString() { + return MessageFormat.format("To:{0}\n" + + "From:{1}\n" + + "Call-ID:{2}\n" + + "Contact:{3}\n" + + "Server:{4}\n" + + "Date:{5}\n" + + "StatusCode:{6}\n" + + "ReasonPhrase:{7}", To, From, CallID, Contact, Server, Date, statusCode, reasonPhrase); + } +} diff --git a/src/jSIPClient.java b/src/SIP/jSIPClient.java similarity index 65% rename from src/jSIPClient.java rename to src/SIP/jSIPClient.java index 39ad526..22a515a 100644 --- a/src/jSIPClient.java +++ b/src/SIP/jSIPClient.java @@ -1,10 +1,6 @@ -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.net.InetAddress; +package SIP; + import java.net.SocketException; -import java.net.UnknownHostException; -import java.text.MessageFormat; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -14,18 +10,14 @@ import Audio.BassFileReaderListener; import Audio.BassSoundManager; import Audio.BassSoundManagerListener; import code.common; -import com.google.gson.JsonIOException; import lombok.Getter; import org.pmw.tinylog.Logger; -import peers.Config; import peers.media.MediaManager; import peers.media.MediaMode; import peers.sip.Utils; import peers.sip.core.useragent.SipListener; import peers.sip.core.useragent.UserAgent; -import peers.sip.syntaxencoding.SipHeaders; -import peers.sip.syntaxencoding.SipURI; import peers.sip.syntaxencoding.SipUriSyntaxException; import peers.sip.transactionuser.Dialog; import peers.sip.transactionuser.DialogManager; @@ -37,12 +29,10 @@ import static code.common.*; @SuppressWarnings({"unused", "UnusedReturnValue"}) public class jSIPClient { - public jSIPClient() { - runningfolder = new File("").getAbsolutePath(); - load_config(); + public jSIPClient(Properties config) { + load_config(config); Runtime.getRuntime().addShutdownHook(new Thread(() -> { - raise_log_event("jSIPClient ShutdownHook called"); - save_config(); + raise_log_event("SIP.jSIPClient ShutdownHook called"); HangUp(); Disconnect(); })); @@ -55,8 +45,7 @@ public class jSIPClient { public CustomConfig cc = new CustomConfig(); private EventManager em; - private final String runningfolder; - + private javaSipEvents jse; @@ -253,7 +242,7 @@ public class jSIPClient { private boolean all_success; //JavaxSoundManager jsm; BassSoundManager jsm; - + public EventManager(final CustomConfig xx) { all_success = false; //Logger lg = new FileLogger(null); @@ -281,7 +270,7 @@ public class jSIPClient { @Override public void log_error(String msg) { raise_log_event("BassSoundManager error : "+msg); - + } @Override @@ -318,15 +307,15 @@ public class jSIPClient { @Override public void ChannelLevel(boolean is_input, int value) { - if (is_input) + if (is_input) raise_inputchannellevel_event(value); else raise_outputchannellevel_event(value); - + } - + }); - + try { user_agent = new UserAgent(this, xx, jsm); exec.submit(() -> { @@ -337,33 +326,33 @@ public class jSIPClient { raise_log_event("EventManager register exception = "+e.getMessage()); } }); - + } catch (SocketException e) { raise_log_event("EventManager create exception = "+e.getMessage()); } - + } - + public void setInputVolume(int value) { if (jsm!=null) jsm.setInputChannelVolume(value); } - + public int getInputVolume() { if (jsm!=null) { return jsm.getInputChannelVolume(); } else return 0; } - + public void setOutputVolume(int value) { if (jsm!=null) jsm.setOutputChannelVolume(value); } - + public int getOutputVolume() { if (jsm!=null) { return jsm.getOutputChannelVolume(); } else return 0; } - + /** * Check if EventManager succesfully created * @return true if success @@ -371,9 +360,9 @@ public class jSIPClient { public boolean IsCreated() { return all_success; } - + /** - * Call + * Call * @param targetsip Target SIP */ public void Call(final String targetsip) { @@ -386,10 +375,10 @@ public class jSIPClient { raise_log_event("Call exception = "+e.getMessage()); } }); - + } } - + /** * Accept Incoming Call * @param req SipRequest to accept @@ -404,11 +393,11 @@ public class jSIPClient { Dialog dialog = dialogManager.getDialog(callId); user_agent.acceptCall(req, dialog); }); - + } } } - + /** * Add Listener for File Streaming * @param event BassFileReaderListener @@ -427,20 +416,20 @@ public class jSIPClient { } return false; } - - - + + + public void DTMF(final char code) { if (user_agent!=null) { exec.submit(() -> { MediaManager mm = user_agent.getMediaManager(); mm.sendDtmf(code); }); - - + + } } - + /** * Reject Incoming Call * @param req SipRequest to reject @@ -449,11 +438,11 @@ public class jSIPClient { if (user_agent!=null) { if (req!=null) { exec.submit(() -> user_agent.rejectCall(req)); - + } } } - + /** * Check if Calling in Progress * @return true if in progress @@ -461,7 +450,7 @@ public class jSIPClient { public boolean CallingInProgress() { return sip_request!=null; } - + /** * Hang-Up current call */ @@ -472,11 +461,11 @@ public class jSIPClient { user_agent.terminate(sip_request); sip_request = null; }); - + } else raise_log_event("HangUp failed, user_agent not available"); } else raise_log_event("HangUp failed, sip_request not available"); } - + /** * Close Connection to SIP Server */ @@ -485,7 +474,7 @@ public class jSIPClient { user_agent.close(); } } - + @Override public void registering(SipRequest sipRequest) { SIP_Request req = new SIP_Request(sipRequest); @@ -532,357 +521,16 @@ public class jSIPClient { @Override public void error(SipResponse sipResponse) { raise_log_event("sip error, response="+common.gson.toJson(sipResponse)); - + } - + } - public static class SIP_Request{ - private @Getter final SipRequest req; - public String To; - public String From; - public String CallID; - public String Contact; - - public SIP_Request(SipRequest source) { - req = source; - if (req!=null) { - SipHeaders head = source.getSipHeaders(); - this.To = common.GetSIPHeaderValue(head,"To", null); - this.From = common.GetSIPHeaderValue(head, "From", null); - this.CallID = common.GetSIPHeaderValue(head, "Call-ID", null); - this.Contact = common.GetSIPHeaderValue(head, "Contact", null); - } - } - - @Override - public String toString() { - return MessageFormat.format("To:{0}\n" - + "From:{1}\n" - + "Call-ID:{2}\n" - + "Contact:{3}", To, From, CallID, Contact); - } - } - public static class SIP_Response{ - public SIP_Response(SipResponse source) { - resp = source; - if (resp!=null) { - this.statusCode = source.getStatusCode(); - this.reasonPhrase = source.getReasonPhrase(); - SipHeaders head = source.getSipHeaders(); - this.To = common.GetSIPHeaderValue(head, "To", null); - this.From = common.GetSIPHeaderValue(head, "From", null); - this.CallID = common.GetSIPHeaderValue(head, "Call-ID", null); - this.Contact = common.GetSIPHeaderValue(head, "Contact", null); - this.Server = common.GetSIPHeaderValue(head, "Server", null); - this.Date = common.GetSIPHeaderValue(head, "Date", null); - } - } - private @Getter final SipResponse resp; - - public int statusCode; - public String reasonPhrase; - public String From; - public String To; - public String CallID; - public String Server; - public String Contact; - public String Date; - - @Override - public String toString() { - return MessageFormat.format("To:{0}\n" - + "From:{1}\n" - + "Call-ID:{2}\n" - + "Contact:{3}\n" - + "Server:{4}\n" - + "Date:{5}\n" - + "StatusCode:{6}\n" - + "ReasonPhrase:{7}", To, From, CallID, Contact, Server, Date, statusCode, reasonPhrase); - } - } + - public class CustomConfig implements Config{ - private InetAddress localIpAddress; - private InetAddress publicIpAddress; - private String registrar; - private String username; - private String password; - private int sip_port; - private int rtp_port; - private transient MediaMode mm; // tidak disave dan load - private SipURI outbondproxy; - private transient boolean mediadebug; // tidak disave dan load - private transient String mediafile; // tidak disave dan load - - - - /** - * Create CustomConfig - * @param registrar Server IP - * @param username username - * @param password password - */ - public CustomConfig(String registrar, String username, String password) { - this.registrar = registrar; - this.password = password; - this.username = username; - setLocalInetAddress(null); - - } - - /** - * Create CustomConfig - * @param registrar Server IP - * @param username username - * @param password password - * @param localip local ethernet to use to register. if not valid, will use default LocalHost - */ - public CustomConfig(String registrar, String username, String password, String localip) { - this.registrar = registrar; - this.password = password; - this.username = username; - SetLocalInetAddress(localip); - - } - - public CustomConfig() { - this.registrar = "192.168.5.1"; - this.username = "1002"; - this.password = "1234"; - setLocalInetAddress(null); - } - /** - * Get Local IP Address - */ - @Override - public InetAddress getLocalInetAddress() { - return localIpAddress; - - } - - /** - * Get public IP Address used - */ - @Override - public InetAddress getPublicInetAddress() { - return publicIpAddress; - } - - /** - * Get Username to use for registering with SIP Server - */ - @Override - public String getUserPart() { - return username; - } - - /** - * Get SIP Server (registrar) - */ - @Override - public String getDomain() { - return registrar; - } - - /** - * Get Password - */ - @Override - public String getPassword() { - return password; - } - - /** - * Get Outbond Proxy used - */ - @Override - public SipURI getOutboundProxy() { - return outbondproxy; - } - - /** - * Get SIP Port . default is 5060 - */ - @Override - public int getSipPort() { - return sip_port; - } - - /** - * Get Current MediaMode - */ - @Override - public MediaMode getMediaMode() { - return mm; - } - - /** - * Not used - */ - @Override - public boolean isMediaDebug() { - return mediadebug; - } - - /** - * Get MediaFile used - */ - @Override - public String getMediaFile() { - return mediafile; - } - - /** - * Get RTP Port used - */ - @Override - public int getRtpPort() { - return rtp_port; - } - - /** - * Set Local Network Interface to use with jSIPClient - * useful when having multiple network interfaces in the machine - */ - @Override - public void setLocalInetAddress(InetAddress inetAddress) { - try { - this.localIpAddress = inetAddress == null ? InetAddress.getLocalHost() : inetAddress; - } catch (UnknownHostException e) { - raise_log_event("setLocalInetAddress exception = "+e.getMessage()); - } - - } - - /** - * Set Local Network Interface to use with jSIPClient - * useful when having multiple network interfaces in the machine - * @param ipaddress IP Address of the network interface to use in the machine - */ - public void SetLocalInetAddress(String ipaddress) { - try { - InetAddress xx = InetAddress.getByName(ipaddress); - setLocalInetAddress(xx); - } catch (UnknownHostException e) { - raise_log_event("SetLocalInetAddress exception = "+e.getMessage()); - } - } - - /** - * Set Public InetAddress to use with JSIPClient - * personal note : dont know if really necessary - */ - @Override - public void setPublicInetAddress(InetAddress inetAddress) { - publicIpAddress = inetAddress; - } - - /** - * Set Public IP Address to use with jSIPClient - * Personal Note : dont know if really necessary - * @param ipaddress IP Address in string - */ - public void SetPublicInetAddress(String ipaddress) { - try { - InetAddress xx = InetAddress.getByName(ipaddress); - setPublicInetAddress(xx); - } catch (UnknownHostException e) { - raise_log_event("SetPublicInetAddress exception = "+e.getMessage()); - } - } - - /** - * Set Username to use for registering to SIP Server - */ - @Override - public void setUserPart(String username) { - this.username = username; - - } - - /** - * Set SIP Server (registrar) IP Address / Domain - */ - @Override - public void setDomain(String domain) { - registrar = domain; - - } - - /** - * Set Password to use for registering to SIP Server - */ - @Override - public void setPassword(String password) { - this.password = password; - - } - - /** - * Not used - */ - @Override - public void setOutboundProxy(SipURI outboundProxy) { - outbondproxy = outboundProxy; - - } - - /** - * Not used - */ - @Override - public void setSipPort(int sipPort) { - this.sip_port = common.ValidPortNumber(sipPort) ? sipPort : 5060; - - } - - /** - * Not used - */ - @Override - public void setMediaMode(MediaMode mediaMode) { - mm = mediaMode; - - } - - /** - * Not used - */ - @Override - public void setMediaDebug(boolean mediaDebug) { - mediadebug = mediaDebug; - - } - - /** - * Not used - */ - @Override - public void setMediaFile(String mediaFile) { - mediafile = mediaFile; - - } - - /** - * Not used - */ - @Override - public void setRtpPort(int rtpPort) { - rtp_port = common.ValidPortNumber(rtpPort) ? rtpPort : 49152 ; - - } - - /** - * Not used - */ - @Override - public void save() {} - - } //////////// private functions /////////////// @@ -962,22 +610,9 @@ public class jSIPClient { //if (need_outputchannellevel_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_outputchannellevel", false, new Object[] {value}); } - /** - * Dipanggil saat ShutdownHook - */ - private void save_config() { - if (cc!=null) { - try { - common.gson.toJson(cc, new FileWriter(new File(runningfolder,"Config.json"))); - raise_log_event("Config.json saved"); - } catch (JsonIOException | IOException e) { - raise_log_event("save_config failed, exception = "+e.getMessage()); - } - } - } - private void load_config(){ - Properties prop = LoadProperties(currentDir,"config.properties"); + + private void load_config(Properties prop) { serverAddress = GetProperties_StringValue(prop,"SipServer","100.64.0.3"); Username = GetProperties_StringValue(prop,"SipUsername","user1"); Password = GetProperties_StringValue(prop,"SipPassword","12345678"); diff --git a/src/SIP/javaSipEvents.java b/src/SIP/javaSipEvents.java new file mode 100644 index 0000000..00231eb --- /dev/null +++ b/src/SIP/javaSipEvents.java @@ -0,0 +1,11 @@ +package SIP; + +public interface javaSipEvents { + void Registering(SIP_Request req); + void RegisterSuccesful(SIP_Response resp); + void RegisterFailed(SIP_Response resp); + void IncomingCall(SIP_Request req, SIP_Response resp); + void RemoteHangUp(SIP_Request req); + void Ringing(SIP_Response resp); + void CalleePickup(SIP_Response resp); +} diff --git a/src/Webpage/WebServer.java b/src/Webpage/WebServer.java index b9606c5..12ed838 100644 --- a/src/Webpage/WebServer.java +++ b/src/Webpage/WebServer.java @@ -1,6 +1,5 @@ package Webpage; -import code.common; import io.javalin.Javalin; import io.javalin.http.staticfiles.Location; @@ -14,8 +13,7 @@ public class WebServer { private final int listenport; private final String webusername; private final String webpassword; - public WebServer() { - Properties prop = common.LoadProperties(currentDir,"config.properties"); + public WebServer(Properties prop) { listenport = GetProperties_IntValue(prop,"WebListenPort", 8080); webusername = GetProperties_StringValue(prop,"WebUsername", "admin"); webpassword = GetProperties_StringValue(prop,"WebPassword", "admin"); diff --git a/src/code/common.java b/src/code/common.java index 44e9ec0..31b7d63 100644 --- a/src/code/common.java +++ b/src/code/common.java @@ -2,6 +2,8 @@ package code; import com.google.gson.Gson; import com.sun.jna.Native; +import com.sun.jna.Platform; +import org.jetbrains.annotations.NotNull; import org.pmw.tinylog.Logger; import peers.sip.syntaxencoding.SipHeaderFieldName; import peers.sip.syntaxencoding.SipHeaderFieldValue; @@ -10,11 +12,17 @@ import peers.sip.syntaxencoding.SipHeaders; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Properties; public class common { public static String currentDir = System.getProperty("user.dir"); public static Gson gson = new Gson(); + public static final Path gpioPath = Paths.get("/sys/class/gpio") ; + public static final Path gpioExportPath = Paths.get("/sys/class/gpio/export"); + public static final Path gpioUnexportPath = Paths.get("/sys/class/gpio/unexport"); public static String GetProperties_StringValue(Properties prop, String key, String defaultavalue){ if (prop!=null){ @@ -140,4 +148,60 @@ public class common { } return defaultvalue; } + + /** + * Check if GPIO is available + * @return true if GPIO is available + */ + public static boolean HaveGPIO(){ + if (Platform.isLinux()){ + if (Files.exists(gpioPath)){ + if (Files.exists(gpioExportPath)) { + return Files.exists(gpioUnexportPath); + } + } + } + return false; + } + + /** + * Write value to file + * @param path file path + * @param value value to write + * @return true if write success + */ + public static boolean WriteFile(Path path, String value){ + try { + Files.write(path, value.getBytes()); + return true; + } catch (Exception e) { + Logger.error("Failed to write file: {}",path); + return false; + } + } + + /** + * Write integer value to file + * @param path file path + * @param value integer value to write + * @return true if write success + */ + public static boolean WriteFile(Path path, int value){ + return WriteFile(path, String.valueOf(value)); + } + + /** + * Read file content + * @param path file path + * @return file content, or empty string if failed to read + */ + public static @NotNull String ReadFile(Path path){ + try { + byte[] data = Files.readAllBytes(path); + return new String(data); + } catch (Exception e) { + Logger.error("Failed to read file: {}",path); + } + return ""; + } } diff --git a/src/javaSipEvents.java b/src/javaSipEvents.java deleted file mode 100644 index c54dcbc..0000000 --- a/src/javaSipEvents.java +++ /dev/null @@ -1,10 +0,0 @@ - -public interface javaSipEvents { - void Registering(jSIPClient.SIP_Request req); - void RegisterSuccesful(jSIPClient.SIP_Response resp); - void RegisterFailed(jSIPClient.SIP_Response resp); - void IncomingCall(jSIPClient.SIP_Request req, jSIPClient.SIP_Response resp); - void RemoteHangUp(jSIPClient.SIP_Request req); - void Ringing(jSIPClient.SIP_Response resp); - void CalleePickup(jSIPClient.SIP_Response resp); -}