From a3e37bd7cd16344ee66fc52840dfd4fa8baa53b7 Mon Sep 17 00:00:00 2001 From: rdkartono Date: Tue, 19 Nov 2024 15:46:52 +0700 Subject: [PATCH] patches 19/11/2024 --- src/Audio/Bass.java | 9 + src/Audio/BassFileReader.java | 38 +- src/Audio/BassSoundManager.java | 265 ++++++ src/Audio/BassSoundManagerListener.java | 18 + src/Main.java | 32 +- src/common.java | 30 + src/jSIPClient.java | 998 ++++++++++++++++++++ src/javaSipEvents.java | 10 + src/peers/sip/core/useragent/UserAgent.java | 118 +-- 9 files changed, 1411 insertions(+), 107 deletions(-) create mode 100644 src/Audio/BassSoundManager.java create mode 100644 src/Audio/BassSoundManagerListener.java create mode 100644 src/common.java create mode 100644 src/jSIPClient.java create mode 100644 src/javaSipEvents.java diff --git a/src/Audio/Bass.java b/src/Audio/Bass.java index 7cae879..f21259e 100644 --- a/src/Audio/Bass.java +++ b/src/Audio/Bass.java @@ -802,6 +802,15 @@ public interface Bass extends Library { // gak bisa int BASS_StreamCreate(int freq, int chans, int flags, int proc, Pointer user); + class Utils { + public static int LOBYTE(int n) { return n&0xff; } + public static int HIBYTE(int n) { return (n>>8)&0xff; } + public static int LOWORD(int n) { return n&0xffff; } + public static int HIWORD(int n) { return (n>>16)&0xffff; } + public static int MAKEWORD(int a, int b) { return (a&0xff)|((b&0xff)<<8); } + public static int MAKELONG(int a, int b) { return (a&0xffff)|(b<<16); } + } + @SuppressWarnings("DataFlowIssue") default String GetBassError(String function, int err) { if (err==0) diff --git a/src/Audio/BassFileReader.java b/src/Audio/BassFileReader.java index 1ef757b..5186755 100644 --- a/src/Audio/BassFileReader.java +++ b/src/Audio/BassFileReader.java @@ -12,7 +12,6 @@ import peers.media.SoundSource; * @author rdkartono * */ -@SuppressWarnings("FieldCanBeLocal") public class BassFileReader implements SoundSource { // Device = 0 --> no sound private final int bassdev = 0; @@ -23,18 +22,18 @@ public class BassFileReader implements SoundSource { // flag ketika open file, BASS_STREAM_DECODE karena akan plug ke mixer private final int openflag = Bass.BASS_STREAM_DECODE; // Mixer frequency untuk convert ke 8khz - private final int mixerfreq = 8000; + private final int mixerfreq = 8000; // Mixer channel untuk convert ke Mono - private final int mixerchannel = 1; + private final int mixerchannel = 1; // Mixer create flag BASS_STREAM_DECODE karena untuk ambil data aja, bukan playback private final int mixerflag = Bass.BASS_STREAM_DECODE; // Mixer_AddChannel flag BAS_STREAM_AUTOFREE , supaya kalau channel habis & selesai, channel free sendiri - //private final int addchannelflag = BassLibrary.Constant.BASS_STREAM_AUTOFREE; + //private final int addchannelflag = Bass.BASS_STREAM_AUTOFREE; private final int addchannelflag = 0; - + // sekali baca data, 256 bytes private final int BUFFER_SIZE = 256; - + private final String filename; private int filehandle = 0; private int mixerhandle = 0; @@ -42,11 +41,10 @@ public class BassFileReader implements SoundSource { private double duration = 0; // indicator if file opened, mixer created, and file plugged to mixer private boolean channeladded = false; - - private final BassFileReaderListener listener; // belum kepake + + private BassFileReaderListener listener; // belum kepake private final Bass BASS = Bass.Instance; private final BassMix BASSMIX = BassMix.Instance; - public BassFileReader(final String filename, BassFileReaderListener listener) { this.filename = filename; this.listener = listener; @@ -56,13 +54,13 @@ public class BassFileReader implements SoundSource { if (initresult) { System.out.println("BassFileReader Bass_Init device = "+bassdev+" success"); } else System.out.println("BassFileReader BASS_Init error = "+BASS.GetBassError("BASS_Init")); - + filehandle = BASS.BASS_StreamCreateFile(false, filename, 0, 0, openflag); if (filehandle!=0){ filesize = BASS.BASS_ChannelGetLength(filehandle, Bass.BASS_POS_BYTE); duration = BASS.BASS_ChannelBytes2Seconds(filehandle, filesize); if (listener!=null) listener.fileopened(filename, filesize, duration); - + mixerhandle = BASSMIX.BASS_Mixer_StreamCreate(mixerfreq, mixerchannel, mixerflag); if (mixerhandle!=0) { if (BASSMIX.BASS_Mixer_StreamAddChannel(mixerhandle, filehandle, addchannelflag)) { @@ -81,7 +79,7 @@ public class BassFileReader implements SoundSource { } else logger_error("BassFileReader BASS_Mixer_GetVersion invalid"); } else logger_error("BassFileReader BASS_GetVersion invalid"); } - + public synchronized void close() { if (mixerhandle!=0) { if (BASS.BASS_StreamFree(mixerhandle)) { @@ -94,12 +92,12 @@ public class BassFileReader implements SoundSource { logger_info(filename+" closed in BassFileReader"); } else logger_error("BassFileReader filehandle BASS_StreamFree error = "+BASS.GetBassError("BASS_StreamFree")); filehandle = 0; - } - + } + if (listener!=null) listener.fileclosed(filename); channeladded = false; } - + @Override public synchronized byte[] readData() { if (channeladded) { @@ -126,15 +124,17 @@ public class BassFileReader implements SoundSource { } return null; } - + + public void AddListener(BassFileReaderListener listener) { + this.listener = listener; + } private void logger_error(String msg) { Logger.error(msg); - } - + private void logger_info(String msg) { Logger.info(msg); } - + } diff --git a/src/Audio/BassSoundManager.java b/src/Audio/BassSoundManager.java new file mode 100644 index 0000000..2de7b04 --- /dev/null +++ b/src/Audio/BassSoundManager.java @@ -0,0 +1,265 @@ +package Audio; + + + +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import peers.media.AbstractSoundManager; + +/** + * Pengganti /AxisAudio/src/net/sourceforge/peers/javaxsound/JavaxSoundManager.java + * karena terbatas codec nya + * @author rdkartono + * + */ +@SuppressWarnings({"unused", "FieldCanBeLocal", "BusyWait", "ConditionalBreakInInfiniteLoop"}) +public class BassSoundManager extends AbstractSoundManager { + private final Bass BASS = Bass.Instance; + private BassSoundManagerListener bsml; + private final int record_device, play_device; + private final int init_freq = 48000; + private final int samplingrate = 8000; + private final int play_initflag = Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_MONO; + private final int streamcreate_flag = 0; + private final int recordstart_flag = 0; + private final int read_size = 320; + + private int streamhandle, recordhandle; + + + public BassSoundManager(int outputdevice , int inputdevice, BassSoundManagerListener listener) { + this.bsml = listener; + this.record_device = inputdevice; + this.play_device = outputdevice; + } + + public void AddListener(BassSoundManagerListener listener) { + this.bsml = listener; + } + + public boolean IsInitialized() { + return (streamhandle!=0) && (recordhandle!=0); + } + + public void setInputChannelVolume(int value) { + if (value<0) value = 0; + if (value>100) value = 100; + + if (!BASS.BASS_RecordSetInput(record_device, Bass.BASS_INPUT_ON, value/100.0f)) { + // gagal + logger_error("BASS_RecordSetInput error = "+BASS.GetBassError("BASS_RecordSetInput")); + } + } + + public int getInputChannelVolume() { + Bass.FloatValue vol = new Bass.FloatValue(); + int code = BASS.BASS_RecordGetInput(record_device, vol); + if (code==-1) { + logger_error("BASS_RecordGetInput error = "+BASS.GetBassError("BASS_RecordGetInput")); + return 0; + } else { + int value = (int)(vol.value * 100); + if (value<0) value = 0; + if (value>100) value = 100; + return value; + } + } + + public void setOutputChannelVolume(int value) { + if (value<0) value = 0; + if (value>100) value = 100; + if (!BASS.BASS_SetVolume(value/100.0f)) { + logger_error("BASS_SetVolume error = "+BASS.GetBassError("BASS_SetVolume")); + } + } + + public int getOutputChannelVolume() { + float fl = BASS.BASS_GetVolume() ; + if (fl==-1) { + logger_error("BASS_GetVolume error = "+BASS.GetBassError("BASS_GetVolume")); + return 0; + } else { + int value = (int)(fl * 100); + if (value<0) value = 0; + if (value>100) value = 100; + return value; + } + + } + + @Override + public byte[] readData() { + if (recordhandle!=0) { + int rs; + Pointer buf = new Memory(read_size); + while(true) { + if (BASS.BASS_ChannelIsActive(recordhandle)!=Bass.BASS_ACTIVE_PLAYING) break; + rs = BASS.BASS_ChannelGetData(recordhandle, buf, read_size); + if (rs<0) { + // ada error + if (bsml!=null) bsml.log_error("readData BASS_ChannelGetData error = "+BASS.GetBassError("BASS_ChannelGetData")); + return null; + } else if (rs>0) { + // ada hasil + byte[] result = buf.getByteArray(0, rs); + if (bsml!=null) bsml.ReadToRTP(rs, result); + return result; + } else { + // nol + try { + Thread.sleep(2); + } catch (InterruptedException e) { + return null; + } + + } + } + + } + return null; + + } + + + + + + @Override + public void init() { + if (streamhandle!=0 || recordhandle!=0) close(); + + if (BASS.BASS_GetVersion()!=0) { + BASS.BASS_Init(play_device, init_freq, play_initflag); + BASS.BASS_RecordInit(record_device); + + recordhandle = BASS.BASS_RecordStart(samplingrate, 1, recordstart_flag,null, null); + if (recordhandle!=0) { + BASS.BASS_ChannelSetSync(recordhandle, Bass.BASS_SYNC_DEV_FAIL, 0, devfail, null); + BASS.BASS_ChannelSetSync(recordhandle, Bass.BASS_SYNC_STALL, 0, bufferinginformation, null); + + if (BASS.BASS_ChannelStart(recordhandle)) { + logger_info("InputChannel Started"); + } else logger_error("BASS_ChannelStart recordhandle error = "+BASS.GetBassError("BASS_ChannelStart")); + } else logger_error("BASS_RecordStart error = "+BASS.GetBassError("BASS_RecordStart")); + + + streamhandle = BASS.BASS_StreamCreate(samplingrate, 1, streamcreate_flag, Bass.STREAMPROC_PUSH, null); + if (streamhandle!=0) { + BASS.BASS_ChannelSetSync(streamhandle, Bass.BASS_SYNC_DEV_FAIL, 0, devfail, null); + BASS.BASS_ChannelSetSync(streamhandle, Bass.BASS_SYNC_STALL, 0, bufferinginformation, null); + + if (BASS.BASS_ChannelStart(streamhandle)) { + logger_info("OutputChannel Started"); + } else logger_error("BASS_ChannelStart streamhandle error = "+BASS.GetBassError("BASS_ChannelStart")); + } else logger_error("BASS_StreamCreate error = "+BASS.GetBassError("BASS_StreamCreate")); + + if (IsInitialized()) { + logger_info("init complete"); + + new Thread(() -> { + int inputvalue; + int outputvalue; + + while(IsInitialized()) { + inputvalue = BASS.BASS_ChannelGetLevel(recordhandle); + outputvalue = BASS.BASS_ChannelGetLevel(streamhandle); + if (inputvalue>=0) { + inputvalue = (int) ((Bass.Utils.LOWORD(inputvalue) * 1.0f)/32768); + if (bsml!=null) bsml.ChannelLevel(true, inputvalue); + } + if (outputvalue>=0) { + outputvalue = (int) ((Bass.Utils.LOWORD(outputvalue) * 1.0f)/32768); + if (bsml!=null) bsml.ChannelLevel(false, outputvalue); + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + logger_info("ChannelLevel thread interrupted"); + } + } + }).start(); + + if (bsml!=null) bsml.Opened(); + return; + } + + logger_info("init failed"); + close(); + + } + + } + + @Override + public void close() { + boolean somethingclosed = false; + if (streamhandle!=0) { + BASS.BASS_StreamFree(streamhandle); + streamhandle = 0; + somethingclosed = true; + } + if (recordhandle!=0) { + BASS.BASS_ChannelStop(recordhandle); + recordhandle = 0; + somethingclosed = true; + } + + if (somethingclosed) { + if (bsml!=null) bsml.Closed(); + } + + } + + @Override + public int writeData(byte[] buffer, int offset, int length) { + if (streamhandle!=0) { + Pointer buf = new Memory(length); + buf.write(0, buffer, 0, length); + int rs = BASS.BASS_StreamPutData(streamhandle, buf, length); + if (rs==-1) { + if (bsml!=null) bsml.log_error("writeData BASS_StreamPutData error = "+BASS.GetBassError("BASS_StreamPutData")); + } else { + + if (bsml!=null) bsml.WriteFromRTP(length, buffer); + return length; + } + + } + return 0; + } + + private void logger_error(String msg) { + if (bsml!=null) bsml.log_error(msg); + + } + + private void logger_info(String msg) { + if (bsml!=null) bsml.log_info(msg); + + } + + Bass.SYNCPROC devfail = new Bass.SYNCPROC() { + + @Override + public void SYNCPROC(int handle, int channel, int data, Pointer user) { + if (channel==streamhandle) { + if (bsml!=null) bsml.DeviceFailure("OutputChannel stops unexpectedly"); + } else if (channel==recordhandle) { + if (bsml!=null) bsml.DeviceFailure("InputChannel stops unexpectedly"); + } + } + }; + + Bass.SYNCPROC bufferinginformation = new Bass.SYNCPROC() { + + @Override + public void SYNCPROC(int handle, int channel, int data, Pointer user) { + if (channel==streamhandle) { + if (bsml!=null) bsml.BufferingInformation("OutputChannel "+ (data==0?"Stalled":"Resumed")); + } else if (channel==recordhandle) { + if (bsml!=null) bsml.BufferingInformation("InputChannel "+ (data==0?"Stalled":"Resumed")); + } + } + + }; +} diff --git a/src/Audio/BassSoundManagerListener.java b/src/Audio/BassSoundManagerListener.java new file mode 100644 index 0000000..2b6e815 --- /dev/null +++ b/src/Audio/BassSoundManagerListener.java @@ -0,0 +1,18 @@ +package Audio; + +/** + * Java Event untuk BassSoundManager + * @author rdkartono + * + */ +public interface BassSoundManagerListener { + public void Opened(); + public void Closed(); + public void WriteFromRTP(int length, byte[] pcmdata); + public void ReadToRTP(int length, byte[] pcmdata); + public void log_info(String msg); + public void log_error(String msg); + public void DeviceFailure(String msg); + public void BufferingInformation(String msg); + public void ChannelLevel(boolean is_input, int value); +} diff --git a/src/Main.java b/src/Main.java index f5620f8..7822332 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,6 +1,32 @@ -public class Main { - public static void main(String[] args) { +import org.pmw.tinylog.Logger; - System.out.println("Hello, World!"); +public class Main { + private static String serverAddress="100.64.0.3"; + private static String Username="user1"; + private static String Password="12345678"; + + public static void main(String[] args) { + GetArguments(args); + Logger.info("Server Address: "+serverAddress); + Logger.info("Username: "+Username); + Logger.info("Password: "+Password); + + + } + + private static void GetArguments(String[] args) { + if (args != null){ + for(String a : args){ + if (a.startsWith("--serverip=")){ + serverAddress=a.substring(11); + } + else if (a.startsWith("--username=")){ + Username=a.substring(11); + } + else if (a.startsWith("--password=")){ + Password=a.substring(11); + } + } + } } } \ No newline at end of file diff --git a/src/common.java b/src/common.java new file mode 100644 index 0000000..6f00c9b --- /dev/null +++ b/src/common.java @@ -0,0 +1,30 @@ +import peers.sip.syntaxencoding.SipHeaderFieldName; +import peers.sip.syntaxencoding.SipHeaderFieldValue; +import peers.sip.syntaxencoding.SipHeaders; + +public class common { + + public static boolean ValidString(String value){ + if (value!=null){ + return !value.isEmpty(); + } + return false; + } + + public static boolean ValidPortNumber(int value){ + return value>0 && value<65536; + } + + public static String GetSIPHeaderValue(SipHeaders head, String headername) { + if (head!=null) { + SipHeaderFieldName _fn = new SipHeaderFieldName(headername); + if (head.contains(_fn)) { + SipHeaderFieldValue _fv = head.get(_fn); + if (_fv!=null) { + return _fv.getValue(); + } + } + } + return null; + } +} diff --git a/src/jSIPClient.java b/src/jSIPClient.java new file mode 100644 index 0000000..b108e84 --- /dev/null +++ b/src/jSIPClient.java @@ -0,0 +1,998 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.text.MessageFormat; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import Audio.BassFileReader; +import Audio.BassFileReaderListener; +import Audio.BassSoundManager; +import Audio.BassSoundManagerListener; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; + +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; +import peers.sip.transport.SipRequest; +import peers.sip.transport.SipResponse; + +@SuppressWarnings({"unused", "UnusedReturnValue"}) +public class jSIPClient { + + public jSIPClient() { + gs = new GsonBuilder() + .setPrettyPrinting() + .create(); + runningfolder = new File("").getAbsolutePath(); + load_config(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + raise_log_event("jSIPClient ShutdownHook called"); + save_config(); + HangUp(); + Disconnect(); + })); + } + + + public CustomConfig cc = new CustomConfig(); + private EventManager em; + private final Gson gs; + private final String runningfolder; + + + + private javaSipEvents jse; + private BassFileReaderListener bfrl; + + private final ExecutorService exec = Executors.newSingleThreadExecutor(); + + + /** + * Connect to SIP Server + * @param serverip SIP Server IP + * @param username Username to register + * @param password Password to register + * @param localip use if need to specify which Network Adapter to use + * @return true if parameter completed + */ + public boolean Connect(String serverip, String username, String password, String localip) { + Disconnect(); + if (cc==null) { + System.out.println("Creating Custom Config"); + cc = new CustomConfig(); + } else System.out.println("Custom Config already created"); + if (common.ValidString(serverip)) cc.setDomain(serverip); + if (common.ValidString(username)) cc.setUserPart(username); + if (common.ValidString(password)) cc.setPassword(password); + if (common.ValidString(localip)) cc.SetLocalInetAddress(localip); + em = new EventManager(cc); + + return false; + } + + public void SetJavaSipEvent(javaSipEvents xx) { + this.jse = xx; + } + + public void SetBassFileReaderListener(BassFileReaderListener xx) { + this.bfrl = xx; + } + + /** + * Set Input Volume + * @param value 0 - 100 + */ + public void setInputVolume(int value) { + if (em!=null) em.setInputVolume(value); + } + + /** + * Get Input Volume + * @return 0 - 100 + */ + public int getInputVolume() { + if (em!=null) { + return em.getInputVolume(); + } else return 0; + } + + /** + * Set Output Volume + * @param value 0 - 100 + */ + public void setOutputVolume(int value) { + if (em!=null) em.setOutputVolume(value); + } + + + /** + * Get Output Volum + * @return 0 - 100 + */ + public int getOutputVolume() { + if (em!=null) { + return em.getOutputVolume(); + } else return 0; + } + + /** + * Disconnect from SIP Server + */ + public void Disconnect() { + if (em!=null) { + em.Close(); + em = null; + } + } + + /** + * HangUp current call + * @return true if success + */ + public boolean HangUp() { + if (em!=null) { + if (em.IsCreated()) { + if (em.CallingInProgress()) { + em.HangUp(); + return true; + } else raise_log_event("HangUp failed, no call made"); + } else raise_log_event("HangUp failed, EventManager not created"); + } else raise_log_event("HangUp failed, Connect first"); + return false; + } + + /** + * Stream an audiofile to somebody + * @param target target to call + * @param filename file to stream + * @return true if can be streamed + */ + public boolean StreamFile(String target, String filename) { + if (em!=null) { + if (em.IsCreated()) { + if (cc!=null) { + cc.setMediaFile(filename); + cc.setMediaMode(MediaMode.file); + em.Call(target); + em.AddListener(bfrl); + return true; + } else raise_log_event("StreamFile failed, Custom Config not created"); + } else raise_log_event("StreamFile failed, EventManager not created"); + } else raise_log_event("StreamFile failed, Connect first"); + return false; + } + + /** + * Call somebody + * @param target target to call + * @return true if can be called + */ + public boolean Call(String target) { + if (em!=null) { + if (em.IsCreated()) { + if (cc!=null) { + cc.setMediaMode(MediaMode.captureAndPlayback); + em.Call(target); + return true; + } else raise_log_event("Call failed, Custom Config not created"); + } else raise_log_event("Call failed, EventManager not created"); + } else raise_log_event("Call failed, Connect first"); + return false; + } + + /** + * Accept Incoming Call + * @param req SIP_Request object + * @return true if call can be accepted + */ + public boolean AcceptIncomingCall(SIP_Request req) { + if (em!=null) { + if (em.IsCreated()) { + if (req!=null) { + cc.setMediaMode(MediaMode.captureAndPlayback); + em.AcceptCall(req.getReq()); + return true; + } else raise_log_event("AcceptIncomingCall failed, SIP_Request is null"); + } else raise_log_event("AcceptIncomingCall failed, EventManager not created"); + } else raise_log_event("AcceptIncomingCall failed, Connect first"); + return false; + } + + /** + * Send DTMF code + * @param code code to send + * @return true if can be send + */ + public boolean SendDTMF(final char code) { + if (em!=null) { + if (em.IsCreated()) { + em.DTMF(code); + return true; + } else raise_log_event("SendDTMF failed, EventManager not created"); + } else raise_log_event("SendDTMF failed, Connect first"); + return false; + } + + /** + * Reject Incoming Call + * @param req SIP_Request to reject + * @return true if can be rejected + */ + public boolean RejectIncomingCall(SIP_Request req) { + if (em!=null) { + if (em.IsCreated()) { + if (req!=null) { + em.RejectCall(req.getReq()); + return true; + } else raise_log_event("RejectIncomingCall failed, SIP_Request is null"); + } else raise_log_event("RejectIncomingCall failed, EventManager not created"); + } else raise_log_event("RejectIncomingCall failed, Connect first"); + return false; + } + + + + /////////// Class Implementation //////////////////// + + public class EventManager implements SipListener{ + private UserAgent user_agent; + private SipRequest sip_request; + private boolean all_success; + //JavaxSoundManager jsm; + BassSoundManager jsm; + + public EventManager(final CustomConfig xx) { + all_success = false; + //Logger lg = new FileLogger(null); + Logger lg = null; +// jsm = new JavaxSoundManager(false, lg, null); + jsm = new BassSoundManager(1,0, new BassSoundManagerListener() { + + @Override + public void Opened() { + raise_log_event("BassSoundManager Opened"); + raise_soundchannelopened_event(); + } + + @Override + public void Closed() { + raise_log_event("BassSoundManager Closed"); + raise_soundchannelclosed_event(); + } + + @Override + public void log_info(String msg) { + raise_log_event("BassSoundManager info : "+msg); + } + + @Override + public void log_error(String msg) { + raise_log_event("BassSoundManager error : "+msg); + + } + + @Override + public void WriteFromRTP(int length, byte[] pcmdata) { + // buat debugging aja, kalau dikeluarin, spamming log + //raise_log_event("BassSoundmanager WriteFromRTP "+length+" bytes"); + raise_outputchannelpcmdata_event(length, pcmdata); + } + + @Override + public void ReadToRTP(int length, byte[] pcmdata) { + // buat debugging aja, kalau dikeluarin, spamming log + //raise_log_event("BassSoundManager ReadToRTP "+length+" bytes"); + raise_inputchannelpcmdata_event(length, pcmdata); + } + + @Override + public void DeviceFailure(String msg) { + raise_log_event("BassSondManager DeviceFailure : "+msg); + if (msg.contains("OutputChannel")) + raise_outputchanneldevicefailure_event(); + else if (msg.contains("InputChannel")) + raise_inputchanneldevicefailure_event(); + } + + @Override + public void BufferingInformation(String msg) { + raise_log_event("BassSoundManager BufferingInformation : "+msg); + if (msg.contains("OutputChannel")) + raise_outputchannelbuffering_event(msg); + else if (msg.contains("InputChannel")) + raise_inputchannelbuffering_event(msg); + } + + @Override + public void ChannelLevel(boolean is_input, int value) { + if (is_input) + raise_inputchannellevel_event(value); + else + raise_outputchannellevel_event(value); + + } + + }); + + try { + user_agent = new UserAgent(this, xx, jsm); + exec.submit(() -> { + try { + user_agent.register(); + all_success = true; + } catch (SipUriSyntaxException e) { + 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 + */ + public boolean IsCreated() { + return all_success; + } + + /** + * Call + * @param targetsip Target SIP + */ + public void Call(final String targetsip) { + if (user_agent!=null) { + exec.submit(() -> { + sip_request = null; + try { + sip_request = user_agent.invite(targetsip, null); + } catch (SipUriSyntaxException e) { + raise_log_event("Call exception = "+e.getMessage()); + } + }); + + } + } + + /** + * Accept Incoming Call + * @param req SipRequest to accept + */ + public void AcceptCall(final SipRequest req) { + if (user_agent!=null) { + if (req!=null) { + exec.submit(() -> { + // source : https://github.com/ymartineau/peers/blob/master/peers-gui/src/main/java/net/sourceforge/peers/gui/EventManager.java + String callId = Utils.getMessageCallId(req); + DialogManager dialogManager = user_agent.getDialogManager(); + Dialog dialog = dialogManager.getDialog(callId); + user_agent.acceptCall(req, dialog); + }); + + } + } + } + + /** + * Add Listener for File Streaming + * @param event BassFileReaderListener + * @return true if can be added + */ + public boolean AddListener(BassFileReaderListener event) { + if (user_agent!=null) { + MediaManager mm = user_agent.getMediaManager(); + if (mm!=null) { + BassFileReader bfr = mm.getFileReader(); + if (bfr!=null) { + bfr.AddListener(event); + return true; + } + } + } + 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 + */ + public void RejectCall(final SipRequest req) { + if (user_agent!=null) { + if (req!=null) { + exec.submit(() -> user_agent.rejectCall(req)); + + } + } + } + + /** + * Check if Calling in Progress + * @return true if in progress + */ + public boolean CallingInProgress() { + return sip_request!=null; + } + + /** + * Hang-Up current call + */ + public void HangUp() { + if (sip_request!=null) { + if (user_agent!=null) { + exec.submit(() -> { + 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 + */ + public void Close() { + if (user_agent!=null) { + user_agent.close(); + } + } + + @Override + public void registering(SipRequest sipRequest) { + SIP_Request req = new SIP_Request(sipRequest); + raise_registering_event(req); + } + + @Override + public void registerSuccessful(SipResponse sipResponse) { + SIP_Response resp = new SIP_Response(sipResponse); + raise_registersuccesfull_event(resp); + } + + @Override + public void registerFailed(SipResponse sipResponse) { + SIP_Response resp = new SIP_Response(sipResponse); + raise_registerfailed_event(resp); + } + + @Override + public void incomingCall(SipRequest sipRequest, SipResponse provResponse) { + SIP_Request req = new SIP_Request(sipRequest); + SIP_Response resp = new SIP_Response(provResponse); + raise_incomingcall_event(req, resp); + } + + @Override + public void remoteHangup(SipRequest sipRequest) { + SIP_Request req = new SIP_Request(sipRequest); + raise_remotehangup_event(req); + } + + @Override + public void ringing(SipResponse sipResponse) { + SIP_Response resp = new SIP_Response(sipResponse); + raise_ringing_event(resp); + } + + @Override + public void calleePickup(SipResponse sipResponse) { + SIP_Response resp = new SIP_Response(sipResponse); + raise_calleepickup_event(resp); + } + + @Override + public void error(SipResponse sipResponse) { + raise_log_event("sip error, response="+gs.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"); + this.From = common.GetSIPHeaderValue(head, "From"); + this.CallID = common.GetSIPHeaderValue(head, "Call-ID"); + this.Contact = common.GetSIPHeaderValue(head, "Contact"); + } + } + + @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"); + this.From = common.GetSIPHeaderValue(head, "From"); + this.CallID = common.GetSIPHeaderValue(head, "Call-ID"); + this.Contact = common.GetSIPHeaderValue(head, "Contact"); + this.Server = common.GetSIPHeaderValue(head, "Server"); + this.Date = common.GetSIPHeaderValue(head, "Date"); + } + } + 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 void raise_log_event(String msg) { + Logger.info(msg); + } + + private void raise_registering_event(SIP_Request req) { + if (jse!=null) jse.Registering(req); + } + + private void raise_registersuccesfull_event(SIP_Response resp) { + if (jse!=null) jse.RegisterSuccesful(resp); + } + + private void raise_registerfailed_event(SIP_Response resp) { + if (jse!=null) jse.RegisterFailed(resp); + } + + private void raise_incomingcall_event(SIP_Request req, SIP_Response resp) { + if (jse!=null) jse.IncomingCall(req, resp); + } + + private void raise_remotehangup_event(SIP_Request req) { + if (jse!=null) jse.RemoteHangUp(req); + } + + private void raise_ringing_event(SIP_Response resp) { + if (jse!=null) jse.Ringing(resp); + } + + private void raise_calleepickup_event(SIP_Response resp) { + if (jse!=null) jse.CalleePickup(resp); + } + + private void raise_inputchanneldevicefailure_event(){ + + //if (need_inputchanneldevicefailure_event) ba.raiseEventFromDifferentThread(Me, null, 0,event+"_inputchanneldevicefailure", false,null ); + } + + private void raise_inputchannelbuffering_event(String msg) { + //if (need_inputchannelbuffering_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_inputchannelbuffering", false, new Object[] {msg}); + } + + private void raise_inputchannelpcmdata_event(int length, byte[] bb) { + //if (need_inputchannelpcmdata_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_inputchannelpcmdata", false, new Object[] {length, bb}); + } + + private void raise_outputchanneldevicefailure_event(){ + //if (need_outputchanneldevicefailure_event) ba.raiseEventFromDifferentThread(Me, null, 0,event+"_outputchanneldevicefailure", false,null ); + } + + private void raise_outputchannelbuffering_event(String msg) { + //if (need_outputchannelbuffering_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_outputchannelbuffering", false, new Object[] {msg}); + } + + private void raise_outputchannelpcmdata_event(int length, byte[] bb) { + //if (need_outputchannelpcmdata_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_outputchannelpcmdata", false, new Object[] {length, bb}); + } + + private void raise_soundchannelclosed_event() { + //if (need_soundchannelclosed_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_soundchannelclosed", false, null); + } + + private void raise_soundchannelopened_event() { + //if (need_soundchannelopened_event) ba.raiseEventFromDifferentThread(Me, null, 0,event+"_soundchannelopened", false, null); + } + + private void raise_inputchannellevel_event(int value) { + //if (need_inputchannellevel_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_inputchannellevel", false, new Object[] {value}); + } + + private void raise_outputchannellevel_event(int 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 { + gs.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()); + } + } + } + + /** + * Dipanggil saat initialization + */ + private void load_config() { + try { + CustomConfig xx = gs.fromJson(new FileReader(new File(runningfolder,"Config.json")), CustomConfig.class); + raise_log_event("Config.json loaded"); + cc = xx; + } catch (JsonSyntaxException | JsonIOException | FileNotFoundException e) { + raise_log_event("load_config failed, exception = "+e.getMessage()); + } + + } +} diff --git a/src/javaSipEvents.java b/src/javaSipEvents.java new file mode 100644 index 0000000..c54dcbc --- /dev/null +++ b/src/javaSipEvents.java @@ -0,0 +1,10 @@ + +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); +} diff --git a/src/peers/sip/core/useragent/UserAgent.java b/src/peers/sip/core/useragent/UserAgent.java index 3fa19c6..8e178d6 100644 --- a/src/peers/sip/core/useragent/UserAgent.java +++ b/src/peers/sip/core/useragent/UserAgent.java @@ -24,6 +24,8 @@ import java.net.SocketException; import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; import org.pmw.tinylog.Logger; import peers.Config; @@ -51,35 +53,47 @@ import peers.sip.transport.SipResponse; import peers.sip.transport.TransportManager; -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "FieldMayBeFinal", "FieldCanBeLocal", "UnusedReturnValue"}) public class UserAgent { public final static String CONFIG_FILE = "conf" + File.separator + "peers.xml"; public final static int RTP_DEFAULT_PORT = 8000; + @Getter private String peersHome; + @Getter private Config config; + @Getter private List peers; //private List dialogs; //TODO factorize echo and captureRtpSender + @Setter + @Getter private Echo echo; + @Getter private UAC uac; + @Getter private UAS uas; private ChallengeManager challengeManager; + @Getter private DialogManager dialogManager; private TransactionManager transactionManager; + @Getter private TransportManager transportManager; private int cseqCounter; + @Getter private SipListener sipListener; private SDPManager sdpManager; + @Getter private AbstractSoundManager soundManager; + @Getter private MediaManager mediaManager; public UserAgent(SipListener sipListener, String peersHome, @@ -94,8 +108,8 @@ public class UserAgent { this(sipListener, config, null, soundManager); } - private UserAgent(SipListener sipListener, Config config, String peersHome, - AbstractSoundManager soundManager) + public UserAgent(SipListener sipListener, Config config, String peersHome, + AbstractSoundManager soundManager) throws SocketException { this.sipListener = sipListener; if (peersHome == null) { @@ -110,18 +124,17 @@ public class UserAgent { this.config = config; cseqCounter = 1; - - StringBuffer buf = new StringBuffer(); - buf.append("starting user agent ["); - buf.append("myAddress: "); - buf.append(config.getLocalInetAddress().getHostAddress()).append(", "); - buf.append("sipPort: "); - buf.append(config.getSipPort()).append(", "); - buf.append("userpart: "); - buf.append(config.getUserPart()).append(", "); - buf.append("domain: "); - buf.append(config.getDomain()).append("]"); - Logger.info(buf.toString()); + + String buf = "starting user agent [" + + "myAddress: " + + config.getLocalInetAddress().getHostAddress() + ", " + + "sipPort: " + + config.getSipPort() + ", " + + "userpart: " + + config.getUserPart() + ", " + + "domain: " + + config.getDomain() + "]"; + Logger.info(buf); //transaction user @@ -204,7 +217,7 @@ public class UserAgent { inviteHandler.setChallengeManager(challengeManager); byeHandler.setChallengeManager(challengeManager); - peers = new ArrayList(); + peers = new ArrayList<>(); //dialogs = new ArrayList(); sdpManager = new SDPManager(this); @@ -252,7 +265,7 @@ public class UserAgent { * Gives the sipMessage if sipMessage is a SipRequest or * the SipRequest corresponding to the SipResponse * if sipMessage is a SipResponse - * @param sipMessage + * @param sipMessage SipMessage * @return null if sipMessage is neither a SipRequest neither a SipResponse */ public SipRequest getSipRequest(SipMessage sipMessage) { @@ -274,33 +287,11 @@ public class UserAgent { return null; } } - -// public List getDialogs() { -// return dialogs; -// } - - public List getPeers() { - return peers; - } - -// public Dialog getDialog(String peer) { -// for (Dialog dialog : dialogs) { -// String remoteUri = dialog.getRemoteUri(); -// if (remoteUri != null) { -// if (remoteUri.contains(peer)) { -// return dialog; -// } -// } -// } -// return null; -// } public String generateCSeq(String method) { - StringBuffer buf = new StringBuffer(); - buf.append(cseqCounter++); - buf.append(' '); - buf.append(method); - return buf.toString(); + return String.valueOf(cseqCounter++) + + ' ' + + method; } public boolean isRegistered() { @@ -308,18 +299,6 @@ public class UserAgent { .isRegistered(); } - public UAS getUas() { - return uas; - } - - public UAC getUac() { - return uac; - } - - public DialogManager getDialogManager() { - return dialogManager; - } - public int getSipPort() { return transportManager.getSipPort(); } @@ -348,35 +327,4 @@ public class UserAgent { return config.getOutboundProxy(); } - public Echo getEcho() { - return echo; - } - - public void setEcho(Echo echo) { - this.echo = echo; - } - - public SipListener getSipListener() { - return sipListener; - } - - public AbstractSoundManager getSoundManager() { - return soundManager; - } - - public MediaManager getMediaManager() { - return mediaManager; - } - - public Config getConfig() { - return config; - } - - public String getPeersHome() { - return peersHome; - } - - public TransportManager getTransportManager() { - return transportManager; - } }