Jonatas Oliveira d178092c2a Creating Verto Communicator.
Verto Communicator is a web interface built on top of Verto and AngularJS.

Brought to you by Evolux Sistemas and FreeSWITCH team. :)

FS-7795 - implements fullscreen menu and doubleclick function.
FS-7795 - added chat icon on fullscreen video
FS-7796 - fix missing tooltips in call icons
FS-7796 - fix tooltip position
FS-7798 - implements change login information in modal view
FS-7828 - fix esc key bug when leave fullscren mode. Using css instead of javascript in fullscreen for elements manipulation.
FS-7826 - fix chat sender id with name instead of extension
FS-7831 - remove demo from title
FS-7841 - fix compatibility verification
FS-7842 - 'settings' data persistent
FS-7859 - moved popup down
FS-7827 - added screen share functionality
FS-7857 - default name for source media
FS-7879 - prompt before logout [incall]
FS-7873 - querystring for autocall
FS-7875 - persist login and password password
FS-7877 - phone feature: hold, transfer, incoming, answer, decline, call direction in history
FS-7878 - small devices
FS-7881 - added modal dialog for contributors
2015-08-05 23:53:10 -05:00

652 lines
19 KiB
JavaScript

'use strict';
/* Controllers */
var videoQuality = [
{id: 'qvga', label: 'QVGA 320x240'},
{id: 'vga', label: 'VGA 640x480'},
{id: 'qvga_wide', label: 'QVGA WIDE 320x180'},
{id: 'vga_wide', label: 'VGA WIDE 640x360'},
{id: 'hd', label: 'HD 1280x720'},
{id: 'hhd', label: 'HHD 1920x1080'},
];
var videoResolution = {
qvga: {width: 320, height: 240},
vga: {width: 640, height: 480},
qvga_wide: {width: 320, height: 180},
vga_wide: {width: 640, height: 360},
hd: {width: 1280, height: 720},
hhd: {width: 1920, height: 1080},
};
var bandwidth = [
{id: '250', label: '250kb'},
{id: '500', label: '500kb'},
{id: '1024', label: '1mb'},
{id: '1536', label: '1.5mb'},
{id: '2048', label: '2mb'},
{id: '5120', label: '5mb'},
{id: '0', label: 'No Limit'},
{id: 'default', label: 'Server Default'},
];
var vertoService = angular.module('vertoService', ['ngCookies']);
vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', function($rootScope, $cookieStore, $location) {
var data = {
// Connection data.
instance: null,
connected: false,
// Call data.
call: null,
shareCall: null,
callState: null,
conf: null,
confLayouts: [],
confRole: null,
chattingWith: null,
liveArray: null,
// Settings data.
videoDevices: [],
audioDevices: [],
shareDevices: [],
extension: $cookieStore.get('verto_demo_ext'),
name: $cookieStore.get('verto_demo_name'),
email: $cookieStore.get('verto_demo_email'),
cid: $cookieStore.get('verto_demo_cid'),
textTo: $cookieStore.get('verto_demo_textto') || "1000",
login: $cookieStore.get('verto_demo_login') || "1008",
password: $cookieStore.get('verto_demo_passwd') || "1234",
hostname: $cookieStore.get('verto_demo_hostname') || window.location.hostname,
wsURL: $cookieStore.get('verto_demo_wsurl') || ("wss://" + window.location.hostname + ":8082"),
useVideo: $cookieStore.get('verto_demo_vid_checked') || true,
useCamera: $cookieStore.get('verto_demo_camera_checked') || true,
useStereo: $cookieStore.get('verto_demo_stereo_checked') || true,
useSTUN: $cookieStore.get('verto_demo_stun_checked') || true,
useDedenc: $cookieStore.get('verto_demo_dedenc_checked') || false,
mirrorInput: $cookieStore.get('verto_demo_mirror_input_checked') || false,
outgoingBandwidth: $cookieStore.get('verto_demo_outgoingBandwidth') || 'default',
incomingBandwidth: $cookieStore.get('verto_demo_incomingBandwidth') || 'default',
vidQual: $cookieStore.get('verto_demo_vqual') || 'qvga',
localVideo: $cookieStore.get('verto_demo_local_video_checked') || false,
selectedVideo: null,
selectedAudio: null,
selectedShare: null
};
function cleanShareCall(that) {
that.refreshVideoResolution();
data.shareCall = null;
data.callState = 'active';
that.refreshDevices();
}
function cleanCall() {
data.call = null;
data.callState = null;
data.conf = null;
data.confLayouts = [];
data.confRole = null;
data.chattingWith = null;
$rootScope.$emit('call.hangup', 'hangup');
}
function inCall() {
$rootScope.$emit('page.incall', 'call');
}
function callActive(last_state) {
$rootScope.$emit('call.active', last_state);
}
function calling() {
$rootScope.$emit('call.calling', 'calling');
}
function incomingCall(number) {
$rootScope.$emit('call.incoming', number);
}
function getVideoParams() {
return {
minWidth: videoResolution[data.vidQual].width,
minHeight: videoResolution[data.vidQual].height,
maxWidth: videoResolution[data.vidQual].width,
maxHeight: videoResolution[data.vidQual].height
};
}
function changeData(verto_data) {
$cookieStore.put('verto_demo_vid_checked', verto_data.data.useVideo);
$cookieStore.put('verto_demo_camera_checked', verto_data.data.useCamera);
$cookieStore.put('verto_demo_stereo_checked', verto_data.data.useStereo);
$cookieStore.put('verto_demo_stun_checked', verto_data.data.useSTUN);
$cookieStore.put('verto_demo_dedenc_checked', verto_data.data.useDedenc);
$cookieStore.put('verto_demo_mirror_input_checked', verto_data.data.mirrorInput);
$cookieStore.put('verto_demo_outgoingBandwidth', verto_data.data.outgoingBandwidth);
$cookieStore.put('verto_demo_incomingBandwidth', verto_data.data.incomingBandwidth);
$cookieStore.put('verto_demo_vqual', verto_data.data.vidQual);
data.useVideo = verto_data.data.useVideo;
data.useCamera = verto_data.data.useCamera;
data.useStereo = verto_data.data.useStereo;
data.useDedenc = verto_data.data.useDedenc;
data.useSTUN = verto_data.data.useSTUN;
data.vidQual = verto_data.data.vidQual;
data.mirrorInput = verto_data.data.mirrorInput;
data.outgoingBandwidth = verto_data.data.outgoingBandwidth;
data.incomingBandwidth = verto_data.data.incomingBandwidth;
}
var callState = {
muteMic: false,
muteVideo: false
};
return {
data: data,
callState: callState,
changeData: changeData,
// Options to compose the interface.
videoQuality: videoQuality,
videoResolution: videoResolution,
bandwidth: bandwidth,
refreshDevices: function(callback) {
console.debug('Attempting to refresh the devices.');
data.videoDevices = [{id: 'none', label: 'No camera'}];
data.shareDevices = [{id: 'screen', label: 'Screen'}];
data.audioDevices = [];
data.selectedVideo = 'none';
data.selectedShare = 'screen';
data.selectedAudio = null;
for (var i in jQuery.verto.videoDevices) {
var device = jQuery.verto.videoDevices[i];
if(!device.label) {
data.videoDevices.push({id: 'Camera ' + i, label: 'Camera ' + i});
} else {
data.videoDevices.push({id: device.id, label: device.label || device.id});
}
// Selecting the first source.
if (i == 0) {
data.selectedVideo = device.id;
}
if(!device.label) {
data.shareDevices.push({id: 'Share Device ' + i, label: 'Share Device ' + i});
continue;
}
data.shareDevices.push({id: device.id, label: device.label || device.id});
}
data.audioDevices = [];
for (var i in jQuery.verto.audioDevices) {
var device = jQuery.verto.audioDevices[i];
// Selecting the first source.
if (i == 0) {
data.selectedAudio = device.id;
}
if(!device.label) {
data.audioDevices.push({id: 'Microphone ' + i, label: 'Microphone ' + i});
continue;
}
data.audioDevices.push({id: device.id, label: device.label || device.id});
}
console.debug('Devices were refreshed.');
if (angular.isFunction(callback)) {
var devices = {
audio: data.audioDevices,
video: data.videoDevices,
share: data.shareDevices
};
callback(data.instance, devices);
}
},
/**
* Updates the video resolutions based on settings.
*/
refreshVideoResolution: function() {
console.debug('Attempting to refresh video resolutions.');
if (data.instance) {
data.instance.videoParams(getVideoParams());
} else {
console.debug('There is no instance of verto.');
}
},
/**
* Connects to the verto server. Automatically calls `onWSLogin`
* callback set in the verto object.
*
* @param callback
*/
connect: function(callback) {
console.debug('Attempting to connect to verto.');
var that = this;
function startConference(v, dialog, pvtData) {
$rootScope.$emit('call.video', 'video');
data.chattingWith = pvtData.chatID;
data.confRole = pvtData.role;
var conf = new $.verto.conf(v, {
dialog: dialog,
hasVid: data.useVideo,
laData: pvtData,
onBroadcast: function(v, conf, message) {
console.log('>>> conf.onBroadcast:', arguments);
if (message.action == 'response') {
// This is a response with the video layouts list.
if (message['conf-command'] == 'list-videoLayouts') {
data.confLayouts = message.responseData.sort();
} else {
$rootScope.$emit('conference.broadcast', message);
}
}
}
});
console.log('>>> conf.listVideoLayouts();');
conf.listVideoLayouts();
data.conf = conf;
data.liveArray = new $.verto.liveArray(
data.instance, pvtData.laChannel,
pvtData.laName,
{subParams: {callID: dialog ? dialog.callID : null}});
data.liveArray.onErr = function(obj, args) {
console.log('liveArray.onErr', obj, args);
};
data.liveArray.onChange = function(obj, args) {
console.log('liveArray.onChange', obj, args);
switch(args.action) {
case 'bootObj':
$rootScope.$emit('members.boot', args.data);
break;
case 'add':
var member = [args.key, args.data];
$rootScope.$emit('members.add', member);
break;
case 'del':
var uuid = args.key;
$rootScope.$emit('members.del', uuid);
break;
case 'clear':
$rootScope.$emit('members.clear');
break;
case 'modify':
var member = [args.key, args.data];
$rootScope.$emit('members.update', member);
break;
default:
console.log('NotImplemented', args.action);
}
};
}
function stopConference() {
console.log('stopConference()');
if (data.liveArray) {
console.log('Has data.liveArray.');
$rootScope.$emit('members.clear');
data.liveArray.destroy();
data.liveArray = null;
} else {
console.log('Doesn\'t found data.liveArray.');
}
}
var callbacks = {
onWSLogin: function(v, success) {
data.connected = success;
console.debug('Connected to verto server:', success);
if (angular.isFunction(callback)) {
callback(v, success);
}
},
onMessage: function(v, dialog, msg, params) {
console.debug('onMessage:', v, dialog, msg, params);
switch (msg) {
case $.verto.enum.message.pvtEvent:
if (params.pvtData) {
switch (params.pvtData.action) {
case "conference-liveArray-join":
console.log("conference-liveArray-join");
startConference(v, dialog, params.pvtData);
break;
case "conference-liveArray-part":
console.log("conference-liveArray-part");
stopConference();
break;
}
}
break;
case $.verto.enum.message.info:
var body = params.body;
var from = params.from_msg_name || params.from;
$rootScope.$emit('chat.newMessage', {from: from, body: body});
break;
default:
break;
}
},
onDialogState: function(d) {
if(!data.call) {
data.call = d;
if(d.state.name !== 'ringing') {
inCall();
}
}
console.debug('onDialogState:', d);
switch (d.state.name) {
case "ringing":
incomingCall(d.params.caller_id_number);
break;
case "trying":
console.debug('Calling:', d.cidString());
data.callState = 'trying';
break;
case "early":
console.debug('Talking to:', d.cidString());
data.callState = 'active';
calling();
break;
case "active":
console.debug('Talking to:', d.cidString());
data.callState = 'active';
callActive(d.lastState.name);
break;
case "hangup":
console.debug('Call ended with cause: ' + d.cause);
data.callState = 'hangup';
break;
case "destroy":
console.debug('Destroying: ' + d.cause);
if(d.params.screenShare) {
cleanShareCall(that);
} else {
cleanCall();
}
break;
}
},
onWSClose: function(v, success) {
console.debug('onWSClose:', success);
},
onEvent: function(v, e) {
console.debug('onEvent:', e);
}
};
var init = function() {
that.refreshVideoResolution();
data.instance = new jQuery.verto({
login: data.login + '@' + data.hostname,
passwd: data.password,
socketUrl: data.wsURL,
tag: "webcam",
ringFile: "sounds/bell_ring2.wav",
loginParams: {
foo: true,
bar: "yes"
},
videoParams: getVideoParams(),
iceServers: data.useSTUN
}, callbacks);
that.refreshDevices();
};
jQuery.verto.init({}, init);
},
/**
* Login the client.
*
* @param callback
*/
login: function(callback) {
data.instance.loginData({
login: data.login + '@' + data.hostname,
passwd: data.password
});
data.instance.login();
if (angular.isFunction(callback)) {
callback(data.instance, true);
}
},
/**
* Disconnects from the verto server. Automatically calls `onWSClose`
* callback set in the verto object.
*
* @param callback
*/
disconnect: function(callback) {
console.debug('Attempting to disconnect to verto.');
data.instance.logout();
data.connected = false;
console.debug('Disconnected from verto server.');
if (angular.isFunction(callback)) {
callback(data.instance, data.connected);
}
},
/**
* Make a call.
*
* @param callback
*/
call: function(destination, callback) {
console.debug('Attempting to call destination ' + destination + '.');
this.refreshVideoResolution();
var call = data.instance.newCall({
destination_number: destination,
caller_id_name: data.name,
caller_id_number: data.login,
outgoingBandwidth: data.outgoingBandwidth,
incomingBandwidth: data.incomingBandwidth,
useVideo: data.useVideo,
useStereo: data.useStereo,
useCamera: data.selectedVideo,
useMic: data.selectedAudio,
dedEnc: data.useDedenc,
mirrorInput: data.mirrorInput
});
data.call = call;
data.mutedMic = false;
data.mutedVideo = false;
this.refreshDevices();
if (angular.isFunction(callback)) {
callback(data.instance, call);
}
},
screenshare: function(destination, callback) {
console.log('share screen video');
this.refreshVideoResolution();
var that = this;
getScreenId(function(error, sourceId, screen_constraints) {
var call = data.instance.newCall({
destination_number: destination + '-screen',
caller_id_name: data.name + ' (Screen)',
caller_id_number: data.login + ' (Screen)',
outgoingBandwidth: data.outgoingBandwidth,
incomingBandwidth: data.incomingBandwidth,
videoParams: screen_constraints.video.mandatory,
useVideo: data.useVideo,
screenShare: true,
dedEnc: data.useDedenc,
mirrorInput: data.mirrorInput
});
data.shareCall = call;
console.log('shareCall', data);
data.mutedMic = false;
data.mutedVideo = false;
that.refreshDevices();
});
},
screenshareHangup: function() {
if(!data.shareCall) {
console.debug('There is no call to hangup.');
return false;
}
console.log('shareCall End', data.shareCall);
data.shareCall.hangup();
console.debug('The screencall was hangup.');
},
/**
* Hangup the current call.
*
* @param callback
*/
hangup: function(callback) {
console.debug('Attempting to hangup the current call.');
if (!data.call) {
console.debug('There is no call to hangup.');
return false;
}
data.call.hangup();
console.debug('The call was hangup.');
if (angular.isFunction(callback)) {
callback(data.instance, true);
}
},
/**
* Send a DTMF to the current call.
*
* @param {string|integer} number
* @param callback
*/
dtmf: function(number, callback) {
console.debug('Attempting to send DTMF "' + number + '".');
if (!data.call) {
console.debug('There is no call to send DTMF.');
return false;
}
data.call.dtmf(number);
console.debug('The DTMF was sent for the call.');
if (angular.isFunction(callback)) {
callback(data.instance, true);
}
},
/**
* Mute the microphone for the current call.
*
* @param callback
*/
muteMic: function(callback) {
console.debug('Attempting to mute mic for the current call.');
if (!data.call) {
console.debug('There is no call to mute.');
return false;
}
data.call.dtmf('0');
data.mutedMic = !data.mutedMic;
console.debug('The mic was muted for the call.');
if (angular.isFunction(callback)) {
callback(data.instance, true);
}
},
/**
* Mute the video for the current call.
*
* @param callback
*/
muteVideo: function(callback) {
console.debug('Attempting to mute video for the current call.');
if (!data.call) {
console.debug('There is no call to mute.');
return false;
}
data.call.dtmf('*0');
data.mutedVideo = !data.mutedVideo;
console.debug('The video was muted for the call.');
if (angular.isFunction(callback)) {
callback(data.instance, true);
}
},
sendMessage: function(body, callback) {
data.call.message({
to: data.chattingWith,
body: body,
from_msg_name: data.name,
from_msg_number: data.cid
});
if (angular.isFunction(callback)) {
callback(data.instance, true);
}
}
};
}]);