FS-8045 [Verto-Communicator] Make the folder structure compliant with AngularJS best practices and adjust build system.
6
html5/verto/verto_communicator/src/contributors.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
"Jonatas Oliveira <jonatas@evolux.net.br>",
|
||||
"Ítalo Rossi <italo@evolux.net.br>",
|
||||
"Stefan Yohansson <stefan@evolux.net.br>",
|
||||
"João Mesquita <jmesquita@indicium.com.ar>"
|
||||
]
|
BIN
html5/verto/verto_communicator/src/css/images/ajax-loader.gif
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
html5/verto/verto_communicator/src/css/images/icons-18-black.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
html5/verto/verto_communicator/src/css/images/icons-18-white.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
html5/verto/verto_communicator/src/css/images/icons-36-black.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
html5/verto/verto_communicator/src/css/images/icons-36-white.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
html5/verto/verto_communicator/src/css/images/loading.gif
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
html5/verto/verto_communicator/src/css/images/login.gif
Normal file
After Width: | Height: | Size: 19 KiB |
1336
html5/verto/verto_communicator/src/css/verto.css
Normal file
BIN
html5/verto/verto_communicator/src/favicon.ico
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
html5/verto/verto_communicator/src/images/ajax-loader.gif
Normal file
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 186 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 12 KiB |
BIN
html5/verto/verto_communicator/src/images/icons-18-black.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
html5/verto/verto_communicator/src/images/icons-18-white.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
html5/verto/verto_communicator/src/images/icons-36-black.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
html5/verto/verto_communicator/src/images/icons-36-white.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
html5/verto/verto_communicator/src/images/loading.gif
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
html5/verto/verto_communicator/src/images/login.gif
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
html5/verto/verto_communicator/src/img/cc_banner.gif
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
html5/verto/verto_communicator/src/img/logo.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
html5/verto/verto_communicator/src/img/logo_big.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
html5/verto/verto_communicator/src/img/logo_med.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
html5/verto/verto_communicator/src/img/verto_black_web.gif
Normal file
After Width: | Height: | Size: 11 KiB |
128
html5/verto/verto_communicator/src/index.html
Normal file
@@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="vertoApp" ng-controller="MainController" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<meta name="description" content="Verto (VER-to) RTC is a FreeSWITCH endpoint that implements a subset of a JSON-RPC connection designed for use over secure websockets.">
|
||||
<meta name="author" content="FreeSWITCH">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
|
||||
<title ng-bind="'[' + title + '] ' + 'FreeSWITCH Verto™ Video Transcoding'"></title>
|
||||
|
||||
<!-- build:css(.) css/vendor.css -->
|
||||
<!-- bower:css -->
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
||||
<link rel="stylesheet" href="bower_components/angular-toastr/dist/angular-toastr.css" />
|
||||
<link rel="stylesheet" href="bower_components/angular-tooltips/dist/angular-tooltips.min.css" />
|
||||
<link rel="stylesheet" href="bower_components/datatables/media/css/jquery.dataTables.css" />
|
||||
<link rel="stylesheet" href="bower_components/bootstrap-material-design/dist/css/material.css" />
|
||||
<link rel="stylesheet" href="bower_components/bootstrap-material-design/dist/css/ripples.css" />
|
||||
<!-- endbower -->
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- CSS -->
|
||||
<!-- build:css(.) css/verto.css -->
|
||||
<link rel="stylesheet" type="text/css" href="src/css/verto.css">
|
||||
<!-- endbuild -->
|
||||
|
||||
|
||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div ng-include="'partials/menu.html'"></div>
|
||||
|
||||
<div id="wrapper" class="toggled">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar-wrapper">
|
||||
<div ng-include="'partials/chat.html'"></div>
|
||||
</div>
|
||||
<!-- /#sidebar-wrapper -->
|
||||
|
||||
<!-- Page Content -->
|
||||
<div id="page-content-wrapper">
|
||||
<div class="container-fluid">
|
||||
<div class="row" ng-view>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<video class="hide" id="webcam" autoplay="autoplay" style="width:100%; height:100%; object-fit:inherit;"></video>
|
||||
|
||||
|
||||
<!--<script type="text/javascript" src="js/jquery/jquery.mobile.min.js"></script>-->
|
||||
|
||||
<!-- build:js(.) scripts/vendor.js -->
|
||||
<!-- bower:js -->
|
||||
<script src="bower_components/jquery/dist/jquery.js"></script>
|
||||
<script src="bower_components/angular/angular.js"></script>
|
||||
<script src="bower_components/angular-gravatar/build/angular-gravatar.js"></script>
|
||||
<script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script src="bower_components/angular-toastr/dist/angular-toastr.tpls.js"></script>
|
||||
<script src="bower_components/angular-route/angular-route.js"></script>
|
||||
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
|
||||
<script src="bower_components/angular-prompt/dist/angular-prompt.js"></script>
|
||||
<script src="bower_components/angular-animate/angular-animate.js"></script>
|
||||
<script src="bower_components/angular-cookies/angular-cookies.js"></script>
|
||||
<script src="bower_components/angular-fullscreen/src/angular-fullscreen.js"></script>
|
||||
<script src="bower_components/ngstorage/ngStorage.js"></script>
|
||||
<script src="bower_components/momentjs/moment.js"></script>
|
||||
<script src="bower_components/humanize-duration/humanize-duration.js"></script>
|
||||
<script src="bower_components/angular-timer/dist/angular-timer.js"></script>
|
||||
<script src="bower_components/angular-tooltips/dist/angular-tooltips.min.js"></script>
|
||||
<script src="bower_components/jquery-cookie/jquery.cookie.js"></script>
|
||||
<script src="bower_components/jquery-json/src/jquery.json.js"></script>
|
||||
<script src="bower_components/datatables/media/js/jquery.dataTables.js"></script>
|
||||
<script src="bower_components/bootstrap-material-design/dist/js/material.js"></script>
|
||||
<script src="bower_components/bootstrap-material-design/dist/js/ripples.js"></script>
|
||||
<!-- endbower -->
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- build:js(.) scripts/scripts.js -->
|
||||
|
||||
<script type="text/javascript" src="../js/src/jquery.jsonrpcclient.js"></script>
|
||||
<script type="text/javascript" src="../js/src/jquery.FSRTC.js"></script>
|
||||
<script type="text/javascript" src="../js/src/jquery.verto.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/3rd-party/getScreenId.js"></script>
|
||||
<script type="text/javascript" src="js/3rd-party/md5.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoApp/vertoApp.module.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoControllers/vertoControllers.module.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/BrowserUpgradeController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ChatController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ContributorsController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/DialPadController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/InCallController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/LoginController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/MainController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/MenuController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalDialpadController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalLoginInformationController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalSettingsController.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoDirectives/vertoDirectives.module.js"></script>
|
||||
<script type="text/javascript" src="src/vertoDirectives/directives/autofocus.js"></script>
|
||||
<script type="text/javascript" src="src/vertoDirectives/directives/showControls.js"></script>
|
||||
<script type="text/javascript" src="src/vertoDirectives/directives/userStatus.js"></script>
|
||||
<script type="text/javascript" src="src/vertoDirectives/directives/videoTag.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoService/vertoService.module.js"></script>
|
||||
<script type="text/javascript" src="src/vertoService/services/vertoService.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/storageService/storageService.module.js"></script>
|
||||
<script type="text/javascript" src="src/storageService/services/storage.js"></script>
|
||||
|
||||
<!-- endbuild -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -0,0 +1,33 @@
|
||||
<div>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close pull-right" ng-click="$dismiss()" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">{{options.title}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<p ng-if="options.message">
|
||||
{{options.message}}
|
||||
</p>
|
||||
|
||||
<form id="cgPromptForm" name="cgPromptForm" ng-if="options.input" ng-submit="submit()">
|
||||
<div class="form-group" ng-class="{'has-error':cgPromptForm.$invalid && changed}">
|
||||
<label for="cgPromptInput">{{options.label}}</label>
|
||||
<input id="cgPromptInput" type="text" class="form-control" placeholder="{{options.label}}" ng-model="input.name" required ng-change="changed=true" ng-if="!options.values || options.values.length === 0"/ autofocus="autofocus">
|
||||
<div class="input-group" ng-if="options.values">
|
||||
<input id="cgPromptInput" type="text" class="form-control" placeholder="{{options.label}}" ng-model="input.name" required ng-change="changed=true" autofocus="autofocus"/>
|
||||
|
||||
<div class="input-group-btn" dropdown>
|
||||
<button type="button" class="btn btn-default dropdown-toggle" dropdown-toggle data-toggle="dropdown"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<li ng-repeat="value in options.values"><a href="" ng-click="input.name = value">{{value}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button ng-repeat="button in options.buttons track by button.label" class="btn btn-default {{button.class}}" ng-class="{'btn-primary':button.primary}" ng-click="buttonClicked(button)">{{button.label}}</button>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,27 @@
|
||||
<div class="centered-block-frame" id="browser_upgrade">
|
||||
<div class="col-md-6 centered-block">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h2>Sorry, your browser is not supported.</h2>
|
||||
<h3>Use one of the following supported browsers.</h3>
|
||||
<ul class="browsers-supported">
|
||||
<li>
|
||||
<a href="https://www.google.com/chrome" target="_blank">
|
||||
<img src="images/browser-logos/chrome_128x128.png" title="Chrome" alt="chrome" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.mozilla.org/en-US/firefox/new/" target="_blank">
|
||||
<img src="images/browser-logos/firefox_128x128.png" title="Firefox" alt="firefox" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.opera.com/" target="_blank">
|
||||
<img src="images/browser-logos/opera_128x128.png" title="Opera" alt="opera" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
120
html5/verto/verto_communicator/src/partials/chat.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<div id="incall-pane" class="sidebar-nav" ng-controller="ChatController">
|
||||
<ul class="nav nav-tabs" role="tablist" ng-init="activePane = 'members'">
|
||||
<li role="presentation" ng-class="{'active': activePane == 'members'}">
|
||||
<a ng-click="activePane = 'members'" href="">
|
||||
Members
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" ng-class="{'active': activePane == 'chat'}">
|
||||
<a ng-click="activePane = 'chat'" href="">
|
||||
Chat
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="chat-members" ng-show="activePane == 'members'">
|
||||
<div ng-show="!members.length">
|
||||
<p class="text-center text-muted">There are no members to show.</p>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="member in members" class="chat-member-item">
|
||||
<span class="chat-members-avatar">
|
||||
<img gravatar-size="40" gravatar-src-once="member.email" class="img-circle" ng-class="{'chat-member-talking': member.status.audio.talking, 'chat-member-muted': member.status.audio.muted}" />
|
||||
</span>
|
||||
<h4 class="chat-members-name">{{ member.name }}</h4>
|
||||
<div class="pull-right action-buttons chat-members-action" ng-show="verto.data.confRole == 'moderator'">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="mdi-navigation-more-vert" style="margin-right: 0px;"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu slidedown pull-right">
|
||||
<li>
|
||||
<a href="" ng-click="confKick(member.id)">
|
||||
<span class="mdi-fw mdi-av-not-interested"></span>
|
||||
Kick
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confMuteMic(member.id)">
|
||||
<span class="mdi-fw mdi-av-mic-off"></span>
|
||||
Mute/Unmute Mic
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confMuteVideo(member.id)">
|
||||
<span class="mdi-fw mdi-av-videocam-off"></span>
|
||||
Mute/Unmute Video
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confPresenter(member.id)">
|
||||
<span class="mdi-fw mdi-action-picture-in-picture"></span>
|
||||
Presenter
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confVideoFloor(member.id)">
|
||||
<span class="mdi-fw mdi-action-aspect-ratio"></span>
|
||||
Video Floor
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confBanner(member.id)">
|
||||
<span class="mdi-fw mdi-av-subtitles"></span>
|
||||
Banner
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confVolumeDown(member.id)">
|
||||
<span class="mdi-fw mdi-av-volume-down"></span>
|
||||
Vol –
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confVolumeUp(member.id)">
|
||||
<span class="mdi-fw mdi-av-volume-up"></span>
|
||||
Vol +
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" ng-click="confTransfer(member.id)">
|
||||
<span class="mdi-fw mdi-communication-call-made"></span>
|
||||
Transfer
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="chat-members-status pull-right">
|
||||
<i class="in-use" ng-class="{'mdi-av-mic': !member.status.audio.muted, 'mdi-av-mic-off': member.status.audio.muted, 'mic_talking': member.status.audio.talking}"></i>
|
||||
<i ng-class="{'mdi-av-videocam': !member.status.video.muted, 'mdi-av-videocam-off': member.status.video.muted, 'in-use': (member.status.video && !member.status.video.muted), 'disabled': !member.status.video}"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-history" ng-show="activePane == 'chat'">
|
||||
<div class="chat-messages">
|
||||
<div class="chat-message" ng-show="!messages.length">
|
||||
<p class="text-center text-muted">There are no messages to show.</p>
|
||||
</div>
|
||||
<div class="chat-message" ng-repeat="message in messages" title="Sent at {{ message.created_at|date }}.">
|
||||
<div class="chat-message-metadata">{{ message.from }}:</div>
|
||||
<p class="chat-message-body">{{ message.body }}</p>
|
||||
</div>
|
||||
<div id="chat-message-bottom"></div>
|
||||
</div>
|
||||
|
||||
<div class="chat-message-input">
|
||||
<form ng-submit="send()" >
|
||||
<div class="chat-message-input-group">
|
||||
<textarea ng-model="message" ng-keyup="($event.keyCode == 13 && $event.shiftKey !== true) && send()" required="required" class="form-control input-sm" placeholder="Type your message here..."></textarea>
|
||||
<button class="btn btn-success btn-sm" type="submit">
|
||||
Send
|
||||
<span class="mdi-navigation-arrow-forward chat-message-input-group-icon-button"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,23 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Contributors</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="contributors">
|
||||
<li ng-repeat="contributor in contributors">
|
||||
<div class="contributor-avatar">
|
||||
<img gravatar-src="contributor.email" gravatar-size="75"/>
|
||||
</div>
|
||||
|
||||
<div class="contributor-info">
|
||||
<h3>{{ contributor.name }}</h3>
|
||||
<h5>{{ contributor.email }}</h5>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
</div>
|
||||
|
143
html5/verto/verto_communicator/src/partials/dialpad.html
Normal file
@@ -0,0 +1,143 @@
|
||||
<div class="centered-block-frame" id="dialpad">
|
||||
<div id="call-history-wrapper">
|
||||
<div id="call_history" class="shadow-z-2 panel">
|
||||
<div class="panel-heading">
|
||||
<div class="panel-title">
|
||||
Call History
|
||||
|
||||
<span class="pull-right pull-right-margin dropdown">
|
||||
<a href="" class="dropdown-toggle" data-target="#" data-toggle="dropdown" aria-expanded="true">
|
||||
<i class="mdi-navigation-more-vert"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="" ng-click="clearCallHistory()">Clear History</a></li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="call-history">
|
||||
<div ng-show="!storage.data.call_history.length">
|
||||
<p class="text-center text-muted">No history calls.</p>
|
||||
</div>
|
||||
|
||||
<li ng-repeat="call in storage.data.call_history">
|
||||
<a ng-show="call.number" href="" ng-dblclick="$parent.call()" ng-click="$parent.fillDialpadNumber(call.number)">
|
||||
<i ng-show="call.direction == 'inbound'" ng-class="{'mdi-communication-call-missed': !call.status,'mdi-communication-call-received': call.status}"></i>
|
||||
<i ng-show="call.direction == 'outbound'" class="mdi-communication-call-made"></i>
|
||||
<h2 class="dialpad-number dialpad-number-limited">{{ call.number }}</h2>
|
||||
<br/>
|
||||
<span class="dialpad-alpha">{{ call.call_start }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12 col-xs-12 centered-block">
|
||||
<div class="panel panel-default shadow-z-2" ng-class="{'shadow-z-4': call_history, 'shadow-z-2': !call_history}">
|
||||
<form name="form">
|
||||
<div class="input-group dialpad-display">
|
||||
<span class="input-group-btn-left">
|
||||
<a href="" ng-click="toggleCallHistory()">
|
||||
<i class="mdi-action-settings-phone"></i>
|
||||
</a>
|
||||
</span>
|
||||
<input name="dialpadnumber" type="text" class="form-control text-center" placeholder="Enter an extension" ng-model="dialpadNumber" autofocus/>
|
||||
<span class="input-group-btn">
|
||||
<a href="" ng-click="backspace()">
|
||||
<i class="mdi-content-backspace"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="dialpad-numbers">
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(1)">
|
||||
<h2 class="dialpad-number">1</h2>
|
||||
<span class="dialpad-alpha">./@</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(2)">
|
||||
<h2 class="dialpad-number">2</h2>
|
||||
<span class="dialpad-alpha">ABC</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(3)">
|
||||
<h2 class="dialpad-number">3</h2>
|
||||
<span class="dialpad-alpha">DEF</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(4)">
|
||||
<h2 class="dialpad-number">4</h2>
|
||||
<span class="dialpad-alpha">GHI</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(5)">
|
||||
<h2 class="dialpad-number">5</h2>
|
||||
<span class="dialpad-alpha">JKL</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(6)">
|
||||
<h2 class="dialpad-number">6</h2>
|
||||
<span class="dialpad-alpha">MNO</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(7)">
|
||||
<h2 class="dialpad-number">7</h2>
|
||||
<span class="dialpad-alpha">PQRS</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(8)">
|
||||
<h2 class="dialpad-number">8</h2>
|
||||
<span class="dialpad-alpha">TUV</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(9)">
|
||||
<h2 class="dialpad-number">9</h2>
|
||||
<span class="dialpad-alpha">WXYZ</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf('*')">
|
||||
<h2 class="dialpad-number dialpad-star">*</h2>
|
||||
<span class="dialpad-alpha"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(0)">
|
||||
<h2 class="dialpad-number">0</h2>
|
||||
<span class="dialpad-alpha">+</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf('#')">
|
||||
<h2 class="dialpad-number dialpad-pound">#</h2>
|
||||
<span class="dialpad-alpha"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<button type="submit" class="btn btn-success btn-fab" ng-click="call(dialpadNumber)" title="Call Extension">
|
||||
<i class="mdi-communication-call"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
111
html5/verto/verto_communicator/src/partials/dialpad_widget.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<div class="panel panel-default shadow-z-2" ng-class="{'shadow-z-4': call_history, 'shadow-z-2': !call_history}">
|
||||
<form name="form">
|
||||
<div class="input-group dialpad-display">
|
||||
<span ng-show="!incall" class="input-group-btn-left">
|
||||
<a href="" ng-click="toggleCallHistory()">
|
||||
<i class="mdi-action-settings-phone"></i>
|
||||
</a>
|
||||
</span>
|
||||
<input name="dialpadnumber" type="text" class="form-control text-center" placeholder="Enter an extension" ng-model="dialpadNumber" />
|
||||
<span class="input-group-btn">
|
||||
<a href="" ng-click="backspace()">
|
||||
<i class="mdi-content-backspace"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="dialpad-numbers">
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(1)">
|
||||
<h2 class="dialpad-number">1</h2>
|
||||
<span class="dialpad-alpha">./@</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(2)">
|
||||
<h2 class="dialpad-number">2</h2>
|
||||
<span class="dialpad-alpha">ABC</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(3)">
|
||||
<h2 class="dialpad-number">3</h2>
|
||||
<span class="dialpad-alpha">DEF</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(4)">
|
||||
<h2 class="dialpad-number">4</h2>
|
||||
<span class="dialpad-alpha">GHI</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(5)">
|
||||
<h2 class="dialpad-number">5</h2>
|
||||
<span class="dialpad-alpha">JKL</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(6)">
|
||||
<h2 class="dialpad-number">6</h2>
|
||||
<span class="dialpad-alpha">MNO</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(7)">
|
||||
<h2 class="dialpad-number">7</h2>
|
||||
<span class="dialpad-alpha">PQRS</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(8)">
|
||||
<h2 class="dialpad-number">8</h2>
|
||||
<span class="dialpad-alpha">TUV</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(9)">
|
||||
<h2 class="dialpad-number">9</h2>
|
||||
<span class="dialpad-alpha">WXYZ</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf('*')">
|
||||
<h2 class="dialpad-number dialpad-star">*</h2>
|
||||
<span class="dialpad-alpha"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf(0)">
|
||||
<h2 class="dialpad-number">0</h2>
|
||||
<span class="dialpad-alpha">+</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 col-xs-4">
|
||||
<a class="btn btn-block" href="" ng-click="dtmf('#')">
|
||||
<h2 class="dialpad-number dialpad-pound">#</h2>
|
||||
<span class="dialpad-alpha"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<button type="submit" class="btn btn-success btn-fab" ng-click="call(); ok()" title="Call Extension">
|
||||
<i class="mdi-communication-call"></i>
|
||||
</button>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-fab" ng-click="transfer(); ok()" title="Transfer">
|
||||
<i class="mdi-notification-phone-forwarded"></i>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
5
html5/verto/verto_communicator/src/partials/incall.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<div class="centered-block-frame" id="incall">
|
||||
<div class="col-md-12 centered-block" ng-class="{'video-call': storage.data.videoCall, 'phone-call': !storage.data.videoCall}">
|
||||
<div class="slide-animate height100" ng-include="callTemplate"></div>
|
||||
</div>
|
||||
</div>
|
56
html5/verto/verto_communicator/src/partials/login.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="centered-block-frame" id="login">
|
||||
<div class="col-md-4 col-xs-12 col-sm-12 centered-block">
|
||||
<div class="panel panel-default shadow-z-2">
|
||||
<div class="panel-body">
|
||||
<h3>Login</h3>
|
||||
|
||||
<div ng-show="form.$submitted && form.$invalid" class="alert alert-danger">
|
||||
<p>Verify the fields bellow and try again.</p>
|
||||
</div>
|
||||
|
||||
<form name="form" class="css-form" novalidate ng-init="advanced = false">
|
||||
<div class="form-group {{ (((!form.name.$pristine || form.$submitted) && !form.name.$valid) ? 'has-error': '') }}">
|
||||
<label class="control-label" for="login-name">Name</label>
|
||||
<input type="text" name="name" class="form-control" id="login-name" placeholder="Your name" required="" ng-model="verto.data.name" autofocus>
|
||||
</div>
|
||||
<div class="form-group {{ (((!form.email.$pristine || form.$submitted) && !form.email.$valid) ? 'has-error': '') }}">
|
||||
<label class="control-label" for="login-email">Email</label>
|
||||
<input type="email" name="email" class="form-control" id="login-email" placeholder="Your email" required="" ng-model="verto.data.email" ng-model-options="{debounce: 250}">
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-user">User</label>
|
||||
<input type="text" class="form-control" id="login-user" placeholder="User" ng-model="verto.data.login">
|
||||
</div>
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-password">Password</label>
|
||||
<input type="password" class="form-control" id="login-password" placeholder="Password" ng-model="verto.data.password">
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-hostname">Hostname</label>
|
||||
<input type="text" class="form-control" id="login-hostname" placeholder="Hostname" ng-model="verto.data.hostname">
|
||||
</div>
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-wsurl">Websocket URL</label>
|
||||
<input type="text" class="form-control" id="login-wsurl" placeholder="Websocket URL" ng-model="verto.data.wsURL">
|
||||
</div>
|
||||
|
||||
<div class="form-group hide">
|
||||
<label for="login-login">Login</label>
|
||||
<input type="text" class="form-control" id="login-login" placeholder="Login" ng-model="verto.data.login">
|
||||
</div>
|
||||
<div class="form-group hide">
|
||||
<label for="login-password">Password</label>
|
||||
<input type="text" class="form-control" id="login-password" placeholder="Password" ng-model="verto.data.password">
|
||||
</div>
|
||||
|
||||
<div class="form-group text-right">
|
||||
<a style="margin-top: 13px;" href="" ng-click="advanced = !advanced" class="pull-left">Settings</a>
|
||||
<button type="submit" class="btn btn-success" ng-click="(form.$valid && login())">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
69
html5/verto/verto_communicator/src/partials/menu.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<nav ng-controller="MenuController" class="navbar navbar-fixed-top navbar-material-blue-900">
|
||||
<div class="container-fluid">
|
||||
<div class="https-untrusted navbar-center" ng-show="!safeProtocol">
|
||||
<div class="https-message">
|
||||
This Connection is Untrusted.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#/">
|
||||
Verto Communicator
|
||||
</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="">
|
||||
<i class="mdi-toggle-radio-button-on" user-status condition="storage.data.userStatus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="incall-number" ng-show="storage.data.called_number">
|
||||
{{ storage.data.called_number && storage.data.userStatus == 'connecting' ? 'Last Call: ' : 'In Call: ' }} {{ storage.data.called_number }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="navbar-item-icon" ng-show="verto.data.connected">
|
||||
<a href="" ng-click="openModal('partials/modal_settings.html', 'ModalSettingsController')">
|
||||
<i class="mdi-action-settings"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="navbar-item-icon" ng-show="verto.data.call && storage.data.videoCall">
|
||||
<a href="" ng-click="toggleChat()">
|
||||
<i class="mdi-communication-chat"></i>
|
||||
<div ng-show="chat_counter" class="chat-notification-badge">
|
||||
<div class="chat-notification">{{ chat_counter }}</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="navbar-item-icon">
|
||||
<a ng-show="!verto.data.connected" href="#/login">
|
||||
<i class="mdi-social-person"></i>
|
||||
</a>
|
||||
<a ng-show="verto.data.connected" href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
||||
<i class="mdi-social-person"></i>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="" ng-click="openModal('partials/modal_logininfo.html', 'ModalLoginInformationController')">Change Login Information</a></li>
|
||||
<!--<li><a href="#">View Device Settings</a></li>-->
|
||||
<li><a href="" ng-click="logout()">Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="navbar-item-icon">
|
||||
<a href="" ng-click="showContributors()">
|
||||
<i class="mdi-action-loyalty"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
@@ -0,0 +1,31 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Login Information</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" name="name" class="form-control" ng-model="storage.data.name" ng-value="storage.data.name"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<input type="text" name="email" class="form-control" ng-model="storage.data.email" ng-value="storage.data.email"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="user">User</label>
|
||||
<input type="text" class="form-control" id="user" placeholder="User" ng-model="storage.data.login">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="password">Password</label>
|
||||
<input type="password" class="form-control" id="password" placeholder="Password" ng-model="verto.data.password">
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!-- <button class="btn btn-primary" ng-click="cancel()">Cancel</button> -->
|
||||
<button class="btn btn-primary" ng-click="ok()">Save Login Information</button>
|
||||
</div>
|
@@ -0,0 +1,95 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Device Settings</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group" ng-show="verto.data.useVideo">
|
||||
<label for="settings-camera">Camera:</label>
|
||||
<select name="camera" id="settings-camera" class="form-control"
|
||||
ng-model="verto.data.selectedVideo" ng-options="item.id as item.label for item in verto.data.videoDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="verto.data.useVideo">
|
||||
<label for="settings-share-device">Share device:</label>
|
||||
<select name="share-device" id="settings-share-device" class="form-control"
|
||||
ng-model="verto.data.selectedShare" ng-options="item.id as item.label for item in verto.data.shareDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">Microphone:</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control"
|
||||
ng-model="verto.data.selectedAudio" ng-options="item.id as item.label for item in verto.data.audioDevices">
|
||||
</select>
|
||||
|
||||
<a class="btn btn-primary" href="" ng-click="refreshDeviceList()">Refresh device list</a>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">General settings:</label>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_video" value="verto.data.useVideo" ng-model="verto.data.useVideo">
|
||||
Use Video
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_stereo_audio" ng-value="verto.data.useStereo" ng-model="verto.data.useStereo">
|
||||
Stereo Audio
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_stun" ng-value="verto.data.useSTUN" ng-model="verto.data.useSTUN">
|
||||
Use STUN
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_dedenc" ng-value="verto.data.useDedenc" ng-model="verto.data.useDedenc">
|
||||
Use Dedicated Remote Encoder
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="mirror_input" ng-value="verto.data.mirrorInput" ng-model="verto.data.mirrorInput">
|
||||
Scale Remote Video To Match Camera Resolution
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="ask_recover_call" ng-value="storage.data.askRecoverCall" ng-model="storage.data.askRecoverCall">
|
||||
Ask before recovering call
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="video-quality">Video quality:</label>
|
||||
<select name="video_quality" id="video-quality" class="form-control"
|
||||
ng-model="verto.data.vidQual"
|
||||
ng-options="item.id as item.label for item in verto.videoQuality"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="outgoing-bandwidth">Max outgoing bandwidth:</label>
|
||||
<select name="outgoing_bandwidth" id="outgoing-bandwidth" class="form-control"
|
||||
ng-model="verto.data.outgoingBandwidth"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="incoming-bandwidth">Max incoming bandwidth:</label>
|
||||
<select name="incoming_bandwidth" id="incoming-bandwidth" class="form-control"
|
||||
ng-model="verto.data.incomingBandwidth"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!-- <button class="btn btn-primary" ng-click="cancel()">Cancel</button> -->
|
||||
<button class="btn btn-primary" ng-click="ok()">Save Device Settings</button>
|
||||
</div>
|
58
html5/verto/verto_communicator/src/partials/phone_call.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<div class="panel panel-default phone">
|
||||
<div class="panel-body phone-body">
|
||||
<div class="col-md-6">
|
||||
<div class="avatar">
|
||||
<img />
|
||||
</div>
|
||||
<div class="call-info">
|
||||
<h2 class="dialed-number">{{ storage.data.called_number }}</h2>
|
||||
<div ng-show="!storage.data.calling" class="video-timer">
|
||||
<timer start-time="start_time" autostart="false" interval="1000">{{hhours}}:{{mminutes}}:{{sseconds}}</timer>
|
||||
</div>
|
||||
<div ng-show="storage.data.calling" class="">
|
||||
<h3>Calling</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="col-md-6 dialpad slide-animate-container">
|
||||
<div class="slide-animate" ng-include="dialpadTemplate"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-footer">
|
||||
<div class="panel-center">
|
||||
<div class="col-md-12">
|
||||
<ul>
|
||||
<li>
|
||||
<button tooltips="" tooltip-title="Dialpad" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-900" ng-click="toggleDialpad()">
|
||||
<i class="big-icon mdi-communication-dialpad"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button tooltips="" tooltip-title="(un)Mute Mic" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-900" ng-click="muteMic()">
|
||||
<i class="big-icon" ng-class="{'mdi-av-mic': !verto.data.mutedMic, 'mdi-av-mic-off': verto.data.mutedMic}"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button tooltips="" tooltip-title="Hold" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-900" ng-click="hold()">
|
||||
<i class="big-icon" ng-class="{'mdi-av-pause':!storage.data.onHold, 'mdi-av-play-arrow': storage.data.onHold}"></i>
|
||||
</button>
|
||||
</li>
|
||||
<!--<li>
|
||||
<button tooltips="" tooltip-title="Video Call" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-900" ng-click="videoCall()">
|
||||
<i class="big-icon mdi-notification-voice-chat"></i>
|
||||
</button>
|
||||
</li>-->
|
||||
<li class="hangup-button">
|
||||
<button tooltips="" tooltip-title="Hangup" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-danger btn-fab btn-raised mdi-communication-call-end" ng-click="hangup()">
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
72
html5/verto/verto_communicator/src/partials/video_call.html
Normal file
@@ -0,0 +1,72 @@
|
||||
<div class="panel panel-default shadow-z-0">
|
||||
<div class="video-wrapper">
|
||||
<div class="video-hover-buttons" ng-show="verto.data.callState == 'active'">
|
||||
<div id="moderator-tools" ng-show="verto.data.confRole == 'moderator'">
|
||||
<button tooltips="" tooltip-title="Play" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="play()">
|
||||
<i class="mdi-av-play-circle-outline"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Stop" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="stop()">
|
||||
<i class="mdi-av-stop"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Record" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="record()">
|
||||
<i class="mdi-toggle-radio-button-on"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Stop Record" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="stopRecord()">
|
||||
<i class="mdi-image-switch-camera"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Snapshot" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="snapshot()">
|
||||
<i class="mdi-image-photo-camera"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Screenshare" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="screenshare()">
|
||||
<i class="mdi-hardware-desktop-windows"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button tooltips="" tooltip-title="Video Mode" tooltip-side="bottom" tooltip-lazy="false" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="mdi-action-view-module"></i>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="layout in verto.data.confLayouts">
|
||||
<a ng-click="confChangeVideoLayout(layout)">{{ layout }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<button tooltips="" tooltip-title="(un)Mute Mic" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="muteMic(cbMuteMic)">
|
||||
<i class="" ng-class="{'mdi-av-mic': !verto.data.mutedMic, 'mdi-av-mic-off': verto.data.mutedMic}"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="(un)Mute Video" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="muteVideo(cbMuteVideo)">
|
||||
<i class="" ng-class="{'mdi-av-videocam': !verto.data.mutedVideo, 'mdi-av-videocam-off': verto.data.mutedVideo}"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Toggle Fullscreen Mode" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="goFullscreen()">
|
||||
<i class="" ng-class="{'mdi-navigation-fullscreen': !fullscreenEnabled, 'mdi-navigation-fullscreen-exit': fullscreenEnabled}"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Open/Close Chat" tooltip-side="right" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="toggleChat()" ng-show="fullscreenEnabled">
|
||||
<i class="mdi-communication-chat"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="video-tag-wrapper" id="video-tag-wrapper" ng-dblclick="goFullscreen()" show-controls>
|
||||
<video-tag ng-class="{'invisible': (verto.data.callState != 'active')}"></video-tag>
|
||||
<svg ng-show="verto.data.callState != 'active'" class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="video-footer panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-xs-6 text-left">
|
||||
<div class="video-timer">
|
||||
<timer start-time="start_time" autostart="false" interval="1000">{{hhours}}:{{mminutes}}:{{sseconds}}</timer>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xs-6 text-right">
|
||||
<button class="btn btn-danger" ng-click="hangup()">
|
||||
<i class="mdi-communication-call-end"></i>
|
||||
End Call
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
BIN
html5/verto/verto_communicator/src/sounds/bell_ring2.mp3
Normal file
BIN
html5/verto/verto_communicator/src/sounds/bell_ring2.wav
Normal file
@@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('storageService')
|
||||
.service('storage', ['$rootScope', '$localStorage',
|
||||
function($rootScope, $localStorage) {
|
||||
var data = $localStorage;
|
||||
|
||||
data.$default({
|
||||
ui_connected: false,
|
||||
ws_connected: false,
|
||||
cur_call: 0,
|
||||
called_number: '',
|
||||
useVideo: true,
|
||||
call_history: [],
|
||||
call_start: false,
|
||||
name: '',
|
||||
email: '',
|
||||
login: '',
|
||||
password: '',
|
||||
userStatus: 'disconnected',
|
||||
mutedVideo: false,
|
||||
mutedMic: false,
|
||||
selectedVideo: null,
|
||||
selectedAudio: null,
|
||||
selectedShare: null,
|
||||
useVideo: '',
|
||||
useCamera: '',
|
||||
useVideo: '',
|
||||
useCamera: '',
|
||||
useStereo: '',
|
||||
useSTUN: '',
|
||||
useDedenc: '',
|
||||
mirrorInput: '',
|
||||
outgoingBandwidth: '',
|
||||
incomingBandwidth: '',
|
||||
vidQual: '',
|
||||
askRecoverCall: false,
|
||||
googNoiseSuppression: false,
|
||||
googHighpassFilter: false,
|
||||
googEchoCancellation: false
|
||||
});
|
||||
|
||||
function changeData(verto_data) {
|
||||
data.selectedVideo = verto_data.data.selectedVideo;
|
||||
data.selectedAudio = verto_data.data.selectedAudio;
|
||||
data.selectedShare = verto_data.data.selectedShare;
|
||||
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;
|
||||
}
|
||||
|
||||
return {
|
||||
data: data,
|
||||
changeData: changeData,
|
||||
reset: function() {
|
||||
data.ui_connected = false;
|
||||
data.ws_connected = false;
|
||||
data.cur_call = 0;
|
||||
data.userStatus = 'disconnected';
|
||||
},
|
||||
};
|
||||
}
|
||||
]);
|
@@ -0,0 +1,4 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
var vertoService = angular.module('storageService', ['ngStorage']);
|
||||
})();
|
@@ -0,0 +1,98 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var vertoApp = angular.module('vertoApp', [
|
||||
'timer',
|
||||
'ngRoute',
|
||||
'vertoControllers',
|
||||
'vertoDirectives',
|
||||
'ngStorage',
|
||||
'ngAnimate',
|
||||
'toastr',
|
||||
'FBAngular',
|
||||
'cgPrompt',
|
||||
'720kb.tooltips',
|
||||
'ui.gravatar',
|
||||
]);
|
||||
|
||||
vertoApp.config(['$routeProvider', 'gravatarServiceProvider',
|
||||
function($routeProvider, gravatarServiceProvider) {
|
||||
$routeProvider.
|
||||
when('/login', {
|
||||
title: 'Login',
|
||||
templateUrl: 'partials/login.html',
|
||||
controller: 'LoginController'
|
||||
}).
|
||||
when('/dialpad', {
|
||||
title: 'Dialpad',
|
||||
templateUrl: 'partials/dialpad.html',
|
||||
controller: 'DialPadController'
|
||||
}).
|
||||
when('/incall', {
|
||||
title: 'In a Call',
|
||||
templateUrl: 'partials/incall.html',
|
||||
controller: 'InCallController'
|
||||
}).
|
||||
/*when('/contributors', {
|
||||
title: 'Contributors',
|
||||
templateUrl: 'partials/contributors.html',
|
||||
controller: 'ContributorsController',
|
||||
}).*/
|
||||
when('/browser-upgrade', {
|
||||
title: '',
|
||||
templateUrl: 'partials/browser_upgrade.html',
|
||||
controller: 'BrowserUpgradeController'
|
||||
}).
|
||||
otherwise({
|
||||
redirectTo: '/login'
|
||||
});
|
||||
|
||||
gravatarServiceProvider.defaults = {
|
||||
default: 'mm' // Mystery man as default for missing avatars
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
vertoApp.run(['$rootScope', '$location', 'toastr', 'prompt',
|
||||
function($rootScope, $location, toastr, prompt) {
|
||||
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
|
||||
$rootScope.title = current.$$route.title;
|
||||
});
|
||||
|
||||
$rootScope.safeProtocol = false;
|
||||
|
||||
if (window.location.protocol == 'https:') {
|
||||
$rootScope.safeProtocol = true;
|
||||
}
|
||||
|
||||
$rootScope.checkBrowser = function() {
|
||||
navigator.getUserMedia = navigator.getUserMedia ||
|
||||
navigator.webkitGetUserMedia ||
|
||||
navigator.mozGetUserMedia;
|
||||
|
||||
if (!navigator.getUserMedia) {
|
||||
$location.path('/browser-upgrade');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$rootScope.promptInput = function(title, message, label, callback) {
|
||||
var ret = prompt({
|
||||
title: title,
|
||||
message: message,
|
||||
input: true,
|
||||
label: label
|
||||
}).then(function(ret) {
|
||||
if (angular.isFunction(callback)) {
|
||||
callback(ret);
|
||||
}
|
||||
}, function() {
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,14 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('BrowserUpgradeController', ['$scope', '$http',
|
||||
'$location', 'verto', 'storage', 'Fullscreen',
|
||||
function($scope, $http, $location, verto, storage, Fullscreen) {
|
||||
console.debug('Executing BrowserUpgradeController.');
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,192 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ChatController', ['$scope', '$rootScope', '$http',
|
||||
'$location', '$anchorScroll', '$timeout', 'verto',
|
||||
function($scope, $rootScope, $http, $location, $anchorScroll, $timeout,
|
||||
verto) {
|
||||
console.debug('Executing ChatController.');
|
||||
|
||||
function scrollToChatBottom() {
|
||||
// Going to the bottom of chat messages.
|
||||
var obj = document.querySelector('.chat-messages');
|
||||
obj.scrollTop = obj.scrollHeight;
|
||||
//var chat_messages_top = jQuery('.chat-messages').scrollTop();
|
||||
//var marker_position = jQuery('#chat-message-bottom').position().top;
|
||||
//jQuery('.chat-messages').scrollTop(chat_messages_top + marker_position);
|
||||
}
|
||||
|
||||
var CLEAN_MESSAGE = '';
|
||||
|
||||
function clearConferenceChat() {
|
||||
$scope.members = [];
|
||||
$scope.messages = [];
|
||||
$scope.message = CLEAN_MESSAGE;
|
||||
}
|
||||
clearConferenceChat();
|
||||
|
||||
$scope.$watch('activePane', function() {
|
||||
if ($scope.activePane == 'chat') {
|
||||
$rootScope.chat_counter = 0;
|
||||
}
|
||||
$rootScope.activePane = $scope.activePane;
|
||||
});
|
||||
|
||||
$rootScope.$on('chat.newMessage', function(event, data) {
|
||||
data.created_at = new Date();
|
||||
console.log('chat.newMessage', data);
|
||||
$scope.$apply(function() {
|
||||
$scope.messages.push(data);
|
||||
if (data.from != verto.data.name && (!$scope.chatStatus ||
|
||||
$scope.activePane != 'chat')) {
|
||||
++$rootScope.chat_counter;
|
||||
}
|
||||
$timeout(function() {
|
||||
scrollToChatBottom();
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
|
||||
function findMemberByUUID(uuid) {
|
||||
var found = false;
|
||||
for (var idx in $scope.members) {
|
||||
var member = $scope.members[idx];
|
||||
if (member.uuid == uuid) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return idx;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
function translateMember(member) {
|
||||
return {
|
||||
'uuid': member[0],
|
||||
'id': member[1][0],
|
||||
'number': member[1][1],
|
||||
'name': member[1][2],
|
||||
'codec': member[1][3],
|
||||
'status': JSON.parse(member[1][4]),
|
||||
'email': member[1][5].email
|
||||
};
|
||||
}
|
||||
|
||||
function addMember(member) {
|
||||
$scope.members.push(translateMember(member));
|
||||
}
|
||||
|
||||
$rootScope.$on('members.boot', function(event, members) {
|
||||
console.log('members.boot', event, members);
|
||||
$scope.$apply(function() {
|
||||
clearConferenceChat();
|
||||
for (var idx in members) {
|
||||
var member = members[idx];
|
||||
addMember(member);
|
||||
console.log($scope.members);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$rootScope.$on('members.add', function(event, member) {
|
||||
$scope.$apply(function() {
|
||||
addMember(member);
|
||||
});
|
||||
});
|
||||
|
||||
$rootScope.$on('members.del', function(event, uuid) {
|
||||
$scope.$apply(function() {
|
||||
var memberIdx = findMemberByUUID(uuid);
|
||||
if (memberIdx != -1) {
|
||||
// Removing the member.
|
||||
$scope.members.splice(memberIdx, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$rootScope.$on('members.update', function(event, member) {
|
||||
member = translateMember(member);
|
||||
var memberIdx = findMemberByUUID(member.uuid);
|
||||
if (memberIdx < 0) {
|
||||
console.log('Didn\'t find the member uuid ' + member.uuid);
|
||||
} else {
|
||||
$scope.$apply(function() {
|
||||
console.log('Updating', memberIdx, ' <', $scope.members[memberIdx],
|
||||
'> with <', member, '>');
|
||||
angular.extend($scope.members[memberIdx], member);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('members.clear', function(event) {
|
||||
$scope.$apply(function() {
|
||||
clearConferenceChat();
|
||||
$scope.closeChat();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Public methods.
|
||||
*/
|
||||
$scope.send = function() {
|
||||
verto.sendMessage($scope.message, function() {
|
||||
$scope.message = CLEAN_MESSAGE;
|
||||
});
|
||||
};
|
||||
|
||||
// Participants moderation.
|
||||
$scope.confKick = function(memberID) {
|
||||
console.log('$scope.confKick');
|
||||
verto.data.conf.kick(memberID);
|
||||
};
|
||||
|
||||
$scope.confMuteMic = function(memberID) {
|
||||
console.log('$scope.confMuteMic');
|
||||
verto.data.conf.muteMic(memberID);
|
||||
};
|
||||
|
||||
$scope.confMuteVideo = function(memberID) {
|
||||
console.log('$scope.confMuteVideo');
|
||||
verto.data.conf.muteVideo(memberID);
|
||||
};
|
||||
|
||||
$scope.confPresenter = function(memberID) {
|
||||
console.log('$scope.confPresenter');
|
||||
verto.data.conf.presenter(memberID);
|
||||
};
|
||||
|
||||
$scope.confVideoFloor = function(memberID) {
|
||||
console.log('$scope.confVideoFloor');
|
||||
verto.data.conf.videoFloor(memberID);
|
||||
};
|
||||
|
||||
$scope.confBanner = function(memberID) {
|
||||
console.log('$scope.confBanner');
|
||||
var text = 'New Banner';
|
||||
verto.data.conf.banner(memberID, text);
|
||||
};
|
||||
|
||||
$scope.confVolumeDown = function(memberID) {
|
||||
console.log('$scope.confVolumeDown');
|
||||
verto.data.conf.volumeDown(memberID);
|
||||
};
|
||||
|
||||
$scope.confVolumeUp = function(memberID) {
|
||||
console.log('$scope.confVolumeUp');
|
||||
verto.data.conf.volumeUp(memberID);
|
||||
};
|
||||
|
||||
$scope.confTransfer = function(memberID) {
|
||||
console.log('$scope.confTransfer');
|
||||
var exten = '1800';
|
||||
verto.data.conf.transfer(memberID, exten);
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,32 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ContributorsController', ['$scope', '$http',
|
||||
'toastr',
|
||||
function($scope, $http, toastr) {
|
||||
$http.get(window.location.pathname + '/contributors.txt')
|
||||
.success(function(data) {
|
||||
|
||||
var contributors = [];
|
||||
|
||||
angular.forEach(data, function(value, key) {
|
||||
var re = /(.*) <(.*)>/;
|
||||
var name = value.replace(re, "$1");
|
||||
var email = value.replace(re, "$2");
|
||||
|
||||
this.push({
|
||||
'name': name,
|
||||
'email': email
|
||||
});
|
||||
}, contributors);
|
||||
|
||||
$scope.contributors = contributors;
|
||||
})
|
||||
.error(function() {
|
||||
toastr.error('contributors not found.');
|
||||
});
|
||||
}
|
||||
]);
|
||||
})();
|
@@ -0,0 +1,75 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('DialPadController', ['$rootScope', '$scope',
|
||||
'$http', '$location', 'toastr', 'verto', 'storage',
|
||||
function($rootScope, $scope, $http, $location, toastr, verto, storage) {
|
||||
console.debug('Executing DialPadController.');
|
||||
|
||||
$scope.checkBrowser();
|
||||
storage.data.videoCall = false;
|
||||
storage.data.userStatus = 'connecting';
|
||||
storage.data.calling = false;
|
||||
|
||||
/**
|
||||
* fill dialpad via querystring [?autocall=\d+]
|
||||
*/
|
||||
if ($location.search().autocall) {
|
||||
$rootScope.dialpadNumber = $location.search().autocall;
|
||||
}
|
||||
|
||||
/**
|
||||
* used to bind click on number in call history to fill dialpad
|
||||
* 'cause inside a ng-repeat the angular isnt in ctrl scope
|
||||
*/
|
||||
$scope.fillDialpadNumber = function(number) {
|
||||
$rootScope.dialpadNumber = number;
|
||||
};
|
||||
|
||||
$rootScope.transfer = function() {
|
||||
if (!$rootScope.dialpadNumber) {
|
||||
return false;
|
||||
}
|
||||
verto.data.call.transfer($rootScope.dialpadNumber);
|
||||
};
|
||||
|
||||
/**
|
||||
* Call to the number in the $rootScope.dialpadNumber.
|
||||
*/
|
||||
$rootScope.call = function(extension) {
|
||||
storage.data.onHold = false;
|
||||
storage.data.cur_call = 0;
|
||||
$rootScope.dialpadNumber = extension;
|
||||
if (!$rootScope.dialpadNumber && storage.data.called_number) {
|
||||
$rootScope.dialpadNumber = storage.data.called_number;
|
||||
return false;
|
||||
} else if (!$rootScope.dialpadNumber && !storage.data.called_number) {
|
||||
toastr.warning('Enter an extension, please.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (verto.data.call) {
|
||||
console.debug('A call is already in progress.');
|
||||
return false;
|
||||
}
|
||||
|
||||
storage.data.mutedVideo = false;
|
||||
storage.data.mutedMic = false;
|
||||
|
||||
storage.data.videoCall = false;
|
||||
verto.call($rootScope.dialpadNumber);
|
||||
|
||||
storage.data.called_number = $rootScope.dialpadNumber;
|
||||
storage.data.call_history.unshift({
|
||||
'number': $rootScope.dialpadNumber,
|
||||
'direction': 'outbound',
|
||||
'call_start': Date()
|
||||
});
|
||||
$location.path('/incall');
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,81 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('InCallController', ['$rootScope', '$scope',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen',
|
||||
function($rootScope, $scope, $http, $location, $modal, $timeout, toatr,
|
||||
verto, storage, prompt, Fullscreen) {
|
||||
|
||||
console.debug('Executing InCallController.');
|
||||
$scope.layout = null;
|
||||
$scope.checkBrowser();
|
||||
$rootScope.dialpadNumber = '';
|
||||
$scope.callTemplate = 'partials/phone_call.html';
|
||||
$scope.dialpadTemplate = '';
|
||||
$scope.incall = true;
|
||||
|
||||
|
||||
if (storage.data.videoCall) {
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
}
|
||||
|
||||
$rootScope.$on('call.video', function(event, data) {
|
||||
$timeout(function() {
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* toggle dialpad in incall page
|
||||
*/
|
||||
$scope.toggleDialpad = function() {
|
||||
$scope.openModal('partials/dialpad_widget.html',
|
||||
'ModalDialpadController');
|
||||
|
||||
/*
|
||||
if(!$scope.dialpadTemplate) {
|
||||
$scope.dialpadTemplate = 'partials/dialpad_widget.html';
|
||||
} else {
|
||||
$scope.dialpadTemplate = '';
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: useless?
|
||||
*/
|
||||
$scope.videoCall = function() {
|
||||
prompt({
|
||||
title: 'Would you like to activate video for this call?',
|
||||
message: 'Video will be active during the next calls.'
|
||||
}).then(function() {
|
||||
storage.data.videoCall = true;
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cbMuteVideo = function(event, data) {
|
||||
storage.data.mutedVideo = !storage.data.mutedVideo;
|
||||
}
|
||||
|
||||
$scope.cbMuteMic = function(event, data) {
|
||||
storage.data.mutedMic = !storage.data.mutedMic;
|
||||
}
|
||||
|
||||
$scope.confChangeVideoLayout = function(layout) {
|
||||
verto.data.conf.setVideoLayout(layout);
|
||||
};
|
||||
|
||||
$scope.muteMic = verto.muteMic;
|
||||
$scope.muteVideo = verto.muteVideo;
|
||||
|
||||
$timeout(function() {
|
||||
console.log('broadcast time-start incall');
|
||||
$scope.$broadcast('timer-start');
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
]);
|
||||
})();
|
@@ -0,0 +1,25 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('LoginController', ['$scope', '$http', '$location',
|
||||
'verto',
|
||||
function($scope, $http, $location, verto) {
|
||||
$scope.checkBrowser();
|
||||
|
||||
/**
|
||||
* using stored data (localStorage) for logon
|
||||
*/
|
||||
verto.data.name = $scope.storage.data.name;
|
||||
verto.data.email = $scope.storage.data.email;
|
||||
if ($scope.storage.data.login != '' && $scope.storage.data.password != '') {
|
||||
verto.data.login = $scope.storage.data.login;
|
||||
verto.data.password = $scope.storage.data.password;
|
||||
}
|
||||
|
||||
console.debug('Executing LoginController.');
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,445 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('MainController',
|
||||
function($scope, $rootScope, $location, $modal, $timeout, verto, storage, toastr, Fullscreen, prompt) {
|
||||
|
||||
console.debug('Executing MainController.');
|
||||
|
||||
var myVideo = document.getElementById("webcam");
|
||||
$scope.verto = verto;
|
||||
$scope.storage = storage;
|
||||
$scope.call_history = angular.element("#call_history").hasClass('active');
|
||||
$scope.chatStatus = angular.element('#wrapper').hasClass('toggled');
|
||||
|
||||
/**
|
||||
* (explanation) scope in another controller extends rootScope (singleton)
|
||||
*/
|
||||
$rootScope.chat_counter = 0;
|
||||
$rootScope.activePane = 'members';
|
||||
/**
|
||||
* The number that will be called.
|
||||
* @type {string}
|
||||
*/
|
||||
$rootScope.dialpadNumber = '';
|
||||
|
||||
|
||||
/**
|
||||
* if user data saved, use stored data for logon
|
||||
*/
|
||||
if (storage.data.ui_connected && storage.data.ws_connected) {
|
||||
$scope.verto.data.name = storage.data.name;
|
||||
$scope.verto.data.email = storage.data.email;
|
||||
$scope.verto.data.login = storage.data.login;
|
||||
$scope.verto.data.password = storage.data.password;
|
||||
|
||||
verto.connect(function(v, connected) {
|
||||
$scope.$apply(function() {
|
||||
if (connected) {
|
||||
toastr.success('Nice to see you again.', 'Welcome back');
|
||||
$location.path('/dialpad');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// If verto is not connected, redirects to login page.
|
||||
if (!verto.data.connected) {
|
||||
console.debug('MainController: WebSocket not connected. Redirecting to login.');
|
||||
$location.path('/login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Login the user to verto server and
|
||||
* redirects him to dialpad page.
|
||||
*/
|
||||
$scope.login = function() {
|
||||
var connectCallback = function(v, connected) {
|
||||
$scope.$apply(function() {
|
||||
if (connected) {
|
||||
storage.data.ui_connected = verto.data.connected;
|
||||
storage.data.ws_connected = verto.data.connected;
|
||||
storage.data.name = verto.data.name;
|
||||
storage.data.email = verto.data.email;
|
||||
storage.data.login = verto.data.login;
|
||||
storage.data.password = verto.data.password;
|
||||
|
||||
console.debug('Redirecting to dialpad page.');
|
||||
storage.changeData(verto);
|
||||
toastr.success('Login successful.', 'Welcome');
|
||||
$location.path('/dialpad');
|
||||
} else {
|
||||
toastr.error('There was an error while trying to login. Please try again.', 'Error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
verto.connect(connectCallback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Logout the user from verto server and
|
||||
* redirects him to login page.
|
||||
*/
|
||||
$scope.logout = function() {
|
||||
var disconnect = function() {
|
||||
var disconnectCallback = function(v, connected) {
|
||||
console.debug('Redirecting to login page.');
|
||||
storage.reset();
|
||||
$location.path('/login');
|
||||
};
|
||||
|
||||
if (verto.data.call) {
|
||||
verto.hangup();
|
||||
}
|
||||
|
||||
$scope.closeChat();
|
||||
verto.disconnect(disconnectCallback);
|
||||
|
||||
verto.hangup();
|
||||
};
|
||||
|
||||
if (verto.data.call) {
|
||||
prompt({
|
||||
title: 'Oops, Active Call in Course.',
|
||||
message: 'It seems that you are in a call. Do you want to hang up?'
|
||||
}).then(function() {
|
||||
disconnect();
|
||||
});
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows a modal with the settings.
|
||||
*/
|
||||
$scope.openModalSettings = function() {
|
||||
var modalInstance = $modal.open({
|
||||
animation: $scope.animationsEnabled,
|
||||
templateUrl: 'partials/modal_settings.html',
|
||||
controller: 'ModalSettingsController',
|
||||
});
|
||||
|
||||
modalInstance.result.then(
|
||||
function(result) {
|
||||
console.log(result);
|
||||
},
|
||||
function() {
|
||||
console.info('Modal dismissed at: ' + new Date());
|
||||
}
|
||||
);
|
||||
|
||||
modalInstance.rendered.then(
|
||||
function() {
|
||||
jQuery.material.init();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.openModal = function(templateUrl, controller) {
|
||||
var modalInstance = $modal.open({
|
||||
animation: $scope.animationsEnabled,
|
||||
templateUrl: templateUrl,
|
||||
controller: controller,
|
||||
});
|
||||
|
||||
modalInstance.result.then(
|
||||
function(result) {
|
||||
console.log(result);
|
||||
},
|
||||
function() {
|
||||
console.info('Modal dismissed at: ' + new Date());
|
||||
}
|
||||
);
|
||||
|
||||
modalInstance.rendered.then(
|
||||
function() {
|
||||
jQuery.material.init();
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
$scope.showContributors = function() {
|
||||
$scope.openModal('partials/contributors.html', 'ContributorsController');
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the display adding the new number touched.
|
||||
*
|
||||
* @param {String} number - New touched number.
|
||||
*/
|
||||
$rootScope.dtmf = function(number) {
|
||||
$rootScope.dialpadNumber = $scope.dialpadNumber + number;
|
||||
if (verto.data.call) {
|
||||
verto.dtmf(number);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the last character from the number.
|
||||
*/
|
||||
$rootScope.backspace = function() {
|
||||
var number = $rootScope.dialpadNumber;
|
||||
var len = number.length;
|
||||
$rootScope.dialpadNumber = number.substring(0, len - 1);
|
||||
};
|
||||
|
||||
|
||||
$scope.toggleCallHistory = function() {
|
||||
if (!$scope.call_history) {
|
||||
angular.element("#call_history").addClass('active');
|
||||
angular.element("#call-history-wrapper").addClass('active');
|
||||
} else {
|
||||
angular.element("#call_history").removeClass('active');
|
||||
angular.element("#call-history-wrapper").removeClass('active');
|
||||
}
|
||||
$scope.call_history = angular.element("#call_history").hasClass('active');
|
||||
};
|
||||
|
||||
$scope.clearCallHistory = function() {
|
||||
storage.data.call_history = [];
|
||||
};
|
||||
|
||||
$scope.toggleChat = function() {
|
||||
if ($scope.chatStatus && $rootScope.activePane === 'chat') {
|
||||
$rootScope.chat_counter = 0;
|
||||
}
|
||||
angular.element('#wrapper').toggleClass('toggled');
|
||||
$scope.chatStatus = angular.element('#wrapper').hasClass('toggled');
|
||||
};
|
||||
|
||||
$scope.openChat = function() {
|
||||
$scope.chatStatus = false;
|
||||
angular.element('#wrapper').removeClass('toggled');
|
||||
};
|
||||
|
||||
$scope.closeChat = function() {
|
||||
$scope.chatStatus = true;
|
||||
angular.element('#wrapper').addClass('toggled');
|
||||
};
|
||||
|
||||
$scope.goFullscreen = function() {
|
||||
if (storage.data.userStatus !== 'connected') {
|
||||
return;
|
||||
}
|
||||
$rootScope.fullscreenEnabled = !Fullscreen.isEnabled();
|
||||
if (Fullscreen.isEnabled()) {
|
||||
Fullscreen.cancel();
|
||||
} else {
|
||||
Fullscreen.enable(document.getElementsByTagName('body')[0]);
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on('call.video', function(event) {
|
||||
storage.data.videoCall = true;
|
||||
});
|
||||
|
||||
$rootScope.$on('call.hangup', function(event, data) {
|
||||
if (Fullscreen.isEnabled()) {
|
||||
Fullscreen.cancel();
|
||||
}
|
||||
|
||||
|
||||
console.log($scope.chatStatus);
|
||||
if (!$scope.chatStatus) {
|
||||
angular.element('#wrapper').toggleClass('toggled');
|
||||
$scope.chatStatus = angular.element('#wrapper').hasClass('toggled');
|
||||
}
|
||||
|
||||
$rootScope.dialpadNumber = '';
|
||||
console.debug('Redirecting to dialpad page.');
|
||||
$location.path('/dialpad');
|
||||
|
||||
try {
|
||||
$rootScope.$digest();
|
||||
} catch (e) {
|
||||
console.log('not digest');
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('page.incall', function(event, data) {
|
||||
if (storage.data.askRecoverCall) {
|
||||
prompt({
|
||||
title: 'Oops, Active Call in Course.',
|
||||
message: 'It seems you were in a call before leaving the last time. Wanna go back to that?'
|
||||
}).then(function() {
|
||||
verto.changeData(storage);
|
||||
console.log('redirect to incall page');
|
||||
$location.path('/incall');
|
||||
}, function() {
|
||||
storage.data.userStatus = 'connecting';
|
||||
verto.hangup();
|
||||
});
|
||||
} else {
|
||||
verto.changeData(storage);
|
||||
console.log('redirect to incall page');
|
||||
$location.path('/incall');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$rootScope.callActive = function(data) {
|
||||
verto.data.mutedMic = storage.data.mutedMic;
|
||||
verto.data.mutedVideo = storage.data.mutedVideo;
|
||||
|
||||
if (!storage.data.cur_call) {
|
||||
storage.data.call_start = new Date();
|
||||
}
|
||||
storage.data.userStatus = 'connected';
|
||||
var call_start = new Date(storage.data.call_start);
|
||||
$rootScope.start_time = call_start;
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$broadcast('timer-start');
|
||||
});
|
||||
myVideo.play();
|
||||
storage.data.calling = false;
|
||||
|
||||
storage.data.cur_call = 1;
|
||||
};
|
||||
|
||||
$rootScope.$on('call.active', function(event, data) {
|
||||
$rootScope.callActive(data);
|
||||
});
|
||||
|
||||
$rootScope.$on('call.calling', function(event, data) {
|
||||
storage.data.calling = true;
|
||||
});
|
||||
|
||||
$rootScope.$on('call.incoming', function(event, data) {
|
||||
console.log('Incoming call from: ' + data);
|
||||
|
||||
storage.data.cur_call = 0;
|
||||
$scope.incomingCall = true;
|
||||
storage.data.videoCall = false;
|
||||
storage.data.mutedVideo = false;
|
||||
storage.data.mutedMic = false;
|
||||
|
||||
prompt({
|
||||
title: 'Incoming Call',
|
||||
message: 'from ' + data
|
||||
}).then(function() {
|
||||
var call_start = new Date(storage.data.call_start);
|
||||
$rootScope.start_time = call_start;
|
||||
console.log($rootScope.start_time);
|
||||
|
||||
$scope.answerCall();
|
||||
storage.data.called_number = data;
|
||||
|
||||
storage.data.call_history.unshift({
|
||||
'number': data,
|
||||
'direction': 'inbound',
|
||||
'status': true,
|
||||
'call_start': Date()
|
||||
});
|
||||
$location.path('/incall');
|
||||
}, function() {
|
||||
$scope.declineCall();
|
||||
storage.data.call_history.unshift({
|
||||
'number': data,
|
||||
'direction': 'inbound',
|
||||
'status': false,
|
||||
'call_start': Date()
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$scope.hold = function() {
|
||||
storage.data.onHold = !storage.data.onHold;
|
||||
verto.data.call.toggleHold();
|
||||
};
|
||||
|
||||
/**
|
||||
* Hangup the current call.
|
||||
*/
|
||||
$scope.hangup = function() {
|
||||
if (!verto.data.call) {
|
||||
toastr.warning('There is no call to hangup.');
|
||||
$location.path('/dialpad');
|
||||
}
|
||||
|
||||
//var hangupCallback = function(v, hangup) {
|
||||
// if (hangup) {
|
||||
// $location.path('/dialpad');
|
||||
// } else {
|
||||
// console.debug('The call could not be hangup.');
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//verto.hangup(hangupCallback);
|
||||
|
||||
verto.hangup();
|
||||
};
|
||||
|
||||
$scope.answerCall = function() {
|
||||
storage.data.onHold = false;
|
||||
|
||||
verto.data.call.answer({
|
||||
useStereo: verto.data.useStereo,
|
||||
useCamera: verto.data.useCamera,
|
||||
useMic: verto.data.useMic,
|
||||
callee_id_name: verto.data.name,
|
||||
callee_id_number: verto.data.login
|
||||
});
|
||||
|
||||
|
||||
$location.path('/incall');
|
||||
};
|
||||
|
||||
$scope.declineCall = function() {
|
||||
$scope.hangup();
|
||||
$scope.incomingCall = false;
|
||||
};
|
||||
|
||||
$scope.screenshare = function() {
|
||||
if (verto.data.shareCall) {
|
||||
verto.screenshareHangup();
|
||||
return false;
|
||||
}
|
||||
verto.screenshare(storage.data.called_number);
|
||||
};
|
||||
|
||||
$scope.play = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
function(file) {
|
||||
verto.data.conf.play(file);
|
||||
console.log('play file :', file);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.stop = function() {
|
||||
verto.data.conf.stop();
|
||||
};
|
||||
|
||||
$scope.record = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
function(file) {
|
||||
verto.data.conf.record(file);
|
||||
console.log('recording file :', file);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.stopRecord = function() {
|
||||
verto.data.conf.stopRecord();
|
||||
};
|
||||
|
||||
$scope.snapshot = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
function(file) {
|
||||
verto.data.conf.snapshot(file);
|
||||
console.log('snapshot file :', file);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
})();
|
@@ -0,0 +1,13 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('MenuController', ['$scope', '$http', '$location',
|
||||
'verto', 'storage',
|
||||
function($scope, $http, $location, verto, storage) {
|
||||
console.debug('Executing MenuController.');
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,20 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ModalDialpadController', ['$scope',
|
||||
'$modalInstance',
|
||||
function($scope, $modalInstance) {
|
||||
|
||||
$scope.ok = function() {
|
||||
$modalInstance.close('Ok.');
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
}
|
||||
]);
|
||||
})();
|
@@ -0,0 +1,25 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ModalLoginInformationController', ['$scope',
|
||||
'$http', '$location', '$modalInstance', 'verto', 'storage',
|
||||
function($scope, $http, $location, $modalInstance, verto, storage) {
|
||||
console.debug('Executing ModalLoginInformationController.');
|
||||
|
||||
$scope.verto = verto;
|
||||
$scope.storage = storage;
|
||||
|
||||
$scope.ok = function() {
|
||||
$modalInstance.close('Ok.');
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,30 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ModalSettingsController', ['$scope', '$http',
|
||||
'$location', '$modalInstance', 'verto', 'storage',
|
||||
function($scope, $http, $location, $modalInstance, verto, storage) {
|
||||
console.debug('Executing ModalSettingsController.');
|
||||
|
||||
verto.changeData(storage);
|
||||
$scope.verto = verto;
|
||||
$scope.storage = storage;
|
||||
|
||||
$scope.ok = function() {
|
||||
storage.changeData(verto);
|
||||
$modalInstance.close('Ok.');
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
$scope.refreshDeviceList = function() {
|
||||
return verto.refreshDevices();
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,11 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var vertoControllers = angular.module('vertoControllers', [
|
||||
'ui.bootstrap',
|
||||
'vertoService',
|
||||
'storageService',
|
||||
'ui.gravatar'
|
||||
]);
|
||||
|
||||
})();
|
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Sometimes autofocus HTML5 directive just isn't enough with SPAs.
|
||||
This directive will force autofocus to work properly under those circumstances.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoDirectives')
|
||||
.directive('autofocus', ['$timeout',
|
||||
function ($timeout) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function ($scope, $element) {
|
||||
$timeout(function () {
|
||||
$element[0].focus();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
})();
|
@@ -0,0 +1,37 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoDirectives')
|
||||
.directive('showControls',
|
||||
function(Fullscreen) {
|
||||
var link = function(scope, element, attrs) {
|
||||
var i = null;
|
||||
jQuery('.video-footer').fadeIn('slow');
|
||||
jQuery('.video-hover-buttons').fadeIn('slow');
|
||||
element.parent().bind('mousemove', function() {
|
||||
if (Fullscreen.isEnabled()) {
|
||||
clearTimeout(i);
|
||||
jQuery('.video-footer').fadeIn('slow');
|
||||
jQuery('.video-hover-buttons').fadeIn(500);
|
||||
i = setTimeout(function() {
|
||||
if (Fullscreen.isEnabled()) {
|
||||
jQuery('.video-footer').fadeOut('slow');
|
||||
jQuery('.video-hover-buttons').fadeOut(500);
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
element.parent().bind('mouseleave', function() {
|
||||
jQuery('.video-footer').fadeIn();
|
||||
jQuery('.video-hover-buttons').fadeIn();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
link: link
|
||||
};
|
||||
});
|
||||
|
||||
})();
|
@@ -0,0 +1,27 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoDirectives').directive('userStatus',
|
||||
function() {
|
||||
var link = function(scope, element, attrs) {
|
||||
scope.$watch('condition', function(condition) {
|
||||
element.removeClass('connected');
|
||||
element.removeClass('disconnected');
|
||||
element.removeClass('connecting');
|
||||
|
||||
element.addClass(condition);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
scope: {
|
||||
'condition': '='
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
})();
|
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* To RTC work properly we need to give a <video> tag as soon as possible
|
||||
* because it needs to attach the video and audio stream to the tag.
|
||||
*
|
||||
* This directive is responsible for moving the video tag from the body to
|
||||
* the right place when a call start and move back to the body when the
|
||||
* call ends. It also hides and display the tag when its convenient.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoDirectives')
|
||||
.directive('videoTag',
|
||||
function() {
|
||||
function link(scope, element, attrs) {
|
||||
// Moving the video tag to the new place inside the incall page.
|
||||
console.log('Moving the video to element.');
|
||||
jQuery('video').removeClass('hide').appendTo(element);
|
||||
jQuery('video').css('display', 'block');
|
||||
scope.callActive();
|
||||
|
||||
element.on('$destroy', function() {
|
||||
// Move the video back to the body.
|
||||
console.log('Moving the video back to body.');
|
||||
jQuery('video').addClass('hide').appendTo(jQuery('body'));
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
link: link
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
@@ -0,0 +1,4 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
var vertoDirectives = angular.module('vertoDirectives', []);
|
||||
})();
|
@@ -0,0 +1,793 @@
|
||||
'use strict';
|
||||
|
||||
/* Controllers */
|
||||
|
||||
var videoQuality = [{
|
||||
id: 'qvga',
|
||||
label: 'QVGA 320x240',
|
||||
width: 320,
|
||||
height: 240
|
||||
}, {
|
||||
id: 'vga',
|
||||
label: 'VGA 640x480',
|
||||
width: 640,
|
||||
height: 480
|
||||
}, {
|
||||
id: 'qvga_wide',
|
||||
label: 'QVGA WIDE 320x180',
|
||||
width: 320,
|
||||
height: 180
|
||||
}, {
|
||||
id: 'vga_wide',
|
||||
label: 'VGA WIDE 640x360',
|
||||
width: 640,
|
||||
height: 360
|
||||
}, {
|
||||
id: 'hd',
|
||||
label: 'HD 1280x720',
|
||||
width: 1280,
|
||||
height: 720
|
||||
}, {
|
||||
id: 'hhd',
|
||||
label: 'HHD 1920x1080',
|
||||
width: 1920,
|
||||
height: 1080
|
||||
}, ];
|
||||
|
||||
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', 'storage',
|
||||
function($rootScope, $cookieStore, $location, storage) {
|
||||
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,
|
||||
bestWidth: '',
|
||||
bestHeight: '',
|
||||
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() {
|
||||
var maxWidth, maxHeight;
|
||||
|
||||
maxWidth = data.bestWidth;
|
||||
maxHeight = data.bestHeight;
|
||||
|
||||
if(!data.bestWidth) {
|
||||
maxWidth = videoResolution[data.vidQual].width;
|
||||
}
|
||||
|
||||
if(!data.bestHeight) {
|
||||
maxHeight = videoResolution[data.vidQual].height;
|
||||
}
|
||||
|
||||
return {
|
||||
minWidth: videoResolution[data.vidQual].width,
|
||||
minHeight: videoResolution[data.vidQual].height,
|
||||
maxWidth: maxWidth,
|
||||
maxHeight: maxHeight,
|
||||
minFrameRate: 15,
|
||||
vertoBestFrameRate: 30
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
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.selectedVideo = verto_data.data.selectedVideo;
|
||||
data.selectedAudio = verto_data.data.selectedAudio;
|
||||
data.selectedShare = verto_data.data.selectedShare;
|
||||
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.');
|
||||
function refreshDevicesCallback() {
|
||||
data.videoDevices = [{
|
||||
id: 'none',
|
||||
label: 'No camera'
|
||||
}];
|
||||
data.shareDevices = [{
|
||||
id: 'screen',
|
||||
label: 'Screen'
|
||||
}];
|
||||
data.audioDevices = [];
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
for (var i in jQuery.verto.audioInDevices) {
|
||||
var device = jQuery.verto.audioInDevices[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.');
|
||||
};
|
||||
|
||||
jQuery.verto.refreshDevices(refreshDevicesCallback);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.');
|
||||
}
|
||||
},
|
||||
|
||||
updateResolutions: function(supportedResolutions) {
|
||||
console.debug('Attempting to sync supported and available resolutions');
|
||||
|
||||
var removed = 0;
|
||||
|
||||
angular.forEach(videoQuality, function(resolution, id) {
|
||||
var supported = false;
|
||||
angular.forEach(supportedResolutions, function(res) {
|
||||
var width = res[0];
|
||||
var height = res[1];
|
||||
|
||||
if(resolution.width == width && resolution.height == height) {
|
||||
supported = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(!supported) {
|
||||
delete videoQuality[id];
|
||||
++removed;
|
||||
}
|
||||
});
|
||||
|
||||
videoQuality.length = videoQuality.length - removed;
|
||||
this.videoQuality = videoQuality;
|
||||
this.data.vidQual = (videoQuality.length > 0) ? videoQuality[videoQuality.length - 1].id : null;
|
||||
|
||||
return videoQuality;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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(resolutions) {
|
||||
data.bestWidth = resolutions['bestResSupported'][0];
|
||||
data.bestHeight = resolutions['bestResSupported'][1];
|
||||
|
||||
that.updateResolutions(resolutions['validRes']);
|
||||
|
||||
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(),
|
||||
// TODO: Add options for this.
|
||||
audioParams: {
|
||||
googEchoCancellation: storage.data.googEchoCancellation || false,
|
||||
googNoiseSuppression: storage.data.googNoiseSuppression || false,
|
||||
googHighpassFilter: storage.data.googHighpassFilter || false
|
||||
},
|
||||
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,
|
||||
userVariables: {
|
||||
email : storage.data.email
|
||||
}
|
||||
});
|
||||
|
||||
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,
|
||||
userVariables: {
|
||||
email : storage.data.email
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
@@ -0,0 +1,4 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
var vertoService = angular.module('vertoService', []);
|
||||
})();
|