var serveraddress_input = null; // serveraddress input field var sipusername_input = null; // sip account username input field var username_input = null; // sip account username input field var password_input = null; // sip account password input field var destination_input = null; // destination number or SIP URI input field var td_started = false; function InitializeTextInputs() { if (isNull(serveraddress_input)) { serveraddress_input = document.getElementById('serveraddress'); sipusername_input = document.getElementById('sipusername'); username_input = document.getElementById('username'); password_input = document.getElementById('password'); destination_input = document.getElementById('destinationnr'); } } function Start() // function called on "Register" button click to start the webphone { td_started = true; InitializeTextInputs(); SaveSettings(); DisplayStatus('EVENT, Initializing...'); webphone_api.start(); // populate advanced settings form PopulateSettings(); } // Wait until the webphone is loaded, before calling any API functions // if automatic start is required, then webphone_api.start() should be called "onLoaded" event like this: // webphone_api.onAppStateChange(function (state) // { // if (state === 'loaded') // { // webphone_api.start(); // } // }); webphone_api.onAppStateChange(function (state) { if (state === 'loaded') { InitializeTextInputs(); PopulateSettings(); var autostart = webphone_api.getparameter('autostart'); if(1 == 1 || autostart.length < 1) { webphone_api.setparameter('autostart',0); //precent auto-start by default } var serveraddress = webphone_api.getparameter('serveraddress'); if (serveraddress.length < 1) { serveraddress = webphone_api.getparameter('serveraddress_user'); } // only for demo var sipusername = webphone_api.getparameter('sipusername'); var password = webphone_api.getparameter('password'); var destination = webphone_api.getparameter('destination'); if (serveraddress.length > 0) { serveraddress_input.value = serveraddress; } if (sipusername.length > 0) { sipusername_input.value = sipusername; } if (password.length > 0) { password_input.value = password; } if (destination.length > 0) { destination_input.value = destination; } var rcolumn = document.getElementById('right_column'); var btnadv = document.getElementById('btn_advanced_sett'); if (isNull(rcolumn) || isNull(btnadv)) { return; } if (rcolumn.style.display === 'none') { btnadv.innerHTML = 'Show more settings'; }else { btnadv.innerHTML = 'Hide Other Settings'; } } }); /** Initiate call to a number, sip username or SIP URI.*/ function Call() { InitializeTextInputs(); if(!td_started) { Start(); } var destnr = destination_input.value; if (isNull(destnr) || (Trim(destnr)).length < 1) { DisplayStatus('ERROR Invalid destination number'); return; } webphone_api.setparameter('destination', destnr, false); webphone_api.call(Trim(destnr)); } /** Disconnect current call(s).*/ function Hangup() { webphone_api.hangup(); } /** Connect incoming call*/ function Accept() { webphone_api.accept(); } /** Disconnect incoming call.*/ function Reject(reason) { webphone_api.reject(null, reason); } /** This callback function will be called on every call state change. * --PARAMETERS -- * status: can have following values: callSetup, callRinging, callConnected, callDisconnected * direction: 1 (outgoing), 2 (incoming) * peername: is the other party username * peerdisplayname: is the other party display name if any * line: the status refers to this line*/ webphone_api.onCallStateChange(function (status, direction, peername, peerdisplayname, line) { if (status === 'setup') { ringingNumber = peername; // if it's an incoming call, then display popup with Accept/Reject buttons if (direction === 2) { AcceptRejectPopup(ringingNumber); } } else if (status === 'disconnected') { // close AcceptReseject popup on call finished, if it's still open if (!isNull(armodal)) { armodal.close(); armodal = null; } } }); /** display / hide chat form*/ function ShowHideChat() { if ($('#chat_box').is(':visible')) { $('#chat_box').hide(); } else { $('#chat_box').show(); } } /** Send a chat message. (SIP MESSAGE method after RFC 3428)*/ function SendChat() { InitializeTextInputs(); var msgF = document.getElementById('message'); var to = destination_input.value; var msg = msgF.value; if (isNull(to) || (Trim(to)).length < 1) { DisplayStatus('ERROR, Invalid chat destination number'); destination_input.focus(); return; } if (isNull(msg) || (Trim(msg)).length < 1) { DisplayStatus('ERROR, Enter chat message to be sent'); msgF.focus(); return; } msgF.value = ''; // Displays messages in chat form window AddMessageToHistory('Me', msg); webphone_api.sendchat(to, msg); } /** Receive incoming messages*/ webphone_api.onChat(function (from, msg, line) { InitializeTextInputs(); if (isNull(from) || isNull(msg)) { return; } var currdest = destination_input.value; if (isNull(currdest) || (Trim(currdest)).length < 1) { destination_input.value = from; }else { if (Trim(currdest) !== from) { AddMessageToHistory('', '
###############################
'); destination_input.value = from; } } // Displays messages in chat form window AddMessageToHistory(from, msg); }); /** Displays sent/received messages in chat form window*/ function AddMessageToHistory(to, message) { var sentmsgF = document.getElementById('msg_list'); var msgconttent = sentmsgF.innerHTML; if (isNull(msgconttent)) { msgconttent = ''; } var item = ''; if (!isNull(to) && to.length > 0) { item = '' + to + ':

' + message + '

' + GetDateForMessage() + '

'; }else { item = '

' + message + '

'; } msgconttent = msgconttent + item + '
'; sentmsgF.innerHTML = msgconttent; // scroll to bottom var d = $('#msg_list'); d.scrollTop(d.prop("scrollHeight")); } /** helper function; returns the current date and time in string displayable format*/ function GetDateForMessage() { var month = new Array(); month[0] = 'Jan'; month[1] = 'Feb'; month[2] = 'Mar'; month[3] = 'Apr'; month[4] = 'May'; month[5] = 'Jun'; month[6] = 'Jul'; month[7] = 'Aug'; month[8] = 'Sep'; month[9] = 'Oct'; month[10] = 'Nov'; month[11] = 'Dec'; try{ var date = new Date(); var minutes = date.getMinutes(); if (minutes < 10) { minutes = '0' + minutes; } var day = date.getDate(); // getDay returns the day of the week if (day < 10) { day = '0' + day; } var datestr = month[date.getMonth()] + ', ' + day + ' ' + date.getFullYear()+ ' ' + date.getHours() + ':' + minutes; return datestr; } catch(err) { PutToDebugLogException(2, "_message: GetDateForMessage", err); } return ''; } /** receive important events from webphone, which will be displayed for the user and parsed to perform other actions*/ webphone_api.onEvent(function (type, evt) { if (type === 'event') { ProcessNotifications(evt); } else { //webphone_api.common.PutToDebugLog(5, 'EVENT, skip not event: '+type+':'+evt); } }); /** parse received notifications*/ var ringingNumber = ''; function ProcessNotifications(not) { try{ if (isNull(not) || not.length < 1) { return; } not = Trim(not); var type = ''; var line = ''; var notifyword = ''; //STATUS,1,Ringing,8888,9999,2,8888 var pos = not.indexOf(','); if (pos > 0) { type = Trim(not.substring(0, pos)); not = Trim(not.substring(pos + 1)); } // get line pos = not.indexOf(','); if (pos > 0) { line = Trim(not.substring(0, pos)); notifyword = Trim(not.substring(pos + 1)); }else { notifyword = not; } var notifywordcontent = ''; // clear junk of notifyword's end pos = notifyword.indexOf(','); if (pos > 0) { notifywordcontent = Trim(notifyword.substring(pos + 1)); notifyword = Trim(notifyword.substring(0, pos)); } pos = notifyword.indexOf('['); if (pos > 0) { notifyword = Trim(notifyword.substring(0, pos)); } pos = notifywordcontent.indexOf('['); if (pos > 0) { notifywordcontent = Trim(notifywordcontent.substring(0, pos)); } // handle incoming call if (type === 'STATUS') { // you can futher process/use the received status event messages // check the documentation for more details } DisplayStatus(type + ',' + notifyword); } catch(err) { PutToDebugLogException(2, 'live_demo: ProcessNotifications', err); } } /** Custom popup with Accept/Reject buttons displayed on incoming call * This is just an example, you can design/use your own custom popup*/ var armodal = null; function AcceptRejectPopup(from) { try{ if (!isNull(armodal)) { armodal.show(); return; } armodal = webphone_api.picoModal( { content: '', //content: "Ah, the pitter patter of tiny feet in huge combat boots.
", overlayStyles: { backgroundColor: "#565656", opacity: 0.6 }, modalStyles: { padding: "0", margin: "0", //top: "0", border: ".2em solid #d8d8d8", borderRadius: ".4em", //width: '65%', width: 'auto', //height: '100%', background: "#ffffff", fontFamily: "sans-serif" }, //closeHtml: "Close", closeButton: false, overlayClose: false, closeStyles: { background: "#eeeeee", position: "absolute", top: ".2em", right: ".3em", textAlign: "center", fontSize: "1.2em", fontWeight: "bold", border: ".15em solid #bbb", borderRadius: ".8em", paddingLeft: ".25em", paddingRight: ".25em", cursor: "pointer" } //comment: custom classes //overlayClass: "customShadow", //modalClass: "customModal", //closeClass: "customClose" // events }).afterCreate(function (modal) { ; }) .beforeShow(function (modal, event) { ; }) .afterShow(function (modal) { ; }) .beforeClose(function (modal, event) { ; }) .afterClose(function(modal) { modal.destroy(); // must be called, otherwise on next show() the onclick will not work armodal = null; }); armodal.show(); $("#btn_np_positive").on("click", function () { armodal.close(); PutToDebugLog(5,"EVENT, live_demo AcceptRejectPopup Accept onclick"); Accept(); }); $("#btn_np_negative").on("click", function () { armodal.close(); PutToDebugLog(5,"EVENT, live_demo AcceptRejectPopup Reject onclick"); Reject(6); }); } catch(err) { PutToDebugLogException(2, 'live_demo: AcceptRejectPopup', err); } } /** display events/status messages for the user*/ var status_e = null; function DisplayStatus(msg_orig) { try{ var msg = msg_orig; if (isNull(status_e)) { status_e = document.getElementById('status'); } if (isNull(msg) || msg.length < 1) { msg = ' '; } if (msg.toLowerCase().indexOf('subscribe') >= 0) { return; } if (msg.indexOf('ERROR') >= 0) { msg = msg.replace('ERROR', ''); msg = Trim(msg); if (msg.indexOf(',') === 0) { msg = msg.replace(',', ''); msg = Trim(msg); } msg = '' + msg + ''; } else if (msg.indexOf('WARNING') >= 0) { msg = msg.replace('WARNING', ''); msg = Trim(msg); if (msg.indexOf(',') === 0) { msg = msg.replace(',', ''); msg = Trim(msg); } msg = '' + msg + ''; } else if (msg.indexOf('STATUS') >= 0 || msg.indexOf('EVENT') >= 0) { msg = msg.replace('STATUS', ''); msg = msg.replace('EVENT', ''); msg = Trim(msg); if (msg.indexOf(',') === 0) { msg = msg.replace(',', ''); msg = Trim(msg); } } status_e.innerHTML = msg; PutToDebugLog(2, 'NOT: ' + msg_orig); } catch(err) { PutToDebugLogException(2, 'live_demo: DisplayStatus', err); } } // ------------------ helper functions /** this function is used to build the form for the Other settings * if you wish to display/present these setting to the user, you should build your own simple html*/ function PopulateSettings() { try{ PutToDebugLog(2,"EVENT, populate settings"); if ( isNull(webphone_api.global.settmap2) || isNull( webphone_api.global.settmap2['magicnumber'] )) { PutToDebugLog(2, 'live_demo: PopulateSettings, webphone_api.global.settmap is NULL'); return; } // callerid, displayname, proxyaddress, webrtcserveraddress var callerid_description = 'This will not be used for authentication. Specify if not the same with the Username for authentication setting. Some VoIP servers will reject if not the same with the username!'; var displayname_description = 'Specify display name. This is an optional setting and it should be your full name'; var proxyaddress_description = 'Outbound SIP proxy address. Leave it empty if you don’t have a stateless/outbound proxy'; var webrtcserveraddress_description = 'Optional setting to indicate the domain name or IP address of your websocket service used for WebRTC if any.'; var content = '' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + //'*WebRTC Server Address is optional. If not set, then the built in WebRTC gateway will be used.' + '
'; var settings_list = document.getElementById('settings_list'); if (!isNull(settings_list)) { settings_list.innerHTML = content; }else { PutToDebugLog(5,"EVENT, live_demo PopulateSettings list element is NULL"); } } catch(err) { PutToDebugLogException(2, 'live_demo: PopulateSettings', err); } } /** called on "Save settings" button clicked * Save settings from Advanced Settings form*/ function SaveSettings() { var lastoop = 0; try{ lastoop = 1; var serveraddress = serveraddress_input.value; lastoop = 2; var sipusername = sipusername_input.value; var password = password_input.value; var destination = destination_input.value; lastoop = 3; if ((isNull(sipusername) || (Trim(sipusername)).length < 1) && !isNull(username_input)) { lastoop = 4; sipusername = username_input.value; } lastoop = 5; if (isNull(serveraddress) || (Trim(serveraddress)).length < 1) { lastoop = 6; DisplayStatus('ERROR Invalid serveraddress'); serveraddress_input.focus(); return; } lastoop = 7; if (isNull(sipusername) || (Trim(sipusername)).length < 1) { lastoop = 8; DisplayStatus('ERROR Invalid auth username'); sipusername_input.focus(); return; } lastoop = 9; if (isNull(password) || (Trim(password)).length < 1) { lastoop = 10; DisplayStatus('ERROR Invalid password'); password_input.focus(); return; } lastoop = 11; if (!isNull(serveraddress) && serveraddress.length > 0) { lastoop = 12; webphone_api.setparameter('serveraddress', serveraddress, false); } lastoop = 13; webphone_api.setparameter('sipusername', sipusername, false); lastoop = 14; webphone_api.setparameter('password', password, false); lastoop = 15; webphone_api.setparameter('destination', destination, false); lastoop = 16; function SaveSett(id) { lastoop = 17; var input = document.getElementById(id); if (!isNull(input)) { lastoop = 18; var val = input.value; if (isNull(val)) { val = ''; } val = Trim(val); lastoop = 19; webphone_api.setparameter(id, val, false); } } lastoop = 20; SaveSett('username'); lastoop = 21; SaveSett('displayname'); lastoop = 22; SaveSett('proxyaddress'); lastoop = 23; SaveSett('webrtcserveraddress'); lastoop = 24; DisplayStatus('EVENT,Saved'); } catch(err) { PutToDebugLogException(2, 'live_demo: SaveSettings '+lastoop.toString(), err); } } /** Display/hide Advanced Settings form*/ function ShowHideAdvancedSettings() { var rcolumn = document.getElementById('right_column'); var btnadv = document.getElementById('btn_advanced_sett'); if (isNull(rcolumn) || isNull(btnadv)) { return; } btnadv.style.display = 'none'; if (rcolumn.style.display === 'none') { document.getElementById('left_column').style.marginLeft = '0'; document.getElementById('right_column').style.display = 'block'; btnadv.innerHTML = 'Hide Advanced Settings'; }else { document.getElementById('right_column').style.display = 'none'; btnadv.innerHTML = 'Show Advanced Settings'; } } /** Helper function which returns "true" if the passed valiable is not NULL and it's not UNDEFINED*/ function isNull (variable) { try{ if (typeof (variable) === 'undefined' || variable === null) { return true; }else { return false; } } catch(err) { PutToDebugLogException(2, "common: isNull", err); } return true; } function Trim(str) { try{ if (isNull(str) || str.length < 1) { return ''; } str = str.toString(); return str.replace(/^\s+|\s+$/g, ''); } catch(err) { PutToDebugLogException(2, "common: Trim", err); } return str; } /** Helper function which returns current browser name*/ var browserName = null; // browser family var browserName2 = null; // browser name function GetBrowser () { try{ if (isNull(browserName) || isNull(browserName2)) { var browser = navigator.userAgent.toLowerCase(); PutToDebugLog(2, "EVENT, common: GetBrowser name: " + browser); // order is important here. Safari userAgent contains mozilla, // IE 11 userAgent contains mozilla and netscape, // and Chrome userAgent contains both mozilla and safari. if ((browser.indexOf('edge') !== -1)) { browserName = 'Edge'; browserName2 = 'Edge'; } else if ((browser.indexOf('msie') !== -1) && (browser.indexOf('opera') === -1)) { browserName = 'MSIE'; browserName2 = 'MSIE'; } else if (browser.indexOf('trident') !== -1 || browser.indexOf('Trident') !== -1) { browserName = 'MSIE'; browserName2 = 'MSIE'; } else if (browser.indexOf('iphone') !== -1) { // this included both iPhone and iPad if (browser.indexOf('fxios') !== -1 || browser.indexOf('firefox') !== -1) { browserName2 = 'Firefox'; } else if (browser.indexOf('crios') !== -1 || browser.indexOf('chrome') !== -1) { browserName2 = 'Chrome'; }else { browserName2 = 'iPhone'; } browserName = 'Netscape Family'; } else if ((browser.indexOf('firefox') !== -1) && (browser.indexOf('opera') === -1)) { browserName = 'Netscape Family'; browserName2 = 'Firefox'; } else if (browser.indexOf('chrome') !== -1) { browserName = 'Netscape Family'; browserName2 = 'Chrome'; } else if (browser.indexOf('safari') !== -1) { browserName = 'Netscape Family'; browserName2 = 'Safari'; } else if ((browser.indexOf('mozilla') !== -1) && (browser.indexOf('opera') === -1)) { browserName = 'Netscape Family'; browserName2 = 'Other'; } else if (browser.indexOf('opera') !== -1) { browserName = 'Netscape Family'; browserName2 = 'Opera'; }else { browserName = '?'; browserName2 = 'unknown'; } PutToDebugLog(2, "EVENT, common: GetBrowser Detected browser name: " + browserName + "; " + browserName2); } } catch(err) { PutToDebugLogException(2, "common: GetBrowser", err); } return browserName2; } /** helper functions: write logs to browser console*/ function PutToDebugLogException(level, msg, err) { PutToDebugLog(level, 'ERROR,' + msg + ' ' + err); } function PutToDebugLog(level, msg) { if (msg.indexOf("ERROR") > -1) { try { console.error(msg); } catch (e1) { } }else { try { console.log(msg); } catch (e2) { } } }