<"+ did + ">
";
}
callAnswerHtml += "
";
callAnswerHtml += "
"+ lang.answer_call +"
";
if(videoInvite) {
callAnswerHtml += "
"+ lang.answer_call_with_video +"
";
}
callAnswerHtml += "
"+ lang.reject_call +"
";
callAnswerHtml += "
";
$.jeegoopopup.open({
title: 'Incoming Call',
html: callAnswerHtml,
width: '290',
height: '300',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#closeImg").click(function() { $.jeegoopopup.close(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
// Add a notification badge
IncreaseMissedBadge(buddyObj.identity);
// Show notification
// =================
if ("Notification" in window) {
if (getDbItem("Notifications", "") == 1) {
var noticeOptions = { body: lang.incomming_call_from +" " + callerID +" \""+ did +"\"", icon: getPicture(buddyObj.identity) }
var inComingCallNotification = new Notification(lang.incomming_call, noticeOptions);
inComingCallNotification.onclick = function (event) {
var buddyId = buddyObj.identity;
window.setTimeout(function() {
// https://github.com/InnovateAsterisk/Browser-Phone/issues/26
if(videoInvite) {
AnswerVideoCall(buddyId)
} else {
AnswerAudioCall(buddyId);
}
}, 4000);
// Select Buddy
SelectBuddy(buddyObj.identity);
return;
}
}
}
}
function AnswerAudioCall(buddy) {
$.jeegoopopup.close();
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj == null) {
console.warn("Audio Answer failed, null buddy");
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
return;
}
var session = getSession(buddy);
if (session == null) {
console.warn("Audio Answer failed, null session");
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
return;
}
// Stop the ringtone
if(session.data.rinngerObj){
session.data.rinngerObj.pause();
session.data.rinngerObj.removeAttribute('src');
session.data.rinngerObj.load();
session.data.rinngerObj = null;
}
// Check vitals
if(HasAudioDevice == false){
Alert(lang.alert_no_microphone);
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
return;
}
$("#contact-" + buddy + "-timer").html("");
$("#contact-" + buddy + "-timer").hide();
$("#contact-" + buddy + "-msg").html("");
$("#contact-" + buddy + "-msg").hide();
$("#contact-" + buddy + "-AnswerCall").hide();
// Create a new Line and move the session over to the line
var callerID = session.remoteIdentity.displayName;
var did = session.remoteIdentity.uri.user;
newLineNumber = newLineNumber + 1;
lineObj = new Line(newLineNumber, callerID, did, buddyObj);
lineObj.SipSession = session;
lineObj.SipSession.data.line = lineObj.LineNumber;
lineObj.SipSession.data.buddyId = lineObj.BuddyObj.identity;
Lines.push(lineObj);
AddLineHtml(lineObj);
SelectLine(newLineNumber);
UpdateBuddyList();
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var spdOptions = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: { deviceId : "default" },
video: false
}
}
}
// Configure Audio
var currentAudioDevice = getAudioSrcID();
if(currentAudioDevice != "default"){
var confirmedAudioDevice = false;
for (var i = 0; i < AudioinputDevices.length; ++i) {
if(currentAudioDevice == AudioinputDevices[i].deviceId) {
confirmedAudioDevice = true;
break;
}
}
if(confirmedAudioDevice) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.deviceId = { exact: currentAudioDevice }
}
else {
console.warn("The audio device you used before is no longer available, default settings applied.");
localDB.setItem("AudioSrcId", "default");
}
}
// Add additional Constraints
if(supportedConstraints.autoGainControl) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.autoGainControl = AutoGainControl;
}
if(supportedConstraints.echoCancellation) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.echoCancellation = EchoCancellation;
}
if(supportedConstraints.noiseSuppression) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.noiseSuppression = NoiseSuppression;
}
// Send Answer
lineObj.SipSession.accept(spdOptions);
lineObj.SipSession.data.withvideo = false;
lineObj.SipSession.data.VideoSourceDevice = null;
lineObj.SipSession.data.AudioSourceDevice = getAudioSrcID();
lineObj.SipSession.data.AudioOutputDevice = getAudioOutputID();
// Wire up UI
wireupAudioSession(lineObj);
$("#contact-" + buddy + "-msg").html(lang.call_in_progress);
// Clear Answer Buttons
$("#contact-" + buddy + "-AnswerCall").hide();
}
function AnswerVideoCall(buddy) {
$.jeegoopopup.close();
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj == null) {
console.warn("Audio Answer failed, null buddy");
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
return;
}
var session = getSession(buddy);
if (session == null) {
console.warn("Video Answer failed, null session");
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
return;
}
// Stop the ringtone
if(session.data.rinngerObj){
session.data.rinngerObj.pause();
session.data.rinngerObj.removeAttribute('src');
session.data.rinngerObj.load();
session.data.rinngerObj = null;
}
// Check vitals
if(HasAudioDevice == false){
Alert(lang.alert_no_microphone);
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
return;
}
if(HasVideoDevice == false){
console.warn("No video devices (webcam) found, switching to audio call.");
AnswerAudioCall(buddy);
return;
}
$("#contact-" + buddy + "-timer").html("");
$("#contact-" + buddy + "-timer").hide();
$("#contact-" + buddy + "-msg").html("");
$("#contact-" + buddy + "-msg").hide();
$("#contact-" + buddy + "-AnswerCall").hide();
// Create a new Line and move the session over to the line
var callerID = session.remoteIdentity.displayName;
var did = session.remoteIdentity.uri.user;
newLineNumber = newLineNumber + 1;
lineObj = new Line(newLineNumber, callerID, did, buddyObj);
lineObj.SipSession = session;
lineObj.SipSession.data.line = lineObj.LineNumber;
lineObj.SipSession.data.buddyId = lineObj.BuddyObj.identity;
Lines.push(lineObj);
AddLineHtml(lineObj);
SelectLine(newLineNumber);
UpdateBuddyList();
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var spdOptions = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: { deviceId : "default" },
video: { deviceId : "default" }
}
}
}
// Configure Audio
var currentAudioDevice = getAudioSrcID();
if(currentAudioDevice != "default"){
var confirmedAudioDevice = false;
for (var i = 0; i < AudioinputDevices.length; ++i) {
if(currentAudioDevice == AudioinputDevices[i].deviceId) {
confirmedAudioDevice = true;
break;
}
}
if(confirmedAudioDevice) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.deviceId = { exact: currentAudioDevice }
}
else {
console.warn("The audio device you used before is no longer available, default settings applied.");
localDB.setItem("AudioSrcId", "default");
}
}
// Add additional Constraints
if(supportedConstraints.autoGainControl) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.autoGainControl = AutoGainControl;
}
if(supportedConstraints.echoCancellation) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.echoCancellation = EchoCancellation;
}
if(supportedConstraints.noiseSuppression) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.noiseSuppression = NoiseSuppression;
}
// Configure Video
var currentVideoDevice = getVideoSrcID();
if(currentVideoDevice != "default"){
var confirmedVideoDevice = false;
for (var i = 0; i < VideoinputDevices.length; ++i) {
if(currentVideoDevice == VideoinputDevices[i].deviceId) {
confirmedVideoDevice = true;
break;
}
}
if(confirmedVideoDevice){
spdOptions.sessionDescriptionHandlerOptions.constraints.video.deviceId = { exact: currentVideoDevice }
}
else {
console.warn("The video device you used before is no longer available, default settings applied.");
localDB.setItem("VideoSrcId", "default"); // resets for later and subsequent calls
}
}
// Add additional Constraints
if(supportedConstraints.frameRate && maxFrameRate != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.frameRate = maxFrameRate;
}
if(supportedConstraints.height && videoHeight != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.height = videoHeight;
}
if(supportedConstraints.aspectRatio && videoAspectRatio != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.aspectRatio = videoAspectRatio;
}
// Send Answer
lineObj.SipSession.data.withvideo = true;
lineObj.SipSession.data.VideoSourceDevice = getVideoSrcID();
lineObj.SipSession.data.AudioSourceDevice = getAudioSrcID();
lineObj.SipSession.data.AudioOutputDevice = getAudioOutputID();
// Send Answer
// If this fails, it must still wireup the call so we can manually close it
$("#contact-" + buddy + "-msg").html(lang.call_in_progress);
// Wire up UI
wireupVideoSession(lineObj);
try{
lineObj.SipSession.accept(spdOptions);
if(StartVideoFullScreen) ExpandVideoArea(lineObj.LineNumber);
$("#contact-" + buddy + "-AnswerCall").hide();
}
catch(e){
console.warn("Failed to answer call", e, lineObj.SipSession);
teardownSession(lineObj, 500, "Client Error");
}
}
function RejectCall(buddy) {
var session = getSession(buddy);
if (session == null) {
console.warn("Reject failed, null session");
$("#contact-" + buddy + "-msg").html(lang.call_failed);
$("#contact-" + buddy + "-AnswerCall").hide();
}
session.data.terminateby = "us";
session.reject({
statusCode: 486,
reasonPhrase: "Rejected by us"
});
$("#contact-" + buddy + "-msg").html(lang.call_rejected);
}
// Session Wireup
// ==============
function wireupAudioSession(lineObj) {
if (lineObj == null) return;
var MessageObjId = "#line-" + lineObj.LineNumber + "-msg";
var session = lineObj.SipSession;
session.on('progress', function (response) {
// Provisional 1xx
if(response.status_code == 100){
$(MessageObjId).html(lang.trying);
} else if(response.status_code == 180){
$(MessageObjId).html(lang.ringing);
var soundFile = audioBlobs.EarlyMedia_European;
if(UserLocale().indexOf("us") > -1) soundFile = audioBlobs.EarlyMedia_US;
if(UserLocale().indexOf("gb") > -1) soundFile = audioBlobs.EarlyMedia_UK;
if(UserLocale().indexOf("au") > -1) soundFile = audioBlobs.EarlyMedia_Australia;
if(UserLocale().indexOf("jp") > -1) soundFile = audioBlobs.EarlyMedia_Japan;
// Play Early Media
console.log("Audio:", soundFile.url);
var earlyMedia = new Audio(soundFile.blob);
earlyMedia.preload = "auto";
earlyMedia.loop = true;
earlyMedia.oncanplaythrough = function(e) {
if (typeof earlyMedia.sinkId !== 'undefined' && getAudioOutputID() != "default") {
earlyMedia.setSinkId(getAudioOutputID()).then(function() {
console.log("Set sinkId to:", getAudioOutputID());
}).catch(function(e){
console.warn("Failed not apply setSinkId.", e);
});
}
earlyMedia.play().then(function(){
// Audio Is Playing
}).catch(function(e){
console.warn("Unable to play audio file.", e);
});
}
session.data.earlyMedia = earlyMedia;
} else {
$(MessageObjId).html(response.reason_phrase + "...");
}
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("progress", session);
});
session.on('trackAdded', function () {
var pc = session.sessionDescriptionHandler.peerConnection;
// Gets Remote Audio Track (Local audio is setup via initial GUM)
var remoteStream = new MediaStream();
pc.getReceivers().forEach(function (receiver) {
if(receiver.track && receiver.track.kind == "audio"){
remoteStream.addTrack(receiver.track);
}
});
var remoteAudio = $("#line-" + lineObj.LineNumber + "-remoteAudio").get(0);
remoteAudio.srcObject = remoteStream;
remoteAudio.onloadedmetadata = function(e) {
if (typeof remoteAudio.sinkId !== 'undefined') {
remoteAudio.setSinkId(getAudioOutputID()).then(function(){
console.log("sinkId applied: "+ getAudioOutputID());
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
}
remoteAudio.play();
}
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("trackAdded", session);
});
session.on('accepted', function (data) {
if(session.data.earlyMedia){
session.data.earlyMedia.pause();
session.data.earlyMedia.removeAttribute('src');
session.data.earlyMedia.load();
session.data.earlyMedia = null;
}
window.clearInterval(session.data.callTimer);
var startTime = moment.utc();
session.data.callTimer = window.setInterval(function(){
var now = moment.utc();
var duration = moment.duration(now.diff(startTime));
$("#line-" + lineObj.LineNumber + "-timer").html(formatShortDuration(duration.asSeconds()));
}, 1000);
if(RecordAllCalls || CallRecordingPolicy == "enabled") {
StartRecording(lineObj.LineNumber);
}
$("#line-" + lineObj.LineNumber + "-progress").hide();
$("#line-" + lineObj.LineNumber + "-VideoCall").hide();
$("#line-" + lineObj.LineNumber + "-ActiveCall").show();
// Audo Monitoring
lineObj.LocalSoundMeter = StartLocalAudioMediaMonitoring(lineObj.LineNumber, session);
lineObj.RemoteSoundMeter = StartRemoteAudioMediaMonitoring(lineObj.LineNumber, session);
$(MessageObjId).html(lang.call_in_progress);
updateLineScroll(lineObj.LineNumber);
UpdateBuddyList();
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("accepted", session);
});
session.on('rejected', function (response, cause) {
// Should only apply befor answer
$(MessageObjId).html(lang.call_rejected +": " + cause);
console.log("Call rejected: " + cause);
teardownSession(lineObj, response.status_code, response.reason_phrase);
});
session.on('failed', function (response, cause) {
$(MessageObjId).html(lang.call_failed + ": " + cause);
console.log("Call failed: " + cause);
teardownSession(lineObj, 0, "Call failed");
});
session.on('cancel', function () {
$(MessageObjId).html(lang.call_cancelled);
console.log("Call Cancelled");
teardownSession(lineObj, 0, "Cancelled by caller");
});
// referRequested
// replaced
session.on('bye', function () {
$(MessageObjId).html(lang.call_ended);
console.log("Call ended, bye!");
teardownSession(lineObj, 16, "Normal Call clearing");
});
session.on('terminated', function (message, cause) {
$(MessageObjId).html(lang.call_ended);
console.log("Session terminated");
teardownSession(lineObj, 16, "Normal Call clearing");
});
session.on('reinvite', function (session) {
console.log("Session reinvited!");
});
//dtmf
session.on('directionChanged', function() {
var direction = session.sessionDescriptionHandler.getDirection();
console.log("Direction Change: ", direction);
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("directionChanged", session);
});
$("#line-" + lineObj.LineNumber + "-btn-settings").removeAttr('disabled');
$("#line-" + lineObj.LineNumber + "-btn-audioCall").prop('disabled','disabled');
$("#line-" + lineObj.LineNumber + "-btn-videoCall").prop('disabled','disabled');
$("#line-" + lineObj.LineNumber + "-btn-search").removeAttr('disabled');
$("#line-" + lineObj.LineNumber + "-btn-remove").prop('disabled','disabled');
$("#line-" + lineObj.LineNumber + "-progress").show();
$("#line-" + lineObj.LineNumber + "-msg").show();
if(lineObj.BuddyObj.type == "group") {
$("#line-" + lineObj.LineNumber + "-conference").show();
}
else {
$("#line-" + lineObj.LineNumber + "-conference").hide();
}
updateLineScroll(lineObj.LineNumber);
UpdateUI();
}
function wireupVideoSession(lineObj) {
if (lineObj == null) return;
var MessageObjId = "#line-" + lineObj.LineNumber + "-msg";
var session = lineObj.SipSession;
session.on('trackAdded', function () {
// Gets remote tracks
var pc = session.sessionDescriptionHandler.peerConnection;
var remoteAudioStream = new MediaStream();
var remoteVideoStream = new MediaStream();
pc.getReceivers().forEach(function (receiver) {
if(receiver.track){
if(receiver.track.kind == "audio"){
remoteAudioStream.addTrack(receiver.track);
}
if(receiver.track.kind == "video"){
remoteVideoStream.addTrack(receiver.track);
}
}
});
if (remoteAudioStream.getAudioTracks().length >= 1) {
var remoteAudio = $("#line-" + lineObj.LineNumber + "-remoteAudio").get(0);
remoteAudio.srcObject = remoteAudioStream;
remoteAudio.onloadedmetadata = function(e) {
if (typeof remoteAudio.sinkId !== 'undefined') {
remoteAudio.setSinkId(getAudioOutputID()).then(function(){
console.log("sinkId applied: "+ getAudioOutputID());
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
}
remoteAudio.play();
}
}
if (remoteVideoStream.getVideoTracks().length >= 1) {
var remoteVideo = $("#line-" + lineObj.LineNumber + "-remoteVideo").get(0);
remoteVideo.srcObject = remoteVideoStream;
remoteVideo.onloadedmetadata = function(e) {
remoteVideo.play();
}
}
// Note: There appears to be a bug in the peerConnection.getSenders()
// The array returns but may or may not be fully populated by the RTCRtpSender
// The track property appears to be null initially and then moments later populated.
// This does not appear to be the case when originating a call, mostly when receiving a call.
window.setTimeout(function(){
var localVideoStream = new MediaStream();
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (sender) {
if(sender.track && sender.track.kind == "video"){
localVideoStream.addTrack(sender.track);
}
});
var localVideo = $("#line-" + lineObj.LineNumber + "-localVideo").get(0);
localVideo.srcObject = localVideoStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
}
}, 1000);
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("trackAdded", session);
});
session.on('progress', function (response) {
// Provisional 1xx
if(response.status_code == 100){
$(MessageObjId).html(lang.trying);
} else if(response.status_code == 180){
$(MessageObjId).html(lang.ringing);
var soundFile = audioBlobs.EarlyMedia_European;
if(UserLocale().indexOf("us") > -1) soundFile = audioBlobs.EarlyMedia_US;
if(UserLocale().indexOf("gb") > -1) soundFile = audioBlobs.EarlyMedia_UK;
if(UserLocale().indexOf("au") > -1) soundFile = audioBlobs.EarlyMedia_Australia;
if(UserLocale().indexOf("jp") > -1) soundFile = audioBlobs.EarlyMedia_Japan;
// Play Early Media
console.log("Audio:", soundFile.url);
var earlyMedia = new Audio(soundFile.blob);
earlyMedia.preload = "auto";
earlyMedia.loop = true;
earlyMedia.oncanplaythrough = function(e) {
if (typeof earlyMedia.sinkId !== 'undefined' && getAudioOutputID() != "default") {
earlyMedia.setSinkId(getAudioOutputID()).then(function() {
console.log("Set sinkId to:", getAudioOutputID());
}).catch(function(e){
console.warn("Failed not apply setSinkId.", e);
});
}
earlyMedia.play().then(function(){
// Audio Is Playing
}).catch(function(e){
console.warn("Unable to play audio file.", e);
});
}
session.data.earlyMedia = earlyMedia;
} else {
$(MessageObjId).html(response.reason_phrase + "...");
}
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("progress", session);
});
session.on('accepted', function (data) {
if(session.data.earlyMedia){
session.data.earlyMedia.pause();
session.data.earlyMedia.removeAttribute('src');
session.data.earlyMedia.load();
session.data.earlyMedia = null;
}
window.clearInterval(session.data.callTimer);
$("#line-" + lineObj.LineNumber + "-timer").show();
var startTime = moment.utc();
session.data.callTimer = window.setInterval(function(){
var now = moment.utc();
var duration = moment.duration(now.diff(startTime));
$("#line-" + lineObj.LineNumber + "-timer").html(formatShortDuration(duration.asSeconds()));
}, 1000);
if(RecordAllCalls || CallRecordingPolicy == "enabled") {
StartRecording(lineObj.LineNumber);
}
$("#line-"+ lineObj.LineNumber +"-progress").hide();
$("#line-"+ lineObj.LineNumber +"-VideoCall").show();
$("#line-"+ lineObj.LineNumber +"-ActiveCall").show();
$("#line-"+ lineObj.LineNumber +"-btn-Conference").hide(); // Cannot conference a Video Call (Yet...)
$("#line-"+ lineObj.LineNumber +"-btn-CancelConference").hide();
$("#line-"+ lineObj.LineNumber +"-Conference").hide();
$("#line-"+ lineObj.LineNumber +"-btn-Transfer").hide(); // Cannot transfer a Video Call (Yet...)
$("#line-"+ lineObj.LineNumber +"-btn-CancelTransfer").hide();
$("#line-"+ lineObj.LineNumber +"-Transfer").hide();
// Default to use Camera
$("#line-"+ lineObj.LineNumber +"-src-camera").prop("disabled", true);
$("#line-"+ lineObj.LineNumber +"-src-canvas").prop("disabled", false);
$("#line-"+ lineObj.LineNumber +"-src-desktop").prop("disabled", false);
$("#line-"+ lineObj.LineNumber +"-src-video").prop("disabled", false);
updateLineScroll(lineObj.LineNumber);
// Start Audio Monitoring
lineObj.LocalSoundMeter = StartLocalAudioMediaMonitoring(lineObj.LineNumber, session);
lineObj.RemoteSoundMeter = StartRemoteAudioMediaMonitoring(lineObj.LineNumber, session);
$(MessageObjId).html(lang.call_in_progress);
if(StartVideoFullScreen) ExpandVideoArea(lineObj.LineNumber);
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("accepted", session);
});
session.on('rejected', function (response, cause) {
// Should only apply before answer
$(MessageObjId).html(lang.call_rejected +": "+ cause);
console.log("Call rejected: "+ cause);
teardownSession(lineObj, response.status_code, response.reason_phrase);
});
session.on('failed', function (response, cause) {
$(MessageObjId).html(lang.call_failed +": "+ cause);
console.log("Call failed: "+ cause);
teardownSession(lineObj, 0, "call failed");
});
session.on('cancel', function () {
$(MessageObjId).html(lang.call_cancelled);
console.log("Call Cancelled");
teardownSession(lineObj, 0, "Cancelled by caller");
});
// referRequested
// replaced
session.on('bye', function () {
$(MessageObjId).html(lang.call_ended);
console.log("Call ended, bye!");
teardownSession(lineObj, 16, "Normal Call clearing");
});
session.on('terminated', function (message, cause) {
$(MessageObjId).html(lang.call_ended);
console.log("Session terminated");
teardownSession(lineObj, 16, "Normal Call clearing");
});
session.on('reinvite', function (session) {
console.log("Session reinvited!");
});
// dtmf
session.on('directionChanged', function() {
var direction = session.sessionDescriptionHandler.getDirection();
console.log("Direction Change: ", direction);
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("directionChanged", session);
});
$("#line-" + lineObj.LineNumber + "-btn-settings").removeAttr('disabled');
$("#line-" + lineObj.LineNumber + "-btn-audioCall").prop('disabled','disabled');
$("#line-" + lineObj.LineNumber + "-btn-videoCall").prop('disabled','disabled');
$("#line-" + lineObj.LineNumber + "-btn-search").removeAttr('disabled');
$("#line-" + lineObj.LineNumber + "-btn-remove").prop('disabled','disabled');
$("#line-" + lineObj.LineNumber + "-progress").show();
$("#line-" + lineObj.LineNumber + "-msg").show();
updateLineScroll(lineObj.LineNumber);
UpdateUI();
}
function teardownSession(lineObj, reasonCode, reasonText) {
if(lineObj == null || lineObj.SipSession == null) return;
var session = lineObj.SipSession;
if(session.data.teardownComplete == true) return;
session.data.teardownComplete = true; // Run this code only once
session.data.reasonCode = reasonCode
session.data.reasonText = reasonText
// Call UI
$.jeegoopopup.close();
// End any child calls
if(session.data.childsession){
try{
if(session.data.childsession.status == SIP.Session.C.STATUS_CONFIRMED){
session.data.childsession.bye();
}
else{
session.data.childsession.cancel();
}
} catch(e){}
}
session.data.childsession = null;
// Mixed Tracks
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
session.data.AudioSourceTrack.stop();
session.data.AudioSourceTrack = null;
}
// Stop any Early Media
if(session.data.earlyMedia){
session.data.earlyMedia.pause();
session.data.earlyMedia.removeAttribute('src');
session.data.earlyMedia.load();
session.data.earlyMedia = null;
}
// Stop Recording if we are
StopRecording(lineObj.LineNumber,true);
// Audio Meters
if(lineObj.LocalSoundMeter != null){
lineObj.LocalSoundMeter.stop();
lineObj.LocalSoundMeter = null;
}
if(lineObj.RemoteSoundMeter != null){
lineObj.RemoteSoundMeter.stop();
lineObj.RemoteSoundMeter = null;
}
// End timers
window.clearInterval(session.data.videoResampleInterval);
window.clearInterval(session.data.callTimer);
// Add to stream
AddCallMessage(lineObj.BuddyObj.identity, session, reasonCode, reasonText);
// Close up the UI
window.setTimeout(function () {
RemoveLine(lineObj);
}, 1000);
UpdateBuddyList();
UpdateUI();
// Custom Web hook
if(typeof web_hook_on_terminate !== 'undefined') web_hook_on_terminate(session);
}
// Mic and Speaker Levels
// ======================
function StartRemoteAudioMediaMonitoring(lineNum, session) {
console.log("Creating RemoteAudio AudioContext on Line:" + lineNum);
// Create local SoundMeter
var soundMeter = new SoundMeter(session.id, lineNum);
if(soundMeter == null){
console.warn("AudioContext() RemoteAudio not available... it fine.");
return null;
}
// Ready the getStats request
var remoteAudioStream = new MediaStream();
var audioReceiver = null;
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getReceivers().forEach(function (RTCRtpReceiver) {
if(RTCRtpReceiver.track && RTCRtpReceiver.track.kind == "audio"){
if(audioReceiver == null) {
remoteAudioStream.addTrack(RTCRtpReceiver.track);
audioReceiver = RTCRtpReceiver;
}
else {
console.log("Found another Track, but audioReceiver not null");
console.log(RTCRtpReceiver);
console.log(RTCRtpReceiver.track);
}
}
});
// Setup Charts
var maxDataLength = 100;
soundMeter.startTime = Date.now();
Chart.defaults.global.defaultFontSize = 12;
var ChatHistoryOptions = {
responsive: false,
maintainAspectRatio: false,
devicePixelRatio: 1,
animation: false,
scales: {
yAxes: [{
ticks: { beginAtZero: true } //, min: 0, max: 100
}]
},
}
// Receive Kilobits per second
soundMeter.ReceiveBitRateChart = new Chart($("#line-"+ lineNum +"-AudioReceiveBitRate"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.receive_kilobits_per_second,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(168, 0, 0, 0.5)',
borderColor: 'rgba(168, 0, 0, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
soundMeter.ReceiveBitRateChart.lastValueBytesReceived = 0;
soundMeter.ReceiveBitRateChart.lastValueTimestamp = 0;
// Receive Packets per second
soundMeter.ReceivePacketRateChart = new Chart($("#line-"+ lineNum +"-AudioReceivePacketRate"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.receive_packets_per_second,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(168, 0, 0, 0.5)',
borderColor: 'rgba(168, 0, 0, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
soundMeter.ReceivePacketRateChart.lastValuePacketReceived = 0;
soundMeter.ReceivePacketRateChart.lastValueTimestamp = 0;
// Receive Packet Loss
soundMeter.ReceivePacketLossChart = new Chart($("#line-"+ lineNum +"-AudioReceivePacketLoss"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.receive_packet_loss,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(168, 99, 0, 0.5)',
borderColor: 'rgba(168, 99, 0, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
soundMeter.ReceivePacketLossChart.lastValuePacketLoss = 0;
soundMeter.ReceivePacketLossChart.lastValueTimestamp = 0;
// Receive Jitter
soundMeter.ReceiveJitterChart = new Chart($("#line-"+ lineNum +"-AudioReceiveJitter"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.receive_jitter,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(0, 38, 168, 0.5)',
borderColor: 'rgba(0, 38, 168, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// Receive Audio Levels
soundMeter.ReceiveLevelsChart = new Chart($("#line-"+ lineNum +"-AudioReceiveLevels"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.receive_audio_levels,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(140, 0, 168, 0.5)',
borderColor: 'rgba(140, 0, 168, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// Connect to Source
soundMeter.connectToSource(remoteAudioStream, function (e) {
if (e != null) return;
// Create remote SoundMeter
console.log("SoundMeter for RemoteAudio Connected, displaying levels for Line: " + lineNum);
soundMeter.levelsInterval = window.setInterval(function () {
// Calculate Levels
//value="0" max="1" high="0.25" (this seems low... )
var level = soundMeter.instant * 4.0;
if (level > 1) level = 1;
var instPercent = level * 100;
$("#line-" + lineNum + "-Speaker").css("height", instPercent.toFixed(2) +"%");
}, 50);
soundMeter.networkInterval = window.setInterval(function (){
// Calculate Network Conditions
if(audioReceiver != null) {
audioReceiver.getStats().then(function(stats) {
stats.forEach(function(report){
var theMoment = utcDateNow();
var ReceiveBitRateChart = soundMeter.ReceiveBitRateChart;
var ReceivePacketRateChart = soundMeter.ReceivePacketRateChart;
var ReceivePacketLossChart = soundMeter.ReceivePacketLossChart;
var ReceiveJitterChart = soundMeter.ReceiveJitterChart;
var ReceiveLevelsChart = soundMeter.ReceiveLevelsChart;
var elapsedSec = Math.floor((Date.now() - soundMeter.startTime)/1000);
if(report.type == "inbound-rtp"){
if(ReceiveBitRateChart.lastValueTimestamp == 0) {
ReceiveBitRateChart.lastValueTimestamp = report.timestamp;
ReceiveBitRateChart.lastValueBytesReceived = report.bytesReceived;
ReceivePacketRateChart.lastValueTimestamp = report.timestamp;
ReceivePacketRateChart.lastValuePacketReceived = report.packetsReceived;
ReceivePacketLossChart.lastValueTimestamp = report.timestamp;
ReceivePacketLossChart.lastValuePacketLoss = report.packetsLost;
return;
}
// Receive Kilobits Per second
var kbitsPerSec = (8 * (report.bytesReceived - ReceiveBitRateChart.lastValueBytesReceived))/1000;
ReceiveBitRateChart.lastValueTimestamp = report.timestamp;
ReceiveBitRateChart.lastValueBytesReceived = report.bytesReceived;
soundMeter.ReceiveBitRate.push({ value: kbitsPerSec, timestamp : theMoment});
ReceiveBitRateChart.data.datasets[0].data.push(kbitsPerSec);
ReceiveBitRateChart.data.labels.push("");
if(ReceiveBitRateChart.data.datasets[0].data.length > maxDataLength) {
ReceiveBitRateChart.data.datasets[0].data.splice(0,1);
ReceiveBitRateChart.data.labels.splice(0,1);
}
ReceiveBitRateChart.update();
// Receive Packets Per Second
var PacketsPerSec = (report.packetsReceived - ReceivePacketRateChart.lastValuePacketReceived);
ReceivePacketRateChart.lastValueTimestamp = report.timestamp;
ReceivePacketRateChart.lastValuePacketReceived = report.packetsReceived;
soundMeter.ReceivePacketRate.push({ value: PacketsPerSec, timestamp : theMoment});
ReceivePacketRateChart.data.datasets[0].data.push(PacketsPerSec);
ReceivePacketRateChart.data.labels.push("");
if(ReceivePacketRateChart.data.datasets[0].data.length > maxDataLength) {
ReceivePacketRateChart.data.datasets[0].data.splice(0,1);
ReceivePacketRateChart.data.labels.splice(0,1);
}
ReceivePacketRateChart.update();
// Receive Packet Loss
var PacketsLost = (report.packetsLost - ReceivePacketLossChart.lastValuePacketLoss);
ReceivePacketLossChart.lastValueTimestamp = report.timestamp;
ReceivePacketLossChart.lastValuePacketLoss = report.packetsLost;
soundMeter.ReceivePacketLoss.push({ value: PacketsLost, timestamp : theMoment});
ReceivePacketLossChart.data.datasets[0].data.push(PacketsLost);
ReceivePacketLossChart.data.labels.push("");
if(ReceivePacketLossChart.data.datasets[0].data.length > maxDataLength) {
ReceivePacketLossChart.data.datasets[0].data.splice(0,1);
ReceivePacketLossChart.data.labels.splice(0,1);
}
ReceivePacketLossChart.update();
// Receive Jitter
soundMeter.ReceiveJitter.push({ value: report.jitter, timestamp : theMoment});
ReceiveJitterChart.data.datasets[0].data.push(report.jitter);
ReceiveJitterChart.data.labels.push("");
if(ReceiveJitterChart.data.datasets[0].data.length > maxDataLength) {
ReceiveJitterChart.data.datasets[0].data.splice(0,1);
ReceiveJitterChart.data.labels.splice(0,1);
}
ReceiveJitterChart.update();
}
if(report.type == "track") {
// Receive Audio Levels
var levelPercent = (report.audioLevel * 100);
soundMeter.ReceiveLevels.push({ value: levelPercent, timestamp : theMoment});
ReceiveLevelsChart.data.datasets[0].data.push(levelPercent);
ReceiveLevelsChart.data.labels.push("");
if(ReceiveLevelsChart.data.datasets[0].data.length > maxDataLength)
{
ReceiveLevelsChart.data.datasets[0].data.splice(0,1);
ReceiveLevelsChart.data.labels.splice(0,1);
}
ReceiveLevelsChart.update();
}
});
});
}
} ,1000);
});
return soundMeter;
}
function StartLocalAudioMediaMonitoring(lineNum, session) {
console.log("Creating LocalAudio AudioContext on line " + lineNum);
// Create local SoundMeter
var soundMeter = new SoundMeter(session.id, lineNum);
if(soundMeter == null){
console.warn("AudioContext() LocalAudio not available... its fine.")
return null;
}
// Ready the getStats request
var localAudioStream = new MediaStream();
var audioSender = null;
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio"){
if(audioSender == null){
console.log("Adding Track to Monitor: ", RTCRtpSender.track.label);
localAudioStream.addTrack(RTCRtpSender.track);
audioSender = RTCRtpSender;
}
else {
console.log("Found another Track, but audioSender not null");
console.log(RTCRtpSender);
console.log(RTCRtpSender.track);
}
}
});
// Setup Charts
var maxDataLength = 100;
soundMeter.startTime = Date.now();
Chart.defaults.global.defaultFontSize = 12;
var ChatHistoryOptions = {
responsive: false,
maintainAspectRatio: false,
devicePixelRatio: 1,
animation: false,
scales: {
yAxes: [{
ticks: { beginAtZero: true }
}]
},
}
// Send Kilobits Per Second
soundMeter.SendBitRateChart = new Chart($("#line-"+ lineNum +"-AudioSendBitRate"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.send_kilobits_per_second,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(0, 121, 19, 0.5)',
borderColor: 'rgba(0, 121, 19, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
soundMeter.SendBitRateChart.lastValueBytesSent = 0;
soundMeter.SendBitRateChart.lastValueTimestamp = 0;
// Send Packets Per Second
soundMeter.SendPacketRateChart = new Chart($("#line-"+ lineNum +"-AudioSendPacketRate"), {
type: 'line',
data: {
labels: MakeDataArray("", maxDataLength),
datasets: [{
label: lang.send_packets_per_second,
data: MakeDataArray(0, maxDataLength),
backgroundColor: 'rgba(0, 121, 19, 0.5)',
borderColor: 'rgba(0, 121, 19, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
soundMeter.SendPacketRateChart.lastValuePacketSent = 0;
soundMeter.SendPacketRateChart.lastValueTimestamp = 0;
// Connect to Source
soundMeter.connectToSource(localAudioStream, function (e) {
if (e != null) return;
console.log("SoundMeter for LocalAudio Connected, displaying levels for Line: " + lineNum);
soundMeter.levelsInterval = window.setInterval(function () {
// Calculate Levels
//value="0" max="1" high="0.25" (this seems low... )
var level = soundMeter.instant * 4.0;
if (level > 1) level = 1;
var instPercent = level * 100;
$("#line-" + lineNum + "-Mic").css("height", instPercent.toFixed(2) +"%");
}, 50);
soundMeter.networkInterval = window.setInterval(function (){
// Calculate Network Conditions
// Sending Audio Track
if(audioSender != null) {
audioSender.getStats().then(function(stats) {
stats.forEach(function(report){
var theMoment = utcDateNow();
var SendBitRateChart = soundMeter.SendBitRateChart;
var SendPacketRateChart = soundMeter.SendPacketRateChart;
var elapsedSec = Math.floor((Date.now() - soundMeter.startTime)/1000);
if(report.type == "outbound-rtp"){
if(SendBitRateChart.lastValueTimestamp == 0) {
SendBitRateChart.lastValueTimestamp = report.timestamp;
SendBitRateChart.lastValueBytesSent = report.bytesSent;
SendPacketRateChart.lastValueTimestamp = report.timestamp;
SendPacketRateChart.lastValuePacketSent = report.packetsSent;
return;
}
// Send Kilobits Per second
var kbitsPerSec = (8 * (report.bytesSent - SendBitRateChart.lastValueBytesSent))/1000;
SendBitRateChart.lastValueTimestamp = report.timestamp;
SendBitRateChart.lastValueBytesSent = report.bytesSent;
soundMeter.SendBitRate.push({ value: kbitsPerSec, timestamp : theMoment});
SendBitRateChart.data.datasets[0].data.push(kbitsPerSec);
SendBitRateChart.data.labels.push("");
if(SendBitRateChart.data.datasets[0].data.length > maxDataLength) {
SendBitRateChart.data.datasets[0].data.splice(0,1);
SendBitRateChart.data.labels.splice(0,1);
}
SendBitRateChart.update();
// Send Packets Per Second
var PacketsPerSec = report.packetsSent - SendPacketRateChart.lastValuePacketSent;
SendPacketRateChart.lastValueTimestamp = report.timestamp;
SendPacketRateChart.lastValuePacketSent = report.packetsSent;
soundMeter.SendPacketRate.push({ value: PacketsPerSec, timestamp : theMoment});
SendPacketRateChart.data.datasets[0].data.push(PacketsPerSec);
SendPacketRateChart.data.labels.push("");
if(SendPacketRateChart.data.datasets[0].data.length > maxDataLength) {
SendPacketRateChart.data.datasets[0].data.splice(0,1);
SendPacketRateChart.data.labels.splice(0,1);
}
SendPacketRateChart.update();
}
if(report.type == "track") {
// Bug/security consern... this seems always to report "0"
// Possible reason: When applied to isolated streams, media metrics may allow an application to infer some characteristics of the isolated stream, such as if anyone is speaking (by watching the audioLevel statistic).
// console.log("Audio Sender: " + report.audioLevel);
}
});
});
}
} ,1000);
});
return soundMeter;
}
// Sounds Meter Class
// ==================
class SoundMeter {
constructor(sessionId, lineNum) {
var audioContext = null;
try {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
audioContext = new AudioContext();
}
catch(e) {
console.warn("AudioContext() LocalAudio not available... its fine.");
}
if (audioContext == null) return null;
this.lineNum = lineNum;
this.sessionId = sessionId;
this.levelsInterval = null;
this.networkInterval = null;
this.startTime = 0;
this.ReceiveBitRateChart = null;
this.ReceiveBitRate = [];
this.ReceivePacketRateChart = null;
this.ReceivePacketRate = [];
this.ReceivePacketLossChart = null;
this.ReceivePacketLoss = [];
this.ReceiveJitterChart = null;
this.ReceiveJitter = [];
this.ReceiveLevelsChart = null;
this.ReceiveLevels = [];
this.SendBitRateChart = null;
this.SendBitRate = [];
this.SendPacketRateChart = null;
this.SendPacketRate = [];
this.context = audioContext;
this.instant = 0.0;
this.script = audioContext.createScriptProcessor(2048, 1, 1);
const that = this;
this.script.onaudioprocess = function (event) {
const input = event.inputBuffer.getChannelData(0);
let i;
let sum = 0.0;
for (i = 0; i < input.length; ++i) {
sum += input[i] * input[i];
}
that.instant = Math.sqrt(sum / input.length);
}
}
connectToSource(stream, callback) {
console.log("SoundMeter connecting...");
try {
this.mic = this.context.createMediaStreamSource(stream);
this.mic.connect(this.script);
// necessary to make sample run, but should not be.
this.script.connect(this.context.destination);
callback(null);
}
catch(e) {
console.error(e); // Probably not audio track
callback(e);
}
}
stop() {
console.log("Disconnecting SoundMeter...");
try {
window.clearInterval(this.levelsInterval);
this.levelsInterval = null;
}
catch(e) { }
try {
window.clearInterval(this.networkInterval);
this.networkInterval = null;
}
catch(e) { }
this.mic.disconnect();
this.script.disconnect();
this.mic = null;
this.script = null;
try {
this.context.close();
}
catch(e) { }
this.context = null;
// Save to IndexDb
var lineObj = FindLineByNumber(this.lineNum);
var QosData = {
ReceiveBitRate: this.ReceiveBitRate,
ReceivePacketRate: this.ReceivePacketRate,
ReceivePacketLoss: this.ReceivePacketLoss,
ReceiveJitter: this.ReceiveJitter,
ReceiveLevels: this.ReceiveLevels,
SendBitRate: this.SendBitRate,
SendPacketRate: this.SendPacketRate,
}
SaveQosData(QosData, this.sessionId, lineObj.BuddyObj.identity);
}
}
function MeterSettingsOutput(audioStream, objectId, direction, interval){
var soundMeter = new SoundMeter(null, null);
soundMeter.startTime = Date.now();
soundMeter.connectToSource(audioStream, function (e) {
if (e != null) return;
console.log("SoundMeter Connected, displaying levels to:"+ objectId);
soundMeter.levelsInterval = window.setInterval(function () {
// Calculate Levels
//value="0" max="1" high="0.25" (this seems low... )
var level = soundMeter.instant * 4.0;
if (level > 1) level = 1;
var instPercent = level * 100;
$("#"+objectId).css(direction, instPercent.toFixed(2) +"%"); // Settings_MicrophoneOutput "width" 50
}, interval);
});
return soundMeter;
}
// QOS
// ===
function SaveQosData(QosData, sessionId, buddy){
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallQosData");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
var IDB = event.target.result;
// Create Object Store
if(IDB.objectStoreNames.contains("CallQos") == false){
var objectStore = IDB.createObjectStore("CallQos", { keyPath: "uID" });
objectStore.createIndex("sessionid", "sessionid", { unique: false });
objectStore.createIndex("buddy", "buddy", { unique: false });
objectStore.createIndex("QosData", "QosData", { unique: false });
}
else {
console.warn("IndexDB requested upgrade, but object store was in place");
}
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallQosData");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("CallQos") == false){
console.warn("IndexDB CallQosData.CallQos does not exists");
return;
}
IDB.onerror = function(event) {
console.error("IndexDB Error:", event);
}
// Prepare data to write
var data = {
uID: uID(),
sessionid: sessionId,
buddy: buddy,
QosData: QosData
}
// Commit Transaction
var transaction = IDB.transaction(["CallQos"], "readwrite");
var objectStoreAdd = transaction.objectStore("CallQos").add(data);
objectStoreAdd.onsuccess = function(event) {
console.log("Call CallQos Sucess: ", sessionId);
}
}
}
function DisplayQosData(sessionId){
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallQosData");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallQosData");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("CallQos") == false){
console.warn("IndexDB CallQosData.CallQos does not exists");
return;
}
var transaction = IDB.transaction(["CallQos"]);
var objectStoreGet = transaction.objectStore("CallQos").index('sessionid').getAll(sessionId);
objectStoreGet.onerror = function(event) {
console.error("IndexDB Get Error:", event);
}
objectStoreGet.onsuccess = function(event) {
if(event.target.result && event.target.result.length == 2){
// This is the correct data
var QosData0 = event.target.result[0].QosData;
// ReceiveBitRate: (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
// ReceiveJitter: (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
// ReceiveLevels: (9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
// ReceivePacketLoss: (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
// ReceivePacketRate: (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
// SendBitRate: []
// SendPacketRate: []
var QosData1 = event.target.result[1].QosData;
// ReceiveBitRate: []
// ReceiveJitter: []
// ReceiveLevels: []
// ReceivePacketLoss: []
// ReceivePacketRate: []
// SendBitRate: (9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
// SendPacketRate: (9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
Chart.defaults.global.defaultFontSize = 12;
var ChatHistoryOptions = {
responsive: true,
maintainAspectRatio: false,
animation: false,
scales: {
yAxes: [{
ticks: { beginAtZero: true } //, min: 0, max: 100
}],
xAxes: [{
display: false
}]
},
}
// ReceiveBitRateChart
var labelset = [];
var dataset = [];
var data = (QosData0.ReceiveBitRate.length > 0)? QosData0.ReceiveBitRate : QosData1.ReceiveBitRate;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var ReceiveBitRateChart = new Chart($("#cdr-AudioReceiveBitRate"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.receive_kilobits_per_second,
data: dataset,
backgroundColor: 'rgba(168, 0, 0, 0.5)',
borderColor: 'rgba(168, 0, 0, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// ReceivePacketRateChart
var labelset = [];
var dataset = [];
var data = (QosData0.ReceivePacketRate.length > 0)? QosData0.ReceivePacketRate : QosData1.ReceivePacketRate;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var ReceivePacketRateChart = new Chart($("#cdr-AudioReceivePacketRate"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.receive_packets_per_second,
data: dataset,
backgroundColor: 'rgba(168, 0, 0, 0.5)',
borderColor: 'rgba(168, 0, 0, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// AudioReceivePacketLossChart
var labelset = [];
var dataset = [];
var data = (QosData0.ReceivePacketLoss.length > 0)? QosData0.ReceivePacketLoss : QosData1.ReceivePacketLoss;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var AudioReceivePacketLossChart = new Chart($("#cdr-AudioReceivePacketLoss"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.receive_packet_loss,
data: dataset,
backgroundColor: 'rgba(168, 99, 0, 0.5)',
borderColor: 'rgba(168, 99, 0, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// AudioReceiveJitterChart
var labelset = [];
var dataset = [];
var data = (QosData0.ReceiveJitter.length > 0)? QosData0.ReceiveJitter : QosData1.ReceiveJitter;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var AudioReceiveJitterChart = new Chart($("#cdr-AudioReceiveJitter"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.receive_jitter,
data: dataset,
backgroundColor: 'rgba(0, 38, 168, 0.5)',
borderColor: 'rgba(0, 38, 168, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// AudioReceiveLevelsChart
var labelset = [];
var dataset = [];
var data = (QosData0.ReceiveLevels.length > 0)? QosData0.ReceiveLevels : QosData1.ReceiveLevels;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var AudioReceiveLevelsChart = new Chart($("#cdr-AudioReceiveLevels"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.receive_audio_levels,
data: dataset,
backgroundColor: 'rgba(140, 0, 168, 0.5)',
borderColor: 'rgba(140, 0, 168, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// SendPacketRateChart
var labelset = [];
var dataset = [];
var data = (QosData0.SendPacketRate.length > 0)? QosData0.SendPacketRate : QosData1.SendPacketRate;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var SendPacketRateChart = new Chart($("#cdr-AudioSendPacketRate"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.send_packets_per_second,
data: dataset,
backgroundColor: 'rgba(0, 121, 19, 0.5)',
borderColor: 'rgba(0, 121, 19, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
// AudioSendBitRateChart
var labelset = [];
var dataset = [];
var data = (QosData0.SendBitRate.length > 0)? QosData0.SendBitRate : QosData1.SendBitRate;
$.each(data, function(i,item){
labelset.push(moment.utc(item.timestamp.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat));
dataset.push(item.value);
});
var AudioSendBitRateChart = new Chart($("#cdr-AudioSendBitRate"), {
type: 'line',
data: {
labels: labelset,
datasets: [{
label: lang.send_kilobits_per_second,
data: dataset,
backgroundColor: 'rgba(0, 121, 19, 0.5)',
borderColor: 'rgba(0, 121, 19, 1)',
borderWidth: 1,
pointRadius: 1
}]
},
options: ChatHistoryOptions
});
} else {
console.warn("Result not expected", event.target.result);
}
}
}
}
function DeleteQosData(buddy){
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallQosData");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
// If this is the case, there will be no call recordings
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallQosData");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("CallQos") == false){
console.warn("IndexDB CallQosData.CallQos does not exists");
return;
}
IDB.onerror = function(event) {
console.error("IndexDB Error:", event);
}
// Loop and Delete
console.log("Deleting CallQosData: ", buddy);
var transaction = IDB.transaction(["CallQos"], "readwrite");
var objectStore = transaction.objectStore("CallQos");
var objectStoreGet = objectStore.index('buddy').getAll(buddy);
objectStoreGet.onerror = function(event) {
console.error("IndexDB Get Error:", event);
}
objectStoreGet.onsuccess = function(event) {
if(event.target.result && event.target.result.length > 0){
// There sre some rows to delete
$.each(event.target.result, function(i, item){
// console.log("Delete: ", item.uID);
try{
objectStore.delete(item.uID);
} catch(e){
console.log("Call CallQosData Delete failed: ", e);
}
});
}
}
}
}
// Presence / Subscribe
// ====================
function SubscribeAll() {
console.log("Subscribe to voicemail Messages...");
// conference, message-summary, dialog, presence, presence.winfo, xcap-diff, dialog.winfo, refer
// Voicemail notice
var vmOptions = { expires: 300 }
voicemailSubs = userAgent.subscribe(SipUsername + "@" + wssServer, 'message-summary', vmOptions); // message-summary = voicemail messages
voicemailSubs.on('notify', function (notification) {
// You have voicemail:
// Message-Account: sip:alice@example.com
// Messages-Waiting: no
// Fax-Message: 2/4
// Voice-Message: 0/0 (0/0) <-- new/old (new & urgent/ old & urgent)
var messagesWaitng = false;
$.each(notification.request.body.split("\n"), function (i, line) {
if(line.indexOf("Messages-Waiting:") != -1){
messagesWaitng = ($.trim(line.replace("Messages-Waiting:", "")) == "yes");
}
});
if(messagesWaitng){
// Notify user of voicemail
console.log("You have voicemail!");
}
});
// Dialog Subscription (This version isnt as nice as PIDF)
// var dialogOptions = { expires: 300, extraHeaders: ['Accept: application/dialog-info+xml'] }
// PIDF Subscription
var dialogOptions = { expires: 300, extraHeaders: ['Accept: application/pidf+xml'] }
// var dialogOptions = { expires: 300, extraHeaders: ['Accept: application/pidf+xml', 'application/xpidf+xml', 'application/simple-message-summary', 'application/im-iscomposing+xml'] }
// Start subscribe all
console.log("Starting Subscribe of all ("+ Buddies.length +") Extension Buddies...");
for(var b=0; b
");
for (var k = 0; k < messageprearr.length; k++) {
if (k == 0) {
// Send the RSA-encrypted AES key as first piece of the message
var messagePiece = messageIdent + "|" + messageprearr.length + "|" + parseInt(k) + "||" + messageprearr[k];
} else if (sendFileCheck == 0 && messageprearr[k] != '') {
var messagePiece = messageIdent + "|" + messageprearr.length + "|" + parseInt(k) + "||" + messageprearr[k];
} else if (sendFileCheck == 1 && sendFileChatErr == '') {
var messagePiece = messageIdent + "|" + messageprearr.length + "|" + parseInt(k) + "|" + upFileName + "|" + messageprearr[k];
} else if (sendFileCheck == 1 && sendFileChatErr != '') {
$("#sendFileFormChat").remove();
sendFileChatErr = '';
sendFileCheck = 0;
return;
}
if (k == 1) { firstPieceCheck = [messageIdent, 0]; }
if (k == (messageprearr.length - 1)) { lastPieceCheck = [messageIdent, 1]; }
SendChatMessageProc(buddy, buddyObj, messageIdent, messagePiece, messagetrim, firstPieceCheck, lastPieceCheck);
}
}
function SendChatMessageProc(buddy, buddyObj, messageIdent, messagePiece, messagetrim, firstPieceCheck, lastPieceCheck) {
var messageId = uID();
if (pubKeyCheck == 1) { pubKeyCheck = 0; $("#selectedFile").val(""); $("#sendFileLoader").remove(); return; }
sendFileChatErr = '';
$("#sendFileFormChat").on('submit', function(ev) {
ev.preventDefault();
$.ajax({
'async': false,
'global': false,
type: 'POST',
url: 'text-chat-upload-file.php',
data: new FormData(this),
dataType: "JSON",
contentType: false,
cache: false,
processData:false,
success: function(respdata) {
if (respdata.error != '') {
sendFileChatErr = respdata.error;
$("#sendFileFormChat").remove();
$("#sendFileLoader").remove();
alert("Error: " + respdata.error);
}
},
error: function(respdata) {
alert("An error occurred while sending the file!");
}
});
});
if (sendFileCheck == 1 && (firstPieceCheck[0] == messageIdent && firstPieceCheck[1] == 1)) {
$("#submitFileChat").click();
}
if (lastPieceCheck[0] == messageIdent && lastPieceCheck[1] == 1 && sendFileCheck == 1 && sendFileChatErr != '') {
$("#sendFileFormChat").remove();
$("#sendFileLoader").remove();
sendFileChatErr = '';
sendFileCheck = 0;
return;
}
if (buddyObj.type == "extension" || buddyObj.type == "group") {
var chatBuddy = buddyObj.ExtNo + "@" + wssServer;
console.log("MESSAGE: "+ chatBuddy + " (extension)");
var messageObj = userAgent.message(chatBuddy, messagePiece);
messageObj.data.direction = "outbound";
messageObj.data.messageId = messageId;
messageObj.on("accepted", function (response, cause){
if(response.status_code == 202) {
console.log("Message Accepted:", messageId);
// Update DB
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "MSG" && item.ItemId == messageId) {
// Found
item.Sent = true;
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
RefreshStream(buddyObj);
}
} else {
console.warn("Message Error", response.status_code, cause);
// Update DB
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "MSG" && item.ItemId == messageId) {
// Found
item.Sent = false;
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
RefreshStream(buddyObj);
}
}
});
// Custom Web hook
if (typeof web_hook_on_message !== 'undefined') web_hook_on_message(messageObj);
}
if (lastPieceCheck[0] == messageIdent && lastPieceCheck[1] == 1) {
// Update Stream
var DateTime = moment.utc().format("YYYY-MM-DD HH:mm:ss UTC");
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream == null) currentStream = InitinaliseStream(buddy);
// Add New Message
var newMessageJson = {
ItemId: messageId,
ItemType: "MSG",
ItemDate: DateTime,
SrcUserId: profileUserID,
Src: "\""+ profileName +"\" <"+ profileUser +">",
DstUserId: buddy,
Dst: "",
MessageData: messagetrim
}
// If a file is sent, add the sent file section
if (sendFileCheck == 1) {
$("#sendFileFormChat").remove();
sendFileCheck = 0;
var newMessageId = uID();
var newDateTime = moment.utc().format("YYYY-MM-DD HH:mm:ss UTC");
var newFileMessageJson = {
ItemId: newMessageId,
ItemType: "FILE",
ItemDate: newDateTime,
SrcUserId: profileUserID,
Src: "\""+ profileName +"\" <"+ profileUser +">",
DstUserId: buddy,
Dst: buddyObj.ExtNo,
SentFileName: upFileName,
MessageData: "Download file"
}
if (sendFileChatErr == '') {
currentStream.DataCollection.push(newFileMessageJson);
}
} else { $("#sendFileFormChat").remove(); }
currentStream.DataCollection.push(newMessageJson);
currentStream.TotalRows = currentStream.DataCollection.length;
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
}
// Post Add Activity
if (lastPieceCheck[0] == messageIdent && lastPieceCheck[1] == 1) {
$("#sendFileLoader").remove();
$("#contact-" + buddy + "-ChatMessage").val("");
}
$("#contact-" + buddy + "-emoji-menu").hide();
if(buddyObj.recognition != null){
buddyObj.recognition.abort();
buddyObj.recognition = null;
}
RefreshStream(buddyObj);
}
function ReceiveMessage(message) {
var callerID = message.remoteIdentity.displayName;
var did = message.remoteIdentity.uri.user;
console.log("New Incoming Message!", "\""+ callerID +"\" <"+ did +">");
message.data.direction = "inbound";
if(did.length > DidLength) {
// Contacts cannot receive Text Messages, because they cannot reply
// This may change with FAX, Email, WhatsApp etc
console.warn("DID length greater then extensions length")
return;
}
var CurrentCalls = countSessions("0");
var buddyObj = FindBuddyByDid(did);
// Make new contact if it's not there
if(buddyObj == null) {
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json == null) json = InitUserBuddies();
// Add Extension
var id = uID();
var dateNow = utcDateNow();
json.DataCollection.push({
Type: "extension",
LastActivity: dateNow,
ExtensionNumber: did,
MobileNumber: "",
ContactNumber1: "",
ContactNumber2: "",
uID: id,
cID: null,
gID: null,
DisplayName: callerID,
Position: "",
Description: "",
Email: "",
MemberCount: 0
});
buddyObj = new Buddy("extension", id, callerID, did, "", "", "", dateNow, "", "");
AddBuddy(buddyObj, true, (CurrentCalls==0), true);
// Update Size
json.TotalRows = json.DataCollection.length;
// Save To DB
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
}
var encryptedtext = message.body;
var originalMessageArr = encryptedtext.split("|");
if (originalMessageArr[3] != '' && typeof originalMessageArr[3] != 'undefined' && originalMessageArr[3] != null) {
var fileSentDuringChat = 1;
var recFileName = originalMessageArr[3];
} else {
var fileSentDuringChat = 0;
var recFileName = '';
}
var currentMId = originalMessageArr[0];
var totalPieceNo = parseInt(originalMessageArr[1]);
var currentPieceNo = parseInt(originalMessageArr[2]);
// Reassemble the original message and decrypt it
if (currentPieceNo == 0) {
if (splitMessage.hasOwnProperty(currentMId)) {
if (currentPieceNo == 0) {
var aesPayload = originalMessageArr[4];
var newdecrypt = new JSEncrypt();
newdecrypt.setPrivateKey(currentChatPrivKey);
var decAESKeyCon = newdecrypt.decrypt(aesPayload);
splitMessage[currentMId].aeskeyandiv = decAESKeyCon;
} else {
splitMessage[currentMId][currentPieceNo] = originalMessageArr[4];
}
} else {
if (currentPieceNo == 0) {
var aesPayload = originalMessageArr[4];
var newdecrypt = new JSEncrypt();
newdecrypt.setPrivateKey(currentChatPrivKey);
var decAESKeyCon = newdecrypt.decrypt(aesPayload);
splitMessage[currentMId] = { "aeskeyandiv": decAESKeyCon };
} else {
splitMessage[currentMId] = { [currentPieceNo]: originalMessageArr[4] };
}
}
return;
} else if (currentPieceNo < (totalPieceNo - 1)) {
if (splitMessage.hasOwnProperty(currentMId)) {
splitMessage[currentMId][currentPieceNo] = originalMessageArr[4];
} else {
splitMessage[currentMId] = { [currentPieceNo]: originalMessageArr[4] };
}
return;
} else if (currentPieceNo == (totalPieceNo - 1)) {
if (splitMessage.hasOwnProperty(currentMId)) {
splitMessage[currentMId][currentPieceNo] = originalMessageArr[4];
} else {
splitMessage[currentMId] = { [currentPieceNo]: originalMessageArr[4] };
}
if (Object.keys(splitMessage[currentMId]).length == totalPieceNo) {
var decryptAesKey = splitMessage[currentMId]["aeskeyandiv"];
delete splitMessage[currentMId]["aeskeyandiv"];
var origMessageEnc = '';
var orderedMPieces = Object.keys(splitMessage[currentMId]).sort().reduce(function(obj, key) {
obj[key] = splitMessage[currentMId][key];
return obj;
},{});
Object.keys(orderedMPieces).forEach(function(key, index) {
origMessageEnc += splitMessage[currentMId][key];
});
var originalMessage = decryptAES(origMessageEnc, decryptAesKey);
delete splitMessage[currentMId];
} else { return; }
}
var messageId = uID();
var DateTime = utcDateNow();
// Get the actual person sending (since all group messages come from the group)
var ActualSender = "";
if(buddyObj.type == "group") {
var assertedIdentity = message.request.headers["P-Asserted-Identity"][0].raw; // Name Surname
var bits = assertedIdentity.split(" <");
var CallerID = bits[0];
var CallerIDNum = bits[1].replace(">", "");
ActualSender = CallerID; // P-Asserted-Identity;
}
// Current stream
var currentStream = JSON.parse(localDB.getItem(buddyObj.identity + "-stream"));
if(currentStream == null) currentStream = InitinaliseStream(buddyObj.identity);
// Add new message
var newMessageJson = {
ItemId: messageId,
ItemType: "MSG",
ItemDate: DateTime,
SrcUserId: buddyObj.identity,
Src: "\""+ buddyObj.CallerIDName +"\" <"+ buddyObj.ExtNo +">",
DstUserId: profileUserID,
Dst: "",
MessageData: originalMessage
}
// If a file is received, add the received file section
if (fileSentDuringChat == 1 && recFileName != '') {
fileSentDuringChat = 0;
var newMessageId = uID();
var newDateTime = moment.utc().format("YYYY-MM-DD HH:mm:ss UTC");
var newFileMessageJson = {
ItemId: newMessageId,
ItemType: "FILE",
ItemDate: newDateTime,
SrcUserId: buddyObj.identity,
Src: "\""+ buddyObj.CallerIDName +"\" <"+ buddyObj.ExtNo +">",
DstUserId: profileUserID,
Dst: profileUser,
ReceivedFileName: recFileName,
MessageData: "Download file"
}
currentStream.DataCollection.push(newFileMessageJson);
}
currentStream.DataCollection.push(newMessageJson);
currentStream.TotalRows = currentStream.DataCollection.length;
localDB.setItem(buddyObj.identity + "-stream", JSON.stringify(currentStream));
// Update Last Activity
// ====================
UpdateBuddyActivity(buddyObj.identity);
RefreshStream(buddyObj);
// Handle Stream Not visible
// =========================
var streamVisible = $("#stream-"+ buddyObj.identity).is(":visible");
if (!streamVisible) {
// Add or Increase the Badge
IncreaseMissedBadge(buddyObj.identity);
if ("Notification" in window) {
if (Notification.permission === "granted") {
var imageUrl = getPicture(buddyObj.identity);
var noticeOptions = { body: originalMessage.substring(0, 250), icon: imageUrl }
var inComingChatNotification = new Notification(lang.message_from + " : " + buddyObj.CallerIDName, noticeOptions);
inComingChatNotification.onclick = function (event) {
// Show Message
SelectBuddy(buddyObj.identity);
}
}
}
// Play Alert
console.log("Audio:", audioBlobs.Alert.url);
var rinnger = new Audio(audioBlobs.Alert.blob);
rinnger.preload = "auto";
rinnger.loop = false;
rinnger.oncanplaythrough = function(e) {
if (typeof rinnger.sinkId !== 'undefined' && getRingerOutputID() != "default") {
rinnger.setSinkId(getRingerOutputID()).then(function() {
console.log("Set sinkId to:", getRingerOutputID());
}).catch(function(e){
console.warn("Failed not apply setSinkId.", e);
});
}
// If there has been no interaction with the page at all... this page will not work
rinnger.play().then(function(){
// Audio Is Playing
}).catch(function(e){
console.warn("Unable to play audio file.", e);
});
}
message.data.rinngerObj = rinnger; // Will be attached to this object until its disposed.
} else {
// Message window is active.
}
}
function AddCallMessage(buddy, session, reasonCode, reasonText) {
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream == null) currentStream = InitinaliseStream(buddy);
var CallEnd = moment.utc(); // Take Now as the Hangup Time
var callDuration = 0;
var totalDuration = 0;
var ringTime = 0;
var CallStart = moment.utc(session.data.callstart.replace(" UTC", "")); // Actual start (both inbound and outbound)
var CallAnswer = null; // On Accept when inbound, Remote Side when Outbound
if(session.startTime){
// The time when WE answered the call (May be null - no answer)
// or
// The time when THEY answered the call (May be null - no answer)
CallAnswer = moment.utc(session.startTime); // Local Time gets converted to UTC
callDuration = moment.duration(CallEnd.diff(CallAnswer));
ringTime = moment.duration(CallAnswer.diff(CallStart));
}
totalDuration = moment.duration(CallEnd.diff(CallStart));
console.log(session.data.reasonCode + "("+ session.data.reasonText +")")
var srcId = "";
var srcCallerID = "";
var dstId = ""
var dstCallerID = "";
if(session.data.calldirection == "inbound") {
srcId = buddy;
dstId = profileUserID;
srcCallerID = "<"+ session.remoteIdentity.uri.user +"> "+ session.remoteIdentity.displayName;
dstCallerID = "<"+ profileUser+"> "+ profileName;
} else if(session.data.calldirection == "outbound") {
srcId = profileUserID;
dstId = buddy;
srcCallerID = "<"+ profileUser+"> "+ profileName;
dstCallerID = session.remoteIdentity.uri.user;
}
var callDirection = session.data.calldirection;
var withVideo = session.data.withvideo;
var sessionId = session.id;
var hanupBy = session.data.terminateby;
var newMessageJson = {
CdrId: uID(),
ItemType: "CDR",
ItemDate: CallStart.format("YYYY-MM-DD HH:mm:ss UTC"),
CallAnswer: (CallAnswer)? CallAnswer.format("YYYY-MM-DD HH:mm:ss UTC") : null,
CallEnd: CallEnd.format("YYYY-MM-DD HH:mm:ss UTC"),
SrcUserId: srcId,
Src: srcCallerID,
DstUserId: dstId,
Dst: dstCallerID,
RingTime: (ringTime != 0)? ringTime.asSeconds() : 0,
Billsec: (callDuration != 0)? callDuration.asSeconds() : 0,
TotalDuration: (totalDuration != 0)? totalDuration.asSeconds() : 0,
ReasonCode: reasonCode,
ReasonText: reasonText,
WithVideo: withVideo,
SessionId: sessionId,
CallDirection: callDirection,
Terminate: hanupBy,
// CRM
MessageData: null,
Tags: [],
//Reporting
Transfers: (session.data.transfer)? session.data.transfer : [],
Mutes: (session.data.mute)? session.data.mute : [],
Holds: (session.data.hold)? session.data.hold : [],
Recordings: (session.data.recordings)? session.data.recordings : [],
ConfCalls: (session.data.confcalls)? session.data.confcalls : [],
QOS: []
}
console.log("New CDR", newMessageJson);
currentStream.DataCollection.push(newMessageJson);
currentStream.TotalRows = currentStream.DataCollection.length;
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
UpdateBuddyActivity(buddy);
}
function SendImageDataMessage(buddy, ImgDataUrl) {
if (userAgent == null) return;
if (!userAgent.isRegistered()) return;
// Ajax Upload
// ===========
var DateTime = moment.utc().format("YYYY-MM-DD HH:mm:ss UTC");
var formattedMessage = ' ';
var messageString = ""
+ "" + DateTime + "
"
+ " "
+ "" + formattedMessage + "
"
+ "
";
$("#contact-" + buddy + "-ChatHistory").append(messageString);
updateScroll(buddy);
ImageEditor_Cancel(buddy);
UpdateBuddyActivity(buddy);
}
function SendFileDataMessage(buddy, FileDataUrl, fileName, fileSize) {
if (userAgent == null) return;
if (!userAgent.isRegistered()) return;
var fileID = uID();
// Ajax Upload
// ===========
$.ajax({
type:'POST',
url: '/api/',
data: ""+ FileDataUrl +" ",
xhr: function(e) {
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',function(event){
var percent = (event.loaded / event.total) * 100;
console.log("Progress for upload to "+ buddy +" ("+ fileID +"):"+ percent);
$("#FileProgress-Bar-"+ fileID).css("width", percent +"%");
}, false);
}
return myXhr;
},
success:function(data, status, jqXHR){
// console.log(data);
$("#FileUpload-"+ fileID).html("Sent");
$("#FileProgress-"+ fileID).hide();
$("#FileProgress-Bar-"+ fileID).css("width", "0%");
},
error: function(data, status, error){
// console.log(data);
$("#FileUpload-"+ fileID).html("Failed ("+ data.status +")");
$("#FileProgress-"+ fileID).hide();
$("#FileProgress-Bar-"+ fileID).css("width", "100%");
}
});
// Add To Message Stream
// =====================
var DateTime = utcDateNow();
var showReview = false;
var fileIcon = ' ';
// Image Icons
if(fileName.toLowerCase().endsWith(".png")) {
fileIcon = ' ';
showReview = true;
}
if(fileName.toLowerCase().endsWith(".jpg")) {
fileIcon = ' ';
showReview = true;
}
if(fileName.toLowerCase().endsWith(".jpeg")) {
fileIcon = ' ';
showReview = true;
}
if(fileName.toLowerCase().endsWith(".bmp")) {
fileIcon = ' ';
showReview = true;
}
if(fileName.toLowerCase().endsWith(".gif")) {
fileIcon = ' ';
showReview = true;
}
// video Icons
if(fileName.toLowerCase().endsWith(".mov")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".avi")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".mpeg")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".mp4")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".mvk")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".webm")) fileIcon = ' ';
// Audio Icons
if(fileName.toLowerCase().endsWith(".wav")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".mp3")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".ogg")) fileIcon = ' ';
// Compressed Icons
if(fileName.toLowerCase().endsWith(".zip")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".rar")) fileIcon = ' ';
if(fileName.toLowerCase().endsWith(".tar.gz")) fileIcon = ' ';
// Pdf Icons
if(fileName.toLowerCase().endsWith(".pdf")) fileIcon = ' ';
var formattedMessage = "Sending : "+ fileIcon +" "+ fileName +"
"
formattedMessage += ""
if(showReview){
formattedMessage += "";
}
var messageString = ""
+ "" + DateTime + "
"
+ " "
+ "" + formattedMessage + "
"
+ "
";
$("#contact-" + buddy + "-ChatHistory").append(messageString);
updateScroll(buddy);
ImageEditor_Cancel(buddy);
// Update Last Activity
// ====================
UpdateBuddyActivity(buddy);
}
function updateLineScroll(lineNum) {
RefreshLineActivity(lineNum);
var element = $("#line-"+ lineNum +"-CallDetails").get(0);
element.scrollTop = element.scrollHeight;
}
function updateScroll(buddy) {
var history = $("#contact-"+ buddy +"-ChatHistory");
if(history.children().length > 0) history.children().last().get(0).scrollIntoView(false);
history.get(0).scrollTop = history.get(0).scrollHeight;
}
function PreviewImage(obj){
$.jeegoopopup.close();
var previewimgHtml = '';
$.jeegoopopup.open({
title: 'Preview Image',
html: previewimgHtml,
width: '800',
height: '600',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
// Missed Item Notification
// ========================
function IncreaseMissedBadge(buddy) {
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj == null) return;
// Up the Missed Count
// ===================
buddyObj.missed += 1;
// Take Out
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json != null) {
$.each(json.DataCollection, function (i, item) {
if(item.uID == buddy || item.cID == buddy || item.gID == buddy){
item.missed = item.missed +1;
return false;
}
});
// Put Back
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
}
// Update Badge
// ============
$("#contact-" + buddy + "-missed").text(buddyObj.missed);
$("#contact-" + buddy + "-missed").show();
console.log("Set Missed badge for "+ buddy +" to: "+ buddyObj.missed);
}
function UpdateBuddyActivity(buddy){
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj == null) return;
// Update Last Activity Time
// =========================
var timeStamp = utcDateNow();
buddyObj.lastActivity = timeStamp;
console.log("Last Activity is now: "+ timeStamp);
// Take Out
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json != null) {
$.each(json.DataCollection, function (i, item) {
if(item.uID == buddy || item.cID == buddy || item.gID == buddy){
item.LastActivity = timeStamp;
return false;
}
});
// Put Back
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
}
// List Update
// ===========
UpdateBuddyList();
}
function ClearMissedBadge(buddy) {
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj == null) return;
buddyObj.missed = 0;
// Take Out
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json != null) {
$.each(json.DataCollection, function (i, item) {
if(item.uID == buddy || item.cID == buddy || item.gID == buddy){
item.missed = 0;
return false;
}
});
// Put Back
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
}
$("#contact-" + buddy + "-missed").text(buddyObj.missed);
$("#contact-" + buddy + "-missed").hide(400);
}
// Outbound Calling
// ================
function VideoCall(lineObj, dialledNumber) {
if (userAgent == null) return;
if (!userAgent.isRegistered()) return;
if(lineObj == null) return;
if(HasAudioDevice == false){
Alert(lang.alert_no_microphone);
return;
}
if(HasVideoDevice == false){
console.warn("No video devices (webcam) found, switching to audio call.");
AudioCall(lineObj, dialledNumber);
return;
}
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var spdOptions = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: { deviceId : "default" },
video: { deviceId : "default" }
}
}
}
// Configure Audio
var currentAudioDevice = getAudioSrcID();
if(currentAudioDevice != "default"){
var confirmedAudioDevice = false;
for (var i = 0; i < AudioinputDevices.length; ++i) {
if(currentAudioDevice == AudioinputDevices[i].deviceId) {
confirmedAudioDevice = true;
break;
}
}
if(confirmedAudioDevice) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.deviceId = { exact: currentAudioDevice }
}
else {
console.warn("The audio device you used before is no longer available, default settings applied.");
localDB.setItem("AudioSrcId", "default");
}
}
// Add additional Constraints
if(supportedConstraints.autoGainControl) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.autoGainControl = AutoGainControl;
}
if(supportedConstraints.echoCancellation) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.echoCancellation = EchoCancellation;
}
if(supportedConstraints.noiseSuppression) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.noiseSuppression = NoiseSuppression;
}
// Configure Video
var currentVideoDevice = getVideoSrcID();
if(currentVideoDevice != "default"){
var confirmedVideoDevice = false;
for (var i = 0; i < VideoinputDevices.length; ++i) {
if(currentVideoDevice == VideoinputDevices[i].deviceId) {
confirmedVideoDevice = true;
break;
}
}
if(confirmedVideoDevice){
spdOptions.sessionDescriptionHandlerOptions.constraints.video.deviceId = { exact: currentVideoDevice }
}
else {
console.warn("The video device you used before is no longer available, default settings applied.");
localDB.setItem("VideoSrcId", "default"); // resets for later and subsequent calls
}
}
// Add additional Constraints
if(supportedConstraints.frameRate && maxFrameRate != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.frameRate = maxFrameRate;
}
if(supportedConstraints.height && videoHeight != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.height = videoHeight;
}
console.log(supportedConstraints)
console.log(supportedConstraints.aspectRatio)
console.log(videoAspectRatio)
if(supportedConstraints.aspectRatio && videoAspectRatio != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.aspectRatio = videoAspectRatio;
}
$("#line-" + lineObj.LineNumber + "-msg").html(lang.starting_video_call);
$("#line-" + lineObj.LineNumber + "-timer").show();
// Invite
console.log("INVITE (video): " + dialledNumber + "@" + wssServer, spdOptions);
lineObj.SipSession = userAgent.invite("sip:" + dialledNumber + "@" + wssServer, spdOptions);
var startTime = moment.utc();
lineObj.SipSession.data.line = lineObj.LineNumber;
lineObj.SipSession.data.buddyId = lineObj.BuddyObj.identity;
lineObj.SipSession.data.calldirection = "outbound";
lineObj.SipSession.data.dst = dialledNumber;
lineObj.SipSession.data.callstart = startTime.format("YYYY-MM-DD HH:mm:ss UTC");
lineObj.SipSession.data.callTimer = window.setInterval(function(){
var now = moment.utc();
var duration = moment.duration(now.diff(startTime));
$("#line-" + lineObj.LineNumber + "-timer").html(formatShortDuration(duration.asSeconds()));
}, 1000);
lineObj.SipSession.data.VideoSourceDevice = getVideoSrcID();
lineObj.SipSession.data.AudioSourceDevice = getAudioSrcID();
lineObj.SipSession.data.AudioOutputDevice = getAudioOutputID();
lineObj.SipSession.data.terminateby = "them";
lineObj.SipSession.data.withvideo = true;
updateLineScroll(lineObj.LineNumber);
// Do Necessary UI Wireup
wireupVideoSession(lineObj);
// Custom Web hook
if(typeof web_hook_on_invite !== 'undefined') web_hook_on_invite(lineObj.SipSession);
}
function ComposeEmail(buddy, obj, event) {
event.stopPropagation();
SelectBuddy(buddy);
var buddyObj = FindBuddyByIdentity(buddy);
$("#roundcubeFrame").remove();
$("#rightContent").show();
$(".streamSelected").each(function() { $(this).css("display", "none"); });
$("#rightContent").append('');
var rcDomain = '';
var rcBasicAuthUser = '';
var rcBasicAuthPass = '';
var rcUsername = '';
var rcPasswd = '';
$.ajax({
'async': false,
'global': false,
type: "POST",
url: "get-email-info.php",
dataType: "JSON",
data: {
username: userName,
s_ajax_call: validateSToken
},
success: function(datafromdb) {
rcDomain = datafromdb.rcdomain;
rcBasicAuthUser = encodeURIComponent(datafromdb.rcbasicauthuser);
rcBasicAuthPass = encodeURIComponent(datafromdb.rcbasicauthpass);
rcUsername = datafromdb.rcuser;
rcPasswd = datafromdb.rcpassword;
},
error: function(datafromdb) {
alert("An error occurred while trying to retrieve data from the database!");
}
});
if (rcBasicAuthUser != '' && rcBasicAuthPass != '') {
var loginURL = "https://"+ rcBasicAuthUser +":"+ rcBasicAuthPass +"@"+ rcDomain +"/";
var composeURL = "https://"+ rcBasicAuthUser +":"+ rcBasicAuthPass +"@"+ rcDomain +"/?_task=mail&_action=compose&_to="+ encodeURIComponent(buddyObj.Email) +"";
} else {
var loginURL = "https://"+ rcDomain +"/";
var composeURL = "https://"+ rcDomain +"/?_task=mail&_action=compose&_to="+ encodeURIComponent(buddyObj.Email) +"";
}
var form = '';
$("#roundcubeFrame").append(form);
if (RCLoginCheck == 0) {
$("#submitButton").click();
RCLoginCheck = 1;
if (rcBasicAuthUser != '' && rcBasicAuthPass != '') {
if (confirm('You are about to log in to the site "'+ rcDomain +'" with the username "'+ rcBasicAuthUser +'".')) {
$("#roundcubeFrame").attr("src", composeURL);
}
} else { setTimeout(function() { $("#roundcubeFrame").attr("src", composeURL); }, 1000); }
} else { $("#roundcubeFrame").attr("src", composeURL); }
}
function AudioCallMenu(buddy, obj){
if (($(window).width() - event.pageX) > 54) { var leftPos = event.pageX - 222; } else { var leftPos = event.pageX - 276; }
if (($(window).height() - event.pageY) > 140) { var topPos = event.pageY + 27; } else { var topPos = event.pageY - 80; }
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj.type == "extension") {
// Extension
var menu = "";
var consoleLogContent = "Menu click AudioCall("+ buddy +", ";
} else if (buddyObj.type == "contact") {
// Contact
var menu = "";
var consoleLogContent = "Menu click AudioCall("+ buddy +", ";
} else if(buddyObj.type == "group") {
var menu = "";
var consoleLogContent = "Menu click AudioCallGroup("+ buddy +", ";
}
$.jeegoopopup.open({
html: menu,
width: 'auto',
height: 'auto',
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: false,
resizable: false,
fadeIn: 0
});
$("#quickCallTable").on("click", ".quickNumDialRow", function() {
var NumberToDial = $(this).closest("tr").find("span.quickNumToDial").html();
console.log(consoleLogContent + NumberToDial +")");
DialByLine("audio", buddy, NumberToDial);
});
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
function AudioCall(lineObj, dialledNumber) {
if(userAgent == null) return;
if(userAgent.isRegistered() == false) return;
if(lineObj == null) return;
if(HasAudioDevice == false){
Alert(lang.alert_no_microphone);
return;
}
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var spdOptions = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: { deviceId : "default" },
video: false
}
}
}
// Configure Audio
var currentAudioDevice = getAudioSrcID();
if(currentAudioDevice != "default"){
var confirmedAudioDevice = false;
for (var i = 0; i < AudioinputDevices.length; ++i) {
if(currentAudioDevice == AudioinputDevices[i].deviceId) {
confirmedAudioDevice = true;
break;
}
}
if(confirmedAudioDevice) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.deviceId = { exact: currentAudioDevice }
}
else {
console.warn("The audio device you used before is no longer available, default settings applied.");
localDB.setItem("AudioSrcId", "default");
}
}
// Add additional Constraints
if(supportedConstraints.autoGainControl) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.autoGainControl = AutoGainControl;
}
if(supportedConstraints.echoCancellation) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.echoCancellation = EchoCancellation;
}
if(supportedConstraints.noiseSuppression) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.noiseSuppression = NoiseSuppression;
}
$("#line-" + lineObj.LineNumber + "-msg").html(lang.starting_audio_call);
$("#line-" + lineObj.LineNumber + "-timer").show();
// Invite
console.log("INVITE (audio): " + dialledNumber + "@" + wssServer);
lineObj.SipSession = userAgent.invite("sip:" + dialledNumber + "@" + wssServer, spdOptions);
var startTime = moment.utc();
lineObj.SipSession.data.line = lineObj.LineNumber;
lineObj.SipSession.data.buddyId = lineObj.BuddyObj.identity;
lineObj.SipSession.data.calldirection = "outbound";
lineObj.SipSession.data.dst = dialledNumber;
lineObj.SipSession.data.callstart = startTime.format("YYYY-MM-DD HH:mm:ss UTC");
lineObj.SipSession.data.callTimer = window.setInterval(function(){
var now = moment.utc();
var duration = moment.duration(now.diff(startTime));
$("#line-" + lineObj.LineNumber + "-timer").html(formatShortDuration(duration.asSeconds()));
}, 1000);
lineObj.SipSession.data.VideoSourceDevice = null;
lineObj.SipSession.data.AudioSourceDevice = getAudioSrcID();
lineObj.SipSession.data.AudioOutputDevice = getAudioOutputID();
lineObj.SipSession.data.terminateby = "them";
lineObj.SipSession.data.withvideo = false;
updateLineScroll(lineObj.LineNumber);
// Do Necessary UI Wireup
wireupAudioSession(lineObj);
// Custom Web hook
if(typeof web_hook_on_invite !== 'undefined') web_hook_on_invite(lineObj.SipSession);
}
// Sessions & During Call Activity
// ===============================
function getSession(buddy) {
if(userAgent == null) {
console.warn("userAgent is null");
return;
}
if(userAgent.isRegistered() == false) {
console.warn("userAgent is not registered");
return;
}
var rtnSession = null;
$.each(userAgent.sessions, function (i, session) {
if(session.data.buddyId == buddy) {
rtnSession = session;
return false;
}
});
return rtnSession;
}
function countSessions(id){
var rtn = 0;
if(userAgent == null) {
console.warn("userAgent is null");
return 0;
}
$.each(userAgent.sessions, function (i, session) {
if(id != session.id) rtn ++;
});
return rtn;
}
function StartRecording(lineNum){
if(CallRecordingPolicy == "disabled") {
console.warn("Policy Disabled: Call Recording");
return;
}
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null) return;
$("#line-"+ lineObj.LineNumber +"-btn-start-recording").hide();
$("#line-"+ lineObj.LineNumber +"-btn-stop-recording").show();
var session = lineObj.SipSession;
if(session == null){
console.warn("Could not find session");
return;
}
var id = uID();
if(!session.data.recordings) session.data.recordings = [];
session.data.recordings.push({
uID: id,
startTime: utcDateNow(),
stopTime: utcDateNow(),
});
if(!session.data.mediaRecorder){
console.log("Creating call recorder...");
var recordStream = new MediaStream();
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
console.log("Adding sender audio track to record:", RTCRtpSender.track.label);
recordStream.addTrack(RTCRtpSender.track);
}
});
pc.getReceivers().forEach(function (RTCRtpReceiver) {
if(RTCRtpReceiver.track && RTCRtpReceiver.track.kind == "audio") {
console.log("Adding receiver audio track to record:", RTCRtpReceiver.track.label);
recordStream.addTrack(RTCRtpReceiver.track);
}
if(session.data.withvideo){
if(RTCRtpReceiver.track && RTCRtpReceiver.track.kind == "video") {
console.log("Adding receiver video track to record:", RTCRtpReceiver.track.label);
recordStream.addTrack(RTCRtpReceiver.track);
}
}
});
// Resample the Video Recording
if(session.data.withvideo){
var recordingWidth = 640;
var recordingHeight = 360;
var pnpVideSize = 100;
if(RecordingVideoSize == "HD"){
recordingWidth = 1280;
recordingHeight = 720;
pnpVideSize = 144;
}
if(RecordingVideoSize == "FHD"){
recordingWidth = 1920;
recordingHeight = 1080;
pnpVideSize = 240;
}
// them-pnp
var pnpVideo = $("#line-" + lineObj.LineNumber + "-localVideo").get(0);
var mainVideo = $("#line-" + lineObj.LineNumber + "-remoteVideo").get(0);
if(RecordingLayout == "us-pnp"){
pnpVideo = $("#line-" + lineObj.LineNumber + "-remoteVideo").get(0);
mainVideo = $("#line-" + lineObj.LineNumber + "-localVideo").get(0);
}
var recordingCanvas = $(' ').get(0);
recordingCanvas.width = (RecordingLayout == "side-by-side")? (recordingWidth * 2) + 5: recordingWidth;
recordingCanvas.height = recordingHeight;
var recordingContext = recordingCanvas.getContext("2d");
window.clearInterval(session.data.recordingRedrawInterval);
session.data.recordingRedrawInterval = window.setInterval(function(){
// Main Video
var videoWidth = (mainVideo.videoWidth > 0)? mainVideo.videoWidth : recordingWidth ;
var videoHeight = (mainVideo.videoHeight > 0)? mainVideo.videoHeight : recordingHeight ;
if(videoWidth >= videoHeight){
// Landscape / Square
var scale = recordingWidth / videoWidth;
videoWidth = recordingWidth;
videoHeight = videoHeight * scale;
if(videoHeight > recordingHeight){
var scale = recordingHeight / videoHeight;
videoHeight = recordingHeight;
videoWidth = videoWidth * scale;
}
}
else {
// Portrait
var scale = recordingHeight / videoHeight;
videoHeight = recordingHeight;
videoWidth = videoWidth * scale;
}
var offsetX = (videoWidth < recordingWidth)? (recordingWidth - videoWidth) / 2 : 0;
var offsetY = (videoHeight < recordingHeight)? (recordingHeight - videoHeight) / 2 : 0;
if(RecordingLayout == "side-by-side") offsetX = recordingWidth + 5 + offsetX;
// Picture-in-Picture Video
var pnpVideoHeight = pnpVideo.videoHeight;
var pnpVideoWidth = pnpVideo.videoWidth;
if(pnpVideoHeight > 0){
if(pnpVideoWidth >= pnpVideoHeight){
var scale = pnpVideSize / pnpVideoHeight;
pnpVideoHeight = pnpVideSize;
pnpVideoWidth = pnpVideoWidth * scale;
}
else{
var scale = pnpVideSize / pnpVideoWidth;
pnpVideoWidth = pnpVideSize;
pnpVideoHeight = pnpVideoHeight * scale;
}
}
var pnpOffsetX = 10;
var pnpOffsetY = 10;
if(RecordingLayout == "side-by-side"){
pnpVideoWidth = pnpVideo.videoWidth;
pnpVideoHeight = pnpVideo.videoHeight;
if(pnpVideoWidth >= pnpVideoHeight){
// Landscape / Square
var scale = recordingWidth / pnpVideoWidth;
pnpVideoWidth = recordingWidth;
pnpVideoHeight = pnpVideoHeight * scale;
if(pnpVideoHeight > recordingHeight){
var scale = recordingHeight / pnpVideoHeight;
pnpVideoHeight = recordingHeight;
pnpVideoWidth = pnpVideoWidth * scale;
}
}
else {
// Portrait
var scale = recordingHeight / pnpVideoHeight;
pnpVideoHeight = recordingHeight;
pnpVideoWidth = pnpVideoWidth * scale;
}
pnpOffsetX = (pnpVideoWidth < recordingWidth)? (recordingWidth - pnpVideoWidth) / 2 : 0;
pnpOffsetY = (pnpVideoHeight < recordingHeight)? (recordingHeight - pnpVideoHeight) / 2 : 0;
}
// Draw Elements
recordingContext.fillRect(0, 0, recordingCanvas.width, recordingCanvas.height);
if(mainVideo.videoHeight > 0){
recordingContext.drawImage(mainVideo, offsetX, offsetY, videoWidth, videoHeight);
}
if(pnpVideo.videoHeight > 0 && (RecordingLayout == "side-by-side" || RecordingLayout == "us-pnp" || RecordingLayout == "them-pnp")){
// Only Draw the Pnp Video when needed
recordingContext.drawImage(pnpVideo, pnpOffsetX, pnpOffsetY, pnpVideoWidth, pnpVideoHeight);
}
}, Math.floor(1000/RecordingVideoFps));
var recordingVideoMediaStream = recordingCanvas.captureStream(RecordingVideoFps);
}
var mixedAudioVideoRecordStream = new MediaStream();
mixedAudioVideoRecordStream.addTrack(MixAudioStreams(recordStream).getAudioTracks()[0]);
if(session.data.withvideo){
mixedAudioVideoRecordStream.addTrack(recordingVideoMediaStream.getVideoTracks()[0]);
}
var mediaType = "audio/webm";
if(session.data.withvideo) mediaType = "video/webm";
var options = {
mimeType : mediaType
}
var mediaRecorder = new MediaRecorder(mixedAudioVideoRecordStream, options);
mediaRecorder.data = {}
mediaRecorder.data.id = ""+ id;
mediaRecorder.data.sessionId = ""+ session.id;
mediaRecorder.data.buddyId = ""+ lineObj.BuddyObj.identity;
mediaRecorder.ondataavailable = function(event) {
console.log("Got Call Recording Data: ", event.data.size +"Bytes", this.data.id, this.data.buddyId, this.data.sessionId);
// Save the Audio/Video file
SaveCallRecording(event.data, this.data.id, this.data.buddyId, this.data.sessionId);
}
console.log("Starting Call Recording", id);
session.data.mediaRecorder = mediaRecorder;
session.data.mediaRecorder.start(); // Safari does not support timeslice
session.data.recordings[session.data.recordings.length-1].startTime = utcDateNow();
$("#line-" + lineObj.LineNumber + "-msg").html(lang.call_recording_started);
updateLineScroll(lineNum);
}
else if(session.data.mediaRecorder.state == "inactive") {
session.data.mediaRecorder.data = {}
session.data.mediaRecorder.data.id = ""+ id;
session.data.mediaRecorder.data.sessionId = ""+ session.id;
session.data.mediaRecorder.data.buddyId = ""+ lineObj.BuddyObj.identity;
console.log("Starting Call Recording", id);
session.data.mediaRecorder.start();
session.data.recordings[session.data.recordings.length-1].startTime = utcDateNow();
$("#line-" + lineObj.LineNumber + "-msg").html(lang.call_recording_started);
updateLineScroll(lineNum);
}
else {
console.warn("Recorder is in an unknown state");
}
}
function SaveCallRecording(blob, id, buddy, sessionid){
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallRecordings");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
var IDB = event.target.result;
// Create Object Store
if(IDB.objectStoreNames.contains("Recordings") == false){
var objectStore = IDB.createObjectStore("Recordings", { keyPath: "uID" });
objectStore.createIndex("sessionid", "sessionid", { unique: false });
objectStore.createIndex("bytes", "bytes", { unique: false });
objectStore.createIndex("type", "type", { unique: false });
objectStore.createIndex("mediaBlob", "mediaBlob", { unique: false });
}
else {
console.warn("IndexDB requested upgrade, but object store was in place");
}
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallRecordings");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("Recordings") == false){
console.warn("IndexDB CallRecordings.Recordings does not exists");
return;
}
IDB.onerror = function(event) {
console.error("IndexDB Error:", event);
}
// Prepare data to write
var data = {
uID: id,
sessionid: sessionid,
bytes: blob.size,
type: blob.type,
mediaBlob: blob
}
// Commit Transaction
var transaction = IDB.transaction(["Recordings"], "readwrite");
var objectStoreAdd = transaction.objectStore("Recordings").add(data);
objectStoreAdd.onsuccess = function(event) {
console.log("Call Recording Sucess: ", id, blob.size, blob.type, buddy, sessionid);
}
}
}
function StopRecording(lineNum, noConfirm){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
var session = lineObj.SipSession;
if(noConfirm == true){
// Called at the end of a call
$("#line-"+ lineObj.LineNumber +"-btn-start-recording").show();
$("#line-"+ lineObj.LineNumber +"-btn-stop-recording").hide();
if(session.data.mediaRecorder){
if(session.data.mediaRecorder.state == "recording"){
console.log("Stopping Call Recording");
session.data.mediaRecorder.stop();
session.data.recordings[session.data.recordings.length-1].stopTime = utcDateNow();
window.clearInterval(session.data.recordingRedrawInterval);
$("#line-" + lineObj.LineNumber + "-msg").html(lang.call_recording_stopped);
updateLineScroll(lineNum);
}
else{
console.warn("Recorder is in an unknow state");
}
}
return;
}
else {
// User attempts to end call recording
if(CallRecordingPolicy == "enabled"){
console.log("Policy Enabled: Call Recording");
}
Confirm(lang.confirm_stop_recording, lang.stop_recording, function(){
$("#line-"+ lineObj.LineNumber +"-btn-start-recording").show();
$("#line-"+ lineObj.LineNumber +"-btn-stop-recording").hide();
if(session.data.mediaRecorder){
if(session.data.mediaRecorder.state == "recording"){
console.log("Stopping Call Recording");
session.data.mediaRecorder.stop();
session.data.recordings[session.data.recordings.length-1].stopTime = utcDateNow();
window.clearInterval(session.data.recordingRedrawInterval);
$("#line-" + lineObj.LineNumber + "-msg").html(lang.call_recording_stopped);
updateLineScroll(lineNum);
}
else{
console.warn("Recorder is in an unknow state");
}
}
});
}
}
function PlayAudioCallRecording(obj, cdrId, uID){
var container = $(obj).parent();
container.empty();
var audioObj = new Audio();
audioObj.autoplay = false;
audioObj.controls = true;
// Make sure you are playing out via the correct device
var sinkId = getAudioOutputID();
if (typeof audioObj.sinkId !== 'undefined') {
audioObj.setSinkId(sinkId).then(function(){
console.log("sinkId applied: "+ sinkId);
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
} else {
console.warn("setSinkId() is not possible using this browser.")
}
container.append(audioObj);
// Get Call Recording
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallRecordings");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallRecordings");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("Recordings") == false){
console.warn("IndexDB CallRecordings.Recordings does not exists");
return;
}
var transaction = IDB.transaction(["Recordings"]);
var objectStoreGet = transaction.objectStore("Recordings").get(uID);
objectStoreGet.onerror = function(event) {
console.error("IndexDB Get Error:", event);
}
objectStoreGet.onsuccess = function(event) {
$("#cdr-media-meta-size-"+ cdrId +"-"+ uID).html(" Size: "+ formatBytes(event.target.result.bytes));
$("#cdr-media-meta-codec-"+ cdrId +"-"+ uID).html(" Codec: "+ event.target.result.type);
// Play
audioObj.src = window.URL.createObjectURL(event.target.result.mediaBlob);
audioObj.oncanplaythrough = function(){
audioObj.play().then(function(){
console.log("Playback started");
}).catch(function(e){
console.error("Error playing back file: ", e);
});
}
}
}
}
function PlayVideoCallRecording(obj, cdrId, uID, buddy){
var container = $(obj).parent();
container.empty();
var videoObj = $("").get(0);
videoObj.id = "callrecording-video-"+ cdrId;
videoObj.autoplay = false;
videoObj.controls = true;
videoObj.ontimeupdate = function(event){
$("#cdr-video-meta-width-"+ cdrId +"-"+ uID).html(lang.width + " : "+ event.target.videoWidth +"px");
$("#cdr-video-meta-height-"+ cdrId +"-"+ uID).html(lang.height +" : "+ event.target.videoHeight +"px");
}
var sinkId = getAudioOutputID();
if (typeof videoObj.sinkId !== 'undefined') {
videoObj.setSinkId(sinkId).then(function(){
console.log("sinkId applied: "+ sinkId);
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
} else {
console.warn("setSinkId() is not possible using this browser.")
}
container.append(videoObj);
// Get Call Recording
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallRecordings");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallRecordings");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("Recordings") == false){
console.warn("IndexDB CallRecordings.Recordings does not exists");
return;
}
var transaction = IDB.transaction(["Recordings"]);
var objectStoreGet = transaction.objectStore("Recordings").get(uID);
objectStoreGet.onerror = function(event) {
console.error("IndexDB Get Error:", event);
}
objectStoreGet.onsuccess = function(event) {
$("#cdr-media-meta-size-"+ cdrId +"-"+ uID).html(" Size: "+ formatBytes(event.target.result.bytes));
$("#cdr-media-meta-codec-"+ cdrId +"-"+ uID).html(" Codec: "+ event.target.result.type);
// Play
videoObj.src = window.URL.createObjectURL(event.target.result.mediaBlob);
videoObj.oncanplaythrough = function(){
try{
videoObj.scrollIntoViewIfNeeded(false);
} catch(e){}
videoObj.play().then(function(){
console.log("Playback started");
}).catch(function(e){
console.error("Error playing back file: ", e);
});
// Create a Post Image after a second
if(buddy){
window.setTimeout(function(){
var canvas = $("").get(0);
var videoWidth = videoObj.videoWidth;
var videoHeight = videoObj.videoHeight;
if(videoWidth > videoHeight){
// Landscape
if(videoHeight > 225){
var p = 225 / videoHeight;
videoHeight = 225;
videoWidth = videoWidth * p;
}
}
else {
// Portrait
if(videoHeight > 225){
var p = 225 / videoWidth;
videoWidth = 225;
videoHeight = videoHeight * p;
}
}
canvas.width = videoWidth;
canvas.height = videoHeight;
canvas.getContext('2d').drawImage(videoObj, 0, 0, videoWidth, videoHeight);
canvas.toBlob(function(blob) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var Poster = { width: videoWidth, height: videoHeight, posterBase64: reader.result }
console.log("Capturing Video Poster...");
// Update DB
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function(i, item) {
if (item.ItemType == "CDR" && item.CdrId == cdrId) {
// Found
if(item.Recordings && item.Recordings.length >= 1){
$.each(item.Recordings, function(r, recording) {
if(recording.uID == uID) recording.Poster = Poster;
});
}
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
console.log("Capturing Video Poster, Done");
}
}
}, 'image/jpeg', PosterJpegQuality);
}, 1000);
}
}
}
}
}
// Stream Manipulations
// ====================
function MixAudioStreams(MultiAudioTackStream){
// Takes in a MediaStream with any number of audio tracks and mixes them together
var audioContext = null;
try {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
audioContext = new AudioContext();
}
catch(e){
console.warn("AudioContext() not available, cannot record");
return MultiAudioTackStream;
}
var mixedAudioStream = audioContext.createMediaStreamDestination();
MultiAudioTackStream.getAudioTracks().forEach(function(audioTrack){
var srcStream = new MediaStream();
srcStream.addTrack(audioTrack);
var streamSourceNode = audioContext.createMediaStreamSource(srcStream);
streamSourceNode.connect(mixedAudioStream);
});
return mixedAudioStream.stream;
}
// Call Transfer & Conference
// ============================
function QuickFindBuddy(obj){
$.jeegoopopup.close();
var leftPos = obj.offsetWidth + 178;
var topPos = obj.offsetHeight + 68;
if($(window).width() < 1467) {
topPos = obj.offsetHeight + 164;
if ($(window).width() < 918) {
leftPos = obj.offsetWidth - 140;
if($(window).width() < 690) {
leftPos = obj.offsetWidth - 70;
topPos = obj.offsetHeight + 164;
}
}
}
var filter = obj.value;
if(filter == "") return;
console.log("Find Buddy: ", filter);
Buddies.sort(function(a, b){
if(a.CallerIDName < b.CallerIDName) return -1;
if(a.CallerIDName > b.CallerIDName) return 1;
return 0;
});
var visibleItems = 0;
var menu = "";
menu += "
";
for(var b = 0; b < Buddies.length; b++){
var buddyObj = Buddies[b];
// Perform Filter Display
var display = false;
if(buddyObj.CallerIDName.toLowerCase().indexOf(filter.toLowerCase()) > -1) display = true;
if(buddyObj.ExtNo.toLowerCase().indexOf(filter.toLowerCase()) > -1) display = true;
if(buddyObj.Desc.toLowerCase().indexOf(filter.toLowerCase()) > -1) display = true;
if(buddyObj.MobileNumber.toLowerCase().indexOf(filter.toLowerCase()) > -1) display = true;
if(buddyObj.ContactNumber1.toLowerCase().indexOf(filter.toLowerCase()) > -1) display = true;
if(buddyObj.ContactNumber2.toLowerCase().indexOf(filter.toLowerCase()) > -1) display = true;
if(display) {
// Filtered Results
var iconColor = "#404040";
if(buddyObj.presence == "Unknown" || buddyObj.presence == "Not online" || buddyObj.presence == "Unavailable") iconColor = "#666666";
if(buddyObj.presence == "Ready") iconColor = "#3fbd3f";
if(buddyObj.presence == "On the phone" || buddyObj.presence == "Ringing" || buddyObj.presence == "On hold") iconColor = "#c99606";
menu += ""+ buddyObj.CallerIDName +" ";
if (buddyObj.ExtNo != "") {
menu += ""+ lang.extension +" ("+ buddyObj.presence + ")" +" "+ buddyObj.ExtNo +" ";
}
if (buddyObj.MobileNumber != "") {
menu += ""+ lang.mobile +" "+ buddyObj.MobileNumber +" ";
}
if (buddyObj.ContactNumber1 != "") {
menu += ""+ lang.contact_number_1 +" "+ buddyObj.ContactNumber1 +" ";
}
if (buddyObj.ContactNumber2 != "") {
menu += ""+ lang.contact_number_2 +" "+ buddyObj.ContactNumber2 +" ";
}
visibleItems++;
}
if(visibleItems >= 5) break;
}
menu += "
";
if(menu.length > 1) {
$.jeegoopopup.open({
html: menu,
width: 'auto',
height: 'auto',
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: false,
resizable: false,
fadeIn: 0
});
$("#jg_popup_inner").focus();
$("#jg_popup_inner #jg_popup_content #quickSearchBuddy #quickSearchBdTable").on("click", ".quickFindBdRow", function() {
var quickFoundNum = $(this).closest("tr").find("span.quickNumFound").html();
$.jeegoopopup.close();
$(document).find("input[id*='-txt-FindTransferBuddy']").focus();
$(document).find("input[id*='-txt-FindTransferBuddy']").val(quickFoundNum);
});
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
}
// Call Transfer
// =============
function StartTransferSession(lineNum){
$("#line-"+ lineNum +"-btn-Transfer").hide();
$("#line-"+ lineNum +"-btn-CancelTransfer").show();
holdSession(lineNum);
$("#line-"+ lineNum +"-txt-FindTransferBuddy").val("");
$("#line-"+ lineNum +"-txt-FindTransferBuddy").parent().show();
$("#line-"+ lineNum +"-btn-blind-transfer").show();
$("#line-"+ lineNum +"-btn-attended-transfer").show();
$("#line-"+ lineNum +"-btn-complete-transfer").hide();
$("#line-"+ lineNum +"-btn-cancel-transfer").hide();
$("#line-"+ lineNum +"-transfer-status").hide();
$("#line-"+ lineNum +"-Transfer").show();
updateLineScroll(lineNum);
}
function CancelTransferSession(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Null line or session");
return;
}
var session = lineObj.SipSession;
if(session.data.childsession){
console.log("Child Transfer call detected:", session.data.childsession.status)
try{
if(session.data.childsession.status == SIP.Session.C.STATUS_CONFIRMED){
session.data.childsession.bye();
}
else{
session.data.childsession.cancel();
}
} catch(e){}
}
$("#line-"+ lineNum +"-btn-Transfer").show();
$("#line-"+ lineNum +"-btn-CancelTransfer").hide();
unholdSession(lineNum);
$("#line-"+ lineNum +"-Transfer").hide();
updateLineScroll(lineNum);
}
function BlindTransfer(lineNum) {
var dstNo = $("#line-"+ lineNum +"-txt-FindTransferBuddy").val().replace(/[^0-9\*\#\+]/g,'');
if(dstNo == ""){
console.warn("Cannot transfer, must be [0-9*+#]");
return;
}
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Null line or session");
return;
}
var session = lineObj.SipSession;
if(!session.data.transfer) session.data.transfer = [];
session.data.transfer.push({
type: "Blind",
to: dstNo,
transferTime: utcDateNow(),
disposition: "refer",
dispositionTime: utcDateNow(),
accept : {
complete: null,
eventTime: null,
disposition: ""
}
});
var transferid = session.data.transfer.length-1;
var transferOptions = {
receiveResponse: function doReceiveResponse(response){
console.log("Blind transfer response: ", response.reason_phrase);
session.data.terminateby = "refer";
session.data.transfer[transferid].accept.disposition = response.reason_phrase;
session.data.transfer[transferid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html("Call Blind Transfered (Accepted)");
updateLineScroll(lineNum);
}
}
console.log("REFER: ", dstNo + "@" + wssServer);
session.refer("sip:" + dstNo + "@" + wssServer, transferOptions);
$("#line-" + lineNum + "-msg").html(lang.call_blind_transfered);
updateLineScroll(lineNum);
}
function AttendedTransfer(lineNum){
var dstNo = $("#line-"+ lineNum +"-txt-FindTransferBuddy").val().replace(/[^0-9\*\#\+]/g,'');
if(dstNo == ""){
console.warn("Cannot transfer, must be [0-9*+#]");
return;
}
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Null line or session");
return;
}
var session = lineObj.SipSession;
$.jeegoopopup.close();
$("#line-"+ lineNum +"-txt-FindTransferBuddy").parent().hide();
$("#line-"+ lineNum +"-btn-blind-transfer").hide();
$("#line-"+ lineNum +"-btn-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-complete-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-cancel-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-terminate-attended-transfer").hide();
var newCallStatus = $("#line-"+ lineNum +"-transfer-status");
newCallStatus.html(lang.connecting);
newCallStatus.show();
if(!session.data.transfer) session.data.transfer = [];
session.data.transfer.push({
type: "Attended",
to: dstNo,
transferTime: utcDateNow(),
disposition: "invite",
dispositionTime: utcDateNow(),
accept : {
complete: null,
eventTime: null,
disposition: ""
}
});
var transferid = session.data.transfer.length-1;
updateLineScroll(lineNum);
// SDP options
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var spdOptions = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: { deviceId : "default" },
video: false
}
}
}
if(session.data.AudioSourceDevice != "default"){
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.deviceId = { exact: session.data.AudioSourceDevice }
}
// Add additional Constraints
if(supportedConstraints.autoGainControl) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.autoGainControl = AutoGainControl;
}
if(supportedConstraints.echoCancellation) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.echoCancellation = EchoCancellation;
}
if(supportedConstraints.noiseSuppression) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.noiseSuppression = NoiseSuppression;
}
if(session.data.withvideo){
spdOptions.sessionDescriptionHandlerOptions.constraints.video = true;
if(session.data.VideoSourceDevice != "default"){
spdOptions.sessionDescriptionHandlerOptions.constraints.video.deviceId = { exact: session.data.VideoSourceDevice }
}
// Add additional Constraints
if(supportedConstraints.frameRate && maxFrameRate != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.frameRate = maxFrameRate;
}
if(supportedConstraints.height && videoHeight != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.height = videoHeight;
}
if(supportedConstraints.aspectRatio && videoAspectRatio != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.aspectRatio = videoAspectRatio;
}
}
// Create new call session
console.log("INVITE: ", "sip:" + dstNo + "@" + wssServer);
var newSession = userAgent.invite("sip:" + dstNo + "@" + wssServer, spdOptions);
session.data.childsession = newSession;
newSession.on('progress', function (response) {
newCallStatus.html(lang.ringing);
session.data.transfer[transferid].disposition = "progress";
session.data.transfer[transferid].dispositionTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.attended_transfer_call_started);
var CancelAttendedTransferBtn = $("#line-"+ lineNum +"-btn-cancel-attended-transfer");
CancelAttendedTransferBtn.off('click');
CancelAttendedTransferBtn.on('click', function(){
newSession.cancel();
newCallStatus.html(lang.call_cancelled);
console.log("New call session canceled");
session.data.transfer[transferid].accept.complete = false;
session.data.transfer[transferid].accept.disposition = "cancel";
session.data.transfer[transferid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.attended_transfer_call_cancelled);
updateLineScroll(lineNum);
});
CancelAttendedTransferBtn.show();
updateLineScroll(lineNum);
});
newSession.on('accepted', function (response) {
newCallStatus.html(lang.call_in_progress);
$("#line-"+ lineNum +"-btn-cancel-attended-transfer").hide();
session.data.transfer[transferid].disposition = "accepted";
session.data.transfer[transferid].dispositionTime = utcDateNow();
var CompleteTransferBtn = $("#line-"+ lineNum +"-btn-complete-attended-transfer");
CompleteTransferBtn.off('click');
CompleteTransferBtn.on('click', function(){
var transferOptions = {
receiveResponse: function doReceiveResponse(response){
console.log("Attended transfer response: ", response.reason_phrase);
session.data.terminateby = "refer";
session.data.transfer[transferid].accept.disposition = response.reason_phrase;
session.data.transfer[transferid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.attended_transfer_complete_accepted);
updateLineScroll(lineNum);
}
}
// Send REFER
session.refer(newSession, transferOptions);
newCallStatus.html(lang.attended_transfer_complete);
console.log("Attended transfer complete");
// Call will now teardown...
session.data.transfer[transferid].accept.complete = true;
session.data.transfer[transferid].accept.disposition = "refer";
session.data.transfer[transferid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.attended_transfer_complete);
updateLineScroll(lineNum);
});
CompleteTransferBtn.show();
updateLineScroll(lineNum);
var TerminateAttendedTransferBtn = $("#line-"+ lineNum +"-btn-terminate-attended-transfer");
TerminateAttendedTransferBtn.off('click');
TerminateAttendedTransferBtn.on('click', function(){
newSession.bye();
newCallStatus.html(lang.call_ended);
console.log("New call session end");
session.data.transfer[transferid].accept.complete = false;
session.data.transfer[transferid].accept.disposition = "bye";
session.data.transfer[transferid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.attended_transfer_call_ended);
updateLineScroll(lineNum);
});
TerminateAttendedTransferBtn.show();
updateLineScroll(lineNum);
});
newSession.on('trackAdded', function () {
var pc = newSession.sessionDescriptionHandler.peerConnection;
// Gets Remote Audio Track (Local audio is setup via initial GUM)
var remoteStream = new MediaStream();
pc.getReceivers().forEach(function (receiver) {
if(receiver.track && receiver.track.kind == "audio"){
remoteStream.addTrack(receiver.track);
}
});
var remoteAudio = $("#line-" + lineNum + "-transfer-remoteAudio").get(0);
remoteAudio.srcObject = remoteStream;
remoteAudio.onloadedmetadata = function(e) {
if (typeof remoteAudio.sinkId !== 'undefined') {
remoteAudio.setSinkId(session.data.AudioOutputDevice).then(function(){
console.log("sinkId applied: "+ session.data.AudioOutputDevice);
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
}
remoteAudio.play();
}
});
newSession.on('rejected', function (response, cause) {
console.log("New call session rejected: ", cause);
newCallStatus.html(lang.call_rejected);
session.data.transfer[transferid].disposition = "rejected";
session.data.transfer[transferid].dispositionTime = utcDateNow();
$("#line-"+ lineNum +"-txt-FindTransferBuddy").parent().show();
$("#line-"+ lineNum +"-btn-blind-transfer").show();
$("#line-"+ lineNum +"-btn-attended-transfer").show();
$("#line-"+ lineNum +"-btn-complete-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-cancel-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-terminate-attended-transfer").hide();
$("#line-"+ lineNum +"-msg").html(lang.attended_transfer_call_rejected);
updateLineScroll(lineNum);
window.setTimeout(function(){
newCallStatus.hide();
updateLineScroll(lineNum);
}, 1000);
});
newSession.on('terminated', function (response, cause) {
console.log("New call session terminated: ", cause);
newCallStatus.html(lang.call_ended);
session.data.transfer[transferid].disposition = "terminated";
session.data.transfer[transferid].dispositionTime = utcDateNow();
$("#line-"+ lineNum +"-txt-FindTransferBuddy").parent().show();
$("#line-"+ lineNum +"-btn-blind-transfer").show();
$("#line-"+ lineNum +"-btn-attended-transfer").show();
$("#line-"+ lineNum +"-btn-complete-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-cancel-attended-transfer").hide();
$("#line-"+ lineNum +"-btn-terminate-attended-transfer").hide();
$("#line-"+ lineNum +"-msg").html(lang.attended_transfer_call_terminated);
updateLineScroll(lineNum);
window.setTimeout(function(){
newCallStatus.hide();
updateLineScroll(lineNum);
}, 1000);
});
}
// Conference Calls
// ================
function StartConferenceCall(lineNum){
$("#line-"+ lineNum +"-btn-Conference").hide();
$("#line-"+ lineNum +"-btn-CancelConference").show();
holdSession(lineNum);
$("#line-"+ lineNum +"-txt-FindConferenceBuddy").val("");
$("#line-"+ lineNum +"-txt-FindConferenceBuddy").parent().show();
$("#line-"+ lineNum +"-btn-conference-dial").show();
$("#line-"+ lineNum +"-btn-cancel-conference-dial").hide();
$("#line-"+ lineNum +"-btn-join-conference-call").hide();
$("#line-"+ lineNum +"-btn-terminate-conference-call").hide();
$("#line-"+ lineNum +"-conference-status").hide();
$("#line-"+ lineNum +"-Conference").show();
updateLineScroll(lineNum);
}
function CancelConference(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Null line or session");
return;
}
var session = lineObj.SipSession;
if(session.data.childsession){
try{
if(session.data.childsession.status == SIP.Session.C.STATUS_CONFIRMED){
session.data.childsession.bye();
}
else{
session.data.childsession.cancel();
}
} catch(e){}
}
$("#line-"+ lineNum +"-btn-Conference").show();
$("#line-"+ lineNum +"-btn-CancelConference").hide();
unholdSession(lineNum);
$("#line-"+ lineNum +"-Conference").hide();
updateLineScroll(lineNum);
}
function ConferenceDial(lineNum){
var dstNo = $("#line-"+ lineNum +"-txt-FindConferenceBuddy").val().replace(/[^0-9\*\#\+]/g,'');
if(dstNo == ""){
console.warn("Cannot transfer, must be [0-9*+#]");
return;
}
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Null line or session");
return;
}
var session = lineObj.SipSession;
$.jeegoopopup.close();
$("#line-"+ lineNum +"-txt-FindConferenceBuddy").parent().hide();
$("#line-"+ lineNum +"-btn-conference-dial").hide();
$("#line-"+ lineNum +"-btn-cancel-conference-dial")
$("#line-"+ lineNum +"-btn-join-conference-call").hide();
$("#line-"+ lineNum +"-btn-terminate-conference-call").hide();
var newCallStatus = $("#line-"+ lineNum +"-conference-status");
newCallStatus.html(lang.connecting);
newCallStatus.show();
if(!session.data.confcalls) session.data.confcalls = [];
session.data.confcalls.push({
to: dstNo,
startTime: utcDateNow(),
disposition: "invite",
dispositionTime: utcDateNow(),
accept : {
complete: null,
eventTime: null,
disposition: ""
}
});
var confcallid = session.data.confcalls.length-1;
updateLineScroll(lineNum);
// SDP options
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var spdOptions = {
sessionDescriptionHandlerOptions: {
constraints: {
audio: { deviceId : "default" },
video: false
}
}
}
if(session.data.AudioSourceDevice != "default"){
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.deviceId = { exact: session.data.AudioSourceDevice }
}
// Add additional Constraints
if(supportedConstraints.autoGainControl) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.autoGainControl = AutoGainControl;
}
if(supportedConstraints.echoCancellation) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.echoCancellation = EchoCancellation;
}
if(supportedConstraints.noiseSuppression) {
spdOptions.sessionDescriptionHandlerOptions.constraints.audio.noiseSuppression = NoiseSuppression;
}
// Unlikely this will work
if(session.data.withvideo){
spdOptions.sessionDescriptionHandlerOptions.constraints.video = true;
if(session.data.VideoSourceDevice != "default"){
spdOptions.sessionDescriptionHandlerOptions.constraints.video.deviceId = { exact: session.data.VideoSourceDevice }
}
// Add additional Constraints
if(supportedConstraints.frameRate && maxFrameRate != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.frameRate = maxFrameRate;
}
if(supportedConstraints.height && videoHeight != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.height = videoHeight;
}
if(supportedConstraints.aspectRatio && videoAspectRatio != "") {
spdOptions.sessionDescriptionHandlerOptions.constraints.video.aspectRatio = videoAspectRatio;
}
}
// Create new call session
console.log("INVITE: ", "sip:" + dstNo + "@" + wssServer);
var newSession = userAgent.invite("sip:" + dstNo + "@" + wssServer, spdOptions);
session.data.childsession = newSession;
newSession.on('progress', function (response) {
newCallStatus.html(lang.ringing);
session.data.confcalls[confcallid].disposition = "progress";
session.data.confcalls[confcallid].dispositionTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.conference_call_started);
var CancelConferenceDialBtn = $("#line-"+ lineNum +"-btn-cancel-conference-dial");
CancelConferenceDialBtn.off('click');
CancelConferenceDialBtn.on('click', function(){
newSession.cancel();
newCallStatus.html(lang.call_cancelled);
console.log("New call session canceled");
session.data.confcalls[confcallid].accept.complete = false;
session.data.confcalls[confcallid].accept.disposition = "cancel";
session.data.confcalls[confcallid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.canference_call_cancelled);
updateLineScroll(lineNum);
});
CancelConferenceDialBtn.show();
updateLineScroll(lineNum);
});
newSession.on('accepted', function (response) {
newCallStatus.html(lang.call_in_progress);
$("#line-"+ lineNum +"-btn-cancel-conference-dial").hide();
session.data.confcalls[confcallid].complete = true;
session.data.confcalls[confcallid].disposition = "accepted";
session.data.confcalls[confcallid].dispositionTime = utcDateNow();
// Join Call
var JoinCallBtn = $("#line-"+ lineNum +"-btn-join-conference-call");
JoinCallBtn.off('click');
JoinCallBtn.on('click', function(){
// Merge Call Audio
if(!session.data.childsession){
console.warn("Conference session lost");
return;
}
var outputStreamForSession = new MediaStream();
var outputStreamForConfSession = new MediaStream();
var pc = session.sessionDescriptionHandler.peerConnection;
var confPc = session.data.childsession.sessionDescriptionHandler.peerConnection;
// Get conf call input channel
confPc.getReceivers().forEach(function (RTCRtpReceiver) {
if(RTCRtpReceiver.track && RTCRtpReceiver.track.kind == "audio") {
console.log("Adding conference session:", RTCRtpReceiver.track.label);
outputStreamForSession.addTrack(RTCRtpReceiver.track);
}
});
// Get session input channel
pc.getReceivers().forEach(function (RTCRtpReceiver) {
if(RTCRtpReceiver.track && RTCRtpReceiver.track.kind == "audio") {
console.log("Adding conference session:", RTCRtpReceiver.track.label);
outputStreamForConfSession.addTrack(RTCRtpReceiver.track);
}
});
// Replace tracks of Parent Call
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
console.log("Switching to mixed Audio track on session");
session.data.AudioSourceTrack = RTCRtpSender.track;
outputStreamForSession.addTrack(RTCRtpSender.track);
var mixedAudioTrack = MixAudioStreams(outputStreamForSession).getAudioTracks()[0];
mixedAudioTrack.IsMixedTrack = true;
RTCRtpSender.replaceTrack(mixedAudioTrack);
}
});
// Replace tracks of Child Call
confPc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
console.log("Switching to mixed Audio track on conf call");
session.data.childsession.data.AudioSourceTrack = RTCRtpSender.track;
outputStreamForConfSession.addTrack(RTCRtpSender.track);
var mixedAudioTrackForConf = MixAudioStreams(outputStreamForConfSession).getAudioTracks()[0];
mixedAudioTrackForConf.IsMixedTrack = true;
RTCRtpSender.replaceTrack(mixedAudioTrackForConf);
}
});
newCallStatus.html(lang.call_in_progress);
console.log("Conference Call In Progress");
session.data.confcalls[confcallid].accept.complete = true;
session.data.confcalls[confcallid].accept.disposition = "join";
session.data.confcalls[confcallid].accept.eventTime = utcDateNow();
$("#line-"+ lineNum +"-btn-terminate-conference-call").show();
$("#line-" + lineNum + "-msg").html(lang.conference_call_in_progress);
// Take the parent call off hold
unholdSession(lineNum);
JoinCallBtn.hide();
updateLineScroll(lineNum);
});
JoinCallBtn.show();
updateLineScroll(lineNum);
// End Call
var TerminateAttendedTransferBtn = $("#line-"+ lineNum +"-btn-terminate-conference-call");
TerminateAttendedTransferBtn.off('click');
TerminateAttendedTransferBtn.on('click', function(){
newSession.bye();
newCallStatus.html(lang.call_ended);
console.log("New call session end");
session.data.confcalls[confcallid].accept.disposition = "bye";
session.data.confcalls[confcallid].accept.eventTime = utcDateNow();
$("#line-" + lineNum + "-msg").html(lang.conference_call_ended);
updateLineScroll(lineNum);
});
TerminateAttendedTransferBtn.show();
updateLineScroll(lineNum);
});
newSession.on('trackAdded', function () {
var pc = newSession.sessionDescriptionHandler.peerConnection;
// Gets Remote Audio Track (Local audio is setup via initial GUM)
var remoteStream = new MediaStream();
pc.getReceivers().forEach(function (receiver) {
if(receiver.track && receiver.track.kind == "audio"){
remoteStream.addTrack(receiver.track);
}
});
var remoteAudio = $("#line-" + lineNum + "-conference-remoteAudio").get(0);
remoteAudio.srcObject = remoteStream;
remoteAudio.onloadedmetadata = function(e) {
if (typeof remoteAudio.sinkId !== 'undefined') {
remoteAudio.setSinkId(session.data.AudioOutputDevice).then(function(){
console.log("sinkId applied: "+ session.data.AudioOutputDevice);
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
}
remoteAudio.play();
}
});
newSession.on('rejected', function (response, cause) {
console.log("New call session rejected: ", cause);
newCallStatus.html(lang.call_rejected);
session.data.confcalls[confcallid].disposition = "rejected";
session.data.confcalls[confcallid].dispositionTime = utcDateNow();
$("#line-"+ lineNum +"-txt-FindConferenceBuddy").parent().show();
$("#line-"+ lineNum +"-btn-conference-dial").show();
$("#line-"+ lineNum +"-btn-cancel-conference-dial").hide();
$("#line-"+ lineNum +"-btn-join-conference-call").hide();
$("#line-"+ lineNum +"-btn-terminate-conference-call").hide();
$("#line-"+ lineNum +"-msg").html(lang.conference_call_rejected);
updateLineScroll(lineNum);
window.setTimeout(function(){
newCallStatus.hide();
updateLineScroll(lineNum);
}, 1000);
});
newSession.on('terminated', function (response, cause) {
console.log("New call session terminated: ", cause);
newCallStatus.html(lang.call_ended);
session.data.confcalls[confcallid].disposition = "terminated";
session.data.confcalls[confcallid].dispositionTime = utcDateNow();
// Ends the mixed audio, and releases the mic
if(session.data.childsession.data.AudioSourceTrack && session.data.childsession.data.AudioSourceTrack.kind == "audio"){
session.data.childsession.data.AudioSourceTrack.stop();
}
// Restore Audio Stream if it was changed
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
RTCRtpSender.replaceTrack(session.data.AudioSourceTrack).then(function(){
if(session.data.ismute){
RTCRtpSender.track.enabled = false;
}
}).catch(function(){
console.error(e);
});
session.data.AudioSourceTrack = null;
}
});
}
$("#line-"+ lineNum +"-txt-FindConferenceBuddy").parent().show();
$("#line-"+ lineNum +"-btn-conference-dial").show();
$("#line-"+ lineNum +"-btn-cancel-conference-dial").hide();
$("#line-"+ lineNum +"-btn-join-conference-call").hide();
$("#line-"+ lineNum +"-btn-terminate-conference-call").hide();
$("#line-"+ lineNum +"-msg").html(lang.conference_call_terminated);
updateLineScroll(lineNum);
window.setTimeout(function(){
newCallStatus.hide();
updateLineScroll(lineNum);
}, 1000);
});
}
function cancelSession(lineNum) {
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
lineObj.SipSession.data.terminateby = "us";
console.log("Cancelling session : "+ lineNum);
lineObj.SipSession.cancel();
$("#line-" + lineNum + "-msg").html(lang.call_cancelled);
}
function holdSession(lineNum) {
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
console.log("Putting Call on hold: "+ lineNum);
if(lineObj.SipSession.local_hold == false){
lineObj.SipSession.hold();
}
// Log Hold
if(!lineObj.SipSession.data.hold) lineObj.SipSession.data.hold = [];
lineObj.SipSession.data.hold.push({ event: "hold", eventTime: utcDateNow() });
$("#line-" + lineNum + "-btn-Hold").hide();
$("#line-" + lineNum + "-btn-Unhold").show();
$("#line-" + lineNum + "-msg").html(lang.call_on_hold);
updateLineScroll(lineNum);
}
function unholdSession(lineNum) {
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
console.log("Taking call off hold: "+ lineNum);
if(lineObj.SipSession.local_hold == true){
lineObj.SipSession.unhold();
}
// Log Hold
if(!lineObj.SipSession.data.hold) lineObj.SipSession.data.hold = [];
lineObj.SipSession.data.hold.push({ event: "unhold", eventTime: utcDateNow() });
$("#line-" + lineNum + "-msg").html(lang.call_in_progress);
$("#line-" + lineNum + "-btn-Hold").show();
$("#line-" + lineNum + "-btn-Unhold").hide();
updateLineScroll(lineNum);
}
function endSession(lineNum) {
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
console.log("Ending call with: "+ lineNum);
lineObj.SipSession.data.terminateby = "us";
lineObj.SipSession.bye();
$("#line-" + lineNum + "-msg").html(lang.call_ended);
$("#line-" + lineNum + "-ActiveCall").hide();
updateLineScroll(lineNum);
}
function sendDTMF(lineNum, itemStr) {
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
console.log("Sending DTMF ("+ itemStr +"): "+ lineNum);
lineObj.SipSession.dtmf(itemStr);
$("#line-" + lineNum + "-msg").html(lang.send_dtmf + ": "+ itemStr);
updateLineScroll(lineNum);
// Custom Web hook
if(typeof web_hook_on_dtmf !== 'undefined') web_hook_on_dtmf(itemStr, lineObj.SipSession);
}
function switchVideoSource(lineNum, srcId){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null");
return;
}
var session = lineObj.SipSession;
$("#line-" + lineNum + "-msg").html(lang.switching_video_source);
var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
var constraints = {
audio: false,
video: { deviceId: "default" }
}
if(srcId != "default"){
constraints.video.deviceId = { exact: srcId }
}
// Add additional Constraints
if(supportedConstraints.frameRate && maxFrameRate != "") {
constraints.video.frameRate = maxFrameRate;
}
if(supportedConstraints.height && videoHeight != "") {
constraints.video.height = videoHeight;
}
if(supportedConstraints.aspectRatio && videoAspectRatio != "") {
constraints.video.aspectRatio = videoAspectRatio;
}
session.data.VideoSourceDevice = srcId;
var pc = session.sessionDescriptionHandler.peerConnection;
var localStream = new MediaStream();
navigator.mediaDevices.getUserMedia(constraints).then(function(newStream){
var newMediaTrack = newStream.getVideoTracks()[0];
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Switching Video Track : "+ RTCRtpSender.track.label + " to "+ newMediaTrack.label);
RTCRtpSender.track.stop();
RTCRtpSender.replaceTrack(newMediaTrack);
localStream.addTrack(newMediaTrack);
}
});
}).catch(function(e){
console.error("Error on getUserMedia", e, constraints);
});
// Restore Audio Stream is it was changed
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
RTCRtpSender.replaceTrack(session.data.AudioSourceTrack).then(function(){
if(session.data.ismute){
RTCRtpSender.track.enabled = false;
}
}).catch(function(){
console.error(e);
});
session.data.AudioSourceTrack = null;
}
});
}
// Set Preview
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.srcObject = localStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
}
}
function SendCanvas(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null");
return;
}
var session = lineObj.SipSession;
$("#line-" + lineNum + "-msg").html(lang.switching_to_canvas);
// Create scratch Pad
RemoveScratchpad(lineNum);
var newCanvas = $(' ');
newCanvas.prop("id", "line-" + lineNum + "-scratchpad");
$("#line-" + lineNum + "-scratchpad-container").append(newCanvas);
$("#line-" + lineNum + "-scratchpad").css("display", "inline-block");
$("#line-" + lineNum + "-scratchpad").css("width", "640px"); // SD
$("#line-" + lineNum + "-scratchpad").css("height", "360px"); // SD
$("#line-" + lineNum + "-scratchpad").prop("width", 640); // SD
$("#line-" + lineNum + "-scratchpad").prop("height", 360); // SD
$("#line-" + lineNum + "-scratchpad-container").show();
console.log("Canvas for Scratchpad created...");
scratchpad = new fabric.Canvas("line-" + lineNum + "-scratchpad");
scratchpad.id = "line-" + lineNum + "-scratchpad";
scratchpad.backgroundColor = "#FFFFFF";
scratchpad.isDrawingMode = true;
scratchpad.renderAll();
scratchpad.redrawIntrtval = window.setInterval(function(){
scratchpad.renderAll();
}, 1000);
CanvasCollection.push(scratchpad);
// Get The Canvas Stream
var canvasMediaStream = $("#line-"+ lineNum +"-scratchpad").get(0).captureStream(25);
var canvasMediaTrack = canvasMediaStream.getVideoTracks()[0];
// Switch Tracks
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Switching Track : "+ RTCRtpSender.track.label + " to Scratchpad Canvas");
RTCRtpSender.track.stop();
RTCRtpSender.replaceTrack(canvasMediaTrack);
}
});
// Restore Audio Stream if it was changed
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
RTCRtpSender.replaceTrack(session.data.AudioSourceTrack).then(function(){
if(session.data.ismute){
RTCRtpSender.track.enabled = false;
}
}).catch(function(){
console.error(e);
});
session.data.AudioSourceTrack = null;
}
});
}
// Set Preview
// ===========
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.srcObject = canvasMediaStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
}
}
function SendVideo(lineNum, src){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null");
return;
}
var session = lineObj.SipSession;
$("#line-"+ lineNum +"-src-camera").prop("disabled", false);
$("#line-"+ lineNum +"-src-canvas").prop("disabled", false);
$("#line-"+ lineNum +"-src-desktop").prop("disabled", false);
$("#line-"+ lineNum +"-src-video").prop("disabled", true);
$("#line-"+ lineNum +"-src-blank").prop("disabled", false);
$("#line-" + lineNum + "-msg").html(lang.switching_to_shared_video);
$("#line-" + lineNum + "-scratchpad-container").hide();
RemoveScratchpad(lineNum);
$("#line-"+ lineNum +"-sharevideo").hide();
$("#line-"+ lineNum +"-sharevideo").get(0).pause();
$("#line-"+ lineNum +"-sharevideo").get(0).removeAttribute('src');
$("#line-"+ lineNum +"-sharevideo").get(0).load();
$("#line-"+ lineNum +"-localVideo").hide();
$("#line-"+ lineNum +"-remoteVideo").appendTo("#line-" + lineNum + "-preview-container");
// Create Video Object
var newVideo = $("#line-" + lineNum + "-sharevideo");
newVideo.prop("src", src);
newVideo.off("loadedmetadata");
newVideo.on("loadedmetadata", function () {
console.log("Video can play now... ");
// Resample Video
var ResampleSize = 360;
if(VideoResampleSize == "HD") ResampleSize = 720;
if(VideoResampleSize == "FHD") ResampleSize = 1080;
var videoObj = newVideo.get(0);
var resampleCanvas = $(' ').get(0);
var videoWidth = videoObj.videoWidth;
var videoHeight = videoObj.videoHeight;
if(videoWidth >= videoHeight){
// Landscape / Square
if(videoHeight > ResampleSize){
var p = ResampleSize / videoHeight;
videoHeight = ResampleSize;
videoWidth = videoWidth * p;
}
}
else {
// Portrate... (phone turned on its side)
if(videoWidth > ResampleSize){
var p = ResampleSize / videoWidth;
videoWidth = ResampleSize;
videoHeight = videoHeight * p;
}
}
resampleCanvas.width = videoWidth;
resampleCanvas.height = videoHeight;
var resampleContext = resampleCanvas.getContext("2d");
window.clearInterval(session.data.videoResampleInterval);
session.data.videoResampleInterval = window.setInterval(function(){
resampleContext.drawImage(videoObj, 0, 0, videoWidth, videoHeight);
}, 40); // 25frames per second
// Capture the streams
var videoMediaStream = null;
if('captureStream' in videoObj) {
videoMediaStream = videoObj.captureStream();
}
else if('mozCaptureStream' in videoObj) {
// This doesn't really work
// see: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/captureStream
videoMediaStream = videoObj.mozCaptureStream();
}
else {
// This is not supported.
// videoMediaStream = videoObj.webkitCaptureStream();
console.warn("Cannot capture stream from video, this will result in no audio being transmitted.")
}
var resampleVideoMediaStream = resampleCanvas.captureStream(25);
// Get the Tracks
var videoMediaTrack = resampleVideoMediaStream.getVideoTracks()[0];
var audioTrackFromVideo = (videoMediaStream != null )? videoMediaStream.getAudioTracks()[0] : null;
// Switch & Merge Tracks
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Switching Track : "+ RTCRtpSender.track.label);
RTCRtpSender.track.stop();
RTCRtpSender.replaceTrack(videoMediaTrack);
}
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
console.log("Switching to mixed Audio track on session");
session.data.AudioSourceTrack = RTCRtpSender.track;
var mixedAudioStream = new MediaStream();
if(audioTrackFromVideo) mixedAudioStream.addTrack(audioTrackFromVideo);
mixedAudioStream.addTrack(RTCRtpSender.track);
var mixedAudioTrack = MixAudioStreams(mixedAudioStream).getAudioTracks()[0];
mixedAudioTrack.IsMixedTrack = true;
RTCRtpSender.replaceTrack(mixedAudioTrack);
}
});
// Set Preview
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.srcObject = videoMediaStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play().then(function(){
console.log("Playing Preview Video File");
}).catch(function(e){
console.error("Cannot play back video", e);
});
}
// Play the video
console.log("Starting Video...");
$("#line-"+ lineNum +"-sharevideo").get(0).play();
});
$("#line-"+ lineNum +"-sharevideo").show();
console.log("Video for Sharing created...");
}
function ShareScreen(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null");
return;
}
var session = lineObj.SipSession;
$("#line-" + lineNum + "-msg").html(lang.switching_to_shared_screeen);
var localStream = new MediaStream();
var pc = session.sessionDescriptionHandler.peerConnection;
if (navigator.getDisplayMedia) {
// EDGE, legacy support
var screenShareConstraints = { video: true, audio: false }
navigator.getDisplayMedia(screenShareConstraints).then(function(newStream) {
console.log("navigator.getDisplayMedia")
var newMediaTrack = newStream.getVideoTracks()[0];
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Switching Video Track : "+ RTCRtpSender.track.label + " to Screen");
RTCRtpSender.track.stop();
RTCRtpSender.replaceTrack(newMediaTrack);
localStream.addTrack(newMediaTrack);
}
});
// Set Preview
// ===========
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.srcObject = localStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
}
}).catch(function (err) {
console.error("Error on getUserMedia");
});
}
else if (navigator.mediaDevices.getDisplayMedia) {
// New standard
var screenShareConstraints = { video: true, audio: false }
navigator.mediaDevices.getDisplayMedia(screenShareConstraints).then(function(newStream) {
console.log("navigator.mediaDevices.getDisplayMedia")
var newMediaTrack = newStream.getVideoTracks()[0];
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Switching Video Track : "+ RTCRtpSender.track.label + " to Screen");
RTCRtpSender.track.stop();
RTCRtpSender.replaceTrack(newMediaTrack);
localStream.addTrack(newMediaTrack);
}
});
// Set Preview
// ===========
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.srcObject = localStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
}
}).catch(function (err) {
console.error("Error on getUserMedia");
});
}
else {
// Firefox, apparently
var screenShareConstraints = { video: { mediaSource: 'screen' }, audio: false }
navigator.mediaDevices.getUserMedia(screenShareConstraints).then(function(newStream) {
console.log("navigator.mediaDevices.getUserMedia")
var newMediaTrack = newStream.getVideoTracks()[0];
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Switching Video Track : "+ RTCRtpSender.track.label + " to Screen");
RTCRtpSender.track.stop();
RTCRtpSender.replaceTrack(newMediaTrack);
localStream.addTrack(newMediaTrack);
}
});
// Set Preview
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.srcObject = localStream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
}
}).catch(function (err) {
console.error("Error on getUserMedia");
});
}
// Restore Audio Stream if it was changed
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
RTCRtpSender.replaceTrack(session.data.AudioSourceTrack).then(function(){
if(session.data.ismute){
RTCRtpSender.track.enabled = false;
}
}).catch(function(){
console.error(e);
});
session.data.AudioSourceTrack = null;
}
});
}
}
function DisableVideoStream(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null");
return;
}
var session = lineObj.SipSession;
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
console.log("Disable Video Track : "+ RTCRtpSender.track.label + "");
RTCRtpSender.track.enabled = false; //stop();
}
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
RTCRtpSender.replaceTrack(session.data.AudioSourceTrack).then(function(){
if(session.data.ismute){
RTCRtpSender.track.enabled = false;
}
}).catch(function(){
console.error(e);
});
session.data.AudioSourceTrack = null;
}
}
});
// Set Preview
console.log("Showing as preview...");
var localVideo = $("#line-" + lineNum + "-localVideo").get(0);
localVideo.pause();
localVideo.removeAttribute('src');
localVideo.load();
$("#line-" + lineNum + "-msg").html(lang.video_disabled);
}
// Phone Lines
// ===========
var Line = function(lineNumber, displayName, displayNumber, buddyObj){
this.LineNumber = lineNumber;
this.DisplayName = displayName;
this.DisplayNumber = displayNumber;
this.IsSelected = false;
this.BuddyObj = buddyObj;
this.SipSession = null;
this.LocalSoundMeter = null;
this.RemoteSoundMeter = null;
}
function ShowDial(obj){
var leftPos = obj.offsetWidth + 104;
var rightPos = 0;
var topPos = obj.offsetHeight + 117;
if ($(window).width() <= 915) {
leftPos = event.pageX + obj.offsetWidth - 120;
rightPos = 0;
topPos = event.pageY + obj.offsetHeight - 11;
}
var html = "
";
html += "
";
html += "1
"
html += "2
ABC "
html += "3
DEF ";
html += "4
GHI "
html += "5
JKL "
html += "6
MNO ";
html += "7
PQRS "
html += "8
TUV "
html += "9
WXYZ ";
html += "* "
html += "0 "
html += "# ";
html += "
";
html += "
";
html += " ";
if(EnableVideoCalling){
html += " ";
}
html += "
";
$.jeegoopopup.open({
html: html,
width: "auto",
height: "auto",
left: leftPos,
right: rightPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
// innerClass: 'showDialInner',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#dialText").focus();
if ($(window).width() <= 915) { $.jeegoopopup.right(6); } else { $.jeegoopopup.width('auto').height('auto').left(leftPos).top(topPos); }
$("#jg_popup_overlay").click(function() { $("#jg_popup_b").empty(); $("#jg_popup_l").empty(); $("#windowCtrls").empty(); $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $("#jg_popup_b").empty(); $("#jg_popup_l").empty(); $("#windowCtrls").empty(); $.jeegoopopup.close(); } });
}
function handleDialInput(obj, event){
if(EnableAlphanumericDial){
$("#dialText").val($("#dialText").val().replace(/[^\da-zA-Z\*\#\+]/g, "").substring(0,MaxDidLength));
}
else {
$("#dialText").val($("#dialText").val().replace(/[^\d\*\#\+]/g, "").substring(0,MaxDidLength));
}
$("#dialVideo").prop('disabled', ($("#dialText").val().length >= DidLength));
}
function dialOnkeydown(event, obj, buddy) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13'){
event.preventDefault();
// Defaults to audio dial
DialByLine('audio');
$("#jg_popup_b").empty(); $("#jg_popup_l").empty(); $("#windowCtrls").empty(); $.jeegoopopup.close();
return false;
}
}
function KeyPress(num){
$("#dialText").val(($("#dialText").val()+num).substring(0,MaxDidLength));
$("#dialVideo").prop('disabled', ($("#dialText").val().length >= DidLength));
}
function DialByLine(type, buddy, numToDial, CallerID){
$.jeegoopopup.close();
if(userAgent == null || userAgent.isRegistered()==false){
ConfigureExtensionWindow();
return;
}
var numDial = (numToDial)? numToDial : $("#dialText").val();
if(EnableAlphanumericDial){
numDial = numDial.replace(/[^\da-zA-Z\*\#\+]/g, "").substring(0,MaxDidLength);
}
else {
numDial = numDial.replace(/[^\d\*\#\+]/g, "").substring(0,MaxDidLength);
}
if(numDial.length == 0) {
console.warn("Enter number to dial");
return;
}
// Create a Buddy if one is not already existing
var buddyObj = (buddy)? FindBuddyByIdentity(buddy) : FindBuddyByDid(numDial);
if(buddyObj == null) {
var buddyType = (numDial.length > DidLength)? "contact" : "extension";
// Assumption but anyway: If the number starts with a * or # then its probably not a subscribable DID,
// and is probably a feature code.
if(buddyType.substring(0,1) == "*" || buddyType.substring(0,1) == "#") buddyType = "contact";
buddyObj = MakeBuddy(buddyType, true, false, true, (CallerID)? CallerID : numDial, numDial);
}
// Create a Line
newLineNumber = newLineNumber + 1;
lineObj = new Line(newLineNumber, buddyObj.CallerIDName, numDial, buddyObj);
Lines.push(lineObj);
AddLineHtml(lineObj);
SelectLine(newLineNumber);
UpdateBuddyList();
// Start Call Invite
if(type == "audio"){
AudioCall(lineObj, numDial);
}
else {
VideoCall(lineObj, numDial);
}
try{
$("#line-" + newLineNumber).get(0).scrollIntoViewIfNeeded();
} catch(e){}
}
function SelectLine(lineNum){
$("#roundcubeFrame").remove();
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null) return;
var displayLineNumber = 0;
for(var l = 0; l < Lines.length; l++) {
if(Lines[l].LineNumber == lineObj.LineNumber) displayLineNumber = l+1;
if(Lines[l].IsSelected == true && Lines[l].LineNumber == lineObj.LineNumber){
// Nothing to do, you re-selected the same buddy;
return;
}
}
console.log("Selecting Line : "+ lineObj.LineNumber);
// Can only display one thing on the right
$(".streamSelected").each(function () {
$(this).prop('class', 'stream');
});
$("#line-ui-" + lineObj.LineNumber).prop('class', 'streamSelected');
$("#line-ui-" + lineObj.LineNumber + "-DisplayLineNo").html(" "+ lang.line +" "+ displayLineNumber);
$("#line-ui-" + lineObj.LineNumber + "-LineIcon").html(displayLineNumber);
// Switch the SIP Sessions
SwitchLines(lineObj.LineNumber);
// Update Lines List
for(var l = 0; l < Lines.length; l++) {
var classStr = (Lines[l].LineNumber == lineObj.LineNumber)? "buddySelected" : "buddy";
if(Lines[l].SipSession != null) classStr = (Lines[l].SipSession.local_hold)? "buddyActiveCallHollding" : "buddyActiveCall";
$("#line-" + Lines[l].LineNumber).prop('class', classStr);
Lines[l].IsSelected = (Lines[l].LineNumber == lineObj.LineNumber);
}
// Update Buddy List
for(var b = 0; b < Buddies.length; b++) {
$("#contact-" + Buddies[b].identity).prop("class", "buddy");
Buddies[b].IsSelected = false;
}
// Change to Stream if in Narrow view
UpdateUI();
}
function FindLineByNumber(lineNum) {
for(var l = 0; l < Lines.length; l++) {
if(Lines[l].LineNumber == lineNum) return Lines[l];
}
return null;
}
function AddLineHtml(lineObj) {
var html = "";
html += "";
// Close|Return|Back Button
html += ""
html += " ";
html += "
"
// Profile UI
html += "";
// Action Buttons
html += "";
html += "
";
// Separator --------------------------------------------------------------------------
html += "
"
// Calling UI --------------------------------------------------------------------------
html += "";
// Gneral Messages
html += "
";
html += "
...
";
// Dialing Out Progress
html += "
";
html += "
";
html += " "+ lang.cancel +" ";
html += "
";
html += "
";
// Active Call UI
html += "
";
// Group Call
html += "
";
// Video UI
if(lineObj.BuddyObj.type == "extension") {
html += "
";
// Presentation
html += "
"+ lang.present +": ";
html += "
";
html += " ";
html += " ";
html += " ";
html += " ";
html += " ";
html += "
";
html += "
";
html += "
";
html += "
";
// Preview
html += "
";
html += " "; // Default Display
html += "
";
// Stage
html += "
";
html += "
"; // Default Display
html += "
";
html += "
";
html += "
";
html += "
";
}
// Audio Call
html += "
";
// In Call Buttons
html += "
";
html += "
";
html += " ";
html += " ";
html += " ";
if(typeof MediaRecorder != "undefined" && (CallRecordingPolicy == "allow" || CallRecordingPolicy == "enabled")){
// Safari: must enable in Develop > Experimental Features > MediaRecorder
html += " ";
html += " ";
}
if(EnableTransfer){
html += " ";
html += " ";
}
html += " ";
html += " ";
html += " ";
html += "
";
// Call Transfer
html += "
";
html += "
";
html += " ";
html += " "+ lang.blind_transfer +" "
html += " "+ lang.attended_transfer +" ";
html += " "+ lang.complete_transfer +"";
html += " "+ lang.cancel_transfer +"";
html += " "+ lang.end_transfer_call +"";
html += "
";
html += "
...
";
html += "
";
html += "
";
// Call Conference
html += "
";
html += "
";
html += " ";
html += " "+ lang.call +" ";
html += " "+ lang.cancel_call +"";
html += " "+ lang.join_conference_call +"";
html += " "+ lang.end_conference_call +"";
html += "
";
html += "
...
";
html += "
";
html += "
";
// Monitoring
html += "
";
html += " ";
html += "";
html += " ";
html += " ";
html += " ";
html += "";
html += " ";
html += " ";
html += " "+ lang.device_settings +" ";
html += " "+ lang.call_stats +" ";
html += "
";
html += "
";
html += "
";
html += "
";
html += ""+ lang.send_statistics +" ";
html += " ";
html += " ";
html += " ";
html += "
";
html += ""+ lang.receive_statistics +" ";
html += " ";
html += " ";
html += " ";
html += " ";
html += " ";
html += " ";
html += "
";
html += "
";
html += "
";
html += "
";
html += " ";
html += "";
html += "";
// In Call Activity
html += "
";
html += " ";
html += "
";
$("#rightContent").append(html);
}
function RemoveLine(lineObj){
if(lineObj == null) return;
for(var l = 0; l < Lines.length; l++) {
if(Lines[l].LineNumber == lineObj.LineNumber) {
Lines.splice(l,1);
break;
}
}
CloseLine(lineObj.LineNumber);
$("#line-ui-"+ lineObj.LineNumber).remove();
UpdateBuddyList();
// Rather than showing nothing, go to the last buddy selected
// Select last user
if(localDB.getItem("SelectedBuddy") != null){
console.log("Selecting previously selected buddy...", localDB.getItem("SelectedBuddy"));
SelectBuddy(localDB.getItem("SelectedBuddy"));
UpdateUI();
}
}
function CloseLine(lineNum){
// Lines and Buddies (Left)
$(".buddySelected").each(function () {
$(this).prop('class', 'buddy');
});
// Streams (Right)
$(".streamSelected").each(function () {
$(this).prop('class', 'stream');
});
SwitchLines(0);
console.log("Closing Line: "+ lineNum);
for(var l = 0; l < Lines.length; l++){
Lines[l].IsSelected = false;
}
selectedLine = null;
for(var b = 0; b < Buddies.length; b++){
Buddies[b].IsSelected = false;
}
selectedBuddy = null;
$.jeegoopopup.close();
// Change to Stream if in Narrow view
UpdateUI();
}
function SwitchLines(lineNum){
$.each(userAgent.sessions, function (i, session) {
// All the other calls, not on hold
if(session.local_hold == false && session.data.line != lineNum) {
console.log("Putting an active call on hold: Line: "+ session.data.line +" buddy: "+ session.data.buddyId);
session.hold(); // Check state
// Log Hold
if(!session.data.hold) session.data.hold = [];
session.data.hold.push({ event: "hold", eventTime: utcDateNow() });
}
$("#line-" + session.data.line + "-btn-Hold").hide();
$("#line-" + session.data.line + "-btn-Unhold").show();
session.data.IsCurrentCall = false;
});
var lineObj = FindLineByNumber(lineNum);
if(lineObj != null && lineObj.SipSession != null) {
var session = lineObj.SipSession;
if(session.local_hold == true) {
console.log("Taking call off hold: Line: "+ lineNum +" buddy: "+ session.data.buddyId);
session.unhold();
// Log Hold
if(!session.data.hold) session.data.hold = [];
session.data.hold.push({ event: "unhold", eventTime: utcDateNow() });
}
$("#line-" + lineNum + "-btn-Hold").show();
$("#line-" + lineNum + "-btn-Unhold").hide();
session.data.IsCurrentCall = true;
}
selectedLine = lineNum;
RefreshLineActivity(lineNum);
}
function RefreshLineActivity(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) {
return;
}
var session = lineObj.SipSession;
$("#line-"+ lineNum +"-CallDetails").empty();
var callDetails = [];
var ringTime = 0;
var CallStart = moment.utc(session.data.callstart.replace(" UTC", ""));
var CallAnswer = null;
if(session.startTime){
CallAnswer = moment.utc(session.startTime);
ringTime = moment.duration(CallAnswer.diff(CallStart));
}
CallStart = CallStart.format("YYYY-MM-DD HH:mm:ss UTC")
CallAnswer = (CallAnswer)? CallAnswer.format("YYYY-MM-DD HH:mm:ss UTC") : null,
ringTime = (ringTime != 0)? ringTime.asSeconds() : 0
var srcCallerID = "";
var dstCallerID = "";
if(session.data.calldirection == "inbound") {
srcCallerID = "<"+ session.remoteIdentity.uri.user +"> "+ session.remoteIdentity.displayName;
}
else if(session.data.calldirection == "outbound") {
dstCallerID = session.remoteIdentity.uri.user;
}
var withVideo = (session.data.withvideo)? "("+ lang.with_video +")" : "";
var startCallMessage = (session.data.calldirection == "inbound")? lang.you_received_a_call_from + " " + srcCallerID +" "+ withVideo : lang.you_made_a_call_to + " " + dstCallerID +" "+ withVideo;
callDetails.push({
Message: startCallMessage,
TimeStr : CallStart
});
if(CallAnswer){
var answerCallMessage = (session.data.calldirection == "inbound")? lang.you_answered_after + " " + ringTime + " " + lang.seconds_plural : lang.they_answered_after + " " + ringTime + " " + lang.seconds_plural;
callDetails.push({
Message: answerCallMessage,
TimeStr : CallAnswer
});
}
var Transfers = (session.data.transfer)? session.data.transfer : [];
$.each(Transfers, function(item, transfer){
var msg = (transfer.type == "Blind")? lang.you_started_a_blind_transfer_to +" "+ transfer.to +". " : lang.you_started_an_attended_transfer_to + " "+ transfer.to +". ";
if(transfer.accept && transfer.accept.complete == true){
msg += lang.the_call_was_completed
}
else if(transfer.accept.disposition != "") {
msg += lang.the_call_was_not_completed +" ("+ transfer.accept.disposition +")"
}
callDetails.push({
Message : msg,
TimeStr : transfer.transferTime
});
});
var Mutes = (session.data.mute)? session.data.mute : []
$.each(Mutes, function(item, mute){
callDetails.push({
Message : (mute.event == "mute")? lang.you_put_the_call_on_mute : lang.you_took_the_call_off_mute,
TimeStr : mute.eventTime
});
});
var Holds = (session.data.hold)? session.data.hold : []
$.each(Holds, function(item, hold){
callDetails.push({
Message : (hold.event == "hold")? lang.you_put_the_call_on_hold : lang.you_took_the_call_off_hold,
TimeStr : hold.eventTime
});
});
var Recordings = (session.data.recordings)? session.data.recordings : []
$.each(Recordings, function(item, recording){
var msg = lang.call_is_being_recorded;
if(recording.startTime != recording.stopTime){
msg += "("+ lang.now_stopped +")"
}
callDetails.push({
Message : msg,
TimeStr : recording.startTime
});
});
var ConfCalls = (session.data.confcalls)? session.data.confcalls : []
$.each(ConfCalls, function(item, confCall){
var msg = lang.you_started_a_conference_call_to +" "+ confCall.to +". ";
if(confCall.accept && confCall.accept.complete == true){
msg += lang.the_call_was_completed
}
else if(confCall.accept.disposition != "") {
msg += lang.the_call_was_not_completed +" ("+ confCall.accept.disposition +")"
}
callDetails.push({
Message : msg,
TimeStr : confCall.startTime
});
});
callDetails.sort(function(a, b){
var aMo = moment.utc(a.TimeStr.replace(" UTC", ""));
var bMo = moment.utc(b.TimeStr.replace(" UTC", ""));
if (aMo.isSameOrAfter(bMo, "second")) {
return -1;
} else return 1;
return 0;
});
$.each(callDetails, function(item, detail){
var Time = moment.utc(detail.TimeStr.replace(" UTC", "")).local().format(DisplayTimeFormat);
var messageString = ""
messageString += ""
messageString += " "+ Time +"
"
messageString += ""+ detail.Message +"
"
messageString += " "
messageString += "
";
$("#line-"+ lineNum +"-CallDetails").prepend(messageString);
});
}
// Buddy & Contacts
// ================
var Buddy = function(type, identity, CallerIDName, ExtNo, MobileNumber, ContactNumber1, ContactNumber2, lastActivity, desc, Email){
this.type = type; // extension | contact | group
this.identity = identity;
this.CallerIDName = CallerIDName;
this.Email = Email;
this.Desc = desc;
this.ExtNo = ExtNo;
this.MobileNumber = MobileNumber;
this.ContactNumber1 = ContactNumber1;
this.ContactNumber2 = ContactNumber2;
this.lastActivity = lastActivity; // Full Date as string eg "1208-03-21 15:34:23 UTC"
this.devState = "dotOffline";
this.presence = "Unknown";
this.missed = 0;
this.IsSelected = false;
this.imageObjectURL = "";
}
function InitUserBuddies(){
var template = { TotalRows:0, DataCollection:[] }
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(template));
return JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
}
function MakeBuddy(type, update, focus, subscribe, callerID, did){
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json == null) json = InitUserBuddies();
var buddyObj = null;
if(type == "contact"){
var id = uID();
var dateNow = utcDateNow();
json.DataCollection.push({
Type: "contact",
LastActivity: dateNow,
ExtensionNumber: "",
MobileNumber: "",
ContactNumber1: did,
ContactNumber2: "",
uID: null,
cID: id,
gID: null,
DisplayName: callerID,
Position: "",
Description: "",
Email: "",
MemberCount: 0
});
buddyObj = new Buddy("contact", id, callerID, "", "", did, "", dateNow, "", "");
AddBuddy(buddyObj, update, focus);
}
else {
var id = uID();
var dateNow = utcDateNow();
json.DataCollection.push({
Type: "extension",
LastActivity: dateNow,
ExtensionNumber: did,
MobileNumber: "",
ContactNumber1: "",
ContactNumber2: "",
uID: id,
cID: null,
gID: null,
DisplayName: callerID,
Position: "",
Description: "",
Email: "",
MemberCount: 0
});
buddyObj = new Buddy("extension", id, callerID, did, "", "", "", dateNow, "", "");
AddBuddy(buddyObj, update, focus, subscribe);
}
// Update Size:
json.TotalRows = json.DataCollection.length;
// Save To DB
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
// Return new buddy
return buddyObj;
}
function UpdateBuddyCalerID(buddyObj, callerID){
buddyObj.CallerIDName = callerID;
var buddy = buddyObj.identity;
// Update DB
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json != null){
$.each(json.DataCollection, function (i, item) {
if(item.uID == buddy || item.cID == buddy || item.gID == buddy){
item.DisplayName = callerID;
return false;
}
});
// Save To DB
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
}
UpdateBuddyList();
}
function AddBuddy(buddyObj, update, focus, subscribe){
Buddies.push(buddyObj);
if(update == true) UpdateBuddyList();
AddBuddyMessageStream(buddyObj);
if(subscribe == true) SubscribeBuddy(buddyObj);
if(focus == true) SelectBuddy(buddyObj.identity);
}
function PopulateBuddyList() {
console.log("Clearing Buddies...");
Buddies = new Array();
console.log("Adding Buddies...");
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
if(json == null) return;
console.log("Total Buddies: " + json.TotalRows);
$.each(json.DataCollection, function (i, item) {
if(item.Type == "extension"){
// extension
var buddy = new Buddy("extension", item.uID, item.DisplayName, item.ExtensionNumber, item.MobileNumber, item.ContactNumber1, item.ContactNumber2, item.LastActivity, item.Position, item.Email);
AddBuddy(buddy, false, false);
}
else if(item.Type == "contact"){
// contact
var buddy = new Buddy("contact", item.cID, item.DisplayName, "", item.MobileNumber, item.ContactNumber1, item.ContactNumber2, item.LastActivity, item.Description, item.Email);
AddBuddy(buddy, false, false);
}
else if(item.Type == "group"){
// group
var buddy = new Buddy("group", item.gID, item.DisplayName, item.ExtensionNumber, "", "", "", item.LastActivity, item.MemberCount + " member(s)", item.Email);
AddBuddy(buddy, false, false);
}
});
// Update List (after add)
console.log("Updating Buddy List...");
UpdateBuddyList();
}
function UpdateBuddyList(){
var filter = $("#txtFindBuddy").val();
$("#myContacts").empty();
var callCount = 0
for(var l = 0; l < Lines.length; l++) {
var classStr = (Lines[l].IsSelected)? "buddySelected" : "buddy";
if(Lines[l].SipSession != null) classStr = (Lines[l].SipSession.local_hold)? "buddyActiveCallHollding" : "buddyActiveCall";
var html = "";
html += "
"+ (l + 1) +"
";
html += "
"+ lang.line +" "+ (l + 1) +"
";
html += "
";
html += "
"+ Lines[l].DisplayName +" <"+ Lines[l].DisplayNumber +">" +"
";
html += "
";
// SIP.Session.C.STATUS_TERMINATED
if(Lines[l].SipSession && Lines[l].SipSession.data.earlyReject != true){
$("#myContacts").append(html);
callCount ++;
}
}
// Sort and shuffle Buddy List
// ===========================
Buddies.sort(function(a, b){
var aMo = moment.utc(a.lastActivity.replace(" UTC", ""));
var bMo = moment.utc(b.lastActivity.replace(" UTC", ""));
if (aMo.isSameOrAfter(bMo, "second")) {
return -1;
} else return 1;
return 0;
});
for(var b = 0; b < Buddies.length; b++) {
var buddyObj = Buddies[b];
if(filter && filter.length >= 1){
// Perform Filter Display
var display = false;
if(buddyObj.CallerIDName.toLowerCase().indexOf(filter.toLowerCase()) > -1 ) display = true;
if(buddyObj.ExtNo.toLowerCase().indexOf(filter.toLowerCase()) > -1 ) display = true;
if(buddyObj.Desc.toLowerCase().indexOf(filter.toLowerCase()) > -1 ) display = true;
if(!display) continue;
}
var today = moment.utc();
var lastActivity = moment.utc(buddyObj.lastActivity.replace(" UTC", ""));
var displayDateTime = "";
if(lastActivity.isSame(today, 'day'))
{
displayDateTime = lastActivity.local().format(DisplayTimeFormat);
}
else {
displayDateTime = lastActivity.local().format(DisplayDateFormat);
}
var classStr = (buddyObj.IsSelected)? "buddySelected" : "buddy";
if(buddyObj.type == "extension") {
var friendlyState = buddyObj.presence;
if (friendlyState == "Unknown") friendlyState = lang.state_unknown;
if (friendlyState == "Not online") friendlyState = lang.state_not_online;
if (friendlyState == "Ready") friendlyState = lang.state_ready;
if (friendlyState == "On the phone") friendlyState = lang.state_on_the_phone;
if (friendlyState == "Ringing") friendlyState = lang.state_ringing;
if (friendlyState == "On hold") friendlyState = lang.state_on_hold;
if (friendlyState == "Unavailable") friendlyState = lang.state_unavailable;
// An extension on the same system
var html = "";
$("#myContacts").append(html);
} else if(buddyObj.type == "contact") {
// An Addressbook Contact
var html = "";
$("#myContacts").append(html);
} else if(buddyObj.type == "group"){
// A collection of extensions and contacts
var html = "";
$("#myContacts").append(html);
}
}
}
function AddBuddyMessageStream(buddyObj) {
var html = "";
html += "";
// Close|Return|Back Button
html += ""
html += " ";
html += "
"
// Profile UI
html += "";
// Action Buttons
html += "";
html += " ";
if(buddyObj.type == "extension" && EnableVideoCalling) {
html += " ";
}
html += " ";
if(buddyObj.type == "extension") {
html += " ";
}
html += " ";
html += "
";
// Separator --------------------------------------------------------------------------
html += "
"
// Calling UI --------------------------------------------------------------------------
html += "";
// Search & Related Elements
html += "";
html += " ";
html += "
";
html += " ";
html += "";
html += "";
// Previous Chat messages
html += "
";
html += " ";
if ((buddyObj.type == "extension" || buddyObj.type == "group") && EnableTextMessaging) {
html += "";
// Send Paste Image
html += "
";
// Send File
html += "";
html += " ";
html += "
";
// Send Audio Recording
html += "
";
// Send Video Recording
html += "
";
// Dictate Message
// html += "
";
// Emoji Menu Bar
html += "";
// =====================================
// Type Area
html += "";
html += " ";
html += " ";
html += " ";
html += " ";
html += "
";
html += " ";
}
html += "
";
$("#rightContent").append(html);
}
function RemoveBuddyMessageStream(buddyObj){
CloseBuddy(buddyObj.identity);
UpdateBuddyList();
// Remove Stream
$("#stream-"+ buddyObj.identity).remove();
var stream = JSON.parse(localDB.getItem(buddyObj.identity + "-stream"));
localDB.removeItem(buddyObj.identity + "-stream");
// Remove Buddy
var json = JSON.parse(localDB.getItem(profileUserID + "-Buddies"));
var x = 0;
$.each(json.DataCollection, function (i, item) {
if(item.uID == buddyObj.identity || item.cID == buddyObj.identity || item.gID == buddyObj.identity){
x = i;
return false;
}
});
json.DataCollection.splice(x,1);
json.TotalRows = json.DataCollection.length;
localDB.setItem(profileUserID + "-Buddies", JSON.stringify(json));
// Remove Images
localDB.removeItem("img-"+ buddyObj.identity +"-extension");
localDB.removeItem("img-"+ buddyObj.identity +"-contact");
localDB.removeItem("img-"+ buddyObj.identity +"-group");
// Remove Call Recordings
if(stream && stream.DataCollection && stream.DataCollection.length >= 1){
DeleteCallRecordings(buddyObj.identity, stream);
}
// Remove QOS Data
DeleteQosData(buddyObj.identity);
}
function DeleteCallRecordings(buddy, stream){
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallRecordings");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
// If this is the case, there will be no call recordings
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallRecordings");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("Recordings") == false){
console.warn("IndexDB CallRecordings.Recordings does not exists");
return;
}
IDB.onerror = function(event) {
console.error("IndexDB Error:", event);
}
// Loop and Delete
$.each(stream.DataCollection, function (i, item) {
if (item.Recordings && item.Recordings.length) {
$.each(item.Recordings, function (i, recording) {
console.log("Deleting Call Recording: ", recording.uID);
var objectStore = IDB.transaction(["Recordings"], "readwrite").objectStore("Recordings");
try{
var deleteRequest = objectStore.delete(recording.uID);
deleteRequest.onsuccess = function(event) {
console.log("Call Recording Deleted: ", recording.uID);
}
} catch(e){
console.log("Call Recording Delete failed: ", e);
}
});
}
});
}
}
function MakeUpName(){
var shortname = 4;
var longName = 12;
var letters = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var rtn = "";
rtn += letters[Math.floor(Math.random() * letters.length)];
for(var n=0; n 1){
if(item.MessageData.toLowerCase().indexOf(filter.toLowerCase()) != -1) return true;
if(filter.toLowerCase().indexOf(item.MessageData.toLowerCase()) != -1) return true;
}
if (item.ItemType == "MSG") {
// Special search
}
else if (item.ItemType == "CDR") {
// Tag search
if(item.Tags && item.Tags.length > 1){
var tagFilter = getFilter(filter, "tag");
if(tagFilter != "") {
if(item.Tags.some(function(i){
if(tagFilter.toLowerCase().indexOf(i.value.toLowerCase()) != -1) return true;
if(i.value.toLowerCase().indexOf(tagFilter.toLowerCase()) != -1) return true;
return false;
}) == true) return true;
}
}
}
else if(item.ItemType == "FILE"){
}
else if(item.ItemType == "SMS"){
// Not yet implemented
}
// return true to keep;
return false;
});
console.log("Rows After Filter: ", json.DataCollection.length);
}
// Create Buffer
if(json.DataCollection.length > StreamBuffer){
console.log("Rows:", json.DataCollection.length, " (will be trimed to "+ StreamBuffer +")");
// Always limit the Stream to {StreamBuffer}, users must search for messages further back
json.DataCollection.splice(StreamBuffer);
}
$.each(json.DataCollection, function (i, item) {
var IsToday = moment.utc(item.ItemDate.replace(" UTC", "")).isSame(moment.utc(), "day");
var DateTime = " " + moment.utc(item.ItemDate.replace(" UTC", "")).local().calendar(null, { sameElse: DisplayDateFormat });
if(IsToday) DateTime = " " + moment.utc(item.ItemDate.replace(" UTC", "")).local().format(DisplayTimeFormat);
if (item.ItemType == "MSG") {
// Add Chat Message
// ===================
var deliveryStatus = " ";
if(item.Sent == true) deliveryStatus = " ";
if(item.Sent == false) deliveryStatus = " ";
if(item.Delivered) deliveryStatus += " ";
var formattedMessage = ReformatMessage(item.MessageData);
var longMessage = (formattedMessage.length > 1000);
if (item.SrcUserId == profileUserID) {
// You are the source (sending)
if (formattedMessage.length != 0) {
var messageString = "";
messageString += "";
messageString += " ";
messageString += "" + formattedMessage + "
";
if(longMessage){
messageString += ""+ lang.read_more +"
";
}
messageString += "" + DateTime + " " + deliveryStatus +"
";
messageString += " ";
messageString += "
";
}
}
else {
// You are the destination (receiving)
var ActualSender = "";
if (formattedMessage.length != 0) {
var messageString = "";
messageString += "";
messageString += " ";
if(buddyObj.type == "group"){
messageString += "" + ActualSender + "
";
}
messageString += "" + formattedMessage + "
";
if(longMessage){
messageString += ""+ lang.read_more +"
";
}
messageString += ""+ DateTime + "
";
messageString += " ";
messageString += "
";
}
}
if (formattedMessage.length != 0) {
$("#contact-" + buddyObj.identity + "-ChatHistory").prepend(messageString);
}
}
else if (item.ItemType == "CDR") {
// Add CDR
// =======
var iconColor = (item.Billsec > 0)? "green" : "red";
var formattedMessage = "";
// Flagged
var flag = "";
flag += " ";
flag += " ";
// Comment
var callComment = "";
if(item.MessageData) callComment = item.MessageData;
// Tags
if(!item.Tags) item.Tags = [];
var CallTags = "";
// Call Type
var callIcon = (item.WithVideo)? "fa-video-camera" : "fa-phone";
formattedMessage += " ";
var audioVideo = (item.WithVideo)? lang.a_video_call : lang.an_audio_call;
// Recordings
var recordingsHtml = "";
if(item.Recordings && item.Recordings.length >= 1){
$.each(item.Recordings, function (i, recording) {
if(recording.uID){
var StartTime = moment.utc(recording.startTime.replace(" UTC", "")).local();
var StopTime = moment.utc(recording.stopTime.replace(" UTC", "")).local();
var recordingDuration = moment.duration(StopTime.diff(StartTime));
recordingsHtml += "";
if(item.WithVideo){
if(recording.Poster){
var posterWidth = recording.Poster.width;
var posterHeight = recording.Poster.height;
var posterImage = recording.Poster.posterBase64;
recordingsHtml += "
";
}
else {
recordingsHtml += "
";
}
}
else {
recordingsHtml += "
";
}
recordingsHtml += "
"+ lang.started +": "+ StartTime.format(DisplayTimeFormat) +" "+ lang.stopped +": "+ StopTime.format(DisplayTimeFormat) +"
";
recordingsHtml += "
"+ lang.recording_duration +": "+ formatShortDuration(recordingDuration.asSeconds()) +"
";
recordingsHtml += "
";
recordingsHtml += " ";
recordingsHtml += " ";
recordingsHtml += " ";
recordingsHtml += " ";
recordingsHtml += "
";
recordingsHtml += "
";
}
});
}
if (item.SrcUserId == profileUserID) {
// (Outbound) You(profileUserID) initiated a call
if(item.Billsec == "0") {
formattedMessage += " "+ lang.you_tried_to_make +" "+ audioVideo +" ("+ item.ReasonText +").";
}
else {
formattedMessage += " "+ lang.you_made + " "+ audioVideo +", "+ lang.and_spoke_for +" " + formatDuration(item.Billsec) + ".";
}
var messageString = ""
messageString += "" + flag + " "
messageString += "";
messageString += " ";
messageString += "" + formattedMessage + "
";
messageString += "" + CallTags + "
";
messageString += "";
messageString += "" + recordingsHtml + "
";
messageString += "" + DateTime + "
";
messageString += " "
messageString += "
";
}
else {
// (Inbound) you(profileUserID) received a call
if(item.Billsec == "0"){
formattedMessage += " "+ lang.you_missed_a_call + " ("+ item.ReasonText +").";
}
else {
formattedMessage += " "+ lang.you_recieved + " "+ audioVideo +", "+ lang.and_spoke_for +" " + formatDuration(item.Billsec) + ".";
}
var messageString = "";
messageString += "";
messageString += " ";
messageString += "" + formattedMessage + "
";
messageString += "" + CallTags + "
";
messageString += "";
messageString += "" + recordingsHtml + "
";
messageString += " " + DateTime + "
";
messageString += " ";
messageString += "" + flag + " ";
messageString += "
";
}
// Messges are reappended here, and appended when logging
$("#contact-" + buddyObj.identity + "-ChatHistory").prepend(messageString);
}
else if (item.ItemType == "FILE") {
if (item.SrcUserId == profileUserID) {
// File is sent
var sentFileSection = ""
sentFileSection += "";
sentFileSection += " ";
sentFileSection += "
";
$("#contact-" + buddyObj.identity + "-ChatHistory").prepend(sentFileSection);
$("#sendFileLoader").remove();
} else {
// File is received
var recFileSection = ""
recFileSection += "";
recFileSection += " ";
recFileSection += "
";
$("#contact-" + buddyObj.identity + "-ChatHistory").prepend(recFileSection);
}
}
else if(item.ItemType == "SMS"){
}
});
// For some reason, the first time this fires, it doesn't always work
updateScroll(buddyObj.identity);
window.setTimeout(function(){
updateScroll(buddyObj.identity);
}, 300);
}
function ShowChatMenu(obj){
$(obj).children("span").show();
}
function HideChatMenu(obj){
$(obj).children("span").hide();
}
function ExpandMessage(obj, ItemId, buddy){
$("#msg-text-" + ItemId).css("max-height", "");
$("#msg-text-" + ItemId).css("overflow", "");
$("#msg-readmore-" + ItemId).remove();
$.jeegoopopup.close();
}
function ShowBuddyDial(obj, buddy){
$("#contact-"+ buddy +"-email").show();
$("#contact-"+ buddy +"-audio-dial").show();
$("#contact-"+ buddy +"-video-dial").show();
}
function HideBuddyDial(obj, buddy){
$("#contact-"+ buddy +"-email").hide();
$("#contact-"+ buddy +"-audio-dial").hide();
$("#contact-"+ buddy +"-video-dial").hide();
}
function QuickDialAudio(buddy, obj, event){
AudioCallMenu(buddy, obj);
event.stopPropagation();
}
function QuickDialVideo(buddy, ExtNo, event){
event.stopPropagation();
window.setTimeout(function(){
DialByLine('video', buddy, ExtNo);
}, 300);
}
// Sessions
// ========
function ExpandVideoArea(lineNum){
$("#line-" + lineNum + "-ActiveCall").prop("class","FullScreenVideo");
$("#line-" + lineNum + "-VideoCall").css("height", "calc(100% - 100px)");
$("#line-" + lineNum + "-VideoCall").css("margin-top", "0px");
$("#line-" + lineNum + "-preview-container").prop("class","PreviewContainer PreviewContainer_FS");
$("#line-" + lineNum + "-stage-container").prop("class","StageContainer StageContainer_FS");
$("#line-" + lineNum + "-restore").show();
$("#line-" + lineNum + "-expand").hide();
$("#line-" + lineNum + "-monitoring").hide();
}
function RestoreVideoArea(lineNum){
$("#line-" + lineNum + "-ActiveCall").prop("class","");
$("#line-" + lineNum + "-VideoCall").css("height", "");
$("#line-" + lineNum + "-VideoCall").css("margin-top", "10px");
$("#line-" + lineNum + "-preview-container").prop("class","PreviewContainer");
$("#line-" + lineNum + "-stage-container").prop("class","StageContainer");
$("#line-" + lineNum + "-restore").hide();
$("#line-" + lineNum + "-expand").show();
$("#line-" + lineNum + "-monitoring").show();
}
function MuteSession(lineNum){
$("#line-"+ lineNum +"-btn-Unmute").show();
$("#line-"+ lineNum +"-btn-Mute").hide();
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
var session = lineObj.SipSession;
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track.kind == "audio") {
if(RTCRtpSender.track.IsMixedTrack == true){
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
console.log("Muting Audio Track : "+ session.data.AudioSourceTrack.label);
session.data.AudioSourceTrack.enabled = false;
}
}
else {
console.log("Muting Audio Track : "+ RTCRtpSender.track.label);
RTCRtpSender.track.enabled = false;
}
}
});
if(!session.data.mute) session.data.mute = [];
session.data.mute.push({ event: "mute", eventTime: utcDateNow() });
session.data.ismute = true;
$("#line-" + lineNum + "-msg").html(lang.call_on_mute);
updateLineScroll(lineNum);
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("mute", session);
}
function UnmuteSession(lineNum){
$("#line-"+ lineNum +"-btn-Unmute").hide();
$("#line-"+ lineNum +"-btn-Mute").show();
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
var session = lineObj.SipSession;
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track.kind == "audio") {
if(RTCRtpSender.track.IsMixedTrack == true){
if(session.data.AudioSourceTrack && session.data.AudioSourceTrack.kind == "audio"){
console.log("Unmuting Audio Track : "+ session.data.AudioSourceTrack.label);
session.data.AudioSourceTrack.enabled = true;
}
}
else {
console.log("Unmuting Audio Track : "+ RTCRtpSender.track.label);
RTCRtpSender.track.enabled = true;
}
}
});
if(!session.data.mute) session.data.mute = [];
session.data.mute.push({ event: "unmute", eventTime: utcDateNow() });
session.data.ismute = false;
$("#line-" + lineNum + "-msg").html(lang.call_off_mute);
updateLineScroll(lineNum);
// Custom Web hook
if(typeof web_hook_on_modify !== 'undefined') web_hook_on_modify("unmute", session);
}
function ShowDtmfMenu(obj, lineNum){
var leftPos = event.pageX - 90;
var topPos = event.pageY + 30;
var html = "";
html += "
";
html += "1
"
html += "2
ABC "
html += "3
DEF ";
html += "4
GHI "
html += "5
JKL "
html += "6
MNO ";
html += "7
PQRS "
html += "8
TUV "
html += "9
WXYZ ";
html += "* "
html += "0 "
html += "# ";
html += "
";
html += "
";
$.jeegoopopup.open({
html: html,
width: "auto",
height: "auto",
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
// Stream Functionality
// =====================
function ShowMessgeMenu(obj, typeStr, cdrId, buddy) {
$.jeegoopopup.close();
var leftPos = event.pageX;
var topPos = event.pageY;
if (($(window).width() - event.pageX) < (obj.offsetWidth + 50)) { leftPos = event.pageX - 200; }
var menu = "";
$.jeegoopopup.open({
html: menu,
width: 'auto',
height: 'auto',
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: false,
resizable: false,
fadeIn: 0
});
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
// CDR messages
$("#CMDetails_1").click(function(event) {
var cdr = null;
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "CDR" && item.CdrId == cdrId) {
// Found
cdr = item;
return false;
}
});
}
if(cdr == null) return;
var callDetails = [];
var html = '';
html += "";
var CallDate = moment.utc(cdr.ItemDate.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat);
var CallAnswer = (cdr.CallAnswer)? moment.utc(cdr.CallAnswer.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat) : null ;
var ringTime = (cdr.RingTime)? cdr.RingTime : 0 ;
var CallEnd = moment.utc(cdr.CallEnd.replace(" UTC", "")).local().format(DisplayDateFormat +" "+ DisplayTimeFormat);
var srcCallerID = "";
var dstCallerID = "";
if(cdr.CallDirection == "inbound") {
srcCallerID = cdr.Src;
}
else if(cdr.CallDirection == "outbound") {
dstCallerID = cdr.Dst;
}
html += "
SIP CallID : "+ cdr.SessionId +"
";
html += "
"+ lang.call_direction +" : "+ cdr.CallDirection +"
";
html += "
"+ lang.call_date_and_time +" : "+ CallDate +"
";
html += "
"+ lang.ring_time +" : "+ formatDuration(ringTime) +" ("+ ringTime +")
";
html += "
"+ lang.talk_time +" : " + formatDuration(cdr.Billsec) +" ("+ cdr.Billsec +")
";
html += "
"+ lang.call_duration +" : "+ formatDuration(cdr.TotalDuration) +" ("+ cdr.TotalDuration +")
";
html += "
"+ lang.video_call +" : "+ ((cdr.WithVideo)? lang.yes : lang.no) +"
";
html += "
"+ lang.flagged +" : "+ ((cdr.Flagged)? " " + lang.yes : lang.no) +"
";
html += "
";
html += "
"+ lang.call_tags +" ";
html += "
";
$.each(cdr.Tags, function(item, tag){
html += "
"+ tag.value +" "
});
html += "
"+ lang.call_notes +" ";
html += "
";
if(cdr.MessageData){
html += "\"" + cdr.MessageData + "\"";
}
html += "
"+ lang.activity_timeline +" ";
html += "
";
var withVideo = (cdr.WithVideo)? "("+ lang.with_video +")" : "";
var startCallMessage = (cdr.CallDirection == "inbound")? lang.you_received_a_call_from + " " + srcCallerID +" "+ withVideo : lang.you_made_a_call_to + " " + dstCallerID +" "+ withVideo;
callDetails.push({
Message: startCallMessage,
TimeStr: cdr.ItemDate
});
if(CallAnswer){
var answerCallMessage = (cdr.CallDirection == "inbound")? lang.you_answered_after + " " + ringTime + " " + lang.seconds_plural : lang.they_answered_after + " " + ringTime + " " + lang.seconds_plural;
callDetails.push({
Message: answerCallMessage,
TimeStr: cdr.CallAnswer
});
}
$.each(cdr.Transfers, function(item, transfer){
var msg = (transfer.type == "Blind")? lang.you_started_a_blind_transfer_to +" "+ transfer.to +". " : lang.you_started_an_attended_transfer_to + " "+ transfer.to +". ";
if(transfer.accept && transfer.accept.complete == true){
msg += lang.the_call_was_completed
}
else if(transfer.accept.disposition != "") {
msg += lang.the_call_was_not_completed +" ("+ transfer.accept.disposition +")"
}
callDetails.push({
Message : msg,
TimeStr : transfer.transferTime
});
});
$.each(cdr.Mutes, function(item, mute){
callDetails.push({
Message : (mute.event == "mute")? lang.you_put_the_call_on_mute : lang.you_took_the_call_off_mute,
TimeStr : mute.eventTime
});
});
$.each(cdr.Holds, function(item, hold){
callDetails.push({
Message : (hold.event == "hold")? lang.you_put_the_call_on_hold : lang.you_took_the_call_off_hold,
TimeStr : hold.eventTime
});
});
$.each(cdr.ConfCalls, function(item, confCall){
var msg = lang.you_started_a_conference_call_to +" "+ confCall.to +". ";
if(confCall.accept && confCall.accept.complete == true){
msg += lang.the_call_was_completed
}
else if(confCall.accept.disposition != "") {
msg += lang.the_call_was_not_completed +" ("+ confCall.accept.disposition +")"
}
callDetails.push({
Message : msg,
TimeStr : confCall.startTime
});
});
$.each(cdr.Recordings, function(item, recording){
var StartTime = moment.utc(recording.startTime.replace(" UTC", "")).local();
var StopTime = moment.utc(recording.stopTime.replace(" UTC", "")).local();
var recordingDuration = moment.duration(StopTime.diff(StartTime));
var msg = lang.call_is_being_recorded;
if(recording.startTime != recording.stopTime){
msg += "("+ formatShortDuration(recordingDuration.asSeconds()) +")"
}
callDetails.push({
Message : msg,
TimeStr : recording.startTime
});
});
callDetails.push({
Message: (cdr.Terminate == "us")? "You ended the call." : "They ended the call",
TimeStr : cdr.CallEnd
});
callDetails.sort(function(a, b){
var aMo = moment.utc(a.TimeStr.replace(" UTC", ""));
var bMo = moment.utc(b.TimeStr.replace(" UTC", ""));
if (aMo.isSameOrAfter(bMo, "second")) {
return 1;
} else return -1;
return 0;
});
$.each(callDetails, function(item, detail){
var Time = moment.utc(detail.TimeStr.replace(" UTC", "")).local().format(DisplayTimeFormat);
var messageString = "
"
messageString += ""
messageString += " "+ Time +"
"
messageString += ""+ detail.Message +"
"
messageString += " "
messageString += "
";
html += messageString;
});
html += "
"+ lang.call_recordings +" ";
html += "
";
var recordingsHtml = "";
$.each(cdr.Recordings, function(r, recording){
if(recording.uID){
var StartTime = moment.utc(recording.startTime.replace(" UTC", "")).local();
var StopTime = moment.utc(recording.stopTime.replace(" UTC", "")).local();
var recordingDuration = moment.duration(StopTime.diff(StartTime));
recordingsHtml += "
";
if(cdr.WithVideo){
recordingsHtml += "
";
}
else {
recordingsHtml += "
";
}
recordingsHtml += "
"+ lang.started +": "+ StartTime.format(DisplayTimeFormat) +" "+ lang.stopped +": "+ StopTime.format(DisplayTimeFormat) +"
";
recordingsHtml += "
"+ lang.recording_duration +": "+ formatShortDuration(recordingDuration.asSeconds()) +"
";
recordingsHtml += "
";
recordingsHtml += "
";
}
});
html += recordingsHtml;
html += "
"+ lang.send_statistics +" ";
html += "
";
html += "
";
html += "
";
html += "
"+ lang.receive_statistics +" ";
html += "
";
html += "
";
html += "
";
html += "
";
html += "
";
html += "
";
html += "
";
$.jeegoopopup.close();
$.jeegoopopup.open({
title: 'Call Statistics',
html: html,
width: '640',
height: '500',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_b").append(''+ lang.ok +' ');
// Display QOS data
DisplayQosData(cdr.SessionId);
var maxWidth = $(window).width() - 12;
var maxHeight = $(window).height() - 88;
if (maxWidth < 656 || maxHeight < 500) {
$.jeegoopopup.width(maxWidth).height(maxHeight);
$.jeegoopopup.center();
$("#maximizeImg").hide();
$("#minimizeImg").hide();
} else {
$.jeegoopopup.width(640).height(500);
$.jeegoopopup.center();
$("#minimizeImg").hide();
$("#maximizeImg").show();
}
$(window).resize(function() {
maxWidth = $(window).width() - 12;
maxHeight = $(window).height() - 88;
$.jeegoopopup.center();
if (maxWidth < 656 || maxHeight < 500) {
$.jeegoopopup.width(maxWidth).height(maxHeight);
$.jeegoopopup.center();
$("#maximizeImg").hide();
$("#minimizeImg").hide();
} else {
$.jeegoopopup.width(640).height(500);
$.jeegoopopup.center();
$("#minimizeImg").hide();
$("#maximizeImg").show();
}
});
$("#minimizeImg").click(function() { $.jeegoopopup.width(640).height(500); $.jeegoopopup.center(); $("#maximizeImg").show(); $("#minimizeImg").hide(); });
$("#maximizeImg").click(function() { $.jeegoopopup.width(maxWidth).height(maxHeight); $.jeegoopopup.center(); $("#minimizeImg").show(); $("#maximizeImg").hide(); });
$("#closeImg").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#ok_button").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); $("#jg_popup_b").empty(); } });
// Queue video and audio
$.each(cdr.Recordings, function(r, recording){
var mediaObj = null;
if(cdr.WithVideo){
mediaObj = $("#callrecording-video-"+ recording.uID).get(0);
}
else {
mediaObj = $("#callrecording-audio-"+ recording.uID).get(0);
}
var downloadURL = $("#download-"+ recording.uID);
// Playback device
var sinkId = getAudioOutputID();
if (typeof mediaObj.sinkId !== 'undefined') {
mediaObj.setSinkId(sinkId).then(function(){
console.log("sinkId applied: "+ sinkId);
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
} else {
console.warn("setSinkId() is not possible using this browser.")
}
// Get Call Recording
var indexedDB = window.indexedDB;
var request = indexedDB.open("CallRecordings");
request.onerror = function(event) {
console.error("IndexDB Request Error:", event);
}
request.onupgradeneeded = function(event) {
console.warn("Upgrade Required for IndexDB... probably because of first time use.");
}
request.onsuccess = function(event) {
console.log("IndexDB connected to CallRecordings");
var IDB = event.target.result;
if(IDB.objectStoreNames.contains("Recordings") == false){
console.warn("IndexDB CallRecordings.Recordings does not exists");
return;
}
var transaction = IDB.transaction(["Recordings"]);
var objectStoreGet = transaction.objectStore("Recordings").get(recording.uID);
objectStoreGet.onerror = function(event) {
console.error("IndexDB Get Error:", event);
}
objectStoreGet.onsuccess = function(event) {
var mediaBlobUrl = window.URL.createObjectURL(event.target.result.mediaBlob);
mediaObj.src = mediaBlobUrl;
// Download Link
if(cdr.WithVideo){
downloadURL.prop("download", "Video-Call-Recording-"+ recording.uID +".webm");
}
else {
downloadURL.prop("download", "Audio-Call-Recording-"+ recording.uID +".webm");
}
downloadURL.prop("href", mediaBlobUrl);
}
}
});
});
$("#CMDetails_2").click(function(event) {
$("#cdr-tags-"+ cdrId).show();
$.jeegoopopup.close();
});
$("#CMDetails_3").click(function(event) {
// Tag / Untag Call
var TagState = $("#cdr-flagged-"+ cdrId).is(":visible");
if(TagState){
console.log("Clearing Flag from: ", cdrId);
$("#cdr-flagged-"+ cdrId).hide();
// Update DB
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "CDR" && item.CdrId == cdrId) {
// Found
item.Flagged = false;
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
}
}
else {
console.log("Flag Call: ", cdrId);
$("#cdr-flagged-"+ cdrId).show();
// Update DB
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "CDR" && item.CdrId == cdrId) {
// Found
item.Flagged = true;
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
}
}
$.jeegoopopup.close();
});
$("#CMDetails_4").click(function(event) {
var currentText = $("#cdr-comment-"+ cdrId).text();
$("#cdr-comment-"+ cdrId).empty();
var textboxObj = $(" ").appendTo("#cdr-comment-"+ cdrId);
textboxObj.on("focus", function(){
$.jeegoopopup.close();
});
textboxObj.on("blur", function(){
var newText = $(this).val();
SaveComment(cdrId, buddy, newText);
});
textboxObj.keypress(function(event){
window.setTimeout(function(){
$.jeegoopopup.close();
}, 500);
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13') {
event.preventDefault();
var newText = $(this).val();
SaveComment(cdrId, buddy, newText);
}
});
textboxObj.val(currentText);
textboxObj.focus();
$.jeegoopopup.close();
});
$("#CMDetails_5").click(function(event) {
// Text Messages
var msgtext = $("#msg-text-"+ cdrId).text();
navigator.clipboard.writeText(msgtext).then(function(){
console.log("Text coppied to the clipboard:", msgtext);
}).catch(function(){
console.error("Error writing to the clipboard:", e);
});
$.jeegoopopup.close();
});
$("#CMDetails_6").click(function(event) {
var msgtext = $("#msg-text-"+ cdrId).text();
msgtext = "\""+ msgtext + "\"";
var textarea = $("#contact-"+ buddy +"-ChatMessage");
console.log("Quote Message:", msgtext);
textarea.val(msgtext +"\n" + textarea.val());
$.jeegoopopup.close();
});
}
function SaveComment(cdrId, buddy, newText){
console.log("Setting Comment:", newText);
$("#cdr-comment-"+ cdrId).empty();
$("#cdr-comment-"+ cdrId).append(newText);
// Update DB
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "CDR" && item.CdrId == cdrId) {
// Found
item.MessageData = newText;
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
}
}
function TagKeyPress(event, obj, cdrId, buddy){
$.jeegoopopup.close();
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13' || keycode == '44') {
event.preventDefault();
if ($(obj).val() == "") return;
console.log("Adding Tag:", $(obj).val());
$("#cdr-tags-"+ cdrId+" li:last").before(""+ $(obj).val() +" ");
$(obj).val("");
// Update DB
UpdateTags(cdrId, buddy);
}
}
function TagClick(obj, cdrId, buddy){
window.setTimeout(function(){
$.jeegoopopup.close();
}, 500);
console.log("Removing Tag:", $(obj).text());
$(obj).remove();
// Dpdate DB
UpdateTags(cdrId, buddy);
}
function UpdateTags(cdrId, buddy){
var currentStream = JSON.parse(localDB.getItem(buddy + "-stream"));
if(currentStream != null || currentStream.DataCollection != null){
$.each(currentStream.DataCollection, function (i, item) {
if (item.ItemType == "CDR" && item.CdrId == cdrId) {
// Found
item.Tags = [];
$("#cdr-tags-"+ cdrId).children('li').each(function () {
if($(this).prop("class") != "tagText") item.Tags.push({ value: $(this).text() });
});
return false;
}
});
localDB.setItem(buddy + "-stream", JSON.stringify(currentStream));
}
}
function TagFocus(obj){
$.jeegoopopup.close();
}
function SendFile(buddy) {
$('#selectedFile').val('');
$("#upFile").empty();
var buddyObj = FindBuddyByIdentity(buddy);
var uploadfile = '';
if ($("#sendFileFormChat").is(":visible")) {
$("#sendFileFormChat").remove();
sendFileCheck = 0;
} else {
sendFileCheck = 1;
$("#contact-"+ buddy +"-ChatMessage").before(uploadfile);
$("#sendFileFormChat").css("display", "block");
$("#selectedFile").bind("change", function() {
upFileName = $(this).val().split('\\').pop();
if (/^[a-zA-Z0-9\-\_\.]+$/.test(upFileName)) {
$("#upFile").html(upFileName);
} else {
$("#sendFileFormChat").remove();
sendFileCheck = 0;
alert("The name of the uploaded file is not valid!");
}
});
}
}
function ShowEmojiBar(buddy) {
var messageContainer = $("#contact-"+ buddy +"-emoji-menu");
var textarea = $("#contact-"+ buddy +"-ChatMessage");
if (messageContainer.is(":visible")) { messageContainer.hide(); } else { messageContainer.show(); }
var menuBar = $("");
menuBar.prop("class", "emojiButton")
var emojis = ["😀","😁","😂","😃","😄","😅","😆","😊","😦","😉","😊","😋","😌","😍","😎","😏","😐","😑","😒","😓","😔","😕","😖","😗","😘","😙","😚","😛","😜","😝","😞","😟","😠","😡","😢","😣","😤","😥","😦","😧","😨","😩","😪","😫","😬","😭","😮","😯","😰","😱","😲","😳","😴","😵","😶","😷","🙁","🙂","🙃","🙄","🤐","🤑","🤒","🤓","🤔","🤕","🤠","🤡","🤢","🤣","🤤","🤥","🤧","🤨","🤩","🤪","🤫","🤬","🥺","🤭","🤯","🧐"];
$.each(emojis, function(i,e){
var emoji = $("
");
emoji.html(e);
emoji.on('click', function() {
var i = textarea.prop('selectionStart');
var v = textarea.val();
textarea.val(v.substring(0, i) + " " + $(this).html() + v.substring(i, v.length) + " ");
messageContainer.hide();
textarea.focus();
updateScroll(buddy);
});
menuBar.append(emoji);
});
$(".chatMessage,.chatHistory").on('click', function(){
messageContainer.hide();
});
messageContainer.empty();
messageContainer.append(menuBar);
updateScroll(buddy);
}
// My Profile
// ==========
function ShowMyProfileMenu(obj){
var leftPos = obj.offsetWidth - 254;
var topPos = obj.offsetHeight + 56 ;
var usrRoleFromDB = getDbItem("userrole", "");
if (usrRoleFromDB == "superadmin") { var usrRole = "(superadmin)"; } else { var usrRole = ""; }
var currentUser = '' + userName + ' ' + usrRole + ' ';
var autoAnswerCheck = AutoAnswerEnabled ? " " : "";
var doNotDisturbCheck = DoNotDisturbEnabled ? " " : "";
var callWaitingCheck = CallWaitingEnabled ? " " : "";
var menu = "";
$.jeegoopopup.open({
html: menu,
width: 'auto',
height: 'auto',
left: '56',
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
innerClass: 'userMenuInner',
contentClass: 'userMenuContent',
overlay: true,
opacity: 0,
draggable: false,
resizable: false,
fadeIn: 0
});
$(window).resize(function() {
$.jeegoopopup.width('auto').height('auto').left('56').top(topPos);
});
$("#userMenu_1").click(function() {
ToggleAutoAnswer();
if (AutoAnswerEnabled) {
$("#autoAnswerTick").append(" ");
} else {
$("#autoAnswerTick").empty();
}
});
$("#userMenu_2").click(function() {
ToggleDoNoDisturb();
if (DoNotDisturbEnabled) {
$("#doNotDisturbTick").append(" ");
} else {
$("#doNotDisturbTick").empty();
}
});
$("#userMenu_3").click(function() {
ToggleCallWaiting();
if (CallWaitingEnabled) {
$("#callWaitingTick").append(" ");
} else {
$("#callWaitingTick").empty();
}
});
$("#userMenu_4").click(function() { RefreshRegistration(); });
$("#userMenu_5").click(function() { AddSomeoneWindow(); });
$("#userMenu_8").click(function() { SignOut(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
function ShowLaunchVidConfMenu(obj){
var leftPos = obj.offsetWidth + 121;
var rightPos = 0;
var topPos = obj.offsetHeight + 117;
if ($(window).width() <= 915) {
leftPos = event.pageX + obj.offsetWidth - 113;
rightPos = 0;
topPos = event.pageY + obj.offsetHeight - 11;
}
var vcmenu = "";
$.jeegoopopup.open({
html: vcmenu,
width: '228',
height: '22',
left: leftPos,
right: rightPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: false,
resizable: false,
fadeIn: 0
});
$(window).resize(function() {
$.jeegoopopup.width('228').height('22').left(leftPos).top(topPos);
});
if ($(window).width() <= 915) { $.jeegoopopup.right(6); } else { $.jeegoopopup.width('228').height('22').left(leftPos).top(topPos); }
$("#launchVConfMenu_1").click(function() { LaunchVideoConference(); $.jeegoopopup.close(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
function ShowAccountSettingsMenu(obj) {
$.jeegoopopup.close();
var leftPos = obj.offsetWidth + 212;
var rightPos = 0;
var topPos = obj.offsetHeight + 117;
if ($(window).width() <= 915) {
leftPos = event.pageX - 32;
rightPos = 0;
topPos = event.pageY + 11;
}
var setconfmenu = "";
$.jeegoopopup.open({
html: setconfmenu,
width: '94',
height: '22',
left: leftPos,
right: rightPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: false,
resizable: false,
fadeIn: 0
});
$(window).resize(function() {
$.jeegoopopup.width('94').height('22').left(leftPos).top(topPos);
});
if ($(window).width() <= 915) { $.jeegoopopup.right(6); } else { $.jeegoopopup.width('94').height('22').left(leftPos).top(topPos); }
$("#settingsCMenu_1").click(function() { ConfigureExtensionWindow(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
function RefreshRegistration(){
Unregister();
console.log("Unregister complete...");
window.setTimeout(function(){
console.log("Starting registration...");
Register();
}, 1000);
}
function SignOut() {
if (getDbItem("useRoundcube", "") == 1 && RCLoginCheck == 1) {
// Log out from Roundcube
$("#roundcubeFrame").remove();
$("#rightContent").show();
$(".streamSelected").each(function() { $(this).css("display", "none"); });
$("#rightContent").append('');
var logoutURL = "https://"+ getDbItem("rcDomain", "") +"/";
var logoutform = '';
$("#rcLogoutFrame").append(logoutform);
$("#submitloButton").click();
RCLoginCheck == 0;
}
// Remove the 'uploads' directory used to temporarily store files received during text chat
removeTextChatUploads(getDbItem("SipUsername", ""));
setTimeout(function() {
// Check if there are any configured external video conference users
var externalLinks = getDbItem("externalUserConfElem", "");
if (typeof externalLinks !== 'undefined' && externalLinks != null && externalLinks != 0) {
checkExternalLinks();
} else {
Unregister();
console.log("Signing Out ...");
localStorage.clear();
if (winVideoConf != null) {
winVideoConf.close();
}
window.open('https://' + window.location.host + '/logout.php', '_self');
}
}, 100);
}
function ToggleAutoAnswer(){
if(AutoAnswerPolicy == "disabled"){
AutoAnswerEnabled = false;
console.warn("Policy AutoAnswer: Disabled");
return;
}
AutoAnswerEnabled = (AutoAnswerEnabled == true)? false : true;
if(AutoAnswerPolicy == "enabled") AutoAnswerEnabled = true;
localDB.setItem("AutoAnswerEnabled", (AutoAnswerEnabled == true)? "1" : "0");
console.log("AutoAnswer:", AutoAnswerEnabled);
}
function ToggleDoNoDisturb(){
if(DoNotDisturbPolicy == "disabled"){
DoNotDisturbEnabled = false;
console.warn("Policy DoNotDisturb: Disabled");
return;
}
DoNotDisturbEnabled = (DoNotDisturbEnabled == true)? false : true;
if(DoNotDisturbPolicy == "enabled") DoNotDisturbEnabled = true;
localDB.setItem("DoNotDisturbEnabled", (DoNotDisturbEnabled == true)? "1" : "0");
$("#dereglink").attr("class", (DoNotDisturbEnabled == true)? "dotDoNotDisturb" : "dotOnline" );
console.log("DoNotDisturb", DoNotDisturbEnabled);
}
function ToggleCallWaiting(){
if(CallWaitingPolicy == "disabled"){
CallWaitingEnabled = false;
console.warn("Policy CallWaiting: Disabled");
return;
}
CallWaitingEnabled = (CallWaitingEnabled == true)? false : true;
if(CallWaitingPolicy == "enabled") CallWaitingPolicy = true;
localDB.setItem("CallWaitingEnabled", (CallWaitingEnabled == true)? "1" : "0");
console.log("CallWaiting", CallWaitingEnabled);
}
function ToggleRecordAllCalls(){
if(CallRecordingPolicy == "disabled"){
RecordAllCalls = false;
console.warn("Policy CallRecording: Disabled");
return;
}
RecordAllCalls = (RecordAllCalls == true)? false : true;
if(CallRecordingPolicy == "enabled") RecordAllCalls = true;
localDB.setItem("RecordAllCalls", (RecordAllCalls == true)? "1" : "0");
console.log("RecordAllCalls", RecordAllCalls);
}
function ShowBuddyProfileMenu(buddy, obj, typeStr){
$.jeegoopopup.close();
leftPos = event.pageX - 60;
topPos = event.pageY + 45;
var buddyObj = FindBuddyByIdentity(buddy);
if (typeStr == "extension") {
var html = "";
html += "
";
html += "
"
html += "
";
$.jeegoopopup.open({
html: html,
width: '200',
height: 'auto',
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'showContactDetails',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
// Done
$("#ProfileInfo").html("");
$("#ProfileInfo").append(""+ buddyObj.CallerIDName +"
");
$("#ProfileInfo").append(""+ buddyObj.Desc +"
");
$("#ProfileInfo").append(""+ lang.extension_number +":
");
$("#ProfileInfo").append(""+ buddyObj.ExtNo +"
");
if(buddyObj.Email && buddyObj.Email != "null" && buddyObj.Email != "undefined"){
$("#ProfileInfo").append(""+ lang.email +":
");
$("#ProfileInfo").append(""+ buddyObj.Email +"
");
}
if(buddyObj.MobileNumber && buddyObj.MobileNumber != "null" && buddyObj.MobileNumber != "undefined"){
$("#ProfileInfo").append(""+ lang.mobile +":
");
$("#ProfileInfo").append(""+ buddyObj.MobileNumber +"
");
}
if(buddyObj.ContactNumber1 && buddyObj.ContactNumber1 != "null" && buddyObj.ContactNumber1 != "undefined"){
$("#ProfileInfo").append(""+ lang.alternative_contact +":
");
$("#ProfileInfo").append(""+ buddyObj.ContactNumber1 +"
");
}
if(buddyObj.ContactNumber2 && buddyObj.ContactNumber2 != "null" && buddyObj.ContactNumber2 != "undefined"){
$("#ProfileInfo").append(""+ lang.alternative_contact +":
");
$("#ProfileInfo").append(""+ buddyObj.ContactNumber2 +"
");
}
} else if (typeStr == "contact") {
var html = "";
html += "
";
html += "
"
html += "
";
$.jeegoopopup.open({
html: html,
width: '200',
height: 'auto',
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'showContactDetails',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#ProfileInfo").html("");
$("#ProfileInfo").append(""+ buddyObj.CallerIDName +"
");
$("#ProfileInfo").append(""+ buddyObj.Desc +"
");
if(buddyObj.Email && buddyObj.Email != "null" && buddyObj.Email != "undefined"){
$("#ProfileInfo").append(""+ lang.email +":
");
$("#ProfileInfo").append(""+ buddyObj.Email +"
");
}
if(buddyObj.MobileNumber && buddyObj.MobileNumber != "null" && buddyObj.MobileNumber != "undefined"){
$("#ProfileInfo").append(""+ lang.mobile +":
");
$("#ProfileInfo").append(""+ buddyObj.MobileNumber +"
");
}
if(buddyObj.ContactNumber1 && buddyObj.ContactNumber1 != "null" && buddyObj.ContactNumber1 != "undefined"){
$("#ProfileInfo").append(""+ lang.alternative_contact +":
");
$("#ProfileInfo").append(""+ buddyObj.ContactNumber1 +"
");
}
if(buddyObj.ContactNumber2 && buddyObj.ContactNumber2 != "null" && buddyObj.ContactNumber2 != "undefined"){
$("#ProfileInfo").append(""+ lang.alternative_contact +":
");
$("#ProfileInfo").append(""+ buddyObj.ContactNumber2 +"
");
}
} else if (typeStr == "group") {
var html = "";
html += "
";
html += "
"
html += "
";
$.jeegoopopup.open({
html: html,
width: '200',
height: 'auto',
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'showContactDetails',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#ProfileInfo").html("");
$("#ProfileInfo").append(""+ buddyObj.CallerIDName +"
");
$("#ProfileInfo").append(""+ buddyObj.Desc +"
");
}
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
// Device and Settings
// ===================
function ChangeSettings(lineNum, obj){
var leftPos = event.pageX - 138;
var topPos = event.pageY + 28;
if (($(window).height() - event.pageY) < 300) { topPos = event.pageY - 170; }
// Check if you are in a call
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null) return;
var session = lineObj.SipSession;
var html = "
";
$.jeegoopopup.open({
html: html,
width: "auto",
height: "auto",
left: leftPos,
top: topPos,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'callSettingsContent',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
var audioSelect = $(' ');
audioSelect.prop("id", "audioSrcSelect");
audioSelect.css("width", "100%");
var videoSelect = $(' ');
videoSelect.prop("id", "videoSrcSelect");
videoSelect.css("width", "100%");
var speakerSelect = $(' ');
speakerSelect.prop("id", "audioOutputSelect");
speakerSelect.css("width", "100%");
var ringerSelect = $(' ');
ringerSelect.prop("id", "ringerSelect");
ringerSelect.css("width", "100%");
// Handle Audio Source changes (Microphone)
audioSelect.change(function() {
console.log("Call to change Microphone: ", this.value);
// First Stop Recording the call
var mustRestartRecording = false;
if(session.data.mediaRecorder && session.data.mediaRecorder.state == "recording"){
StopRecording(lineNum, true);
mustRestartRecording = true;
}
// Stop Monitoring
if(lineObj.LocalSoundMeter) lineObj.LocalSoundMeter.stop();
// Save Setting
session.data.AudioSourceDevice = this.value;
var constraints = {
audio: {
deviceId: (this.value != "default")? { exact: this.value } : "default"
},
video: false
}
navigator.mediaDevices.getUserMedia(constraints).then(function(newStream){
// Assume that since we are selecting from a dropdown, this is possible
var newMediaTrack = newStream.getAudioTracks()[0];
var pc = session.sessionDescriptionHandler.peerConnection;
pc.getSenders().forEach(function (RTCRtpSender) {
if(RTCRtpSender.track && RTCRtpSender.track.kind == "audio") {
console.log("Switching Audio Track : "+ RTCRtpSender.track.label + " to "+ newMediaTrack.label);
RTCRtpSender.track.stop(); // Must stop, or this mic will stay in use
RTCRtpSender.replaceTrack(newMediaTrack).then(function(){
// Start recording again
if(mustRestartRecording) StartRecording(lineNum);
// Monitor audio stream
lineObj.LocalSoundMeter = StartLocalAudioMediaMonitoring(lineNum, session);
}).catch(function(e){
console.error("Error replacing track: ", e);
});
}
});
}).catch(function(e){
console.error("Error on getUserMedia");
});
});
// Handle output change (speaker)
speakerSelect.change(function() {
console.log("Call to change Speaker: ", this.value);
// Save Setting
session.data.AudioOutputDevice = this.value;
// Also change the sinkId
// ======================
var sinkId = this.value;
console.log("Attempting to set Audio Output SinkID for line "+ lineNum +" [" + sinkId + "]");
// Remote audio
var element = $("#line-"+ lineNum +"-remoteAudio").get(0);
if (element) {
if (typeof element.sinkId !== 'undefined') {
element.setSinkId(sinkId).then(function(){
console.log("sinkId applied: "+ sinkId);
}).catch(function(e){
console.warn("Error using setSinkId: ", e);
});
} else {
console.warn("setSinkId() is not possible using this browser.")
}
}
});
// Handle video input change (WebCam)
videoSelect.change(function(){
console.log("Call to change WebCam");
switchVideoSource(lineNum, this.value);
});
// Load Devices
if(!navigator.mediaDevices) {
console.warn("navigator.mediaDevices not possible.");
return;
}
for (var i = 0; i < AudioinputDevices.length; ++i) {
var deviceInfo = AudioinputDevices[i];
var devideId = deviceInfo.deviceId;
var DisplayName = (deviceInfo.label)? deviceInfo.label : "";
if(DisplayName.indexOf("(") > 0) DisplayName = DisplayName.substring(0,DisplayName.indexOf("("));
// Create Option
var option = $(' ');
option.prop("value", devideId);
option.text((DisplayName != "")? DisplayName : "Microphone");
if(session.data.AudioSourceDevice == devideId) option.prop("selected", true);
audioSelect.append(option);
}
for (var i = 0; i < VideoinputDevices.length; ++i) {
var deviceInfo = VideoinputDevices[i];
var devideId = deviceInfo.deviceId;
var DisplayName = (deviceInfo.label)? deviceInfo.label : "";
if(DisplayName.indexOf("(") > 0) DisplayName = DisplayName.substring(0,DisplayName.indexOf("("));
// Create Option
var option = $(' ');
option.prop("value", devideId);
option.text((DisplayName != "")? DisplayName : "Webcam");
if(session.data.VideoSourceDevice == devideId) option.prop("selected", true);
videoSelect.append(option);
}
if(HasSpeakerDevice){
for (var i = 0; i < SpeakerDevices.length; ++i) {
var deviceInfo = SpeakerDevices[i];
var devideId = deviceInfo.deviceId;
var DisplayName = (deviceInfo.label)? deviceInfo.label : "";
if(DisplayName.indexOf("(") > 0) DisplayName = DisplayName.substring(0,DisplayName.indexOf("("));
// Create Option
var option = $(' ');
option.prop("value", devideId);
option.text((DisplayName != "")? DisplayName : "Speaker");
if(session.data.AudioOutputDevice == devideId) option.prop("selected", true);
speakerSelect.append(option);
}
}
// Mic Serttings
$("#DeviceSelector").append(""+ lang.microphone +":
");
$("#DeviceSelector").append(audioSelect);
// Speaker
if(HasSpeakerDevice){
$("#DeviceSelector").append(""+ lang.speaker +":
");
$("#DeviceSelector").append(speakerSelect);
}
// Camera
if(session.data.withvideo == true){
$("#DeviceSelector").append(""+ lang.camera +":
");
$("#DeviceSelector").append(videoSelect);
}
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
// Media Presentation
// ==================
function PresentCamera(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null.");
return;
}
var session = lineObj.SipSession;
$("#line-"+ lineNum +"-src-camera").prop("disabled", true);
$("#line-"+ lineNum +"-src-canvas").prop("disabled", false);
$("#line-"+ lineNum +"-src-desktop").prop("disabled", false);
$("#line-"+ lineNum +"-src-video").prop("disabled", false);
$("#line-"+ lineNum +"-src-blank").prop("disabled", false);
$("#line-"+ lineNum + "-scratchpad-container").hide();
RemoveScratchpad(lineNum);
$("#line-"+ lineNum +"-sharevideo").hide();
$("#line-"+ lineNum +"-sharevideo").get(0).pause();
$("#line-"+ lineNum +"-sharevideo").get(0).removeAttribute('src');
$("#line-"+ lineNum +"-sharevideo").get(0).load();
window.clearInterval(session.data.videoResampleInterval);
$("#line-"+ lineNum + "-localVideo").show();
$("#line-"+ lineNum + "-remoteVideo").appendTo("#line-"+ lineNum + "-stage-container");
switchVideoSource(lineNum, session.data.VideoSourceDevice);
}
function PresentScreen(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null.");
return;
}
var session = lineObj.SipSession;
$("#line-"+ lineNum +"-src-camera").prop("disabled", false);
$("#line-"+ lineNum +"-src-canvas").prop("disabled", false);
$("#line-"+ lineNum +"-src-desktop").prop("disabled", true);
$("#line-"+ lineNum +"-src-video").prop("disabled", false);
$("#line-"+ lineNum +"-src-blank").prop("disabled", false);
$("#line-"+ lineNum + "-scratchpad-container").hide();
RemoveScratchpad(lineNum);
$("#line-"+ lineNum +"-sharevideo").hide();
$("#line-"+ lineNum +"-sharevideo").get(0).pause();
$("#line-"+ lineNum +"-sharevideo").get(0).removeAttribute('src');
$("#line-"+ lineNum +"-sharevideo").get(0).load();
window.clearInterval(session.data.videoResampleInterval);
$("#line-"+ lineNum + "-localVideo").hide();
$("#line-"+ lineNum + "-remoteVideo").appendTo("#line-"+ lineNum + "-stage-container");
ShareScreen(lineNum);
}
function PresentScratchpad(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null.");
return;
}
var session = lineObj.SipSession;
$("#line-"+ lineNum +"-src-camera").prop("disabled", false);
$("#line-"+ lineNum +"-src-canvas").prop("disabled", true);
$("#line-"+ lineNum +"-src-desktop").prop("disabled", false);
$("#line-"+ lineNum +"-src-video").prop("disabled", false);
$("#line-"+ lineNum +"-src-blank").prop("disabled", false);
$("#line-"+ lineNum + "-scratchpad-container").hide();
RemoveScratchpad(lineNum);
$("#line-"+ lineNum +"-sharevideo").hide();
$("#line-"+ lineNum +"-sharevideo").get(0).pause();
$("#line-"+ lineNum +"-sharevideo").get(0).removeAttribute('src');
$("#line-"+ lineNum +"-sharevideo").get(0).load();
window.clearInterval(session.data.videoResampleInterval);
$("#line-"+ lineNum + "-localVideo").hide();
$("#line-"+ lineNum + "-remoteVideo").appendTo("#line-"+ lineNum + "-preview-container");
SendCanvas(lineNum);
}
function PresentVideo(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null.");
return;
}
var session = lineObj.SipSession;
$.jeegoopopup.close();
var presentVideoHtml = "";
presentVideoHtml += '
';
presentVideoHtml += "
Select File ";
presentVideoHtml += "
";
presentVideoHtml += "
";
$.jeegoopopup.open({
html: presentVideoHtml,
width: '180',
height: '80',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
overlay: true,
opacity: 0,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#SelectVideoToSend").on('change', function(event){
var input = event.target;
if(input.files.length >= 1){
$.jeegoopopup.close();
// Send Video (Can only send one file)
SendVideo(lineNum, URL.createObjectURL(input.files[0]));
}
else {
console.warn("Please Select a file to present.");
}
});
$("#closeImg").click(function() { $.jeegoopopup.close(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
}
function PresentBlank(lineNum){
var lineObj = FindLineByNumber(lineNum);
if(lineObj == null || lineObj.SipSession == null){
console.warn("Line or Session is Null.");
return;
}
var session = lineObj.SipSession;
$("#line-"+ lineNum +"-src-camera").prop("disabled", false);
$("#line-"+ lineNum +"-src-canvas").prop("disabled", false);
$("#line-"+ lineNum +"-src-desktop").prop("disabled", false);
$("#line-"+ lineNum +"-src-video").prop("disabled", false);
$("#line-"+ lineNum +"-src-blank").prop("disabled", true);
$("#line-"+ lineNum + "-scratchpad-container").hide();
RemoveScratchpad(lineNum);
$("#line-"+ lineNum +"-sharevideo").hide();
$("#line-"+ lineNum +"-sharevideo").get(0).pause();
$("#line-"+ lineNum +"-sharevideo").get(0).removeAttribute('src');
$("#line-"+ lineNum +"-sharevideo").get(0).load();
window.clearInterval(session.data.videoResampleInterval);
$("#line-"+ lineNum + "-localVideo").hide();
$("#line-"+ lineNum + "-remoteVideo").appendTo("#line-"+ lineNum + "-stage-container");
DisableVideoStream(lineNum);
}
function RemoveScratchpad(lineNum){
var scratchpad = GetCanvas("line-" + lineNum + "-scratchpad");
if(scratchpad != null){
window.clearInterval(scratchpad.redrawIntrtval);
RemoveCanvas("line-" + lineNum + "-scratchpad");
$("#line-"+ lineNum + "-scratchpad-container").empty();
scratchpad = null;
}
}
// Call Statistics
// ===============
function ShowCallStats(lineNum, obj){
console.log("Show Call Stats");
$("#line-"+ lineNum +"-AudioStats").show(300);
}
function HideCallStats(lineNum, obj){
console.log("Hide Call Stats");
$("#line-"+ lineNum +"-AudioStats").hide(300);
}
// Chatting
// ========
function chatOnbeforepaste(event, obj, buddy){
console.log("Handle paste, checking for Images...");
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
// Find pasted image among pasted items
var preventDefault = false;
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") === 0) {
console.log("Image found! Opening image editor...");
var blob = items[i].getAsFile();
// Read the image in
var reader = new FileReader();
reader.onload = function (event) {
// Image has loaded, open Image Preview Editor
// ===========================================
console.log("Image loaded... setting placeholder...");
var placeholderImage = new Image();
placeholderImage.onload = function () {
console.log("Placeholder loaded... CreateImageEditor...");
CreateImageEditor(buddy, placeholderImage);
}
placeholderImage.src = event.target.result;
}
reader.readAsDataURL(blob);
preventDefault = true;
continue;
}
}
// Pevent default if you found an image
if (preventDefault) event.preventDefault();
}
function chatOnkeydown(event, obj, buddy) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13'){
if(event.ctrlKey) {
SendChatMessage(buddy);
return false;
}
}
}
function ReformatMessage(str) {
var msg = str;
// Simple tex=>HTML
msg = msg.replace(//gi, ">");
msg = msg.replace(/\n/gi, " ");
// Emojy
// Skype: :) :( :D :O ;) ;( (:| :| :P :$ :^) |-) |-( :x ]:)
// (cool) (hearteyes) (stareyes) (like) (unamused) (cwl) (xd) (pensive) (weary) (hysterical) (flushed) (sweatgrinning) (disappointed) (loudlycrying) (shivering) (expressionless) (relieved) (inlove) (kiss) (yawn) (puke) (doh) (angry) (wasntme) (worry) (confused) (veryconfused) (mm) (nerd) (rainbowsmile) (devil) (angel) (envy) (makeup) (think) (rofl) (happy) (smirk) (nod) (shake) (waiting) (emo) (donttalk) (idea) (talk) (swear) (headbang) (learn) (headphones) (morningafter) (selfie) (shock) (ttm) (dream)
msg = msg.replace(/(:\)|:\-\)|:o\))/g, String.fromCodePoint(0x1F642)); // :) :-) :o)
msg = msg.replace(/(:\(|:\-\(|:o\()/g, String.fromCodePoint(0x1F641)); // :( :-( :o(
msg = msg.replace(/(;\)|;\-\)|;o\))/g, String.fromCodePoint(0x1F609)); // ;) ;-) ;o)
msg = msg.replace(/(:'\(|:'\-\()/g, String.fromCodePoint(0x1F62A)); // :'( :'‑(
msg = msg.replace(/(:'\(|:'\-\()/g, String.fromCodePoint(0x1F602)); // :') :'‑)
msg = msg.replace(/(:\$)/g, String.fromCodePoint(0x1F633)); // :$
msg = msg.replace(/(>:\()/g, String.fromCodePoint(0x1F623)); // >:(
msg = msg.replace(/(:\×)/g, String.fromCodePoint(0x1F618)); // :×
msg = msg.replace(/(:\O|:\‑O)/g, String.fromCodePoint(0x1F632)); // :O :‑O
msg = msg.replace(/(:P|:\-P|:p|:\-p)/g, String.fromCodePoint(0x1F61B)); // :P :-P :p :-p
msg = msg.replace(/(;P|;\-P|;p|;\-p)/g, String.fromCodePoint(0x1F61C)); // ;P ;-P ;p ;-p
msg = msg.replace(/(:D|:\-D)/g, String.fromCodePoint(0x1F60D)); // :D :-D
msg = msg.replace(/(\(like\))/g, String.fromCodePoint(0x1F44D)); // (like)
// Make clickable Hyperlinks
msg = msg.replace(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/gi, function (x) {
var niceLink = (x.length > 50) ? x.substring(0, 47) + "..." : x;
var rtn = "" + niceLink + " ";
return rtn;
});
return msg;
}
function getPicture(buddy, typestr){
if(buddy == "profilePicture"){
// Special handling for profile image
var dbImg = localDB.getItem("profilePicture");
if(dbImg == null){
return hostingPrefex + "images/default.png";
}
else {
return dbImg;
}
}
typestr = (typestr)? typestr : "extension";
var buddyObj = FindBuddyByIdentity(buddy);
if(buddyObj.imageObjectURL != ""){
// Use Cache
return buddyObj.imageObjectURL;
}
var dbImg = localDB.getItem("img-"+ buddy +"-"+ typestr);
if(dbImg == null){
return hostingPrefex + "images/default.png";
} else {
buddyObj.imageObjectURL = URL.createObjectURL(base64toBlob(dbImg, 'image/png'));
return buddyObj.imageObjectURL;
}
}
// Image Editor
// ============
function CreateImageEditor(buddy, placeholderImage){
// Show Interface
// ==============
console.log("Setting Up ImageEditor...");
if($("#contact-" + buddy + "-imagePastePreview").is(":visible")) {
console.log("Resetting ImageEditor...");
$("#contact-" + buddy + "-imagePastePreview").empty();
RemoveCanvas("contact-" + buddy + "-imageCanvas")
} else {
$("#contact-" + buddy + "-imagePastePreview").show();
}
// Create UI
// =========
var toolBarDiv = $('
');
toolBarDiv.css("margin-bottom", "5px")
toolBarDiv.append(' ');
toolBarDiv.append(' | ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' | ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' | ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' | ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
toolBarDiv.append(' | ');
toolBarDiv.append(' ');
toolBarDiv.append(' ');
$("#contact-" + buddy + "-imagePastePreview").append(toolBarDiv);
// Create the canvas
// =================
var newCanvas = $(' ');
newCanvas.prop("id", "contact-" + buddy + "-imageCanvas");
newCanvas.css("border", "1px solid #CCCCCC");
$("#contact-" + buddy + "-imagePastePreview").append(newCanvas);
console.log("Canvas for ImageEditor created...");
var imgWidth = placeholderImage.width;
var imgHeight = placeholderImage.height;
var maxWidth = $("#contact-" + buddy + "-imagePastePreview").width()-2; // for the border
var maxHeight = 480;
$("#contact-" + buddy + "-imageCanvas").prop("width", maxWidth);
$("#contact-" + buddy + "-imageCanvas").prop("height", maxHeight);
// Handle Initial Zoom
var zoomToFitImage = 1;
var zoomWidth = 1;
var zoomHeight = 1;
if(imgWidth > maxWidth || imgHeight > maxHeight)
{
if(imgWidth > maxWidth)
{
zoomWidth = (maxWidth / imgWidth);
}
if(imgHeight > maxHeight)
{
zoomHeight = (maxHeight / imgHeight);
console.log("Scale to fit height: "+ zoomHeight);
}
zoomToFitImage = Math.min(zoomWidth, zoomHeight) // need the smallest because less is more zoom.
console.log("Scale down to fit: "+ zoomToFitImage);
// Shape the canvas to fit the image and the new zoom
imgWidth = imgWidth * zoomToFitImage;
imgHeight = imgHeight * zoomToFitImage;
console.log("resizing canvas to fit new image size...");
$("#contact-" + buddy + "-imageCanvas").prop("width", imgWidth);
$("#contact-" + buddy + "-imageCanvas").prop("height", imgHeight);
}
else {
console.log("Image is able to fit, resizing canvas...");
$("#contact-" + buddy + "-imageCanvas").prop("width", imgWidth);
$("#contact-" + buddy + "-imageCanvas").prop("height", imgHeight);
}
// Fabric Canvas API
// =================
console.log("Creating fabric API...");
var canvas = new fabric.Canvas("contact-" + buddy + "-imageCanvas");
canvas.id = "contact-" + buddy + "-imageCanvas";
canvas.ToolSelected = "None";
canvas.PenColour = "rgb(255, 0, 0)";
canvas.PenWidth = 2;
canvas.PaintColour = "rgba(227, 230, 3, 0.6)";
canvas.PaintWidth = 10;
canvas.FillColour = "rgb(255, 0, 0)";
canvas.isDrawingMode = false;
canvas.selectionColor = 'rgba(112,179,233,0.25)';
canvas.selectionBorderColor = 'rgba(112,179,233, 0.8)';
canvas.selectionLineWidth = 1;
// Zoom to fit Width or Height
// ===========================
canvas.setZoom(zoomToFitImage);
// Canvas Events
// =============
canvas.on('mouse:down', function(opt) {
var evt = opt.e;
if (this.ToolSelected == "Pan") {
this.isDragging = true;
this.selection = false;
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
}
// Make nicer grab handles
if(opt.target != null){
if(evt.altKey === true)
{
opt.target.lockMovementX = true;
}
if(evt.shiftKey === true)
{
opt.target.lockMovementY = true;
}
opt.target.set({
transparentCorners: false,
borderColor: 'rgba(112,179,233, 0.4)',
cornerColor: 'rgba(112,179,233, 0.8)',
cornerSize: 6
});
}
});
canvas.on('mouse:move', function(opt) {
if (this.isDragging) {
var e = opt.e;
this.viewportTransform[4] += e.clientX - this.lastPosX;
this.viewportTransform[5] += e.clientY - this.lastPosY;
this.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
});
canvas.on('mouse:up', function(opt) {
this.isDragging = false;
this.selection = true;
if(opt.target != null){
opt.target.lockMovementX = false;
opt.target.lockMovementY = false;
}
});
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom + delta/200;
if (zoom > 10) zoom = 10;
if (zoom < 0.1) zoom = 0.1;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
// Add Image
// ==========
canvas.backgroundImage = new fabric.Image(placeholderImage);
CanvasCollection.push(canvas);
// Add Key Press Events
// ====================
$("#contact-" + buddy + "-imagePastePreview").keydown(function(evt) {
evt = evt || window.event;
var key = evt.keyCode;
console.log("Key press on Image Editor ("+ buddy +"): "+ key);
// Delete Key
if (key == 46) ImageEditor_Clear(buddy);
});
console.log("ImageEditor: "+ canvas.id +" created");
ImageEditor_FreedrawPen(buddy);
}
function GetCanvas(canvasId){
for(var c = 0; c < CanvasCollection.length; c++){
try {
if(CanvasCollection[c].id == canvasId) return CanvasCollection[c];
} catch(e) {
console.warn("CanvasCollection.id not available");
}
}
return null;
}
function RemoveCanvas(canvasId){
for(var c = 0; c < CanvasCollection.length; c++){
try{
if(CanvasCollection[c].id == canvasId) {
console.log("Found Old Canvas, Disposing...");
CanvasCollection[c].clear()
CanvasCollection[c].dispose();
CanvasCollection[c].id = "--deleted--";
console.log("CanvasCollection.splice("+ c +", 1)");
CanvasCollection.splice(c, 1);
break;
}
}
catch(e){ }
}
console.log("There are "+ CanvasCollection.length +" canvas now.");
}
var ImageEditor_Select = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
return true;
}
return false;
}
var ImageEditor_FreedrawPen = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.freeDrawingBrush.color = canvas.PenColour;
canvas.freeDrawingBrush.width = canvas.PenWidth;
canvas.ToolSelected = "Draw";
canvas.isDrawingMode = true;
console.log(canvas)
return true;
}
return false;
}
var ImageEditor_FreedrawPaint = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.freeDrawingBrush.color = canvas.PaintColour;
canvas.freeDrawingBrush.width = canvas.PaintWidth;
canvas.ToolSelected = "Paint";
canvas.isDrawingMode = true;
return true;
}
return false;
}
var ImageEditor_Pan = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "Pan";
canvas.isDrawingMode = false;
return true;
}
return false;
}
var ImageEditor_ResetZoom = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.setZoom(1);
canvas.setViewportTransform([1,0,0,1,0,0]);
return true;
}
return false;
}
var ImageEditor_ZoomIn = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
var zoom = canvas.getZoom();
zoom = zoom + 0.5;
if (zoom > 10) zoom = 10;
if (zoom < 0.1) zoom = 0.1;
var point = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2);
var center = fabric.util.transformPoint(point, canvas.viewportTransform);
canvas.zoomToPoint(point, zoom);
return true;
}
return false;
}
var ImageEditor_ZoomOut = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
var zoom = canvas.getZoom();
zoom = zoom - 0.5;
if (zoom > 10) zoom = 10;
if (zoom < 0.1) zoom = 0.1;
var point = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2);
var center = fabric.util.transformPoint(point, canvas.viewportTransform);
canvas.zoomToPoint(point, zoom);
return true;
}
return false;
}
var ImageEditor_AddCircle = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
var circle = new fabric.Circle({
radius: 20, fill: canvas.FillColour
})
canvas.add(circle);
canvas.centerObject(circle);
canvas.setActiveObject(circle);
return true;
}
return false;
}
var ImageEditor_AddRectangle = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
var rectangle = new fabric.Rect({
width: 40, height: 40, fill: canvas.FillColour
})
canvas.add(rectangle);
canvas.centerObject(rectangle);
canvas.setActiveObject(rectangle);
return true;
}
return false;
}
var ImageEditor_AddTriangle = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
var triangle = new fabric.Triangle({
width: 40, height: 40, fill: canvas.FillColour
})
canvas.add(triangle);
canvas.centerObject(triangle);
canvas.setActiveObject(triangle);
return true;
}
return false;
}
var ImageEditor_AddEmoji = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
var text = new fabric.Text(String.fromCodePoint(0x1F642), { fontSize : 24 });
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
return true;
}
return false;
}
var ImageEditor_AddText = function (buddy, textString){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
var text = new fabric.IText(textString, { fill: canvas.FillColour, fontFamily: 'arial', fontSize : 18 });
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
return true;
}
return false;
}
var ImageEditor_Clear = function (buddy){
var canvas = GetCanvas("contact-" + buddy + "-imageCanvas");
if(canvas != null) {
canvas.ToolSelected = "none";
canvas.isDrawingMode = false;
var activeObjects = canvas.getActiveObjects();
for (var i=0; i ';
html += "" + messageStr + "
";
html += " "
$.jeegoopopup.open({
title: TitleStr,
html: html,
width: '260',
height: 'auto',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'confirmDelContact',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_b").append("
");
$("#AlertOkButton").click(function () {
console.log("Alert OK clicked");
if (onOk) onOk();
});
$(window).resize(function() {
$.jeegoopopup.center();
});
$("#closeImg").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#AlertOkButton").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); $("#jg_popup_b").empty(); } });
}
function AlertConfigExtWindow(messageStr, TitleStr) {
$("#jg_popup_l").empty();
$("#jg_popup_b").empty();
$("#windowCtrls").empty();
$.jeegoopopup.close();
videoAudioCheck = 1;
var html = "
"
$.jeegoopopup.open({
title: TitleStr,
html: html,
width: '260',
height: 'auto',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'confirmDelContact',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_b").append("
");
$(window).resize(function() {
$.jeegoopopup.center();
});
$("#closeImg").click(function() { $("#windowCtrls").empty(); $("#jg_popup_b").empty(); $.jeegoopopup.close(); ConfigureExtensionWindow(); });
$("#AlertOkButton").click(function() { console.log("Alert OK clicked"); $("#windowCtrls").empty(); $("#jg_popup_b").empty(); $.jeegoopopup.close(); ConfigureExtensionWindow(); });
$("#jg_popup_overlay").click(function() { $("#windowCtrls").empty(); $("#jg_popup_b").empty(); $.jeegoopopup.close(); ConfigureExtensionWindow(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $("#windowCtrls").empty(); $("#jg_popup_b").empty(); $.jeegoopopup.close(); ConfigureExtensionWindow(); } });
}
function Confirm(messageStr, TitleStr, onOk, onCancel) {
$("#jg_popup_l").empty();
$("#jg_popup_b").empty();
$("#windowCtrls").empty();
$.jeegoopopup.close();
var html = "
";
$.jeegoopopup.open({
html: html,
width: '260',
height: 'auto',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'confirmDelContact',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_b").append("
");
$("#ConfirmOkButton").click(function () {
console.log("Confirm OK clicked");
if (onOk) onOk();
});
$("#ConfirmCancelButton").click(function () {
console.log("Confirm Cancel clicked");
if (onCancel) onCancel();
});
$(window).resize(function() {
$.jeegoopopup.center();
});
$("#closeImg").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#ConfirmOkButton").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#ConfirmCancelButton").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); $("#jg_popup_b").empty(); } });
}
function ConfirmConfigExtWindow(messageStr, TitleStr, onOk, onCancel) {
$("#jg_popup_l").empty();
$("#jg_popup_b").empty();
$("#windowCtrls").empty();
$.jeegoopopup.close();
var html = "
";
$.jeegoopopup.open({
html: html,
width: '260',
height: 'auto',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'ConfCloseAccount',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_b").append("
");
$("#ConfirmOkButton").click(function () {
console.log("Confirm OK clicked");
if (onOk) onOk();
});
$("#ConfirmCancelButton").click(function () {
console.log("Confirm Cancel clicked");
if (onCancel) onCancel();
$("#windowCtrls").empty();
$("#jg_popup_b").empty();
$.jeegoopopup.close();
ConfigureExtensionWindow();
});
$(window).resize(function() {
$.jeegoopopup.center();
});
$("#closeImg").click(function() { $("#jg_popup_b").empty(); $("#windowCtrls").empty(); $.jeegoopopup.close(); ConfigureExtensionWindow(); });
}
function Prompt(messageStr, TitleStr, FieldText, defaultValue, dataType, placeholderText, onOk, onCancel) {
$("#jg_popup_l").empty();
$("#jg_popup_b").empty();
$("#windowCtrls").empty();
$.jeegoopopup.close();
var html = "
";
$.jeegoopopup.open({
html: html,
width: '260',
height: 'auto',
center: true,
scrolling: 'no',
skinClass: 'jg_popup_basic',
contentClass: 'confirmDelContact',
overlay: true,
opacity: 50,
draggable: true,
resizable: false,
fadeIn: 0
});
$("#jg_popup_b").append("
");
$("#PromptOkButton").click(function () {
console.log("Prompt OK clicked, with value: " + $("#PromptValueField").val());
if (onOk) onOk($("#PromptValueField").val());
});
$("#PromptCancelButton").click(function () {
console.log("Prompt Cancel clicked");
if (onCancel) onCancel();
});
$(window).resize(function() {
$.jeegoopopup.center();
});
$("#closeImg").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#PromptOkButton").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#PromptCancelButton").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); $("#jg_popup_b").empty(); });
$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); $("#jg_popup_b").empty(); } });
}
// Device Detection
// ================
function DetectDevices(){
navigator.mediaDevices.enumerateDevices().then(function(deviceInfos){
// deviceInfos will not have a populated lable unless to accept the permission
// during getUserMedia. This normally happens at startup/setup
// so from then on these devices will be with lables.
HasVideoDevice = false;
HasAudioDevice = false;
HasSpeakerDevice = false; // Safari and Firefox don't have these
AudioinputDevices = [];
VideoinputDevices = [];
SpeakerDevices = [];
for (var i = 0; i < deviceInfos.length; ++i) {
if (deviceInfos[i].kind === "audioinput") {
HasAudioDevice = true;
AudioinputDevices.push(deviceInfos[i]);
}
else if (deviceInfos[i].kind === "audiooutput") {
HasSpeakerDevice = true;
SpeakerDevices.push(deviceInfos[i]);
}
else if (deviceInfos[i].kind === "videoinput") {
HasVideoDevice = true;
VideoinputDevices.push(deviceInfos[i]);
}
}
}).catch(function(e){
console.error("Error enumerating devices", e);
});
}
DetectDevices();
window.setInterval(function(){
DetectDevices();
}, 10000);
// STATUS_NULL: 0
// STATUS_INVITE_SENT: 1
// STATUS_1XX_RECEIVED: 2
// STATUS_INVITE_RECEIVED: 3
// STATUS_WAITING_FOR_ANSWER: 4
// STATUS_ANSWERED: 5
// STATUS_WAITING_FOR_PRACK: 6
// STATUS_WAITING_FOR_ACK: 7
// STATUS_CANCELED: 8
// STATUS_TERMINATED: 9
// STATUS_ANSWERED_WAITING_FOR_PRACK: 10
// STATUS_EARLY_MEDIA: 11
// STATUS_CONFIRMED: 12
// =======================================
// End Of File