Build a web phone with JsSIP
Updated:
If you have a web application and need it to make calls through the PBX, WebRTC is the protocol that lets you do this.
JsSIP has a very good online demo. Use an extension account you have been given and test it at https://tryit.jssip.net/ with the WebSocket server wss://sbcwrtchcm.ccall.vn:8080 (northern Vietnam: wss://sbcwrtchn.ccall.vn:8080).
- Technical background
WebRTC (Web Real-Time Communication) is an API that lets web browsers make voice or video calls in real time. It was open-sourced on 1 June 2011 and, with the support of Google, Mozilla and Opera, became a W3C recommended standard. SIP (Session Initiation Protocol) is a protocol developed by the IETF MMUSIC working group. As a standard, SIP is designed to create, modify and terminate interactive user sessions, including video, voice, instant messaging, online games and virtual reality. In November 2000, SIP was officially approved as one of the 3GPP signaling protocols and became a permanent part of the IMS architecture. Like H.323, SIP is one of the most important signaling protocols for VoIP.
In general, you can make calls with a phone (a hardware device) or by installing SIP client software on a computer. Phone hardware is expensive, while SIP client software is often poorly compatible, does not work across platforms, and is easily killed by antivirus software.
WebRTC can be a better solution, as long as the browser can make real-time voice and video calls. Using the web browser itself to make calls is a very good option. WebSocket carries the SIP signaling, while WebRTC carries the real-time voice and video streams.
- Front-end WebRTC deployment diagram
In practice, you do not need to handle WebRTC methods, voice and video processing or media streaming yourself. There are already good free, open-source modules (libraries) available.
That library is JsSIP (jssip.net)
JsSIP has the following features:
- It runs in the browser or in Node.js
- Uses WebSocket to carry the SIP protocol
- Uses WebRTC to carry real-time voice and video
- Very lightweight
- 100% pure JavaScript
- Simple yet powerful API
- Works with many servers: OverSIP, Kamailio, Asterisk, OfficeSIP, reSIProcate, Frafos ABC SBC, TekSIP
- Developed by the authors of RFC 7118 and OverSIP
Here is an example of using JsSIP to make a phone call. It is very simple:
// Create our JsSIP instance and run it:
var socket = new JsSIP.WebSocketInterface('wss://sip.myhost.com');
var configuration = {
sockets : [ socket ],
uri : 'sip:alice@example.com',
password : 'superpassword'
};
var ua = new JsSIP.UA(configuration);
ua.start();
// Register callbacks to desired call events
var eventHandlers = {
'progress': function(e) {
console.log('call is in progress');
},
'failed': function(e) {
console.log('call failed with cause: '+ e.data.cause);
},
'ended': function(e) {
console.log('call ended with cause: '+ e.data.cause);
},
'confirmed': function(e) {
console.log('call confirmed');
}
};
var options = {
'eventHandlers' : eventHandlers,
'mediaConstraints' : { 'audio': true, 'video': true }
};
var session = ua.call('sip:bob@example.com', options);- Browsers that support WebRTC
WebRTC places high demands on the browser. Browsers that support WebRTC: Chrome, Firefox, Microsoft Edge
- References and practice
- JsSIP Getting Started, https://jssip.net/documentation/3.8.x/getting_started/
- SIP status code (error) 422: "Session Interval Too Small". By default JsSIP sets Session-Expires: 90. If this timer is lower than the value set on the server, the server responds with 422. Check the SIP status codes; you can set sessionTimersExpires higher than the server's value.
Sample code#
JsSIP sample code
var infocall = {
wsuri: 'sbcwrtchcm.ccall.vn',
port: '8080',
user_extend: '100',
server: 'epacific.com.vn',
password: '123456'
};
// login extend in server
var loginExtend = function(){
var configuration = {
'ws_servers': 'wss://' + infocall['wsuri'] + ':' + infocall['port']+'/ws',
'uri': infocall['user_extend'] + '@' + infocall['server'],
'password': infocall['pass_extend']
};
ua = new JsSIP.UA(configuration);
ua.start();
}
// call out
var outGoing = function(number){
if(!ua) {
console.log('Cannot login ua');
return false;
}
else{
var options = {
'mediaConstraints': {'audio': true, 'video': false},
'sessionTimersExpires': 120
};
ua.call(number, options);
}
}
//get info call
var getInfoCall = function(){
if(!ua) {
console.log('Cannot login ua');
return false;
}
else {
ua.on('newRTCSession', function(e){
console.log(e);
eventCall(e);
})
}
}
//get event call
var eventCall = function(session){
session['session'].on('progress', function(e){
console.log('call is in progress');
console.log(e)
})
session['session'].on('failed', function(e){
console.log('call failed');
console.log(e)
})
session['session'].on('ended', function(e){
console.log('call end');
console.log(e);
})
session['session'].on('confirmed', function(e){
console.log('call accept');
console.log(e)
})
session['session'].on('addstream', function(e){
audio_callcenter.src = window.URL.createObjectURL(e.stream);
})
}JsSIP embed sample for placing outbound calls
var ua;
var ws_was_connected = false;
var ws_registered = false;
jQuery(document).ready(function() {
var BrowserSignature = webrtcDetectedBrowser +' ('+ webrtcDetectedVersion +')';
var soundPlayer = document.createElement("audio");
soundPlayer.volume = 1;
//var selfView = document.getElementById('selfView');
//var remoteView = document.getElementById('remoteView');
var localStream, remoteStream;
// Flags indicating whether local peer can renegotiate RTC (or PC reset is required).
var localCanRenegotiateRTC = function () {
return JsSIP.rtcninja.canRenegotiate;
};
window.GUI = {
jssipCall : function(target) {
ua.call(target, {
//pcConfig: peerconnection_config,
mediaConstraints: { audio: true, video:false },
extraHeaders: [
//'X-Can-Renegotiate: ' + String(localCanRenegotiateRTC())
'X-Browser: '+ BrowserSignature
],
rtcOfferConstraints: {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
},
rtcConstraints: { mandatory: { googIPv6:false } }
});
}
,
jssipMessage : function(uri, text) {
ua.sendMessage(uri,text);
},
jssipIsComposing : function(uri, active) {
//JsSIP.API.is_composing(uri, active);
//console.info('is compossing..')
}
,
getSession : function(uri) {
var session_found = null;
jQuery("#sessions > .session").each(function(i, session) {
if (uri === jQuery(this).find(".peer > .uri").text()) {
session_found = session;
return false;
}
});
if (session_found)
return session_found;
else
return false;
}
,
createSession : function(display_name, uri) {
var session_div = jQuery('<div class="session"></div>');
var session_inner_div = jQuery('\
<div class="close"></div> \
<div class="container"> \
<div class="peer"> \
<span class="display-name">' + display_name + '</span> \
<span><</span><span class="uri">' + uri + '</span><span>></span> \
</div> \
<div class="call inactive"> \
<div class="button dial"></div> \
<div class="button hangup"></div> \
<div class="button dtmf"></div> \
<!--<div class="button hold"></div> \
<div class="button resume"></div>--> \
<div class="dtmf-box"> \
<div class="dtmf-row"> \
<div class="dtmf-button digit-1">1</div> \
<div class="dtmf-button digit-2">2</div> \
<div class="dtmf-button digit-3">3</div> \
</div> \
<div class="dtmf-row"> \
<div class="dtmf-button digit-4">4</div> \
<div class="dtmf-button digit-5">5</div> \
<div class="dtmf-button digit-6">6</div> \
</div> \
<div class="dtmf-row"> \
<div class="dtmf-button digit-7">7</div> \
<div class="dtmf-button digit-8">8</div> \
<div class="dtmf-button digit-9">9</div> \
</div> \
<div class="dtmf-row"> \
<div class="dtmf-button digit-asterisk">*</div> \
<div class="dtmf-button digit-0">0</div> \
<div class="dtmf-button digit-pound">#</div> \
</div> \
</div> \
<div class="call-status"></div> \
</div> \
<div id="webcam_wrapper"> \
<div id="webcam"> \
<video id="remoteView" autoplay _hidden=true poster="'+ images[1]+'"></video>\
<video id="selfView" autoplay muted="true" _hidden=true poster="'+ images[0]+'"></video>\
</div>\
</div>\
<div class="chat"> \
<!--<div class="chatting inactive"></div> \
<input class="inactive" type="text" name="chat-input" value="type to chat..."/>--> \
<div class="iscomposing"></div> \
</div> \
</div> \
\
');
session_div.css('cursor', 'move').draggable(); //.draggable();
session_div.append(session_inner_div);
jQuery("#sessions").append(session_div);
//jQuery(document).append(session_div);
var session = jQuery("#sessions .session").filter(":last");
var call_status = jQuery(session).find(".call");
var close = jQuery(session).find("> .close");
//var chat_input = jQuery(session).find(".chat > input[type='text']");
selfView = document.getElementById('selfView');
remoteView = document.getElementById('remoteView');
//alert("Self: "+selfView.innerHTML);
//alert("Remote: "+remoteView.innerHTML);
options.eventHandlers.confirmed = function(e){
selfView.src = window.URL.createObjectURL(session.connection.getLocalStreams()[0]);
}
options.eventHandlers.addstream = function(e){
var stream = e.stream;
// alert(stream);
remoteView.src = window.URL.createObjectURL(stream);
}
var div_webcam = jQuery("#sessions").find("#webcam");// jQuery("div#webcam");
//alert(div_webcam.html());
div_webcam.show();
jQuery(session).hover(function() {
if (jQuery(call_status).hasClass("inactive"))
jQuery(close).show();
},
function() {
jQuery(close).hide();
});
close.click(function() {
GUI.removeSession(session, null, true);
});
/*
chat_input.focus(function(e) {
if (jQuery(this).hasClass("inactive")) {
jQuery(this).val("");
jQuery(this).removeClass("inactive");
}
});
chat_input.blur(function(e) {
if (jQuery(this).val() == "") {
jQuery(this).addClass("inactive");
jQuery(this).val("type to chat...");
}
});
chat_input.keydown(function(e) {
// Ignore TAB and ESC.
if (e.which == 9 || e.which == 27) {
return false;
}
// Enter pressed? so send chat.
else if (e.which == 13 && jQuery(this).val() != "") {
var text = chat_input.val();
GUI.addChatMessage(session, "me", text);
chat_input.val("");
GUI.jssipMessage(uri, text);
}
// Ignore Enter when empty input.
else if (e.which == 13 && jQuery(this).val() == "") {
return false;
}
// NOTE is-composing stuff.
// Ignore "windows" and ALT keys, DEL, mayusculas and 0 (que no sé qué es).
else if (e.which == 18 || e.which == 91 || e.which == 46 || e.which == 16 || e.which == 0)
return false;
// If this is the first char in the input and the chatting session
// is active, then send a iscomposing notification.
else if (e.which != 8 && jQuery(this).val() == "") {
GUI.jssipIsComposing(uri, true);
}
// If this is a DELETE key and the input has been totally clean, then send "idle" isomposing.
else if (e.which == 8 && jQuery(this).val().match("^.$"))
GUI.jssipIsComposing(uri, false);
});
*/
jQuery(session).fadeIn(100);
// Return the jQuery object for the created session div.
return session;
}
,
setCallSessionStatus : function(cur_session, status, description, realHack) {
var session = cur_session;
var uri = jQuery(session).find(".peer > .uri").text();
var call = jQuery(session).find(".call");
var status_text = jQuery(session).find(".call-status");
var button_dial = jQuery(session).find(".button.dial");
var button_hangup = jQuery(session).find(".button.hangup");
var button_hold = jQuery(session).find(".button.hold");
var button_resume = jQuery(session).find(".button.resume");
var button_dtmf = jQuery(session).find(".button.dtmf");
var dtmf_box = jQuery(session).find(".dtmf-box");
// If the call is not inactive or terminated, then hide the
// close button (without waiting for blur() in the session div).
if (status != "inactive" && status != "terminated") {
jQuery(session).unbind("hover");
jQuery(session).find("> .close").hide();
}
// Unset all the functions assigned to buttons.
button_dial.unbind("click");
button_hangup.unbind("click");
button_hold.unbind("click");
button_resume.unbind("click");
button_dtmf.unbind("click");
if (session.call && session.call.status !== JsSIP.C.SESSION_TERMINATED) {
button_hangup.click(function() {
GUI.setCallSessionStatus(session, "terminated", "terminated");
session.call.terminate();
GUI.removeSession(session, 500);
});
}
else {
button_dtmf.unbind("click");
}
switch(status) {
case "inactive":
call.removeClass();
call.addClass("call inactive");
status_text.text("");
button_dial.click(function() {
GUI.jssipCall(uri);
});
// Hide DTMF box.
dtmf_box.hide();
break;
case "trying":
call.removeClass();
call.addClass("call trying");
status_text.text(description || "trying...");
// unhide HTML Video Elements
//jQuery('#remoteView').attr('hidden', false);
//jQuery('#selfView').attr('hidden', false);
// Set background image
//jQuery('#remoteView').attr('poster', "images/logo.png");
// Hide DTMF box.
dtmf_box.hide();
break;
case "in-progress":
call.removeClass();
call.addClass("call in-progress");
status_text.text(description || "in progress...");
// ring-back.
soundPlayer.setAttribute("src", base_url + "embed/sounds/outgoing-call2.ogg");
soundPlayer.play();
// Hide DTMF box.
dtmf_box.hide();
break;
case "answered":
call.removeClass();
call.addClass("call answered");
status_text.text(description || "answered");
button_hold.click(function(){
if (! session.call.isReadyToReOffer()) {
console.warn('Tryit: not ready to reoffer');
return;
}
if (! localCanRenegotiateRTC() || ! session.call.data.remoteCanRenegotiateRTC) {
console.warn('Tryit: resetting PeerConnection before hold');
session.call.connection.reset();
session.call.connection.addStream(localStream);
}
session.call.hold({useUpdate: false});
});
button_dtmf.click(function() {
dtmf_box.toggle();
});
if (realHack) { return; }
var dtmf_button = jQuery(dtmf_box).find(".dtmf-button");
window.dtmf_button = dtmf_button;
var sound_file;
dtmf_button.click(function() {
if (jQuery(this).hasClass("digit-asterisk"))
sound_file = "asterisk";
else if (jQuery(this).hasClass("digit-pound"))
sound_file = "pound";
else
sound_file = jQuery(this).text();
soundPlayer.setAttribute("src", base_url + "embed/sounds/dialpad/" + sound_file + ".ogg");
soundPlayer.play();
session.call.sendDTMF(jQuery(this).text());
});
break;
case "hold":
case "unhold":
if (session.call.isOnHold().local) {
call.removeClass();
call.addClass("call on-hold");
button_resume.click(function(){
if (! session.call.isReadyToReOffer()) {
console.warn('Tryit: not ready to reoffer');
return;
}
if (! localCanRenegotiateRTC() || ! session.call.data.remoteCanRenegotiateRTC) {
console.warn('Tryit: resetting PeerConnection before unhold');
session.call.connection.reset();
session.call.connection.addStream(localStream);
}
session.call.unhold();
});
} else {
GUI.setCallSessionStatus(session, 'answered', null, true);
}
var local_hold = session.call.isOnHold().local;
var remote_hold = session.call.isOnHold().remote;
var status = "hold by";
status += local_hold?" local ":"";
if (remote_hold) {
if (local_hold)
status += "/";
status += " remote";
}
if (local_hold||remote_hold) {
status_text.text(status);
}
break;
case "terminated":
call.removeClass();
call.addClass("call terminated");
status_text.text(description || "terminated");
button_hangup.unbind("click");
// Hide DTMF box.
dtmf_box.hide();
break;
case "incoming":
call.removeClass();
call.addClass("call incoming");
status_text.text("incoming call...");
soundPlayer.setAttribute("src", base_url + "embed/sounds/incoming-call2.ogg");
soundPlayer.play();
button_dial.click(function() {
session.call.answer({
//pcConfig: peerconnection_config,
// TMP:
mediaConstraints: {audio: true, video: false},
extraHeaders: [
'X-Can-Renegotiate: ' + String(localCanRenegotiateRTC())
],
rtcOfferConstraints: {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
}//,
});
});
// unhide HTML Video Elements
//jQuery('#remoteView').attr('hidden', false);
//jQuery('#selfView').attr('hidden', false);
// Set background image
//jQuery('#remoteView').attr('poster', "images/logo.png");
// Hide DTMF box.
dtmf_box.hide();
break;
default:
alert("ERROR: setCallSessionStatus() called with unknown status '" + status + "'");
break;
}
}
,
/*
* JsSIP.UA new_session event listener
*/
newSession : function(e) {
var display_name, status,
request = e.request,
call = e.session,
uri = call.remote_identity.uri.toString(),
session = GUI.getSession(uri);
display_name = call.remote_identity.display_name || call.remote_identity.uri.user;
if (call.direction === 'incoming') {
status = "incoming";
if (request.getHeader('X-Can-Renegotiate') === 'false') {
call.data.remoteCanRenegotiateRTC = false;
}
else {
call.data.remoteCanRenegotiateRTC = true;
}
} else {
status = "trying";
}
// If the session exists with active call reject it.
if (session && !jQuery(session).find(".call").hasClass("inactive")) {
call.terminate();
return false;
}
// If this is a new session create it
if (!session) {
session = GUI.createSession(display_name, uri);
}
// Associate the JsSIP Session to the HTML div session
session.call = call;
GUI.setCallSessionStatus(session, status);
jQuery(session).find(".chat input").focus();
// EVENT CALLBACK DEFINITION
call.on('connecting', function() {
// TMP
if (call.connection.getLocalStreams().length > 0) {
window.localStream = call.connection.getLocalStreams()[0];
}
});
// Progress
call.on('progress',function(e){
if (e.originator === 'remote') {
GUI.setCallSessionStatus(session, 'in-progress');
}
});
// Started
call.on('accepted',function(e){
//Attach the streams to the views if it exists.
if (call.connection.getLocalStreams().length > 0) {
localStream = call.connection.getLocalStreams()[0];
selfView = JsSIP.rtcninja.attachMediaStream(selfView, localStream);
selfView.volume = 0;
// TMP
window.localStream = localStream;
}
if (e.originator === 'remote') {
if (e.response.getHeader('X-Can-Renegotiate') === 'false') {
call.data.remoteCanRenegotiateRTC = false;
}
else {
call.data.remoteCanRenegotiateRTC = true;
}
}
GUI.setCallSessionStatus(session, 'answered');
});
call.on('addstream', function(e) {
console.log('Tryit: addstream()');
remoteStream = e.stream;
remoteView = JsSIP.rtcninja.attachMediaStream(remoteView, remoteStream);
});
// Failed
call.on('failed',function(e) {
var
cause = e.cause,
response = e.response;
if (e.originator === 'remote' && cause.match("SIP;cause=200", "i")) {
cause = 'answered_elsewhere';
}
GUI.setCallSessionStatus(session, 'terminated', cause);
soundPlayer.setAttribute("src", base_url + "embed/sounds/outgoing-call-rejected.wav");
soundPlayer.play();
GUI.removeSession(session, 1500);
selfView.src = '';
remoteView.src = '';
_Session = null;
});
// NewDTMF
call.on('newDTMF',function(e) {
if (e.originator === 'remote') {
sound_file = e.dtmf.tone;
soundPlayer.setAttribute("src", base_url + "embed/sounds/dialpad/" + sound_file + ".ogg");
soundPlayer.play();
}
});
call.on('hold',function(e) {
soundPlayer.setAttribute("src", base_url + "embed/sounds/dialpad/pound.ogg");
soundPlayer.play();
GUI.setCallSessionStatus(session, 'hold', e.originator);
});
call.on('unhold',function(e) {
soundPlayer.setAttribute("src", base_url + "embed/sounds/dialpad/pound.ogg");
soundPlayer.play();
GUI.setCallSessionStatus(session, 'unhold', e.originator);
});
// Ended
call.on('ended', function(e) {
var cause = e.cause;
GUI.setCallSessionStatus(session, "terminated", cause);
GUI.removeSession(session, 1500);
selfView.src = '';
remoteView.src = '';
_Session = null;
JsSIP.rtcninja.closeMediaStream(localStream);
});
// received UPDATE
call.on('update', function(e) {
var request = e.request;
if (! request.body) { return; }
if (! localCanRenegotiateRTC() || ! call.data.remoteCanRenegotiateRTC) {
console.warn('Tryit: UPDATE received, resetting PeerConnection');
call.connection.reset();
call.connection.addStream(localStream);
}
});
// received reINVITE
call.on('reinvite', function(e) {
var request = e.request;
if (! request.body) { return; }
if (! localCanRenegotiateRTC() || ! call.data.remoteCanRenegotiateRTC) {
console.warn('Tryit: reINVITE received, resetting PeerConnection');
call.connection.reset();
call.connection.addStream(localStream);
}
});
}
,
removeSession : function(session, time, force) {
var default_time = 500;
var uri = jQuery(session).find(".peer > .uri").text();
var chat_input = jQuery(session).find(".chat > input[type='text']");
//if (force || (jQuery(session).find(".chat .chatting").hasClass("inactive") && (chat_input.hasClass("inactive") || chat_input.val() == ""))) {
time = ( time ? time : default_time );
jQuery(session).fadeTo(time, 0.7, function() {
jQuery(session).slideUp(100, function() {
jQuery(session).remove();
});
});
// Enviar "iscomposing idle" si estábamos escribiendo.
if (! chat_input.hasClass("inactive") && chat_input.val() != "")
GUI.jssipIsComposing(uri, false);
/*
}
else {
// Como existe una sesión de chat, no cerramos el div de sesión,
// en su lugar esperamos un poco antes de ponerlo como "inactive".
setTimeout('GUI.setDelayedCallSessionStatus("'+uri+'", "inactive")', 1000);
}
*/
// hide HTML Video Elements
//jQuery('#remoteView').attr('hidden', true);
//jQuery('#selfView').attr('hidden', true);
}
,
setDelayedCallSessionStatus : function(uri, status, description, force) {
var session = GUI.getSession(uri.toString());
if (session)
GUI.setCallSessionStatus(session, status, description, force);
}
,
/*
* - who: "me" o "peer".
* - text: el texto del mensaje.
*/
addChatMessage : function(session, who, text) {
var chatting = jQuery(session).find(".chat > .chatting");
jQuery(chatting).removeClass("inactive");
if (who != "error") {
var who_text = ( who == "me" ? "Me" : jQuery(session).find(".peer > .display-name").text() );
var message_div = jQuery('<p class="' + who + '"><b>' + who_text + '</b>: ' + text + '</p>');
}
// ERROR sending the MESSAGE.
else {
var message_div = jQuery('<p class="error"><i>message failed: ' + text + '</i>');
}
jQuery(chatting).append(message_div);
jQuery(chatting).scrollTop(1e4);
if (who == "peer") {
soundPlayer.setAttribute("src", base_url + "embed/sounds/incoming-chat.ogg");
soundPlayer.play();
}
// Si se había recibido un iscomposing quitarlo (sólo si es message entrante!!!).
if (who == "peer")
jQuery(session).find(".chat .iscomposing").hide();
}
}
// Add/remove video during a call.
jQuery('#enableVideo').change(function() {
if (! _Session) { return; }
if (! _Session.isReadyToReOffer()) {
console.warn('Tryit: not ready to reoffer');
return;
}
var mediaConstraints = { audio: true, video: true };
if (! jQuery(this).is(':checked')) {
mediaConstraints.video = false;
}
JsSIP.rtcninja.getUserMedia(mediaConstraints,
useNewLocalStream,
function(error) {
throw error;
}
);
/*
function useNewLocalStream(stream) {
if (! _Session) { return; }
var oldStream = _Session.connection.getLocalStreams()[0];
_Session.connection.removeStream(oldStream);
JsSIP.rtcninja.closeMediaStream(oldStream);
_Session.connection.addStream(stream);
_Session.renegotiate();
selfView = JsSIP.rtcninja.attachMediaStream(selfView, stream);
}
*/
function useNewLocalStream(stream) {
if (! _Session) { return; }
var oldStream = localStream;
if (localCanRenegotiateRTC() && _Session.data.remoteCanRenegotiateRTC) {
_Session.connection.removeStream(localStream);
_Session.connection.addStream(stream);
}
else {
console.warn('Tryit: resetting PeerConnection before renegotiating the session');
_Session.connection.reset();
_Session.connection.addStream(stream);
}
JsSIP.rtcninja.closeMediaStream(localStream);
_Session.renegotiate({
useUpdate: true,
rtcOfferConstraints: { offerToReceiveAudio: true, offerToReceiveVideo: true }
});
localStream = stream;
selfView = JsSIP.rtcninja.attachMediaStream(selfView, stream);
}
});
});
function initPhone(user_name, password, display_name, extension_domain, ws_servers){
ws_registered = false;
var sip_password = password;
var username = user_name;
var sip_uri = 'sip:'+username+'@'+extension_domain;
//alert('Init URI: '+ sip_uri);
//alert('Init Display: '+ display_name);
//var sip_uri = 'sip:849389891010001@epacific.net';
var configuration = {
log: { level: 'debug' },
uri: sip_uri,
password: sip_password,
ws_servers: ws_servers,
display_name: display_name
};
div_webcam.show();
try {
ua = new JsSIP.UA(configuration);
} catch(e) {
console.log(e.toString());
//alert(e.toString());
return;
}
// Call/Message reception callbacks
ua.on('newRTCSession', function(e) {
// Set a global '_Session' variable with the session for testing.
_Session = e.session;
GUI.newSession(e)
});
ua.on('newMessage', function(e) {
GUI.newMessage(e)
});
ua.on('connected', function(e) {
//document.title = 'Connected';
//GUI.setStatus("connected");
// Habilitar el phone.
//obj.attr('disabled', true);
ws_was_connected = true;
//alert('Connected');
});
ua.on('disconnected', function(e) {
//document.title = 'Disconnected';
//GUI.setStatus("disconnected");
if (! ws_was_connected) {
//alert("WS connection error:\n\n- WS close code: " + e.data.code + "\n- WS close reason: " + e.data.reason);
console.error("WS connection error | WS close code: " + e.code + " | WS close reason: " + e.reason);
//if (! window.CustomJsSIPSettings) { window.location.reload(false); }
}
//alert('Disconnected');
});
ua.on('registered', function(e){
console.info('Registered');
//GUI.setStatus("Registered");
//alert('Registered');
//GUI.jssipCall(target);
ws_registered = true;
//jQuery('span.display-name').html(configuration.display_name);
//jQuery('span.uri').html(configuration.uri);
});
ua.on('unregistered', function(e){
console.info('Unregistered');
GUI.setStatus("Unregistered");
ws_registered = false;
//alert('Unregistered');
});
ua.on('registrationFailed', function(e) {
console.info('Registration failure');
ws_registered = false;
//alert('Register Fail!');
if (! e.response) {
// alert("SIP registration error:\n" + e.data.cause);
}
else {
// alert("SIP registration error:\n" + e.data.response.status_code.toString() + " " + e.data.response.reason_phrase)
}
// if (! window.CustomJsSIPSettings) { window.location.reload(false); }
});
// Start
ua.start();
//ua.call('800@');
}
var timer;
function waitAndCall(){
timer = setTimeout("waitAndCall()", 1000);
if(ws_registered){
if(timer) clearTimeout(timer);
//alert(main_phone);
GUI.jssipCall(main_phone);
}
}Was this page helpful?
