patches 20/11/2024
This commit is contained in:
@@ -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 Webpage.WebServer;
|
||||||
import code.common;
|
import code.common;
|
||||||
import org.pmw.tinylog.Logger;
|
import org.pmw.tinylog.Logger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import static code.common.currentDir;
|
import static code.common.currentDir;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
private static jSIPClient client;
|
private static jSIPClient client;
|
||||||
private static WebServer webserver;
|
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) {
|
public static void main(String[] args) {
|
||||||
common.ExtractProperties(currentDir,"config.properties", false);
|
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
|
// SIP Section
|
||||||
client = new jSIPClient();
|
client = new jSIPClient(config);
|
||||||
client.SetJavaSipEvent(new javaSipEvents() {
|
client.SetJavaSipEvent(new javaSipEvents() {
|
||||||
@Override
|
@Override
|
||||||
public void Registering(jSIPClient.SIP_Request req) {
|
public void Registering(SIP_Request req) {
|
||||||
Logger.info("Registering to SIP Server, 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
|
@Override
|
||||||
public void RegisterSuccesful(jSIPClient.SIP_Response resp) {
|
public void RegisterSuccesful(SIP_Response resp) {
|
||||||
Logger.info("Registered to SIP Server, 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
|
@Override
|
||||||
public void RegisterFailed(jSIPClient.SIP_Response resp) {
|
public void RegisterFailed(SIP_Response resp) {
|
||||||
Logger.info("Failed to register to SIP Server, Response: {}",resp);
|
Logger.info("Failed to register to SIP Server, Response: {}",resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
Logger.info("Incoming Call, Request: {}, Response: {}",req,resp);
|
||||||
client.AcceptIncomingCall(req);
|
client.AcceptIncomingCall(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void RemoteHangUp(jSIPClient.SIP_Request req) {
|
public void RemoteHangUp(SIP_Request req) {
|
||||||
Logger.info("Remote Hangup, Request: {}",req);
|
Logger.info("Remote Hangup, Request: {}",req);
|
||||||
client.HangUp();
|
client.HangUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void Ringing(jSIPClient.SIP_Response resp) {
|
public void Ringing(SIP_Response resp) {
|
||||||
Logger.info("Ringing, Response: {}",resp);
|
Logger.info("Ringing, Response: {}",resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void CalleePickup(jSIPClient.SIP_Response resp) {
|
public void CalleePickup(SIP_Response resp) {
|
||||||
Logger.info("Callee Pickup, Response: {}",resp);
|
Logger.info("Callee Pickup, Response: {}",resp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -56,13 +95,35 @@ public class Main {
|
|||||||
|
|
||||||
|
|
||||||
// Web Server Section
|
// Web Server Section
|
||||||
webserver = new WebServer();
|
webserver = new WebServer(config);
|
||||||
webserver.Start();
|
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(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
Logger.info("Shutting down SIPIntercom");
|
Logger.info("Shutting down SIPIntercom");
|
||||||
if (client!=null) client.Disconnect();
|
if (client!=null) client.Disconnect();
|
||||||
if (webserver!=null) webserver.Stop();
|
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();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
74
src/SBC/GpioInput.java
Normal file
74
src/SBC/GpioInput.java
Normal file
@@ -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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
97
src/SBC/GpioOutput.java
Normal file
97
src/SBC/GpioOutput.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/SBC/NanopiDuo2.java
Normal file
24
src/SBC/NanopiDuo2.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/SBC/RaspberryPi3B.java
Normal file
42
src/SBC/RaspberryPi3B.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/SBC/RaspberryPi5B.java
Normal file
42
src/SBC/RaspberryPi5B.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
291
src/SIP/CustomConfig.java
Normal file
291
src/SIP/CustomConfig.java
Normal file
@@ -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() {}
|
||||||
|
|
||||||
|
}
|
||||||
37
src/SIP/SIP_Request.java
Normal file
37
src/SIP/SIP_Request.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/SIP/SIP_Response.java
Normal file
48
src/SIP/SIP_Response.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
import java.io.File;
|
package SIP;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -14,18 +10,14 @@ import Audio.BassFileReaderListener;
|
|||||||
import Audio.BassSoundManager;
|
import Audio.BassSoundManager;
|
||||||
import Audio.BassSoundManagerListener;
|
import Audio.BassSoundManagerListener;
|
||||||
import code.common;
|
import code.common;
|
||||||
import com.google.gson.JsonIOException;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.pmw.tinylog.Logger;
|
import org.pmw.tinylog.Logger;
|
||||||
import peers.Config;
|
|
||||||
import peers.media.MediaManager;
|
import peers.media.MediaManager;
|
||||||
import peers.media.MediaMode;
|
import peers.media.MediaMode;
|
||||||
import peers.sip.Utils;
|
import peers.sip.Utils;
|
||||||
import peers.sip.core.useragent.SipListener;
|
import peers.sip.core.useragent.SipListener;
|
||||||
import peers.sip.core.useragent.UserAgent;
|
import peers.sip.core.useragent.UserAgent;
|
||||||
import peers.sip.syntaxencoding.SipHeaders;
|
|
||||||
import peers.sip.syntaxencoding.SipURI;
|
|
||||||
import peers.sip.syntaxencoding.SipUriSyntaxException;
|
import peers.sip.syntaxencoding.SipUriSyntaxException;
|
||||||
import peers.sip.transactionuser.Dialog;
|
import peers.sip.transactionuser.Dialog;
|
||||||
import peers.sip.transactionuser.DialogManager;
|
import peers.sip.transactionuser.DialogManager;
|
||||||
@@ -37,12 +29,10 @@ import static code.common.*;
|
|||||||
@SuppressWarnings({"unused", "UnusedReturnValue"})
|
@SuppressWarnings({"unused", "UnusedReturnValue"})
|
||||||
public class jSIPClient {
|
public class jSIPClient {
|
||||||
|
|
||||||
public jSIPClient() {
|
public jSIPClient(Properties config) {
|
||||||
runningfolder = new File("").getAbsolutePath();
|
load_config(config);
|
||||||
load_config();
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
raise_log_event("jSIPClient ShutdownHook called");
|
raise_log_event("SIP.jSIPClient ShutdownHook called");
|
||||||
save_config();
|
|
||||||
HangUp();
|
HangUp();
|
||||||
Disconnect();
|
Disconnect();
|
||||||
}));
|
}));
|
||||||
@@ -55,8 +45,7 @@ public class jSIPClient {
|
|||||||
|
|
||||||
public CustomConfig cc = new CustomConfig();
|
public CustomConfig cc = new CustomConfig();
|
||||||
private EventManager em;
|
private EventManager em;
|
||||||
private final String runningfolder;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private javaSipEvents jse;
|
private javaSipEvents jse;
|
||||||
@@ -253,7 +242,7 @@ public class jSIPClient {
|
|||||||
private boolean all_success;
|
private boolean all_success;
|
||||||
//JavaxSoundManager jsm;
|
//JavaxSoundManager jsm;
|
||||||
BassSoundManager jsm;
|
BassSoundManager jsm;
|
||||||
|
|
||||||
public EventManager(final CustomConfig xx) {
|
public EventManager(final CustomConfig xx) {
|
||||||
all_success = false;
|
all_success = false;
|
||||||
//Logger lg = new FileLogger(null);
|
//Logger lg = new FileLogger(null);
|
||||||
@@ -281,7 +270,7 @@ public class jSIPClient {
|
|||||||
@Override
|
@Override
|
||||||
public void log_error(String msg) {
|
public void log_error(String msg) {
|
||||||
raise_log_event("BassSoundManager error : "+msg);
|
raise_log_event("BassSoundManager error : "+msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -318,15 +307,15 @@ public class jSIPClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void ChannelLevel(boolean is_input, int value) {
|
public void ChannelLevel(boolean is_input, int value) {
|
||||||
if (is_input)
|
if (is_input)
|
||||||
raise_inputchannellevel_event(value);
|
raise_inputchannellevel_event(value);
|
||||||
else
|
else
|
||||||
raise_outputchannellevel_event(value);
|
raise_outputchannellevel_event(value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
user_agent = new UserAgent(this, xx, jsm);
|
user_agent = new UserAgent(this, xx, jsm);
|
||||||
exec.submit(() -> {
|
exec.submit(() -> {
|
||||||
@@ -337,33 +326,33 @@ public class jSIPClient {
|
|||||||
raise_log_event("EventManager register exception = "+e.getMessage());
|
raise_log_event("EventManager register exception = "+e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
raise_log_event("EventManager create exception = "+e.getMessage());
|
raise_log_event("EventManager create exception = "+e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInputVolume(int value) {
|
public void setInputVolume(int value) {
|
||||||
if (jsm!=null) jsm.setInputChannelVolume(value);
|
if (jsm!=null) jsm.setInputChannelVolume(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInputVolume() {
|
public int getInputVolume() {
|
||||||
if (jsm!=null) {
|
if (jsm!=null) {
|
||||||
return jsm.getInputChannelVolume();
|
return jsm.getInputChannelVolume();
|
||||||
} else return 0;
|
} else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOutputVolume(int value) {
|
public void setOutputVolume(int value) {
|
||||||
if (jsm!=null) jsm.setOutputChannelVolume(value);
|
if (jsm!=null) jsm.setOutputChannelVolume(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOutputVolume() {
|
public int getOutputVolume() {
|
||||||
if (jsm!=null) {
|
if (jsm!=null) {
|
||||||
return jsm.getOutputChannelVolume();
|
return jsm.getOutputChannelVolume();
|
||||||
} else return 0;
|
} else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if EventManager succesfully created
|
* Check if EventManager succesfully created
|
||||||
* @return true if success
|
* @return true if success
|
||||||
@@ -371,9 +360,9 @@ public class jSIPClient {
|
|||||||
public boolean IsCreated() {
|
public boolean IsCreated() {
|
||||||
return all_success;
|
return all_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call
|
* Call
|
||||||
* @param targetsip Target SIP
|
* @param targetsip Target SIP
|
||||||
*/
|
*/
|
||||||
public void Call(final String targetsip) {
|
public void Call(final String targetsip) {
|
||||||
@@ -386,10 +375,10 @@ public class jSIPClient {
|
|||||||
raise_log_event("Call exception = "+e.getMessage());
|
raise_log_event("Call exception = "+e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accept Incoming Call
|
* Accept Incoming Call
|
||||||
* @param req SipRequest to accept
|
* @param req SipRequest to accept
|
||||||
@@ -404,11 +393,11 @@ public class jSIPClient {
|
|||||||
Dialog dialog = dialogManager.getDialog(callId);
|
Dialog dialog = dialogManager.getDialog(callId);
|
||||||
user_agent.acceptCall(req, dialog);
|
user_agent.acceptCall(req, dialog);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Listener for File Streaming
|
* Add Listener for File Streaming
|
||||||
* @param event BassFileReaderListener
|
* @param event BassFileReaderListener
|
||||||
@@ -427,20 +416,20 @@ public class jSIPClient {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void DTMF(final char code) {
|
public void DTMF(final char code) {
|
||||||
if (user_agent!=null) {
|
if (user_agent!=null) {
|
||||||
exec.submit(() -> {
|
exec.submit(() -> {
|
||||||
MediaManager mm = user_agent.getMediaManager();
|
MediaManager mm = user_agent.getMediaManager();
|
||||||
mm.sendDtmf(code);
|
mm.sendDtmf(code);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reject Incoming Call
|
* Reject Incoming Call
|
||||||
* @param req SipRequest to reject
|
* @param req SipRequest to reject
|
||||||
@@ -449,11 +438,11 @@ public class jSIPClient {
|
|||||||
if (user_agent!=null) {
|
if (user_agent!=null) {
|
||||||
if (req!=null) {
|
if (req!=null) {
|
||||||
exec.submit(() -> user_agent.rejectCall(req));
|
exec.submit(() -> user_agent.rejectCall(req));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Calling in Progress
|
* Check if Calling in Progress
|
||||||
* @return true if in progress
|
* @return true if in progress
|
||||||
@@ -461,7 +450,7 @@ public class jSIPClient {
|
|||||||
public boolean CallingInProgress() {
|
public boolean CallingInProgress() {
|
||||||
return sip_request!=null;
|
return sip_request!=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hang-Up current call
|
* Hang-Up current call
|
||||||
*/
|
*/
|
||||||
@@ -472,11 +461,11 @@ public class jSIPClient {
|
|||||||
user_agent.terminate(sip_request);
|
user_agent.terminate(sip_request);
|
||||||
sip_request = null;
|
sip_request = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
} else raise_log_event("HangUp failed, user_agent not available");
|
} else raise_log_event("HangUp failed, user_agent not available");
|
||||||
} else raise_log_event("HangUp failed, sip_request not available");
|
} else raise_log_event("HangUp failed, sip_request not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close Connection to SIP Server
|
* Close Connection to SIP Server
|
||||||
*/
|
*/
|
||||||
@@ -485,7 +474,7 @@ public class jSIPClient {
|
|||||||
user_agent.close();
|
user_agent.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registering(SipRequest sipRequest) {
|
public void registering(SipRequest sipRequest) {
|
||||||
SIP_Request req = new SIP_Request(sipRequest);
|
SIP_Request req = new SIP_Request(sipRequest);
|
||||||
@@ -532,357 +521,16 @@ public class jSIPClient {
|
|||||||
@Override
|
@Override
|
||||||
public void error(SipResponse sipResponse) {
|
public void error(SipResponse sipResponse) {
|
||||||
raise_log_event("sip error, response="+common.gson.toJson(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 ///////////////
|
//////////// private functions ///////////////
|
||||||
@@ -962,22 +610,9 @@ public class jSIPClient {
|
|||||||
//if (need_outputchannellevel_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_outputchannellevel", false, new Object[] {value});
|
//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");
|
serverAddress = GetProperties_StringValue(prop,"SipServer","100.64.0.3");
|
||||||
Username = GetProperties_StringValue(prop,"SipUsername","user1");
|
Username = GetProperties_StringValue(prop,"SipUsername","user1");
|
||||||
Password = GetProperties_StringValue(prop,"SipPassword","12345678");
|
Password = GetProperties_StringValue(prop,"SipPassword","12345678");
|
||||||
11
src/SIP/javaSipEvents.java
Normal file
11
src/SIP/javaSipEvents.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package Webpage;
|
package Webpage;
|
||||||
|
|
||||||
import code.common;
|
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.http.staticfiles.Location;
|
import io.javalin.http.staticfiles.Location;
|
||||||
|
|
||||||
@@ -14,8 +13,7 @@ public class WebServer {
|
|||||||
private final int listenport;
|
private final int listenport;
|
||||||
private final String webusername;
|
private final String webusername;
|
||||||
private final String webpassword;
|
private final String webpassword;
|
||||||
public WebServer() {
|
public WebServer(Properties prop) {
|
||||||
Properties prop = common.LoadProperties(currentDir,"config.properties");
|
|
||||||
listenport = GetProperties_IntValue(prop,"WebListenPort", 8080);
|
listenport = GetProperties_IntValue(prop,"WebListenPort", 8080);
|
||||||
webusername = GetProperties_StringValue(prop,"WebUsername", "admin");
|
webusername = GetProperties_StringValue(prop,"WebUsername", "admin");
|
||||||
webpassword = GetProperties_StringValue(prop,"WebPassword", "admin");
|
webpassword = GetProperties_StringValue(prop,"WebPassword", "admin");
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package code;
|
|||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.Platform;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.pmw.tinylog.Logger;
|
import org.pmw.tinylog.Logger;
|
||||||
import peers.sip.syntaxencoding.SipHeaderFieldName;
|
import peers.sip.syntaxencoding.SipHeaderFieldName;
|
||||||
import peers.sip.syntaxencoding.SipHeaderFieldValue;
|
import peers.sip.syntaxencoding.SipHeaderFieldValue;
|
||||||
@@ -10,11 +12,17 @@ import peers.sip.syntaxencoding.SipHeaders;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
public class common {
|
public class common {
|
||||||
public static String currentDir = System.getProperty("user.dir");
|
public static String currentDir = System.getProperty("user.dir");
|
||||||
public static Gson gson = new Gson();
|
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){
|
public static String GetProperties_StringValue(Properties prop, String key, String defaultavalue){
|
||||||
if (prop!=null){
|
if (prop!=null){
|
||||||
@@ -140,4 +148,60 @@ public class common {
|
|||||||
}
|
}
|
||||||
return defaultvalue;
|
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 "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user