/** * This is a simple test application for JVoIP. * * Copy/include the JVoIP.jar file to your project required libraries list! * Demo download: https://www.mizu-voip.com/Portals/0/Files/JVoIP.zip * (It is also recommended to copy the mediaench libraries near your jar or class files: https://www.mizu-voip.com/Portals/0/Files/mediaench.zip) */ package JVoIPTestPackage; //you might change this after your app package name import webphone.*; //import JVoIP. You will have an error here if you haven't added the JVoIP.jar to your project public class JVoIPTest { webphone wobj = null; /** * Construct and show the application. */ public JVoIPTest() { Go(); } /** * Application entry point. */ public static void main(String[] args) { try { new JVoIPTest(); }catch(Exception e) {System.out.println("Exception at main: "+e.getMessage()+"\r\n"+e.getStackTrace()); } } /** * This is the important function where all the real work is done. * In this example we start the JVoIP (a webphone instance), set parameters and make an outbound call. */ void Go() { try{ //create a JVoIP instance (a webphone class instance) Log("init..."); wobj = new webphone(0); //the 0 parameter means that the SIP stack will not be started automatically. We will start it below with the API_Start() function (otherwise migth start with previous/cached settings) //subscribe to notification events MyNotificationListener listener = new MyNotificationListener(this); wobj.API_SetNotificationListener(listener); //set parameters wobj.API_SetParameter("loglevel", 5); //for development you should set the loglevel to 5. for production you should set the loglevel to 1 wobj.API_SetParameter("logtoconsole", true); //if the loglevel is set to 5 then a log window will appear automatically. it can be disabled with this setting //wobj.API_SetParameter("notificationevents", 4); //we will use notification event objects only, but no need to set because it is set automatically by API_SetNotificationListener //wobj.API_SetParameter("startsipstack", 1); //auto start the sipstack (1/auto is the default) //wobj.API_SetParameter("register", 1); //auto register (set to 0 if you don't need to register or if you wish to call the API_Register explicitely later or set to 2 if must register) //wobj.API_SetParameter("transport", "0"); //the default transport for signaling is -1/auto (UDP with failover to TCP). Set to 0 if your server is listening on UDP only, 1 if you need TCP or to 2 if you need TLS //wobj.API_SetParameter("proxyaddress", "x.x.x.x"); //set this only if you have a (outbound) proxy (which is different from the serveraddress) //wobj.API_SetParameter("realm", "xxxx"); //your sip realm. set to your server logical SIP domain only if that is different from the serveraddress and your server doesn't accept the address as the realm/domain wobj.API_SetParameter("serveraddress", "voip3.mizu-voip.com"); //your sip server domain or IP:port (the port number must be set only if not the standard 5060) wobj.API_SetParameter("username", "jvoiptest"); wobj.API_SetParameter("password", "jvoiptestpwd"); //you might set any other required parameters here for your use-case, for example proxyaddres, transport, others. See the parameter list in the documentation. //start the SIP stack Log("start..."); //wobj.API_StartGUI(); //you might uncomment this line if you wish to use the built-in user interface instead wobj.API_Start(); Thread.sleep(200); //optionally you might wait a bit for the sip stack to fully initialize (to make this more accurate and reduce the wait time, you might remove this sleep in your app and continue instead when you receive the SIPNotification.Start.START_SIP noification) /* //register to sip server (optional) //if the serveraddress/username/password are set, then JVoIP will register automatically at API_Start so this is commented out (you can disable this behavior if you wish by setting the "register" parameter to 0) Log("registering..."); wobj.API_Register(); */ Log("SIP stack initialized. Press enter to make a call"); WaitForEnterKeyPress(); //send a IM text message to evelin //wobj.API_SendChat(-1, "evelin", "", "Hi!"); //make an outbound call Log("calling..."); wobj.API_Call( -1, "testivr3"); //normally your app logic might be continued elsewhere (handling user interactions such as disconnect button click) and you should process the notifications about the call state changes in the SIPNotification.java -> ProcessNotifications() function //the call state (such as ringing/connected/disconnected) can be obtained from the STATUS (SIPNotification.Status) notifications. See the MyNotificationListener below. //once the call is connected, you can send DTMF messages like this //wobj.API_Dtmf(-1, "5"); //once the call is connected, you might transfer the call to +44123456789 like this //wobj.API_Transfer(-1, "+44123456789"); //wait for key press Log("Call initiated. Press enter to stop"); WaitForEnterKeyPress(); //disconnect the call and stop the SIP stack Log("closing..."); wobj.API_Hangup( -1); //disconnect the call Log("stop..."); wobj.API_Stop(); //stop the sip stack (this will also unregister) Log("Finished. Press enter to exit"); WaitForEnterKeyPress(); System.exit(0); //exit the JVM }catch(Exception e) {Log("Exception at Go: "+e.getMessage()+"\r\n"+e.getStackTrace()); } } /** * Just a helper function to simplify logging */ void Log(String msg) { System.out.println(msg); //pass it also to JVoIP so it will be easier to follow the JVoIP logs: if(wobj != null) { try{ wobj.API_Log(msg); } catch(Throwable e){} } } /** * just a helper funtin used to wait for a key press before to continue */ void WaitForEnterKeyPress() { try{ //skip existing (old) input int avail = System.in.available(); if(avail > 0) System.in.read(new byte[avail]); }catch(Exception e) {} try{ //wait for enter press while (true) { int ch = System.in.read(); if(ch == '\n') break; } }catch(Exception e) {} } } /** * You will receive the notification events from JVoIP in this class by overriding the SIPNotificationListener base class member functions. * Don't block or wait in the overwritten functions for too long. * See the "Notifications" chapter in the documentation and/or the following javadoc for the details: * https://www.mizu-voip.com/Portals/0/Files/jvoip_javadoc/index.html */ class MyNotificationListener extends SIPNotificationListener { JVoIPTest app = null; //useful if we wish to refer to our main app class from here public MyNotificationListener(JVoIPTest app_in) { app = app_in; } void Log(String msg) { System.out.println(msg); //pass it also to JVoIP so it will be easier to follow the JVoIP logs: if(app != null && app.wobj != null) { try{ app.wobj.API_Log(msg); } catch(Throwable e){} } } //here are some examples about how to handle the notifications: public void onAll(SIPNotification e) { //we receive all notifications (also) here. we just print them from here Log("\t\t\t"+e.getNotificationTypeText()+" notification received: " + e.toString()); } //handle connection (REGISTER) state public void onRegister( SIPNotification.Register e) { //check if/when we are registered to the SIP server if(!e.getIsMain()) return; //we ignore secondary accounts here switch(e.getStatus()) { case SIPNotification.Register.STATUS_INPROGRESS: Log("\tRegistering..."); break; case SIPNotification.Register.STATUS_SUCCESS: Log("\tRegistered successfully."); break; case SIPNotification.Register.STATUS_FAILED: Log("\tRegister failed because "+e.getReason()); break; case SIPNotification.Register.STATUS_UNREGISTERED: Log("\tUnregistered."); break; } } //an example for STATUS handling public void onStatus( SIPNotification.Status e) { if(e.getLine() == -1) return; //we are ignoring the global state here (but you might check only the global state instead or look for the particular lines separately if you must handle multiple simultaneous calls) //log call state if(e.getStatus() >= SIPNotification.Status.STATUS_CALL_SETUP && e.getStatus() <= SIPNotification.Status.STATUS_CALL_FINISHED) { Log("\tCall state is: "+ e.getStatusText()); } //catch outgoing call connect if(e.getStatus() == SIPNotification.Status.STATUS_CALL_CONNECT && e.getEndpointType() == SIPNotification.Status.DIRECTION_OUT) { Log("\tOutgoing call connected to "+ e.getPeer()); /* //there are many things we can do on call connect. for example: app.wobj.API_Dtmf(e.getLine(),"1"); //send DTMF digit 1 app.wobj.API_PlaySound(e.getLine(), "mysound.wav", 0, false, true, true, -1,"",false); //stream an audio file */ } //catch incoming calls else if(e.getStatus() == SIPNotification.Status.STATUS_CALL_RINGING && e.getEndpointType() == SIPNotification.Status.DIRECTION_IN) { Log("\tIncoming call from "+ e.getPeerDisplayname()); //auto accepting the incoming call (instead of auto accept, you might present an Accept/Reject button for the user which will call API_Accept / API_Reject) app.wobj.API_Accept(e.getLine()); } //catch incoming call connect else if(e.getStatus() == SIPNotification.Status.STATUS_CALL_CONNECT && e.getEndpointType() == SIPNotification.Status.DIRECTION_IN) { Log("\tIncoming call connected"); } } //print important events (EVENT) public void onEvent( SIPNotification.Event e) { Log("\tImportant event: "+e.getText()); } //wait for SIP start started before any other SIP stack function call (such as call attempts) public void onStart( SIPNotification.Start e) { if(e.getWhat() == SIPNotification.Start.START_SIP) { Log("\tSIP stack started"); //you should do any SIP operation only after this notification have been triggered (such as API_Call or API_SendChat) } } //IM handling public void onChat( SIPNotification.Chat e) { Log("\tMessage from "+e.getPeer()+": "+e.getMsg()); //auto answer app.wobj.API_SendChat(e.getPeer(),"Received"); } //change the above function bodies after your app logic requirements and handle other notifications as required for your use-case /* //here is a template to handle all notifications //uncomment and replace the function bodies after your needs (by default it will just log the events, using most of the SIPNotification class member functions) public void onAll( SIPNotification e) { Log("\tANY notification received. type: "+Integer.toString(e.getNotificationType())+"/"+e.getNotificationTypeText()+", as string: "+e.toString()); } public void onLog( SIPNotification.Log e) { Log("\tLOG notification received. type: "+Integer.toString(e.getType())+"/"+e.getTypeText()+", message: "+e.getText()+", as string: "+e.toString()); } public void onEvent( SIPNotification.Event e) { Log("\tEVENT notification received. type: "+Integer.toString(e.getType())+"/"+e.getTypeText()+", message: "+e.getText()+", as string: "+e.toString()); } public void onPopup( SIPNotification.Popup e) { Log("\tPOPUP notification received. message: "+e.getText()+", as string: "+e.toString()); } public void onLine( SIPNotification.Line e) { Log("\tLINE notification received. line: "+Integer.toString(e.getLine())+", as string: "+e.toString()); } public void onStatus( SIPNotification.Status e) { Log("\tSTATUS notification received. line: "+Integer.toString(e.getLine())+", status: "+Integer.toString(e.getStatus())+"/"+e.getStatusText()+", peer: "+e.getPeer()+"/"+e.getPeerDisplayname()+", local: "+e.getLocalname()+", eptype: "+Integer.toString(e.getEndpointType())+"/"+e.getEndpointTypeText()+", callid: "+e.getCallID()+", online: "+Integer.toString(e.getOnline())+"/"+e.getOnlineText()+", registered: "+Integer.toString(e.getRegistered())+"/"+e.getRegisteredText()+", incall: "+Integer.toString(e.getIncall())+"/"+e.getIncallText()+", mute: "+Integer.toString(e.getMute())+"/"+e.getMuteText()+", hold: "+Integer.toString(e.getHold())+"/"+e.getHoldText()+", encryption: "+Integer.toString(e.getEncrypted())+"/"+e.getEncryptedText()+", video: "+Integer.toString(e.getVideo())+"/"+e.getVideodText()+", group: "+e.getGroup()+", rtp_sent: "+Common.LongToStr(e.getRtpsent())+", rtp_rec: "+Common.LongToStr(e.getRtprec())+", rtp_lost: "+Common.LongToStr(e.getRtploss())+"/"+Common.LongToStr(e.getRtplosspercent())+"%, video_hold: "+Integer.toString(e.getVideoHold())+"/"+e.getVideoHoldText()+", video_rtp_sent: "+Common.LongToStr(e.getVideoRtpsent())+", video_rtp_rec: "+Common.LongToStr(e.getVideoRtprec())+", serverstats: "+e.getServerstats()+", as string: "+e.toString()); } public void onRegister( SIPNotification.Register e) { Log("\tREGISTER notification received. line: "+Integer.toString(e.getLine())+", status: "+Integer.toString(e.getStatus())+"/"+e.getText()+"/"+e.getReason()+", ismain: "+Common.BoolToString(e.getIsMain())+", isfcm: "+Integer.toString(e.getFcm())+", user: "+e.getUser()+", as string: "+e.toString()); } public void onPresence( SIPNotification.Presence e) { Log("\tPRESENCE notification received. peer: "+e.getPeer()+"/"+e.getPeerDisplayname()+"/"+e.getEmail()+", status: "+Integer.toString(e.getStatus())+"/"+e.getStatusText()+"/"+e.getDetails()+", as string: "+e.toString()); } public void onBLF( SIPNotification.BLF e) { Log("\tBLF notification received. peer: "+e.getPeer()+"/"+e.getCallid()+" "+Integer.toString(e.getDirecton())+"/"+e.getDirectionText()+", status: "+Integer.toString(e.getStatus())+"/"+e.getStatusText()+", as string: "+e.toString()); } public void onDTMF( SIPNotification.DTMF e) { Log("\tDTMF notification received. line: "+Integer.toString(e.getLine())+", message: "+e.getMsg()+", as string: "+e.toString()); } public void onINFO( SIPNotification.INFO e) { Log("\tINFO notification received. line: "+Integer.toString(e.getLine())+", peer: "+e.getPeer()+", type: "+Integer.toString(e.getType())+"/"+e.getTypeText()+" message: "+e.getText()+", as string: "+e.toString()); } public void onUSSD( SIPNotification.USSD e) { Log("\tUSSD notification received. line: "+Integer.toString(e.getLine())+", status: "+Integer.toString(e.getStatus())+"/"+e.getStatusText()+", message: "+e.getText()+", as string: "+e.toString()); } public void onChat( SIPNotification.Chat e) { Log("\tCHAT notification received. line: "+Integer.toString(e.getLine())+", peer: "+e.getPeer()+", message: "+e.getMsg()+", as string: "+e.toString()); } public void onChatReport( SIPNotification.ChatReport e) { Log("\tCHATREPORT notification received. line: "+Integer.toString(e.getLine())+", peer: "+e.getPeer()+", status: "+Integer.toString(e.getStatus())+"/"+e.getStatusText()+", group: "+e.getGroup()+", md5: "+e.getMD5()+", id: "+Integer.toString(e.getID())+", as string: "+e.toString()); } public void onChatComposing( SIPNotification.ChatComposing e) { Log("\tCHATCOMPOSING notification received. line: "+Integer.toString(e.getLine())+", peer: "+e.getPeer()+", status: "+e.getStatus()+"/"+e.getStatusText()+", as string: "+e.toString()); } public void onCDR( SIPNotification.CDR e) { Log("\tCDR notification received. line: "+Integer.toString(e.getLine())+", peer: "+e.getPeer()+"/"+e.getPeerAddress()+", caller: "+e.getCaller()+", called: "+e.getCalled()+", connect: "+Common.LongToStr(e.getConnectTime())+" msec, duration: "+Common.LongToStr(e.getDuration())+" msec, disc_by: "+Integer.toString(e.getDiscParty())+"/"+e.getDiscPartyText()+", disc_reason: "+e.getDiscReason()+", as string: "+e.toString()); } public void onStart( SIPNotification.Start e) { Log("\tSTART notification received. what: "+Integer.toString(e.getWhat())+"/"+e.getWhatText()+", as string: "+e.toString()); } public void onStop( SIPNotification.Stop e) { Log("\tSTOP notification received. what: "+Integer.toString(e.getWhat())+"/"+e.getWhatText()+", as string: "+e.toString()); } public void onShouldReset( SIPNotification.ShouldReset e) { Log("\tSHOULDRESET notification received. reason: "+e.getReason()+", as string: "+e.toString()); } public void onPlayReady( SIPNotification.PlayReady e) { Log("\tPLAYREADY notification received. line: "+Integer.toString(e.getLine())+", callid: "+e.getCallID()+", as string: "+e.toString()); } public void onSRS( SIPNotification.SRS e) { Log("\tSRS notification received. line: "+Integer.toString(e.getLine())+", siprec session: "+e.getSessionID()+", call-id: "+e.getCallID()+", sipsession1: "+e.getSIPSessionID1()+", user1: "+e.getUserID1()+", aor1: "+e.getAOR1()+", name1: "+e.getName1()+", sipsession2: "+e.getSIPSessionID2()+", user2: "+e.getUserID2()+", aor2: "+e.getAOR2()+", name2: "+e.getName2()+", codec: "+e.getCodec()+", as string: "+e.toString()); } public void onSIP( SIPNotification.SIP e) { Log("\tSIP notification received. dir: "+Integer.toString(e.getDirection())+"/"+e.getDirectionText()+", address: "+e.getAddress()+", message: "+e.getMessage()+", as string: "+e.toString()); } public void onBlock( SIPNotification.Block e) { Log("\tBLOCK notification received. type: "+Integer.toString(e.getType())+"/"+e.getTypeText()+", message: "+e.getMessage()+", as string: "+e.toString()); } public void onVAD( SIPNotification.VAD e) { Log("\tVAD notification received. line: "+Integer.toString(e.getLine())+", "+ (e.getLocalValid() ? "LOCAL: avg: "+Common.LongToString(e.getLocalAvg())+" max: "+Common.LongToString(e.getLocalMax())+" speaking: "+Common.BoolToString(e.getLocalSpeaking()) : "")+ (e.getRemoteValid() ? " REMOTE: avg: "+Common.LongToString(e.getRemoteAvg())+" max: "+Common.LongToString(e.getRemoteMax())+" speaking: "+Common.BoolToString(e.getRemoteSpeaking()) : "") +", as string: "+e.toString()); } public void onRTPE( SIPNotification.RTPE e) { Log("\tRTPE notification received. profile: "+Integer.toString(e.getProfile())+", extension: "+e.getExtension()+", as string: "+e.toString()); } public void onRTPT( SIPNotification.RTPT e) { Log("\tRTPT notification received. type: "+Integer.toString(e.getType())+"/"+e.getTypeText()+", SQU: "+Common.BoolToString(e.getSQU())+", id: "+Common.IntToString(e.getID())+", SCT: "+Common.BoolToString(e.getSCT())+", VF: "+Common.BoolToString(e.getVF())+", extension: "+e.getExtension()+", as string: "+e.toString()); } public void onRTPStat( SIPNotification.RTPStat e) { Log("\tRTPSTAT notification received. quality: "+Integer.toString(e.getQuality())+"/"+e.getQualityText()+", sent: "+Common.LongToString(e.getSent())+", rec: "+Common.LongToString(e.getRec())+", issues: "+Common.LongToString(e.getIssues())+", lost: "+Common.LongToString(e.getLoss())+", as string: "+e.toString()); } public void onCredit( SIPNotification.Credit e) { Log("\tCREDIT notification received. message: "+e.getText()+", as string: "+e.toString()); } public void onRating( SIPNotification.Rating e) { Log("\tRATING notification received. message: "+e.getText()+", as string: "+e.toString()); } public void onServerContacts( SIPNotification.ServerContacts e) { Log("\tSERVERCONTACTS notification received. message: "+e.getText()+", as string: "+e.toString()); } public void onMWI( SIPNotification.MWI e) { Log("\tMWI notification received. has: "+Common.BoolToString(e.getHasMessage())+", vmnumber: "+e.getVMNumber()+", to: "+e.getTo()+", count: "+Integer.toString(e.getCount())+", message: "+e.getMessage()+", as string: "+e.toString()); } public void onNewContact( SIPNotification.NewContact e) { Log("\tNEWUSER notification received. username: "+e.getUsername()+", displayname: "+e.getDisplayname()+", as string: "+e.toString()); } public void onAnswer( SIPNotification.Answer e) { Log("\tANSWER notification received. answer: "+e.getResult()+", request: "+e.getRequest()+", as string: "+e.toString()); } public void onVideo( SIPNotification.Video e) { Log("\tVIDEO notification received. startstop: "+Integer.toString(e.getStartOrStop())+"/"+e.getStartOrStopText()+", type: "+Integer.toString(e.getType())+"/"+e.getTypeText()+", line: "+Integer.toString(e.getLine())+", reason: "+e.getReason()+", ip: "+e.getIp()+", port: "+Integer.toString(e.getPort())+", codec: "+e.getCodec()+", payload: "+Integer.toString(e.getPayload())+", quality: "+Integer.toString(e.getQuality())+", bw: "+Integer.toString(e.getBw())+", max_bw: "+Integer.toString(e.getMaxBw())+", fps: "+Integer.toString(e.getFps())+", max_fps: "+Integer.toString(e.getMaxFps())+", width: "+Integer.toString(e.getWidth())+", height: "+Integer.toString(e.getHeight())+", profilelevelid: "+Integer.toString(e.getProfilelevelid())+", profile: "+e.getProfile()+", pixelfmt: "+e.getPixelfmt()+", level: "+e.getLevel()+", pm: "+e.getPm()+", sprop: "+e.getSprop()+", srtp_alg: "+e.getSrtpAlg()+", srtp_key: "+e.getSrtpKey()+", srtp_remotekey: "+e.getSrtpRemoteKey()+", device: "+e.getDevice()+", fmtp: "+e.getFmtp()+", as string: "+e.toString()); } */ }