diff --git a/.gitignore b/.gitignore index 0732f74..11df243 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.settings /bower_components /node_modules -.project \ No newline at end of file +.project +*.swp diff --git a/Gruntfile.js b/Gruntfile.js index 163e0ed..8b7bfc6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -5,74 +5,74 @@ module.exports = function(grunt) { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), - + meta: { banner: '/**\n' + - ' * Copyright 2014 IBM Corp.\n' + - ' *\n' + - ' * Licensed under the Apache License, Version 2.0 (the "License");\n' + - ' * you may not use this file except in compliance with the License.\n' + - ' * You may obtain a copy of the License at\n' + - ' *\n' + - ' * http://www.apache.org/licenses/LICENSE-2.0\n' + - ' *\n' + - ' * Unless required by applicable law or agreed to in writing, software\n' + - ' * distributed under the License is distributed on an "AS IS" BASIS,\n' + - ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' + - ' * See the License for the specific language governing permissions and\n' + - ' * limitations under the License.\n' + - ' *\n' + - ' * <%= pkg.description %>\n' + - ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + - ' * @link <%= pkg.homepage %>\n' + - ' * @author <%= pkg.author %>\n' + - ' */\n' + ' * Copyright 2014 IBM Corp.\n' + + ' *\n' + + ' * Licensed under the Apache License, Version 2.0 (the "License");\n' + + ' * you may not use this file except in compliance with the License.\n' + + ' * You may obtain a copy of the License at\n' + + ' *\n' + + ' * http://www.apache.org/licenses/LICENSE-2.0\n' + + ' *\n' + + ' * Unless required by applicable law or agreed to in writing, software\n' + + ' * distributed under the License is distributed on an "AS IS" BASIS,\n' + + ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' + + ' * See the License for the specific language governing permissions and\n' + + ' * limitations under the License.\n' + + ' *\n' + + ' * <%= pkg.description %>\n' + + ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + + ' * @link <%= pkg.homepage %>\n' + + ' * @author <%= pkg.author %>\n' + + ' */\n' }, - + dirs: { src: 'src', dest: 'dist' }, - + concat: { options: { banner: '<%= meta.banner %>' }, dist: { -// src: ['<%= dirs.src %>/*.js', '<%= dirs.src %>/**/*.js'], - src: ['<%= dirs.src %>/js/angular-rtcomm.js', '<%= dirs.src %>/js/rtcomm-services.js', '<%= dirs.src %>/js/rtcomm-directives.js', '<%= dirs.src %>/js/rtcomm-presence.js'], + // src: ['<%= dirs.src %>/*.js', '<%= dirs.src %>/**/*.js'], + src: ['<%= dirs.src %>/js/**/*.module.js', '<%= dirs.src %>/js/**/*.js', '!**/*.spec.js'], dest: '<%= dirs.dest %>/<%= pkg.name %>.js' } }, - + copy: { - main: { - expand: true, - cwd: '<%= dirs.src %>', - src: ['css/*.css'], - dest: '<%= dirs.dest %>', - } + main: { + expand: true, + cwd: '<%= dirs.src %>', + src: ['css/*.css'], + dest: '<%= dirs.dest %>', + } }, cssmin: { - my_target: { - files: [{ - expand: true, - cwd: '<%= dirs.src %>', - src: ['css/*.css'], - dest: '<%= dirs.dest %>', - ext: '.min.css' - }] - } + my_target: { + files: [{ + expand: true, + cwd: '<%= dirs.src %>', + src: ['css/*.css'], + dest: '<%= dirs.dest %>', + ext: '.min.css' + }] + } }, - + ngAnnotate: { - dist: { - files: { - '<%= dirs.dest %>/<%= pkg.name %>.js': ['<%= dirs.dest %>/<%= pkg.name %>.js'] - } + dist: { + files: { + '<%= dirs.dest %>/<%= pkg.name %>.js': ['<%= dirs.dest %>/<%= pkg.name %>.js'] } - }, + } + }, uglify: { options: { @@ -107,39 +107,63 @@ module.exports = function(grunt) { } } }, - - watch: { + karma: { + unit: { + configFile: 'karma.conf.js', + singleRun: true + }, + watch :{ + configFile: 'karma.conf.js' + } + + }, + watch: { dev: { files: ['<%= dirs.src %>/**'], tasks: ['build'] }, }, - - ngtemplates: { - 'angular-rtcomm-ui': { - cwd: '<%= dirs.src %>', - src: ['templates/rtcomm/**.html', '!templates/rtcomm/rtcomm-presence.html'], - dest: '<%= dirs.dest %>/<%= pkg.name %>.js', - options: { - htmlmin: { collapseWhitespace: true, collapseBooleanAttributes: true }, - append: 'true' - } - }, - 'angular-rtcomm-presence': { - cwd: '<%= dirs.src %>', - src: 'templates/rtcomm/rtcomm-presence.html', - dest: '<%= dirs.dest %>/<%= pkg.name %>.js', - options: { - htmlmin: { collapseWhitespace: true, collapseBooleanAttributes: true }, - append: 'true' - } - - } - } + wiredep: { + task: { + src: ['<%= dirs.src %>/test/**/*.html'] + }, + options: { + ignorePath: '../../..' + } + }, + ngtemplates: { + 'angular-rtcomm-ui': { + cwd: '<%= dirs.src %>', + src: ['templates/rtcomm/**.html', '!templates/rtcomm/rtcomm-presence.html'], + dest: '<%= dirs.dest %>/<%= pkg.name %>.js', + options: { + htmlmin: { + collapseWhitespace: true, + collapseBooleanAttributes: true + }, + append: 'true' + } + }, + 'angular-rtcomm-presence': { + cwd: '<%= dirs.src %>', + src: 'templates/rtcomm/rtcomm-presence.html', + dest: '<%= dirs.dest %>/<%= pkg.name %>.js', + options: { + htmlmin: { + collapseWhitespace: true, + collapseBooleanAttributes: true + }, + append: 'true' + } + + } + }, + + }); // Build task. - grunt.registerTask('build', ['jshint', 'concat', 'ngtemplates', 'ngAnnotate', 'uglify', 'copy', 'cssmin']); + grunt.registerTask('build', ['karma:unit', 'jshint', 'concat', 'ngtemplates', 'ngAnnotate', 'uglify', 'copy', 'cssmin']); // Default task. //grunt.registerTask('default', ['build', 'watch']); diff --git a/README.md b/README.md index 2b9428b..8a5583b 100644 --- a/README.md +++ b/README.md @@ -4,33 +4,55 @@ This repository contains the Rtcomm Angular.js module. The Rtcomm Angular module This module is built on the [rtcomm.js](https://github.com/WASdev/lib.rtcomm.clientjs) open source JavaScript library which wraps [WebRTC](http://www.webrtc.org/) with call signaling and a number of advanced real-time communications capabilities like presence and chat. -##Requirements +## Requirements Rtcomm utilizes MQTT for call signaling so at a minimum you will need an MQTT message broker that supports web sockets. There are many open source and productized versions of MQTT message brokers available. A great option is to download the WebSphere Liberty Server which includes an embedded MQTT broker and a number of backend Rtcomm services such as call queueing. The WebSphere Liberty server is free for development and the beta version that includes support for MQTT can be downloaded from [here](https://developer.ibm.com/wasdev/downloads/liberty-profile-beta/). -##Install +## Install To install the angular-rtcomm module for use in an AngularJS application, you can use bower: **bower install angular-rtcomm** -##Build -To build the angular-rtcomm module, you can use npm: +## Build +To build the angular-rtcomm module, you can use npm and [Grunt](http://gruntjs.com/): +``` +npm install +grunt build +``` This is useful if you want to modify the angular-rtcomm templates. -##Test -This repository relies on Karma for testing. To run the test framework you can type the following in the root lib.angular-rtcomm directory: +## Test + +This repository relies on [Karma](https://github.com/karma-runner/karma) and [Protractor](http://www.protractortest.org/) for Unit and Integration testing respectively. + +To run Unit Tests against this project: -**karma start** +``` +karma start karma.conf.js +``` -Note that the test framework assumes the MQTT broker is running on localhost:9080. There is also currently a dependency on the WebSphere Liberty server (which includes an embedded MQTT broker) for some of the Rtcomm features. The link to download a version of WebSphere Liberty for development and testing can be found at the top of the page. +Integration Testing requires more previous configuration. First you'll want to update and start a Selenium Webdriver server on your machine: -We are working on an npm install of the development environment so stay tuned. +``` +$ node_modules/.bin/webdriver-manager update +$ node_modules/.bin/webdriver-manager start +``` + +Once that is setup you can simply start the MQTT broker + Static Server combo: + +``` +npm start +``` + +And finally, run the integration test: +``` +npm test +``` -A sample page is also included in the test directory along with a sample config file that can be used to run the test. -##Usage +## Usage -###Initialization +### Initialization To use the module, you will need to include the following js and css files with your project: First the angular-rtcomm related files: @@ -64,12 +86,12 @@ The above dependencies can be accessed via CDN as above or via your bower_compon We are also working to reduce the number of dependencies (or to at least provide more flexibility in when these dependencies are required). -###Module injection +### Module injection AngularJS applications inject the angular-rtcomm module as follows: var sampleModule = angular.module('sampleModule', ['angular-rtcomm']); -###RtcommService +### RtcommService The RtcommService is the singleton that controls all aspects of the Rtcomm module. Its the only service AngularJS applications need to inject when using the angular-rtcomm module. The RtcommService broadcasts all its related events to the $rootScope. The events published by the RtcommService are a combination of events generated by the angular-rtcomm module and the rtcomm.js library described above that this module wraps. Here is the list of events: @@ -128,53 +150,53 @@ And the methods exposed by the RtcommService include the following: * setVideoView -###List of AngularJS directives +### List of AngularJS directives Here is a complete list of all the currently supported directives. -####rtcomm-register: +#### rtcomm-register: Directive used to register an endpoint. Registration implies creation of a user record as a retained message on the configured presence topic which can be accessed by any endpoint or service that has permissions to subscribe on the registration topic. This is registration is required after initialization. If the user name is specified in advance, for example via a cookie, the userid can be specified when initializing the RtcommService: ```html ``` No init parameters. -####rtcomm-queues: +#### rtcomm-queues: Directive used to view and join any available call queue. Can be used by helpdesk agents (only availble when working with WebSphere): ```html ``` -####rtcomm-presence: +#### rtcomm-presence: Directive used to view presence information: ```html ``` -####rtcomm-chat: +#### rtcomm-chat: Directive used to display a chat window: ```html ``` -####rtcomm-video: +#### rtcomm-video: Directive that contains a WebRTC video window (both self and remote views): ```html ``` -####rtcomm-endpoint-status: +#### rtcomm-endpoint-status: Directive that displays status about the active endpoint: ```html ``` -####rtcomm-sessionmgr: +#### rtcomm-sessionmgr: Directive that manages multiple endpoints and their associated sessions. For instance, used by a helpdesk agent to manage multiple sessions: ```html ``` -###List of AngularJS Controllers +### List of AngularJS Controllers This controller can read configuration from a specified JSON file: **RtcommConfigController** diff --git a/bower.json b/bower.json index 66f28ec..c2054b4 100644 --- a/bower.json +++ b/bower.json @@ -1,12 +1,10 @@ { "name": "angular-rtcomm", - "version": "1.0.3", + "version": "1.0.4", "description": "Angular module for Rtcomm", "main": [ "dist/angular-rtcomm.js", - "dist/angular-rtcomm.min.js", - "dist/css/angular-rtcomm.css", - "dist/css/angular-rtcomm.min.css" + "dist/css/angular-rtcomm.css" ], "keywords": [ "webrtc", @@ -30,11 +28,14 @@ "package.json" ], "dependencies": { - "jquery": "~2.1.1", - "angular-tree-control": "~0.2.7", - "bootstrap": "~3.3.1", - "angular": "^1.4.6", - "angular-bootstrap": "~0.13.0", + "jquery": "~2.2.x", + "angular-tree-control": "~0.2.x", + "bootstrap": "~3.3.6", + "angular": "~1.4.0", + "angular-bootstrap": "1.2.x", "rtcomm": "^1.0.0" + }, + "devDependencies": { + "angular-mocks": "~1.4.0" } } diff --git a/dist/angular-rtcomm.js b/dist/angular-rtcomm.js index 4a85458..fcab06b 100644 --- a/dist/angular-rtcomm.js +++ b/dist/angular-rtcomm.js @@ -14,12 +14,24 @@ * limitations under the License. * * Angular module for Rtcomm - * @version v1.0.3 - 2016-02-18 + * @version v1.0.3 - 2016-03-29 * @link https://github.com/WASdev/lib.angular-rtcomm * @author Brian Pulito (https://github.com/bpulito) */ -/* - * This is the main angular-rtcomm module. +/** + * (C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ (function() { angular.module('angular-rtcomm', [ @@ -31,1647 +43,1219 @@ ]); })(); + /** - * Definition for the rtcommModule + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + (function() { - angular.module('angular-rtcomm-service', []) - /** - * Set debugEnabled to true to enable the debug messages in this rtcomm angular module. - */ - .config(["$logProvider", function($logProvider){ - $logProvider.debugEnabled(true); - }]) - /* This causes a problem in ionic/iosrtc - .config(function($locationProvider) { - $locationProvider.html5Mode( {enabled: true, - requireBase: false}); - }) */ - .factory('RtcommConfigService', RtcommConfigService) - .factory('RtcommService', RtcommService); - /** - * - */ - RtcommConfigService.$inject = ['$location', '$log', '$window']; - function RtcommConfigService($location, $log, $window) { - // First we check to see if the URL includes the query string disableRtcomm=true. - // This is typically done when a URL is being shared vian an iFrame that includes Rtcomm directives. - // If it is set we just return without setting up Rtcomm. - $log.debug('RtcommConfigService: Abs URL: ' + $location.absUrl()); - var _disableRtcomm = $location.search().disableRtcomm; - if (typeof _disableRtcomm === "undefined" || _disableRtcomm === null) { - _disableRtcomm = false; - } else if (_disableRtcomm === "true") { - _disableRtcomm = true; - } else { - _disableRtcomm = false; - } + 'use strict'; - $log.debug('RtcommConfigService: _disableRtcomm = ' + _disableRtcomm); + angular + .module('angular-rtcomm-service', []); +})(); - var providerConfig = { - server : $location.host(), - port : $location.port(), - rtcommTopicPath : "/rtcomm/", - createEndpoint : false, - appContext: 'default', - userid: "", - presence : {topic : ""} - }; +/** + * (C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * The angular-rtcomm-ui module + * This has controllers and directives in it. + */ +(function(){ - $log.debug('providerConfig.server: ' + providerConfig.server); - $log.debug('providerConfig.port: ' + providerConfig.port); +angular + .module('angular-rtcomm-ui', [ + 'ui.bootstrap', + 'angular-rtcomm-service']); - var endpointConfig = { - chat: true, - webrtc: true - }; +})(); - // Default to enabling audio and video. It must be disabled through config. - var broadcastAudio = true; - var broadcastVideo = true; - var rtcommDebug = "DEBUG"; - var ringtone = null; - var ringbacktone = null; - var trickleICE = true; +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * The angular-rtcomm-presence module + * This has controllers and directives in it. + */ +(function(){ + angular + .module('angular-rtcomm-presence', [ + 'ui.bootstrap', + 'treeControl', + 'angular-rtcomm-service']) + .directive('rtcommPresence', rtcommPresence); + + /** + * This directive manages the chat portion of a session. The data model for chat + * is maintained in the RtcommService. This directive handles switching between + * active endpoints. + * + * Here is the formate of the presenceData: + * + * This is a Node: + * { + * "name" : "agents", + * "record" : false, + * "nodes" : [] + * } + * + * This is a record with a set of user defines: + * { + * "name" : "Brian Pulito", + * "record" : true, + * "nodes" : [ + * { + * "name" : "queue", + * "value" : "appliances" + * }, + * { + * "name" : "sessions", + * "value" : "3" + * } + * ] + */ + rtcommPresence.$inject=['RtcommService', '$log']; + function rtcommPresence(RtcommService, $log) { + return { + restrict: 'E', + templateUrl: "templates/rtcomm/rtcomm-presence.html", + controller: ["$scope", "$rootScope", function ($scope, $rootScope) { + + $scope.monitorTopics = []; + $scope.presenceData = []; + $scope.expandedNodes = []; - var setConfig = function(config){ - providerConfig.server = (typeof config.server !== "undefined")? config.server : providerConfig.server; - providerConfig.port = (typeof config.port !== "undefined")? config.port : providerConfig.port; - providerConfig.rtcommTopicPath = (typeof config.rtcommTopicPath !== "undefined")? config.rtcommTopicPath : providerConfig.rtcommTopicPath; - providerConfig.createEndpoint = (typeof config.createEndpoint !== "undefined")? config.createEndpoint : providerConfig.createEndpoint; - providerConfig.appContext = (typeof config.appContext !== "undefined")? config.appContext : providerConfig.appContext; - providerConfig.presence.topic = (typeof config.presenceTopic !== "undefined")? config.presenceTopic : providerConfig.presence.topic; + // Default protocol list initiated from presence. Start with chat only. + $scope.protocolList = { + chat : true, + webrtc : false}; - // We no longer need to set 'useSSL' This will be set based on how page is served. -// providerConfig.useSSL = (typeof config.useSSL !== "undefined")? config.useSSL : providerConfig.useSSL; - // Protocol related booleans - endpointConfig.chat= (typeof config.chat!== "undefined")? config.chat: endpointConfig.chat; - endpointConfig.webrtc = (typeof config.webrtc!== "undefined")? config.webrtc: endpointConfig.webrtc; + // use a tree view or flatten. + $scope.flatten = false; + $scope.treeOptions = { + nodeChildren: "nodes", + dirSelectable: true, + injectClasses: { + ul: "a1", + li: "a2", + liSelected: "a7", + iExpanded: "a3", + iCollapsed: "a4", + iLeaf: "a5", + label: "a6", + labelSelected: "a8" + } + }; - broadcastAudio = (typeof config.broadcastAudio !== "undefined")? config.broadcastAudio: broadcastAudio; - broadcastVideo = (typeof config.broadcastVideo !== "undefined")? config.broadcastVideo: broadcastVideo; - trickleICE = (typeof config.trickleICE !== "undefined")? config.trickleICE: trickleICE; + $scope.init = function(options) { + $scope.protocolList.chat = (typeof options.chat === 'boolean') ? options.chat : $scope.protocolList.chat; + $scope.protocolList.webrtc = (typeof options.webrtc === 'boolean') ? options.webrtc : $scope.protocolList.webrtc; + $scope.flatten = (typeof options.flatten === 'boolean') ? options.flatten: $scope.flatten; + }; - ringbacktone = (typeof config.ringbacktone !== "undefined")? config.ringbacktone: ringbacktone; - ringtone = (typeof config.ringtone !== "undefined")? config.ringtone : ringtone; + $scope.onCallClick = function(calleeEndpointID){ + var endpoint = RtcommService.getEndpoint(); + RtcommService.setActiveEndpoint(endpoint.id); - rtcommDebug = (typeof config.rtcommDebug !== "undefined")? config.rtcommDebug: rtcommDebug; + if ($scope.protocolList.chat == true) + endpoint.chat.enable(); - $log.debug('rtcommDebug from config is: ' + config.rtcommDebug); + if ($scope.protocolList.webrtc == true){ + endpoint.webrtc.enable(function(value, message) { + if (!value) { + RtcommService.alert({type: 'danger', msg: message}); + } + }); + } - if (typeof config.userid !== "undefined") - providerConfig.userid = config.userid; + endpoint.connect(calleeEndpointID); + $rootScope.$broadcast('rtcomm::presence-click'); + }; - $log.debug('providerConfig is now: ', providerConfig); + $scope.$on('rtcomm::init', function (event, success, details) { + RtcommService.publishPresence(); + var presenceMonitor = RtcommService.getPresenceMonitor(); - }; + presenceMonitor.on('updated', function(presenceData){ + $log.debug('<<------rtcommPresence: updated------>>'); + if ($scope.flatten) { + $log.debug('<<------rtcommPresence: updated using flattened data ------>>'); + $scope.presenceData = presenceData[0].flatten(); + } + $scope.$apply(); + }); - return { - setProviderConfig : function(config){setConfig(config);}, + // Binding data if we are going to flatten causes a flash in the UI when it changes. + if (!$scope.flatten) { + $scope.presenceData = presenceMonitor.getPresenceData(); + } - getProviderConfig : function(){return providerConfig;}, + if ($scope.presenceData.length >= 1) + $scope.expandedNodes.push($scope.presenceData[0]); - getWebRTCEnabled : function(){return endpointConfig.webrtc;}, + for (var index = 0; index < $scope.monitorTopics.length; index++) { + $log.debug('rtcommPresence: monitorTopic: ' + $scope.monitorTopics[index]); + presenceMonitor.add($scope.monitorTopics[index]); + } + }); - getChatEnabled : function(){return endpointConfig.chat;}, + }], + controllerAs: 'presence' + }; + }; +})(); - getBroadcastAudio : function(){return broadcastAudio;}, +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ - getBroadcastVideo : function(){return broadcastVideo;}, +(function() { + 'use strict'; - getRingTone : function(){return ringtone;}, + angular + .module('angular-rtcomm-service') + .factory('RtcommConfigService', RtcommConfigService); + + /* @ngInject */ + function RtcommConfigService($location, $log, $window) { + var service = { + setProviderConfig: setProviderConfig, + getProviderConfig: getProviderConfig, + getWebRTCEnabled: getWebRTCEnabled, + getChatEnabled: getChatEnabled, + getBroadcastAudio: getBroadcastAudio, + getBroadcastVideo: getBroadcastVideo, + getRingTone: getRingTone, + getRingBackTone: getRingBackTone, + getRtcommDebug: getRtcommDebug, + isRtcommDisabled: isRtcommDisabled, + getMediaConfig: getMediaConfig + }; - getRingBackTone : function(){return ringbacktone;}, + //Default provider + var providerConfig = { + server: $location.host(), + port: $location.port(), + rtcommTopicPath: '/rtcomm/', + createEndpoint: false, + appContext: 'default', + userid: '', + presence: { + topic: '' + } + }; - getRtcommDebug: function(){return rtcommDebug;}, + //Rtcomm Endpoint Config Defaults + var mediaConfig = { + chat: true, + webrtc: true, + webrtcConfig: { + broadcast: { + audio: true, + video: true + }, + trickleICE: true + }, + ringbacktone: null, + ringtone: null + }; - isRtcommDisabled : function(){return _disableRtcomm;}, + //Rtcomm Debug + var rtcommDebug = 'DEBUG'; - getTrickleICE: function(){return trickleICE;} - }; - }; + $log.debug('RtcommConfigService: Abs Url: ' + $location.absUrl()); + $log.debug('providerConfig.server: ' + providerConfig.server); + $log.debug('providerConfig.port: ' + providerConfig.port); - RtcommService.$inject=['$rootScope', '$log', '$http', 'RtcommConfigService']; - function RtcommService($rootScope, $log, $http, RtcommConfigService) { - /** Setup the endpoint provider first **/ - var myEndpointProvider = new rtcomm.EndpointProvider(); - var endpointProviderInitialized = false; - var queueList = null; - var sessions = []; - var presenceRecord = null; - var karmaTesting = false; - var _selfView = "selfView"; // Default self view - var _remoteView = "remoteView"; // Default remote view + return service; - myEndpointProvider.setLogLevel(RtcommConfigService.getRtcommDebug()); - $log.debug('rtcomm-service - endpointProvider log level is: '+myEndpointProvider.getLogLevel()); - $log.debug('rtcomm-service - endpointProvider log level should be: '+RtcommConfigService.getRtcommDebug()); - myEndpointProvider.setAppContext(RtcommConfigService.getProviderConfig().appContext); + function setProviderConfig(config) { - var getPresenceRecord = function(){ - if (presenceRecord == null) - presenceRecord = {'state': 'available', userDefines: []}; + //Provider Config + providerConfig = { - return (presenceRecord); - }; + server: (typeof config.server !== 'undefined') ? config.server : providerConfig.server, + port: (typeof config.port !== 'undefined') ? config.port : providerConfig.port, + rtcommTopicPath: (typeof config.rtcommTopicPath !== 'undefined') ? config.rtcommTopicPath : providerConfig.rtcommTopicPath, + createEndpoint: (typeof config.createEndpoint !== 'undefined') ? config.createEndpoint : providerConfig.createEndpoint, + appContext: (typeof config.appContext !== 'undefined') ? config.appContext : providerConfig.appContext, + presence: { + topic: (typeof config.presenceTopic !== 'undefined') ? config.presenceTopic : providerConfig.presence.topic, + }, + userid: (typeof config.userid !== 'undefined') ? config.userid : providerConfig.userid + }; - // This defines all the media related configuration and is controlled through external config. - var getMediaConfig = function() { - - var mediaConfig = { - ringbacktone: RtcommConfigService.getRingBackTone(), - ringtone: RtcommConfigService.getRingTone(), - webrtcConfig: { - broadcast : { - audio : RtcommConfigService.getBroadcastAudio(), - video : RtcommConfigService.getBroadcastVideo() - }, - trickleICE: RtcommConfigService.getTrickleICE() + //Media Configuration + mediaConfig = { + chat: (typeof config.chat !== 'undefined') ? config.chat : mediaConfig.chat, + webrtc: (typeof config.video !== 'undefined') ? config.webrtc : mediaConfig.webrtc, + webrtcConfig: { + broadcast: { + video: typeof config.broadcastVideo !== 'undefined' ? config.broadcastVideo : mediaConfig.webrtcConfig.broadcast.video, + audio: typeof config.broadcastAudio !== 'undefined' ? config.broadcastAudio : mediaConfig.webrtcConfig.broadcast.audio }, - webrtc : RtcommConfigService.getWebRTCEnabled(), - chat : RtcommConfigService.getChatEnabled(), + trickleICE: typeof config.trickleICE !== 'undefined' ? config.trickleICE : mediaConfig.webrtcConfig.trickleICE + }, + ringbacktone: typeof config.ringbacktone !== 'undefined' ? config.ringbacktone : mediaConfig.ringbacktone, + ringtone: typeof config.ringtone !== 'undefined' ? config.ringtone : mediaConfig.ringtone }; - return (mediaConfig); - }; - - myEndpointProvider.on('reset', function(event_object) { - //The Endpoint provider is destroyed on reset - endpointProviderInitialized = false; - _alert({type:'danger', msg: event_object.reason}); - }); + rtcommDebug = (typeof config.rtcommDebug !== 'undefined') ? config.rtcommDebug : rtcommDebug; + $log.debug('rtcommDebug from config is: ' + config.rtcommDebug); - myEndpointProvider.on('queueupdate', function(queuelist) { - $log.debug('<<------rtcomm-service------>> - Event: queueupdate'); - $log.debug('queueupdate', queuelist); - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('queueupdate', queuelist); - } - ); - }); + $log.debug('providerConfig is: ' + providerConfig); + } - myEndpointProvider.on('newendpoint', function(endpoint) { - $log.debug('<<------rtcomm-service------>> - Event: newendpoint remoteEndpointID: ' + endpoint.getRemoteEndpointID()); - - endpoint.on('onetimemessage',function(event){ - $log.debug('<<------rtcomm-onetimemessage------>> - Event: ', event); - if (event.onetimemessage.type != "undefined" && event.onetimemessage.type == 'iFrameURL'){ - var session = _createSession(event.endpoint.id); - session.iFrameURL = event.onetimemessage.iFrameURL; - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::iframeUpdate', event.endpoint.id, event.onetimemessage.iFrameURL); - } - ); - } - }); + function getProviderConfig() { + return providerConfig; + } - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('newendpoint', endpoint); - } - ); - }); + function getWebRTCEnabled() { + return mediaConfig.webrtc; + } - var callback = function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - if (eventObject.eventName.indexOf("session:") > -1){ - var session = _createSession(eventObject.endpoint.id); - session.sessionState = eventObject.eventName; - } - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); + function getChatEnabled() { + return mediaConfig.chat; + } - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); + function getBroadcastAudio() { + return mediaConfig.webrtcConfig.broadcast.audio; + } - }; + function getBroadcastVideo() { + return mediaConfig.webrtcConfig.broadcast.video; + } - // Setup all the callbacks here because they are all static. - myEndpointProvider.setRtcommEndpointConfig ({ - ringtone: RtcommConfigService.getRingTone(), - ringbacktone: RtcommConfigService.getRingBackTone(), - // These are all the session related events. - 'session:started' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - var session = _createSession(eventObject.endpoint.id); - _setActiveEndpoint(eventObject.endpoint.id); + function getRingTone() { + return mediaConfig.ringtone; + } - session.sessionStarted = true; - session.remoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); + function getRingBackTone() { + return mediaConfig.ringbacktone; + } - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); + function getRtcommDebug() { + return rtcommDebug; + } - }, + function isRtcommDisabled() { + return false; + } - 'session:alerting' : callback, - 'session:trying' : callback, - 'session:ringing' : callback, - 'session:queued' : callback, + function getMediaConfig() { + return mediaConfig; + } + } + RtcommConfigService.$inject = ["$location", "$log", "$window"]; +})(); - 'session:failed' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - _removeSession(eventObject.endpoint.id); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); +/** + *(C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ - }, - 'session:stopped' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - _removeSession(eventObject.endpoint.id); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); +/** + * Definition for the rtcommModule + */ - }, +(function() { + angular.module('angular-rtcomm-service') + /** + * Set debugEnabled to true to enable the debug messages in this rtcomm angular module. + */ + .config(["$logProvider", function($logProvider) { + $logProvider.debugEnabled(true); + }]) + .constant('rtcomm', rtcomm) + .factory('RtcommService', RtcommService); + RtcommService.$inject = ['$rootScope', '$log', 'RtcommConfigService', 'RtcommSessions', 'rtcomm', '$http']; - 'session:connecting' : callback, + function RtcommService($rootScope, $log, RtcommConfigService, RtcommSessions, rtcomm, $http) { + /** Setup the endpoint provider first **/ - // These are all the WebRTC related events. - 'webrtc:connected' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); + var service = { - $rootScope.$evalAsync( - function () { - _createSession(eventObject.endpoint.id).webrtcConnected = true; - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, - // These are all the WebRTC related events. - 'webrtc:remotemuted' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, + alert: alert, - 'webrtc:disconnected' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); + isInitialized: isInitialized, - $rootScope.$evalAsync( - function () { - var session = _getSession(eventObject.endpoint.id); - if (session != null) - session.webrtcConnected = false; - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); + setConfig: setConfig, - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, + getPresenceMonitor: getPresenceMonitor, - // These are all the chat related events. - 'chat:connected' : callback, - 'chat:disconnected' : callback, + publishPresence: publishPresence, - 'chat:message' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - var chat = { - time : new Date(), - name : eventObject.message.from, - message : angular.copy(eventObject.message.message) - }; - - _createSession(eventObject.endpoint.id).chats.push(chat); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); + addToPresenceRecord: addToPresenceRecord, - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, + removeFromPresenceRecord: removeFromPresenceRecord, - // Endpoint destroyed - 'destroyed' : callback - }); + setPresenceRecordState: setPresenceRecordState, - var initSuccess = function(event) { - $log.debug('<<------rtcomm-service------>> - Event: Provider init succeeded'); + getEndpoint: getEndpoint, - if (presenceRecord != null){ - $log.debug('RtcommService: initSuccess: updating presence record'); - myEndpointProvider.publishPresence(presenceRecord); - } + destroyEndpoint: destroyEndpoint, - $rootScope.$evalAsync( - function () { - var broadcastEvent = { - 'ready': event.ready, - 'registered': event.registered, - 'endpoint': event.endpoint, - 'userid' : RtcommConfigService.getProviderConfig().userid - }; - - $rootScope.$broadcast('rtcomm::init', true, broadcastEvent); - } - ); + register: register, - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }; + unregister: unregister, - var initFailure = function(error) { - $log.debug('<<------rtcomm-service------>> - Event: Provider init failed: error: ',error); - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::init', false, error); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }; + joinQueue: joinQueue, - /* - * Get session from local endpoint ID - */ - var _getSession = function(endpointUUID){ + leaveQueue: leaveQueue, - var session = null; + getQueues: getQueues, - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].endpointUUID === endpointUUID){ - session = sessions[index]; - break; - } - } + sendChatMessage: sendChatMessage, - return (session); - }; + getChats: getChats, - /* - * Get session from local endpoint ID - */ - var _createSession = function(endpointUUID){ + isWebrtcConnected: isWebrtcConnected, - var session = null; + getSessionState: getSessionState, - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].endpointUUID === endpointUUID){ - session = sessions[index]; - break; - } - } + setAlias: setAlias, - if (session == null){ - session = { - endpointUUID : endpointUUID, - chats : [], - webrtcConnected : false, - sessionStarted : false, - iFrameURL : 'about:blank', - remoteEndpointID : null, - activated : true, - sessionState : 'session:stopped' - }; - sessions[sessions.length] = session; - } + setUserID: setUserID, - return (session); - }; + setPresenceTopic: setPresenceTopic, - var _removeSession = function(endpointUUID){ + getIframeURL: getIframeURL, - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].endpointUUID === endpointUUID){ + putIframeURL: putIframeURL, - var endpoint = _getEndpoint(endpointUUID); - if(typeof endpoint !== 'undefined') - endpoint.destroy(); + placeCall: placeCall, - // Remove the disconnected endpoint from the list. - sessions.splice(index, 1); + getSessions: getSessions, - // Now we need to set the active endpoint to someone else or to no endpoint if none are left. - if (sessions.length == 0){ - $rootScope.$broadcast('noEndpointActivated'); - } - else{ - _setActiveEndpoint(sessions[0].endpointUUID); - } - break; - } - } - }; + endCall: endCall, + setActiveEndpoint: setActiveEndpoint, - var _getEndpoint = function(uuid) { - var endpoint = null; + getActiveEndpoint: getActiveEndpoint, - if ((typeof uuid === "undefined") || uuid == null){ - $log.debug('getEndpoint: create new endpoint and setup onetimemessage event'); - endpoint = myEndpointProvider.createRtcommEndpoint(); - endpoint.on('onetimemessage',function(event){ - $log.debug('<<------rtcomm-onetimemessage------>> - Event: ', event); - if (event.onetimemessage.type != "undefined" && event.onetimemessage.type == 'iFrameURL'){ - var session = _createSession(event.endpoint.id); + getRemoteEndpoint: getRemoteEndpoint, - session.iFrameURL = event.onetimemessage.iFrameURL; + setDefaultViewSelector: setDefaultViewSelector, - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::iframeUpdate', event.endpoint.id, event.onetimemessage.iFrameURL); - } - ); - } - }); - } - else - endpoint = myEndpointProvider.getRtcommEndpoint(uuid); + setViewSelector: setViewSelector, - return (endpoint); + setVideoView: setVideoView }; - var _setActiveEndpoint = function(endpointID){ - // First get the old active endpoint - var activeEndpoint = _getActiveEndpointUUID(); - if ((activeEndpoint != null) && (activeEndpoint != endpointID)){ - var session = _getSession(activeEndpoint); - if (session != null) - session.activated = false; - } + var endpointProviderInitialized = false; + var queueList = null; + var presenceRecord = null; + var _selfView = 'selfView'; // Default self view + var _remoteView = 'remoteView'; // Default remote view + var myEndpointProvider = null; + activate(); + return service; - var session = _createSession(endpointID); - session.activated = true; + function activate() { + myEndpointProvider = new rtcomm.EndpointProvider(); - $rootScope.$broadcast('endpointActivated', endpointID); - }; + myEndpointProvider.setLogLevel(RtcommConfigService.getRtcommDebug()); - var _getActiveEndpointUUID = function(){ - var activeEndpoint = null; + $log.debug('rtcomm-service - endpointProvider log level is: ' + myEndpointProvider.getLogLevel()); + $log.debug('rtcomm-service - endpointProvider log level should be: ' + RtcommConfigService.getRtcommDebug()); + myEndpointProvider.setAppContext(RtcommConfigService.getProviderConfig().appContext); - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].activated == true){ - activeEndpoint = sessions[index].endpointUUID; - break; - } - } - return (activeEndpoint); - }; - var _alert = function _alert(alertObject) { - var a = { type: 'info', - msg: 'default message'}; - if (typeof alertObject === 'string') { - a.msg = alertObject; - } else { - a = alertObject; - } + + myEndpointProvider.on('reset', function(event_object) { + // Should have a reason. + alert({ + type: 'danger', + msg: event_object.reason + }); + }); + + + myEndpointProvider.on('queueupdate', function(queuelist) { + $log.debug('<<------rtcomm-service------>> - Event: queueupdate'); + $log.debug('queueupdate', queuelist); $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::alert', a); + function() { + $rootScope.$broadcast('queueupdate', queuelist); } ); - }; + }); + myEndpointProvider.on('newendpoint', function(endpoint) { + $log.debug('<<------rtcomm-service------>> - Event: newendpoint remoteEndpointID: ' + endpoint.getRemoteEndpointID()); - return { + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('newendpoint', endpoint); + } + ); + }); - alert: _alert, + function sessionEstablishmentCallback(eventObject) { + var id = eventObject.endpoint.id; - setKarmaTesting : function(){ - karmaTesting = true; - }, + var session = RtcommSessions.getSession(id); + if (session === null) session = RtcommSessions.createSession(id); - isInitialized : function(){ - return(endpointProviderInitialized); - }, - setConfig : function(config){ - if (RtcommConfigService.isRtcommDisabled() == true){ - $log.debug('RtcommService:setConfig: isRtcommDisabled = true; return with no setup'); - return; - } + session.state = eventObject.eventName; + broadcastRtcommEvent(eventObject); + }; - $log.debug('rtcomm-services: setConfig: config: ', config); + /** + * Setup all the callbacks here because they are all static. + */ + myEndpointProvider.setRtcommEndpointConfig({ + // These are all the session related events. - RtcommConfigService.setProviderConfig(config); - myEndpointProvider.setRtcommEndpointConfig(getMediaConfig()); + 'onetimemessage': function(eventObject) { + $log.debug('<<------- rtcomm-service ----->> - Event: ' + eventObject); - if (endpointProviderInitialized == false){ - // If an identityServlet is defined we will get the User ID from the servlet. - // This is used when the user ID needs to be derived from an SSO token like LTPA. - if (typeof config.identityServlet !== "undefined" && config.identityServlet != null){ - $http.get(config.identityServlet).success (function(data){ + if (eventObject.onetimemessage.type !== 'undefined' && eventObject.onetimemessage.type === 'iFrameURL') { + var id = eventObject.endpoint.id; - if (typeof data.userid !== "undefined"){ - RtcommConfigService.setProviderConfig(data); - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - endpointProviderInitialized = true; + var session = RtcommSessions.getSession(id); + if (session === null) { + session = RtcommSessions.createSession(id); + } + session.iFrameURL = eventObject.onetimemessage.iFrameURL; + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('rtcomm::iframeUpdate', eventObject.endpoint.id, eventObject.onetimemessage.iFrameURL); } - else - $log.error('RtcommService: setConfig promise: Invalid JSON object return from identityServlet: ', data); - }).error(function(data, status, headers, config) { - $log.debug('RtcommService: setConfig promise: error accessing userid from identityServlet: ' + status); - }); + ); } - else{ - // If the user does not specify a userid, that says one will never be specified so go ahead - // and initialize the endpoint provider and let the provider assign a name. If a defined empty - // string is passed in, that means to wait until the end user registers a name. - if (typeof config.userid == "undefined" || RtcommConfigService.getProviderConfig().userid != ''){ - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - endpointProviderInitialized = true; - } + }, + 'session:started': function(eventObject) { + $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); + var id = eventObject.endpoint.id; + var endpoint = eventObject.endpoint; + var session = RtcommSessions.getSession(id); + + if (session === null) $log.error('Session:started but a previous session hasn\'t been created!'); + else { + _setActiveEndpoint(id); + session.started = true; + session.remoteEndpointID = endpoint.getRemoteEndpointID(); + broadcastRtcommEvent(eventObject); } - } - }, + }, + 'session:alerting': sessionEstablishmentCallback, - // Presence related methods - getPresenceMonitor:function(topic) { - return myEndpointProvider.getPresenceMonitor(topic); - }, + 'session:trying': sessionEstablishmentCallback, - publishPresence:function() { - if (endpointProviderInitialized == true) - myEndpointProvider.publishPresence(getPresenceRecord()); - }, + 'session:ringing': sessionEstablishmentCallback, - /** - * userDefines is an array of JSON objects that look like: - * - * { - * name : "some name", - * value : "some value" - * } - * - * The only rule is that some name and some value have to both be strings. - */ - addToPresenceRecord:function(userDefines) { + 'session:queued': sessionEstablishmentCallback, - for (var index = 0; index < userDefines.length; index++) { - getPresenceRecord().userDefines.push(userDefines[index]); - } + 'session:failed': function(eventObject) { - if (endpointProviderInitialized == true){ - $log.debug('RtcommService: addToPresenceRecord: updating presence record to: ', getPresenceRecord()); - myEndpointProvider.publishPresence(getPresenceRecord()); - } - }, + RtcommSessions.removeSession(eventObject.endpoint.id); + broadcastRtcommEvent(eventObject); + }, - /** - * userDefines is an array of JSON objects that look like: - * - * { - * name : "some name", - * value : "some value" - * } - * - * The only rule is that some name and some value have to both be strings. - */ - removeFromPresenceRecord:function(userDefines, doPublish) { + /** + * Handle when the endpoint stops the session + */ + 'session:stopped': function(eventObject) { + //Remove the session + RtcommSessions.removeSession(eventObject.endpoint.id); - for (var i = 0; i < userDefines.length; i++) { - for (var j = 0; j < getPresenceRecord().userDefines.length; j++) { + broadcastRtcommEvent(eventObject); + }, - if (getPresenceRecord().userDefines[j].name == userDefines[i].name){ - getPresenceRecord().userDefines.splice(j,1); - break; - } + // These are all the WebRTC related events. + 'webrtc:connected': function(eventObject) { + + var session = RtcommSessions.getSession(eventObject.endpoint.id); + if (session !== null) { + session.webrtcConnected = true; + broadcastRtcommEvent(eventObject); } - } + }, + 'webrtc:remotemuted': function(eventObject) { + broadcastRtcommEvent(eventObject); + }, - if ((endpointProviderInitialized == true) && doPublish){ - $log.debug('RtcommService: removeFromPresenceRecord: updating presence record to: ', getPresenceRecord()); - myEndpointProvider.publishPresence(getPresenceRecord()); - } - }, + 'webrtc:disconnected': function(eventObject) { - setPresenceRecordState:function(state) { - getPresenceRecord().state = state; - return myEndpointProvider.publishPresence(getPresenceRecord()); - }, + var session = RtcommSessions.getSession(eventObject.endpoint.id); + if (session !== null) + session.webrtcConnected = false; + broadcastRtcommEvent(eventObject); + }, - // Endpoint related methods - getEndpoint : function(uuid) { - return(_getEndpoint(uuid)); - }, + // These are all the chat related events. + 'chat:connected': broadcastRtcommEvent, + 'chat:disconnected': broadcastRtcommEvent, - destroyEndpoint : function(uuid) { - myEndpointProvider.getRtcommEndpoint(uuid).destroy(); - }, + 'chat:message': function(eventObject) { - // Registration related methods. - register : function(userid) { - if (endpointProviderInitialized == false){ - RtcommConfigService.getProviderConfig().userid = userid; + //Create a message object - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - endpointProviderInitialized = true; - } - else - $log.error('rtcomm-services: register: ERROR: endpoint provider already initialized'); - }, + var chat = { + time: new Date(), + name: eventObject.message.from, + message: angular.copy(eventObject.message.message) + }; - unregister : function() { - if (endpointProviderInitialized == true){ - myEndpointProvider.destroy(); - endpointProviderInitialized = false; - initFailure("destroyed"); - } - else - $log.error('rtcomm-services: unregister: ERROR: endpoint provider not initialized'); - }, + var session = RtcommSessions.getSession(eventObject.endpoint.id); - // Queue related methods - joinQueue : function(queueID) { - myEndpointProvider.joinQueue(queueID); - }, + if (session !== null) { + session.chats.push(chat); + broadcastRtcommEvent(eventObject); + } + }, - leaveQueue : function(queueID) { - myEndpointProvider.leaveQueue(queueID); - }, + // Endpoint destroyed + 'destroyed': broadcastRtcommEvent + }); + } - getQueues : function() { - return(queueList); - }, + function broadcastRtcommEvent(eventObject) { - /** - * Chat related methods - */ - sendChatMessage : function(chat, endpointUUID){ - // Save this chat in the local session store - var session = _createSession(endpointUUID); - session.chats.push(chat); + $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast(eventObject.eventName, eventObject); + } + ); + } - myEndpointProvider.getRtcommEndpoint(endpointUUID).chat.send(chat.message); - }, + function getPresenceRecord() { + if (presenceRecord == null) + presenceRecord = { + 'state': 'available', + userDefines: [] + }; - getChats : function(endpointUUID) { - if (typeof endpointUUID !== "undefined" && endpointUUID != null){ - var session = _getSession(endpointUUID); - if (session != null) - return (session.chats); - else - return(null); + return (presenceRecord); + }; + + function initSuccess(event) { + $log.debug('<<------rtcomm-service------>> - Event: Provider init succeeded'); + + if (presenceRecord != null) { + $log.debug('RtcommService: initSuccess: updating presence record'); + myEndpointProvider.publishPresence(presenceRecord); + } + + $rootScope.$evalAsync( + function() { + var broadcastEvent = { + 'ready': event.ready, + 'registered': event.registered, + 'endpoint': event.endpoint, + 'userid': RtcommConfigService.getProviderConfig().userid + }; + + $rootScope.$broadcast('rtcomm::init', true, broadcastEvent); } - else - return(null); - }, + ); + }; - isWebrtcConnected : function(endpointUUID) { - if (typeof endpointUUID !== 'undefined' && endpointUUID != null){ - var session = _getSession(endpointUUID); - if (session != null) - return (session.webrtcConnected); - else - return(false); + function initFailure(error) { + $log.debug('<<------rtcomm-service------>> - Event: Provider init failed: error: ', error); + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('rtcomm::init', false, error); } - else - return(false); - }, + ); + }; - getSessionState : function(endpointUUID) { - if (typeof endpointUUID !== "undefined" && endpointUUID != null) - return (myEndpointProvider.getRtcommEndpoint(endpointUUID).getState()); - else - return ("session:stopped"); - }, + function _getEndpoint(uuid) { + var endpoint = null; - setAlias : function(aliasID) { - if ((typeof aliasID !== "undefined") && aliasID != '') - myEndpointProvider.setUserID(aliasID); - }, + if (typeof uuid === 'undefined' || uuid === null) { + $log.debug('getEndpoint: create new endpoint'); + endpoint = myEndpointProvider.createRtcommEndpoint(); + } else { + $log.debug('getEndpoint: get an endpoint with id -> ' + uuid); + endpoint = myEndpointProvider.getRtcommEndpoint(uuid); + } - setUserID : function(userID) { - if ((typeof userID !== "undefined") && userID != ''){ - RtcommConfigService.setProviderConfig({userid: userID}); - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - } - }, + return (endpoint); + }; - setPresenceTopic : function(presenceTopic) { - if ((typeof presenceTopic !== "undefined") && presenceTopic != ''){ - RtcommConfigService.setProviderConfig({presenceTopic : presenceTopic}); - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - } - }, + function _setActiveEndpoint(endpointID) { - getIframeURL : function(endpointUUID){ - if (typeof endpointUUID !== "undefined" && endpointUUID != null){ - var session = _getSession(endpointUUID); - if (session != null) - return (session.iFrameURL); - else - return(null); - } - else - return(null); - }, + var activeEndpoint = _getActiveEndpointUUID(); - putIframeURL : function(endpointUUID, newUrl){ - $log.debug('RtcommService: putIframeURL: endpointUUID: ' + endpointUUID + ' newURL: ' + newUrl); - var endpoint = myEndpointProvider.getRtcommEndpoint(endpointUUID); + if ((activeEndpoint !== null) && (activeEndpoint !== endpointID)) { + var session = RtcommSessions.getSession(activeEndpoint); + if (session !== null) + session.activated = false; + } + var session = RtcommSessions.getSession(endpointID); - if (endpoint != null){ - var session = _createSession(endpointUUID); - session.iFrameURL = newUrl; + if (session === null) session = RtcommSessions.createSession(endpointID); + session.activated = true; - var message = { type : 'iFrameURL', - iFrameURL : newUrl}; - $log.debug('RtcommService: putIframeURL: sending new iFrame URL'); - endpoint.sendOneTimeMessage(message); - } - }, + $rootScope.$broadcast('endpointActivated', endpointID); + }; - placeCall : function(calleeID, mediaToEnable){ - var endpoint = _getEndpoint(); + function _getActiveEndpointUUID() { + var activeEndpoint = null; + var sessions = RtcommSessions.getAllSessions(); - if (mediaToEnable.indexOf('chat') > -1) - endpoint.chat.enable(); + for (var index = 0; index < sessions.length; index++) { + if (sessions[index].activated === true) { + activeEndpoint = sessions[index].endpointUUID; + break; + } + } + return (activeEndpoint); + }; - if (mediaToEnable.indexOf('webrtc') > -1) { - // Support turning off trickle ICE - var trickleICE = true; - if (mediaToEnable.indexOf('disableTrickleICE') > -1) { - trickleICE = false; - } - endpoint.webrtc.enable({'trickleICE': trickleICE}); + function alert(alertObject) { + var a = { + type: 'info', + msg: 'default message' + }; + if (typeof alertObject === 'string') { + a.msg = alertObject; + } else { + a = alertObject; + } + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('rtcomm::alert', a); } - _setActiveEndpoint(endpoint.id); + ); + }; - endpoint.connect(calleeID); - return(endpoint.id); - }, + /** External functionalities fror the RtcommService API */ + function isInitialized() { + return endpointProviderInitialized; + } - getSessions : function(){ - return(sessions); - }, + function setConfig(config) { - endCall : function(endpoint) { - endpoint.disconnect(); - }, + if (RtcommConfigService.isRtcommDisabled() == true) { + $log.debug('RtcommService:setConfig: isRtcommDisabled = true; return with no setup'); + return; + } - setActiveEndpoint : function(endpointID){ - _setActiveEndpoint(endpointID); - }, + if (config.rtcommDebug === 'INFO' || config.rtcommDebug === 'DEBUG') { + myEndpointProvider.setLogLevel(config.rtcommDebug); + } + $log.debug('rtcomm-services: setConfig: config: ', config); - getActiveEndpoint : function(){ - return(_getActiveEndpointUUID()); - }, + RtcommConfigService.setProviderConfig(config); + myEndpointProvider.setRtcommEndpointConfig(RtcommConfigService.getMediaConfig()); - getRemoteEndpoint : function(localEndpointID){ - var remoteEndpointID = null; + if (endpointProviderInitialized === false) { - if (localEndpointID != null){ - var session = _getSession(localEndpointID); + if (typeof config.identityServlet !== "undefined" && config.identityServlet != null) { + $http.get(config.identityServlet).success(function(data) { - if (session != null){ - remoteEndpointID = session.remoteEndpointID; + if (typeof data.userid !== "undefined") { + RtcommConfigService.setProviderConfig(data); + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + endpointProviderInitialized = true; + } else + $log.error('RtcommService: setConfig promise: Invalid JSON object return from identityServlet: ', data); + }).error(function(data, status, headers, config) { + $log.debug('RtcommService: setConfig promise: error accessing userid from identityServlet: ' + status); + }); + } else { + // If the user does not specify a userid, that says one will never be specified so go ahead + // and initialize the endpoint provider and let the provider assign a name. If a defined empty + // string is passed in, that means to wait until the end user registers a name. + if (typeof config.userid === 'undefined' || RtcommConfigService.getProviderConfig().userid !== '') { + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + endpointProviderInitialized = true; } } + } + } - return (remoteEndpointID); - }, - setDefaultViewSelector : function() { - _selfView = "selfView"; - _remoteView = "remoteView"; - }, + function getPresenceMonitor(topic) { + return myEndpointProvider.getPresenceMonitor(topic); + } - setViewSelector : function(selfView, remoteView) { - _selfView = selfView; - _remoteView = remoteView; - }, + function publishPresence() { - setVideoView : function(endpointUUID){ - $log.debug('rtcommVideo: setting local media'); - var endpoint = null; + if (endpointProviderInitialized === true) + myEndpointProvider.publishPresence(getPresenceRecord()); + } - if (typeof endpointUUID != "undefined" && endpointUUID != null) - endpoint = _getEndpoint(endpointUUID); - else if (_getActiveEndpointUUID() != null) - endpoint = _getEndpoint(_getActiveEndpointUUID()); + function addToPresenceRecord(userDefines) { - if (endpoint != null){ + for (var index = 0; index < userDefines.length; index++) { + getPresenceRecord().userDefines.push(userDefines[index]); + } - endpoint.webrtc.setLocalMedia( - { - mediaOut: document.querySelector('#' + _selfView), - mediaIn: document.querySelector('#' + _remoteView) - }); - } - }, - }; - }; + if (endpointProviderInitialized === true) { + $log.debug('RtcommService: addToPresenceRecord: updating presence record to: ', getPresenceRecord()); + myEndpointProvider.publishPresence(getPresenceRecord()); + } + } -})(); + function removeFromPresenceRecord(userDefines, doPublish) { -/* - * The angular-rtcomm-ui module - * This has controllers and directives in it. - */ -(function(){ + for (var i = 0; i < userDefines.length; i++) { + for (var j = 0; j < getPresenceRecord().userDefines.length; j++) { -angular - .module('angular-rtcomm-ui', [ - 'ui.bootstrap', - 'angular-rtcomm-service']) - .directive('rtcommSessionManager', rtcommSessionManager) - .directive('rtcommRegister', rtcommRegister) - .directive('rtcommQueues', rtcommQueues) - .directive('rtcommAlert', rtcommAlert) - .directive('rtcommEndpointStatus', rtcommEndpointStatus) - .directive('rtcommVideo', rtcommVideo) - .directive('rtcommChat', rtcommChat) - .directive('rtcommIframe', rtcommIframe) - .controller('RtcommAlertModalController', RtcommAlertModalController) - .controller('RtcommAlertModalInstanceController', RtcommAlertModalInstanceController) - .controller('RtcommCallModalController', RtcommCallModalController) - .controller('RtcommCallModalInstanceController', RtcommCallModalInstanceController) - .controller('RtcommConfigController', RtcommConfigController) - .controller('RtcommVideoController', RtcommVideoController) - .controller('RtcommEndpointController', RtcommEndpointController); - -/************* Endpoint Provider Directives *******************************/ -/** - * This directive is used to manage multiple sessions. If you are only supporting at most one session you wont need - * this directive. The associated template provides a way to switch between active sessions. The session must be in - * the started state to be managed by this directive and is removed when the session stops. - */ + if (getPresenceRecord().userDefines[j].name === userDefines[i].name) { + getPresenceRecord().userDefines.splice(j, 1); + break; + } + } + } -rtcommSessionManager.$inject=['RtcommService', '$log']; -function rtcommSessionManager (RtcommService, $log) { - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-sessionmgr.html', - controller: ["$scope", function ($scope) { - $scope.sessions = RtcommService.getSessions(); - $scope.sessMgrActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.publishPresence = false; - $scope.sessionPresenceData = []; - - $scope.init = function(publishPresence) { - $scope.publishPresence = publishPresence; - $scope.updatePresence(); - }; + if ((endpointProviderInitialized === true) && doPublish) { + $log.debug('RtcommService: removeFromPresenceRecord: updating presence record to: ', getPresenceRecord()); + myEndpointProvider.publishPresence(getPresenceRecord()); + } + } - $scope.$on('endpointActivated', function (event, endpointUUID) { - $log.debug('rtcommSessionmgr: endpointActivated =' + endpointUUID); - $scope.sessMgrActiveEndpointUUID = endpointUUID; - }); + function setPresenceRecordState(state) { - $scope.$on('session:started', function (event, eventObject) { - $log.debug('rtcommSessionmgr: session:started: uuid =' + eventObject.endpoint.id); + getPresenceRecord().state = state; + return myEndpointProvider.publishPresence(getPresenceRecord()); + } - $scope.updatePresence(); - }); + function getEndpoint(uuid) { + return _getEndpoint(uuid); + } + + function destroyEndpoint(uuid) { + myEndpointProvider.getRtcommEndpoint(uuid).destroy(); + } + + function register(userid) { + + if (endpointProviderInitialized === false) { + RtcommConfigService.getProviderConfig().userid = userid; + + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + endpointProviderInitialized = true; + } else + $log.error('rtcomm-services: register: ERROR: endpoint provider already initialized'); + } + + function unregister() { + + if (endpointProviderInitialized == true) { + myEndpointProvider.destroy(); + endpointProviderInitialized = false; + initFailure('destroyed'); + } else + $log.error('rtcomm-services: unregister: ERROR: endpoint provider not initialized'); + } + + + /** + * Queue API + */ + function joinQueue(queueID) { + myEndpointProvider.joinQueue(queueID); + } + + function leaveQueue(queueID) { + myEndpointProvider.leaveQueue(queueID); + } + + function getQueues() { + return queueList; + } + + /** + * Chat API + */ + function sendChatMessage(chat, endpointUUID) { + + var session; + // Save this chat in the local session store + session = RtcommSessions.getSession(endpointUUID); + if (session === null) session = RtcommSessions.createSession(endpointUUID); + + session.chats.push(chat); + + myEndpointProvider.getRtcommEndpoint(endpointUUID).chat.send(chat.message); + + } + + function getChats(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) { + var session = RtcommSessions.getSession(endpointUUID); + if (session !== null) + return (session.chats); + else + return (null); + } else + return (null); + + } + + function isWebrtcConnected(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) { + var session = RtcommSessions.getSession(endpointUUID); + if (session != null) + return (session.webrtcConnected); + else + return (false); + } else + return (false); + } + + function getSessionState(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) + return (myEndpointProvider.getRtcommEndpoint(endpointUUID).getState()); + else + return ('session:stopped'); + } + + function setAlias(aliasID) { + + if ((typeof aliasID !== 'undefined') && aliasID !== '') + myEndpointProvider.setUserID(aliasID); + } + + function setUserID(userID) { + + if ((typeof userID !== 'undefined') && userID !== '') { + RtcommConfigService.setProviderConfig({ + userid: userID + }); + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + } + } + + function setPresenceTopic(presenceTopic) { + + if ((typeof presenceTopic !== 'undefined') && presenceTopic !== '') { + RtcommConfigService.setProviderConfig({ + presenceTopic: presenceTopic + }); + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + } + + } + + function getIframeURL(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) { + var session = RtcommSessions.getSession(endpointUUID); + if (session != null) + return (session.iFrameURL); + else + return (null); + } else + return (null); + } + + function putIframeURL(endpointUUID, newUrl) { + + + $log.debug('RtcommService: putIframeURL: endpointUUID: ' + endpointUUID + ' newURL: ' + newUrl); + var endpoint = myEndpointProvider.getRtcommEndpoint(endpointUUID); + + if (endpoint != null) { + var session = RtcommSessions.getSession(endpointUUID); + + if (session === null) session = RtcommSessions.createSession(endpointUUID); + session.iFrameURL = newUrl; + + var message = { + type: 'iFrameURL', + iFrameURL: newUrl + }; + + $log.debug('RtcommService: putIframeURL: sending new iFrame URL'); + endpoint.sendOneTimeMessage(message); + } + } + + function placeCall(calleeID, mediaToEnable) { - $scope.activateSession = function(endpointUUID) { - $log.debug('rtcommSessionmgr: activateEndpoint =' + endpointUUID); - if ($scope.sessMgrActiveEndpointUUID != endpointUUID){ - RtcommService.setActiveEndpoint(endpointUUID); + //Create new endpoint + var endpoint = _getEndpoint(); + + if (mediaToEnable.indexOf('chat') > -1) + endpoint.chat.enable(); + + if (mediaToEnable.indexOf('webrtc') > -1) { + // Support turning off trickle ICE + var trickleICE = true; + if (mediaToEnable.indexOf('disableTrickleICE') > -1) { + trickleICE = false; } - }; + endpoint.webrtc.enable({ + 'trickleICE': trickleICE + }); + } + _setActiveEndpoint(endpoint.id); + endpoint.connect(calleeID); + return (endpoint.id); + } + + function getSessions() { + return RtcommSessions.getAllSessions(); + } + + function endCall(endpoint) { + endpoint.disconnect(); + } + + function setActiveEndpoint(endpointID) { + _setActiveEndpoint(endpointID); + } - $scope.updatePresence = function(){ - // Update the presence record if enabled - if ($scope.publishPresence == true){ - RtcommService.removeFromPresenceRecord ($scope.sessionPresenceData, false); + function getActiveEndpoint() { + return _getActiveEndpointUUID(); + } - $scope.sessionPresenceData = [{ - 'name' : "sessions", - 'value' : String($scope.sessions.length)}]; + function getRemoteEndpoint(localEndpointID) { - RtcommService.addToPresenceRecord ($scope.sessionPresenceData); + + var remoteEndpointID = null; + + if (localEndpointID != null) { + var session = RtcommSessions.getSession(localEndpointID); + + if (session != null) { + remoteEndpointID = session.remoteEndpointID; } - }; + } - }], - controllerAs: 'sessionmgr' - }; -}; + return (remoteEndpointID); + } -/** - * This directive is used to manage the registration of an endpoint provider. Since the registered name can only - * be set on initialization of the endpoint provider, this directive actually controls the initialization of the - * provider. Note that the endpoint provider must be initialized before any sessions can be created or received. - */ -rtcommRegister.$inject=['RtcommService', '$log']; -function rtcommRegister(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-register.html', - controller: ["$scope", function ($scope) { + function setDefaultViewSelector() { + + _selfView = 'selfView'; + _remoteView = 'remoteView'; + } - $scope.nextAction = 'Register'; + function setViewSelector(selfView, remoteView) { + _selfView = selfView; + _remoteView = remoteView; + } - $scope.reguserid = ''; + function setVideoView(endpointUUID) { - $scope.invalid = false; + $log.debug('rtcommVideo: setting local media'); + var endpoint = null; - var invalidCharacters = /(\$|#|\+|\/|\\)+/i; //Invalid characters for MQTT Topic Path + if (typeof endpointUUID !== 'undefined' && endpointUUID !== null) + endpoint = _getEndpoint(endpointUUID); + else if (_getActiveEndpointUUID() != null) + endpoint = _getEndpoint(_getActiveEndpointUUID()); - //Watch for changes in reguserid - $scope.$watch('reguserid', function(){ + if (endpoint != null) { + $log.debug(endpoint); + endpoint.webrtc.setLocalMedia({ + mediaOut: document.querySelector('#' + _selfView), + mediaIn: document.querySelector('#' + _remoteView) + }); + } + } + } +})(); - if($scope.reguserid.length < 1 || invalidCharacters.test($scope.reguserid)){ +(function() { + 'use strict'; - $scope.invalid = true; - } - else{ - $scope.invalid = false; - } - }); + angular + .module('angular-rtcomm-service') + .factory('RtcommSessions', RtcommSessions); + + /* @ngInject */ + function RtcommSessions($log) { + var service = { + getAllSessions: getAllSessions, + createSession: createSession, + getSession: getSession, + updateSession: updateSession, + removeSession: removeSession + }; - $scope.onRegClick = function() { - if ($scope.nextAction === 'Register' && !invalidCharacters.test($scope.reguserid)){ - - $log.debug('Register: reguserid =' + $scope.reguserid); - RtcommService.register($scope.reguserid); - } - else { - $log.debug('Unregister: reguserid =' + $scope.reguserid); - RtcommService.unregister(); - } - }; - - $scope.$on('rtcomm::init', function (event, success, details) { - - if (success == true){ - $scope.nextAction = 'Unregister'; - $scope.reguserid = details.userid; - } - else{ - $scope.nextAction = 'Register'; - - if (details == 'destroyed') - $scope.reguserid = ''; - else - $scope.reguserid = 'Init failed:' + details; - } - }); - }], - controllerAs: 'register' - }; -}; + var sessions = []; + return service; -/** - * This directive manages call queues. It provides the ability to display all the available queues - * (along with their descriptions) and by clicking on a queue, allows an agent (or any type of user) - * to subscribe on that queue. - */ -rtcommQueues.$inject = ['RtcommService', '$log']; -function rtcommQueues(RtcommService, $log) { - return { - restrict : 'E', - templateUrl : 'templates/rtcomm/rtcomm-queues.html', - controller : ["$scope", function($scope) { - $scope.rQueues = []; - $scope.autoJoinQueues = false; - $scope.queuePresenceData = []; - $scope.queuePublishPresence = false; - $scope.queueFilter = null; - - /** - * autoJoinQueues - automatically join any queues that are not filtered out - * queuePublishedPresence - will add to the presence document information about what queues this person joins. - * queueFilter - If defined, this specifies which queues should be joined. All others will be ignored. - */ - $scope.init = function(autoJoinQueues, queuePublishPresence, queueFilter) { - $log.debug('rtcommQueues: autoJoinQueues = ' + autoJoinQueues); - $scope.autoJoinQueues = autoJoinQueues; - $scope.queuePublishPresence = queuePublishPresence; - - if (typeof queueFilter !== "undefined") - $scope.queueFilter = queueFilter; - }; - - $scope.$on('queueupdate', function(event, queues) { - $log.debug('rtcommQueues: scope queues', $scope.rQueues); - - Object.keys(queues).forEach(function(key) { - $log.debug('rtcommQueues: Push queue: ' + queues[key]); - $log.debug('rtcommQueues: autoJoinQueues: ' + $scope.autoJoinQueues); - - // Check to make sure queue is not filteres out before adding it. - if ($scope.filterOutQueue(queues[key]) == false){ - $scope.rQueues.push(queues[key]); - - // If autoJoin we go ahead and join the queue as soon as we get the queue update. - if ($scope.autoJoinQueues == true){ - $scope.onQueueClick(queues[key]); - } - } - }); - - $scope.updateQueuePresence(); - }); - - $scope.$on('rtcomm::init', function (event, success, details) { - if (success == false){ - $log.debug('rtcommQueues: init: clear queues'); - $scope.rQueues = []; - } - }); - - // - $scope.filterOutQueue = function(queue){ - var returnValue = true; - - if ($scope.queueFilter != null){ - - for (var index = 0; index < $scope.queueFilter.length; ++index) { - var entry = $scope.queueFilter[index]; - if (entry == queue.endpointID) { - returnValue = false; - break; - } - } - } - else - returnValue = false; - - return (returnValue); - }; - - $scope.onQueueClick = function(queue){ - $log.debug('rtcommQueues: onClick: TOP'); - for (var index = 0; index < $scope.rQueues.length; index++) { - if($scope.rQueues[index].endpointID === queue.endpointID) - { - $log.debug('rtcommQueues: onClick: queue.endpointID = ' + queue.endpointID); - - if (queue.active == false){ - RtcommService.joinQueue(queue.endpointID); - $scope.rQueues[index].active = true; - } - else{ - RtcommService.leaveQueue(queue.endpointID); - $scope.rQueues[index].active = false; - } - } - else if (index == ($scope.rQueues.length - 1)){ - $log.debug('rtcommQueues: ERROR: queue.endpointID: ' + queue.endpointID + ' not found in list of queues'); - - } - } - - $scope.updateQueuePresence(); - }; - - $scope.updateQueuePresence = function(){ - // Update the presence record if enabled - if ($scope.queuePublishPresence == true){ - RtcommService.removeFromPresenceRecord ($scope.queuePresenceData, false); - - $scope.queuePresenceData = []; - - for (var index = 0; index < $scope.rQueues.length; index++) { - if($scope.rQueues[index].active === true){ - $scope.queuePresenceData.push ( - { - 'name' : "queue", - 'value' : $scope.rQueues[index].endpointID - }); - } - } - - RtcommService.addToPresenceRecord ($scope.queuePresenceData); - } - }; - }], - controllerAs : 'queues' - }; -}; - -//rtcommModule.controller('RtcommAlertController', ['$scope', '$log', function($scope, $log){ -rtcommAlert.$inject = ['$log']; -function rtcommAlert($log) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-alert.html", - controller: ["$scope", function ($scope) { - $scope.alerts = []; - $scope.addAlert = function(alert) { - $scope.alerts.push(alert); - }; - $scope.closeAlert = function(index) { - $scope.alerts.splice(index, 1); - }; - $scope.$on('rtcomm::alert', function(event, eventObject) { - $scope.addAlert(eventObject); + //////////////// + + function getAllSessions() { + return sessions; + } + + function removeAllSessions() { + + sessions.forEach(function(session) { + removeSession(session.endpointUUID); }); - }] - } -}; + } -/********************** Endpoint Directives *******************************/ + function getSession(endpointUUID) { + $log.debug('Retrieving session linked to EndpointUUID: ' + endpointUUID); -/** - * This endpoint status controller only shows the active endpoint. The $scope.sessionState always contains the - * state of the active endpoint if one exist. It will be one of the following states: - * - * 'session:alerting' - * 'session:trying' - * 'session:ringing' - * 'session:queued' - for this one $scope.queueCount will tell you where you are in the queue. - * 'session:failed' - for this one $scope.reason will tell you why the call failed. - * 'session:started' - * 'session:stopped' - * - * You can bind to $scope.sessionState to track state in the view. - */ -rtcommEndpointStatus.$inject = ['RtcommService', '$log']; -function rtcommEndpointStatus(RtcommService, $log){ - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-endpoint-status.html', - controller: ["$scope", function ($scope) { - - // Session states. - $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint($scope.epCtrlActiveEndpointUUID); - $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); - $scope.failureReason = ''; - $scope.queueCount = 0; // FIX: Currently not implemented! - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:started'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:stopped', function (event, eventObject) { - $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:stopped'; - $scope.epCtrlRemoteEndpointID = null; - } - }); - - $scope.$on('session:failed', function (event, eventObject) { - $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:failed'; - $scope.failureReason = eventObject.reason; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:alerting', function (event, eventObject) { - $log.debug('session:alerting received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID != eventObject.endpoint.id){ - $scope.sessionState = 'session:alerting'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:connecting', function (event, eventObject) { - $log.debug('session:connecting received: endpointID = ' + eventObject.endpoint.id); - // if ($scope.epCtrlActiveEndpointUUID != eventObject.endpoint.id){ - $scope.sessionState = 'session:connecting'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - // } + var session = null; + sessions.forEach(function(_session) { + if (_session.endpointUUID === endpointUUID) { + session = _session; + } }); + return session; + } + + function createSession(endpointUUID) { + $log.debug('Creating a session for EndpointUUID: ' + endpointUUID); + + var session; + + /* Define a session */ + session = { + + endpointUUID: endpointUUID, + remoteEndpointID: null, + chats: [], + webrtcConnected: false, + started: false, + state: 'session:stopped', + activated: true, + iFrameURL: 'about:blank', + }; + sessions.push(session); + return session; + + } + + function updateSession(endpointUUID, config) { + + $log.debug('Updating session for EndpointUUID: ' + endpointUUID); + + var session = getSession(endpointUUID); + + if (typeof session === 'undefined') + $log.debug('Unable to update endpoint due to it not existing'); + else { - $scope.$on('session:queued', function (event, eventObject) { - $log.debug('session:queued received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:queued'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:trying', function (event, eventObject) { - $log.debug('session:trying received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:trying'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:ringing', function (event, eventObject) { - $log.debug('session:ringing received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:ringing'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $scope.epCtrlActiveEndpointUUID = endpointUUID; - $scope.epCtrlRemoteEndpointID = RtcommService.getEndpoint(endpointUUID).getRemoteEndpointID(); - $scope.sessionState = RtcommService.getSessionState(endpointUUID); - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.epCtrlRemoteEndpointID = null; - $scope.sessionState = 'session:stopped'; - }); - - $scope.$on('rtcomm::init', function(event, success, details){ - if(success === true){ - $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint($scope.epCtrlActiveEndpointUUID); - $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); - $scope.failureReason = ''; + for (var property in session) { + if (session.hasOwnProperty(property)) { + + session[property] = typeof config[property] !== 'undefined' ? config[property] : session[property]; + } } - if(success == false){ - $scope.sessionState = 'session:stopped'; - $scope.epCtrlRemoteEndpointID = null; - } - }); + } + return session; + } - }] - }; -}; + function removeSession(endpointUUID) { + $log.debug('Destroy session for EndpointUUID: ' + endpointUUID); + var session; + for (var i = 0; i < sessions.length; i++) { + session = sessions[i]; -/** - * This directive manages the WebRTC video screen, including both the self view and the remote view. It - * also takes care of switching state between endpoints based on which endpoint is "actively" being viewed. - */ -rtcommVideo.$inject = ['RtcommService', '$log']; -function rtcommVideo(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-video.html', - controller: 'RtcommVideoController' - }; -}; + if (session.endpointUUID === endpointUUID) { + sessions.splice(i, 1); -/** - * This directive manages the chat portion of a session. The data model for chat - * is maintained in the RtcommService. This directive handles switching between - * active endpoints. - */ -rtcommChat.$inject = ['RtcommService', '$log']; -function rtcommChat(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-chat.html", - controller: ["$scope", function ($scope) { - $scope.chatActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.chats = RtcommService.getChats($scope.chatActiveEndpointUUID); - // This forces the scroll bar to the bottom and watches the $location.hash - //$anchorScroll(); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $log.debug('rtcommChat: endpointActivated =' + endpointUUID); - - // The data model for the chat is maintained in the RtcommService. - $scope.chats = RtcommService.getChats(endpointUUID); - $scope.chatActiveEndpointUUID = endpointUUID; - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.chats = []; - $scope.chatActiveEndpointUUID = null; - }); - - $scope.keySendMessage = function(keyEvent){ - if (keyEvent.which === 13) - $scope.sendMessage(); - }; - - $scope.sendMessage = function() { - var chat = { - time : new Date(), - name : RtcommService.getEndpoint($scope.chatActiveEndpointUUID).getLocalEndpointID(), - message : angular.copy($scope.message) - }; - - $scope.message = ''; - $scope.scrollToBottom(true); - RtcommService.sendChatMessage(chat, $scope.chatActiveEndpointUUID); - }; - - }], - controllerAs: 'chat', - link: function(scope, element){ - var chatPanel = angular.element(element.find('.panel-body')[0]); - - var bottom = true; - - //Chooses if the scrollbar should be forced to the bottom on the next lifecycle - scope.scrollToBottom = function(flag){ - bottom = flag; - } - - if (chatPanel.length > 0) { - //Watch scroll events - chatPanel.bind('scroll', function(){ - if(chatPanel.prop('scrollTop') + chatPanel.prop('clientHeight') == chatPanel.prop('scrollHeight')){ - scope.scrollToBottom(true); - } - else { - scope.scrollToBottom(false); - } - }); - //Watch the chat messages, if the scroll bar is in the bottom keep it on the bottom so the user can view incoming chat messages, else possibly send a notification and don't scroll down - scope.$watch('chats', function(){ - if(bottom){ - chatPanel.scrollTop(chatPanel.prop('scrollHeight')); - } - else { - //In this else, a notification could be sent - } - },true); - } - else { - $log.warn('chatPanel not found: most likely you need to load jquery prior to angular'); - } - } - }; - -}; + $log.debug('Session with endpointUUID === ' + endpointUUID + 'has been removed'); + break; + } + } -/** - * This directive manages the shared iFrame. - */ -rtcommIframe.$inject = ['RtcommService', '$log', '$sce', '$location', '$window']; -function rtcommIframe(RtcommService, $log, $sce, $location, $window) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-iframe.html", - controller: ["$scope", function ($scope) { - $scope.iframeActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.iframeURL = null; - $scope.initiframeURL = null; - $scope.syncSource = false; - - /* - * syncSourcing means you a providing the URL source but no UI. Typically used in - * customer/agent scenarios. - */ - $scope.init = function(syncSource) { - if (syncSource == true){ - $scope.syncSource = true; - $scope.initiframeURL = $location.absUrl(); // init to current URL - } - }; - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); - - if ($scope.syncSource == true){ - RtcommService.putIframeURL(eventObject.endpoint.id,$scope.initiframeURL); //Update on the current or next endpoint to be activated. - } - }); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $log.debug('rtcommIframe: endpointActivated =' + endpointUUID); - - if ($scope.syncSource == false){ - $scope.iframeURL = $sce.trustAsResourceUrl(RtcommService.getIframeURL(endpointUUID)); - $scope.iframeActiveEndpointUUID = endpointUUID; - } - }); - - $scope.$on('noEndpointActivated', function (event) { - if ($scope.syncSource == false){ - $scope.iframeURL = $sce.trustAsResourceUrl('about:blank'); - $scope.iframeActiveEndpointUUID = null; - } - }); - - $scope.$on('rtcomm::iframeUpdate', function (eventType, endpointUUID, url) { - if ($scope.syncSource == false){ - $log.debug('rtcomm::iframeUpdate: ' + url); - // This is needed to prevent rtcomm from logging in when the page is loaded in the iFrame. - url = url + "?disableRtcomm=true"; - $scope.iframeURL = $sce.trustAsResourceUrl(url); - } - else{ - $log.debug('rtcomm::iframeUpdate: load this url in a new tab: ' + url); - // In this case we'll open the pushed URL in a new tab. - $window.open($sce.trustAsResourceUrl(url), '_blank'); - } - }); - - $scope.setURL = function(newURL){ - $log.debug('rtcommIframe: setURL: newURL: ' + newURL); - RtcommService.putIframeURL($scope.iframeActiveEndpointUUID, newURL); - $scope.iframeURL = $sce.trustAsResourceUrl(newURL); - }; - - $scope.forward = function() { - }; - - $scope.backward = function() { - }; - }], - controllerAs: 'rtcommiframe' - }; -}; - - - -/******************************** Rtcomm Modals ************************************************/ + if (session === null) { + $log.debug('Unable to destroy session due to it not existing'); + } + return session; + + } -/** - * This modal is displayed on receiving an inbound call. It handles the alerting event. - * Note that it can also auto accept requests for enabling A/V. - */ -RtcommAlertModalController.$inject=['$rootScope', '$scope', 'RtcommService', '$modal', '$log']; -function RtcommAlertModalController($rootScope, $scope, RtcommService, $modal, $log) { - - $scope.alertingEndpointUUID = null; - $scope.autoAnswerNewMedia = false; - $scope.alertActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.caller = null; - - $scope.init = function(autoAnswerNewMedia) { - $log.debug('rtcommAlert: autoAnswerNewMedia = ' + autoAnswerNewMedia); - $scope.autoAnswerNewMedia = autoAnswerNewMedia; - }; - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $scope.alertActiveEndpointUUID = endpointUUID; - }); - - $scope.$on('session:alerting', function (event, eventObject) { - - if (($scope.alertActiveEndpointUUID == eventObject.endpoint.id && $scope.autoAnswerNewMedia == false) || - ($scope.alertActiveEndpointUUID != eventObject.endpoint.id)) - { - $log.debug('rtcommAlert: display alterting model: alertActiveEndpointUUID = ' + eventObject.endpoint + ' autoAnswerNewMedia = ' + $scope.autoAnswerNewMedia); - $scope.caller = eventObject.endpoint.getRemoteEndpointID(); - $scope.alertingEndpointUUID = eventObject.endpoint.id; - $scope.showAlerting(); - } - else{ - $log.debug('Accepting media from: ' + eventObject.endpoint.getRemoteEndpointID() + ' for endpoint: ' + eventObject.endpoint.id); - eventObject.endpoint.accept(); - } - }); - - $scope.showAlerting = function (size) { - - var modalInstance = $modal.open({ - templateUrl: 'templates/rtcomm/rtcomm-modal-alert.html', - controller: 'RtcommAlertModalInstanceController', - size: size, - backdrop: 'static', - resolve: { - caller: function () { - return $scope.caller; - }} - }); - - modalInstance.result.then( - function() { - var alertingEndpointObject = RtcommService.getEndpoint($scope.alertingEndpointUUID); - - if(alertingEndpointObject){ - $log.debug('Accepting call from: ' + $scope.caller + ' for endpoint: ' + $scope.alertingEndpointUUID); - alertingEndpointObject.accept(); - $rootScope.$broadcast('rtcomm::alert-success'); - alertingEndpointObject = null; - } - }, - function () { - var alertingEndpointObject = RtcommService.getEndpoint($scope.alertingEndpointUUID); - if(alertingEndpointObject){ - $log.debug('Rejecting call from: ' + $scope.caller + ' for endpoint: ' + $scope.alertingEndpointUUID); - alertingEndpointObject.reject(); - alertingEndpointObject = null; - } - }); - }; -}; - -RtcommAlertModalInstanceController.$inject = ['$scope', '$modalInstance', '$log', 'caller']; - -function RtcommAlertModalInstanceController($scope, $modalInstance, $log, caller) { - $scope.caller = caller; - $scope.ok = function () { - $log.debug('Accepting alerting call'); - $modalInstance.close(); - }; - - $scope.cancel = function () { - $log.debug('Rejecting alerting call'); - $modalInstance.dismiss('cancel'); - }; -}; + } + RtcommSessions.$inject = ["$log"]; +})(); /** - * This is a modal controller for placing an outbound call to a static callee such as a queue. + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ -RtcommCallModalController.$inject = ['$scope', 'RtcommService', '$modal', '$log']; -function RtcommCallModalController($scope, RtcommService, $modal, $log) { - $scope.calleeID = null; - $scope.callerID = null; - - $scope.enableCallModel = false; - $scope.mediaToEnable = ['chat']; - - $scope.init = function(calleeID, mediaToEnable) { - $scope.calleeID = calleeID; - - if (typeof mediaToEnable !== "undefined") - $scope.mediaToEnable = mediaToEnable; - }; - - $scope.$on('rtcomm::init', function (event, success, details) { - $log.debug('RtcommCallModalController: rtcomm::init: success = ' + success); - if (success == true) - $scope.enableCallModel = true; - else - $scope.enableCallModel = false; - }); - - $scope.$on('session:started', function (event, eventObject) { - $scope.enableCallModel = false; - }); - - $scope.$on('session:stopped', function (event, eventObject) { - $scope.enableCallModel = true; - }); - - $scope.placeCall = function (size) { - - var modalInstance = $modal.open({ - templateUrl: 'templates/rtcomm/rtcomm-modal-call.html', - controller: 'RtcommCallModalInstanceController', - size: size, - resolve: {} - }); - - modalInstance.result.then( - function (resultName) { - $log.debug('rtcommCallModal: Calling calleeID: ' + $scope.calleeID); - $log.debug('rtcommCallModal: CallerID: ' + resultName); - - // This is used to set an alias when the endoint is not defined. - if ($scope.callerID == null && (typeof resultName !== "undefined") && resultName != ''){ - $scope.callerID = resultName; - RtcommService.setAlias(resultName); - } - - RtcommService.placeCall($scope.calleeID, $scope.mediaToEnable); - }, - function () { - $log.info('Modal dismissed at: ' + new Date()); - }); - }; -}; - -RtcommCallModalInstanceController.$inject = ['$scope', '$modalInstance', 'RtcommService']; -function RtcommCallModalInstanceController($scope, $modalInstance, RtcommService) { - $scope.endpointAlias = ''; - $scope.ok = function () { - $modalInstance.close($scope.endpointAlias); - }; - $scope.cancel = function () { - $modalInstance.dismiss('cancel'); - }; -}; - -/********************************************* Rtcomm Controllers ******************************************************/ - /** * This is the controller for config loader. It reads a JSON object and utilizes the RtcommService to set the configuration. * This can also result in the initialization of the endpoint provider if the config JSON object includes a registration name. @@ -1694,307 +1278,1254 @@ function RtcommCallModalInstanceController($scope, $modalInstance, RtcommService * the endpoint provider. */ -RtcommConfigController.$inject = ['$scope','$http', 'RtcommService', '$log']; -function RtcommConfigController($scope, $http, RtcommService, $log) { - $scope.extendedConfig = null; - - $log.debug('RtcommConfigController: configURL = ' + $scope.configURL); - - $scope.setConfig = function(data) { - $log.debug('RtcommConfigController: setting config data:' + data); - RtcommService.setConfig(data); - }; - - $scope.init = function(configURL,extendedConfig) { - $log.debug('RtcommConfigController: initing configURL = ' + configURL); - $scope.configURL = configURL; - - if (typeof extendedConfig !== "undefined") - $scope.extendedConfig = extendedConfig; - - $scope.getConfig(); - }; - - $scope.getConfig = function() { - $http.get($scope.configURL).success (function(config){ - - // Now we need to update the config with any extensions passed in on init. - if ($scope.extendedConfig != null){ - angular.extend(config, $scope.extendedConfig); - $log.debug('RtcommConfigController: extended config object: ' + config); - } - - RtcommService.setConfig(config); - }).error(function(data, status, headers, config) { - $log.debug('RtcommConfigController: error accessing config: ' + status); - }); - }; -}; - - -RtcommVideoController.$inject= ['$scope','$http', 'RtcommService', '$log']; -function RtcommVideoController($scope, $http, RtcommService, $log) { - $scope.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); - $scope.init = function(selfView,remoteView) { - RtcommService.setViewSelector(selfView,remoteView); - - var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); - if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null) - RtcommService.setVideoView(videoActiveEndpointUUID); - }; - - // Go ahead and initialize the local media here if an endpoint already exist. - var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); - if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null) - RtcommService.setVideoView(videoActiveEndpointUUID); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - // Not to do something here to show that this button is live. - $log.debug('rtcommVideo: endpointActivated =' + endpointUUID); - RtcommService.setVideoView(endpointUUID); - $scope.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.avConnected = false; - }); - - $scope.$on('webrtc:connected', function (event, eventObject) { - if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) - $scope.avConnected = true; - }); - - $scope.$on('webrtc:disconnected', function (event, eventObject) { - if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) - $scope.avConnected = false; - }); -}; - - -RtcommEndpointController.$inject = ['$scope', '$rootScope', '$http', 'RtcommService', '$log']; -function RtcommEndpointController($scope, $rootScope, $http, RtcommService, $log) { - // Session states. - $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected($scope.epCtrlActiveEndpointUUID); - $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); - - $scope.disconnect = function() { - $log.debug('Disconnecting call for endpoint: ' + $scope.epCtrlActiveEndpointUUID); - RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).disconnect(); - }; - - $scope.toggleAV = function() { - $log.debug('Enable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); - - if ($scope.epCtrlAVConnected == false){ - RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.enable(function(value, message) { - if (!value) { - $log.debug('Enable failed: ',message); - RtcommService.alert({type: 'danger', msg: message}); - } - }); - } - else{ - $log.debug('Disable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); - RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.disable(); - } - }; - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:started'; - } - }); - - $scope.$on('session:stopped', function (event, eventObject) { - $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:stopped'; - } - }); - - $scope.$on('session:failed', function (event, eventObject) { - $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:failed'; - } - }); - - $scope.$on('webrtc:connected', function (event, eventObject) { - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) - $scope.epCtrlAVConnected = true; - }); - - $scope.$on('webrtc:disconnected', function (event, eventObject) { - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) - $scope.epCtrlAVConnected = false; - }); - - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $scope.epCtrlActiveEndpointUUID = endpointUUID; - $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected(endpointUUID); - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.epCtrlAVConnected = false; - }); -}; - -})(); +(function() { + 'use strict'; -/* - * The angular-rtcomm-presence module - * This has controllers and directives in it. - */ -(function(){ angular - .module('angular-rtcomm-presence', [ - 'ui.bootstrap', - 'treeControl', - 'angular-rtcomm-service']) - .directive('rtcommPresence', rtcommPresence); + .module('angular-rtcomm-ui') + .controller('RtcommConfigController', RtcommConfigController); - /** - * This directive manages the chat portion of a session. The data model for chat - * is maintained in the RtcommService. This directive handles switching between - * active endpoints. - * - * Here is the formate of the presenceData: - * - * This is a Node: - * { - * "name" : "agents", - * "record" : false, - * "nodes" : [] - * } - * - * This is a record with a set of user defines: - * { - * "name" : "Brian Pulito", - * "record" : true, - * "nodes" : [ - * { - * "name" : "queue", - * "value" : "appliances" - * }, - * { - * "name" : "sessions", - * "value" : "3" - * } - * ] - */ - rtcommPresence.$inject=['RtcommService', '$log']; - function rtcommPresence(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-presence.html", - controller: ["$scope", "$rootScope", function ($scope, $rootScope) { + RtcommConfigController.$inject = ['RtcommService', '$http', '$scope', '$log']; - $scope.monitorTopics = []; - $scope.presenceData = []; - $scope.expandedNodes = []; + /* @ngInject */ + function RtcommConfigController(RtcommService, $http, $scope, $log) { + var vm = this; + vm.extendedConfig = null; - // Default protocol list initiated from presence. Start with chat only. - $scope.protocolList = { - chat : true, - webrtc : false}; + $log.debug('RtcommConfigController: configURL = ' + vm.configURL); - // use a tree view or flatten. - $scope.flatten = false; - $scope.treeOptions = { - nodeChildren: "nodes", - dirSelectable: true, - injectClasses: { - ul: "a1", - li: "a2", - liSelected: "a7", - iExpanded: "a3", - iCollapsed: "a4", - iLeaf: "a5", - label: "a6", - labelSelected: "a8" - } - }; + $scope.init = function(configURL, extendedConfig) { - $scope.init = function(options) { - $scope.protocolList.chat = (typeof options.chat === 'boolean') ? options.chat : $scope.protocolList.chat; - $scope.protocolList.webrtc = (typeof options.webrtc === 'boolean') ? options.webrtc : $scope.protocolList.webrtc; - $scope.flatten = (typeof options.flatten === 'boolean') ? options.flatten: $scope.flatten; + $log.debug('RtcommConfigController: initing configURL = ' + configURL); + vm.configURL = configURL; + + if (typeof extendedConfig !== 'undefined') + vm.extendedConfig = extendedConfig; + + vm.getConfig(); + }; + + vm.getConfig = function() { + $http.get(vm.configURL).success(function(config) { + + // Now we need to update the config with any extensions passed in on init. + if (vm.extendedConfig != null) { + angular.extend(config, vm.extendedConfig); + $log.debug('RtcommConfigController: extended config object: ' + config); + } + + RtcommService.setConfig(config); + }).error(function(data, status, headers, config) { + $log.debug('RtcommConfigController: error accessing config: ' + status); + }); + }; + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommAlert', rtcommAlert); + + /* @ngInject */ + function rtcommAlert() { + var directive = { + restrict: 'E', + templateUrl: "templates/rtcomm/rtcomm-alert.html", + controller: AlertController, + controllerAs: 'alertVM', + bindToController: true }; - $scope.onCallClick = function(calleeEndpointID){ - var endpoint = RtcommService.getEndpoint(); - RtcommService.setActiveEndpoint(endpoint.id); + return directive; + } - if ($scope.protocolList.chat == true) - endpoint.chat.enable(); + AlertController.$inject = ['$scope', '$log']; - if ($scope.protocolList.webrtc == true){ - endpoint.webrtc.enable(function(value, message) { - if (!value) { - RtcommService.alert({type: 'danger', msg: message}); - } + /* @ngInject */ + function AlertController($scope, $log) { + var vm = this; + vm.alerts = []; + vm.addAlert = function(alert) { + vm.alerts.push(alert); + }; + vm.closeAlert = function(index) { + vm.alerts.splice(index, 1); + }; + $scope.$on('rtcomm::alert', function(event, eventObject) { + vm.addAlert(eventObject); + }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive manages call queues. It provides the ability to display all the available queues + * (along with their descriptions) and by clicking on a queue, allows an agent (or any type of user) + * to subscribe on that queue. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommQueues', rtcommQueues); + + /* @ngInject */ + function rtcommQueues() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-queues.html', + controller: QueuesController, + controllerAs: 'queuesVM', + bindToController: true + }; + + return directive; + + } + + QueuesController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function QueuesController(RtcommService, $scope, $log) { + var vm = this; + + vm.rQueues = []; + vm.autoJoinQueues = false; + vm.queuePresenceData = []; + vm.queuePublishPresence = false; + vm.queueFilter = null; + + /** + * autoJoinQueues - automatically join any queues that are not filtered out + * queuePublishedPresence - will add to the presence document information about what queues this person joins. + * queueFilter - If defined, this specifies which queues should be joined. All others will be ignored. + */ + $scope.init = function(autoJoinQueues, queuePublishPresence, queueFilter) { + $log.debug('rtcommQueues: autoJoinQueues = ' + autoJoinQueues); + vm.autoJoinQueues = autoJoinQueues; + vm.queuePublishPresence = queuePublishPresence; + if (typeof queueFilter !== "undefined") + vm.queueFilter = queueFilter; + }; + + // + vm.filterOutQueue = function(queue) { + var returnValue = true; + + if (vm.queueFilter != null) { + + for (var index = 0; index < vm.queueFilter.length; ++index) { + var entry = vm.queueFilter[index]; + if (entry == queue.endpointID) { + returnValue = false; + break; + } + } + } else + returnValue = false; + + return (returnValue); + }; + + vm.onQueueClick = function(queue) { + $log.debug('rtcommQueues: onClick: TOP'); + for (var index = 0; index < vm.rQueues.length; index++) { + if (vm.rQueues[index].endpointID === queue.endpointID) { + $log.debug('rtcommQueues: onClick: queue.endpointID = ' + queue.endpointID); + + if (queue.active == false) { + RtcommService.joinQueue(queue.endpointID); + vm.rQueues[index].active = true; + } else { + RtcommService.leaveQueue(queue.endpointID); + vm.rQueues[index].active = false; + } + } else if (index == (vm.rQueues.length - 1)) { + $log.debug('rtcommQueues: ERROR: queue.endpointID: ' + queue.endpointID + ' not found in list of queues'); + + } + } + + vm.updateQueuePresence(); + }; + + vm.updateQueuePresence = function() { + // Update the presence record if enabled + if (vm.queuePublishPresence == true) { + RtcommService.removeFromPresenceRecord(vm.queuePresenceData, false); + + vm.queuePresenceData = []; + + for (var index = 0; index < vm.rQueues.length; index++) { + if (vm.rQueues[index].active === true) { + vm.queuePresenceData.push({ + 'name': "queue", + 'value': vm.rQueues[index].endpointID + }); + } + } + + RtcommService.addToPresenceRecord(vm.queuePresenceData); + } + } + + $scope.$on('queueupdate', function(event, queues) { + $log.debug('rtcommQueues: scope queues', vm.rQueues); + Object.keys(queues).forEach(function(key) { + $log.debug('rtcommQueues: Push queue: ' + queues[key]); + $log.debug('rtcommQueues: autoJoinQueues: ' + vm.autoJoinQueues); + + // Check to make sure queue is not filteres out before adding it. + if (vm.filterOutQueue(queues[key]) == false) { + vm.rQueues.push(queues[key]); + // If autoJoin we go ahead and join the queue as soon as we get the queue update. + if (vm.autoJoinQueues == true) { + vm.onQueueClick(queues[key]); + } + } }); - } - endpoint.connect(calleeEndpointID); - $rootScope.$broadcast('rtcomm::presence-click'); + vm.updateQueuePresence(); + }); + + $scope.$on('rtcomm::init', function(event, success, details) { + if (success == false) { + $log.debug('rtcommQueues: init: clear queues'); + vm.rQueues = []; + } + }); + + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive is used to manage the registration of an endpoint provider. Since the registered name can only + * be set on initialization of the endpoint provider, this directive actually controls the initialization of the + * provider. Note that the endpoint provider must be initialized before any sessions can be created or received. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommRegister', rtcommRegister); + + /* @ngInject */ + function rtcommRegister() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-register.html', + controller: RegisterController, + controllerAs: 'registerVM', + bindToController: true }; - $scope.$on('rtcomm::init', function (event, success, details) { - RtcommService.publishPresence(); - var presenceMonitor = RtcommService.getPresenceMonitor(); + return directive; - presenceMonitor.on('updated', function(presenceData){ - $log.debug('<<------rtcommPresence: updated------>>'); - if ($scope.flatten) { - $log.debug('<<------rtcommPresence: updated using flattened data ------>>'); - $scope.presenceData = presenceData[0].flatten(); + } + + RegisterController.$inject = ['RtcommService', '$scope', '$log']; + + // /* @ngInject */ + function RegisterController(RtcommService, $scope, $log) { + var vm = this; + + vm.nextAction = 'Register'; + vm.reguserid = ''; + vm.invalid = false; + + var invalidCharacters = /(\$|#|\+|\/|\\)+/i; //Invalid characters for MQTT Topic Path + + vm.onRegClick = function() { + if (vm.nextAction === 'Register' && !invalidCharacters.test(vm.reguserid)) { + $log.debug('Register: reguserid =' + vm.reguserid); + RtcommService.register(vm.reguserid); + } else { + $log.debug('Unregister: reguserid =' + vm.reguserid); + RtcommService.unregister(); } - $scope.$apply(); - }); + }; - // Binding data if we are going to flatten causes a flash in the UI when it changes. - if (!$scope.flatten) { - $scope.presenceData = presenceMonitor.getPresenceData(); - } + //Watch for changes in reguserid + $scope.$watch(function(){ return vm.reguserid}, function() { - if ($scope.presenceData.length >= 1) - $scope.expandedNodes.push($scope.presenceData[0]); + if (vm.reguserid.length < 1 || invalidCharacters.test(vm.reguserid)) { + vm.invalid = true; + } else { + vm.invalid = false; + } + }); - for (var index = 0; index < $scope.monitorTopics.length; index++) { - $log.debug('rtcommPresence: monitorTopic: ' + $scope.monitorTopics[index]); - presenceMonitor.add($scope.monitorTopics[index]); - } + $scope.$on('rtcomm::init', function(event, success, details) { + + vm.nextAction = success ? 'Unregister' : 'Register'; + + if (success === true) { + vm.reguserid = details.userid; + } else { + if (details === 'destroyed') + vm.reguserid = ''; + else + vm.reguserid = 'Init failed:' + details; + } }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive is used to manage multiple sessions. If you are only supporting at most one session you wont need + * this directive. The associated template provides a way to switch between active sessions. The session must be in + * the started state to be managed by this directive and is removed when the session stops. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommSessionManager', rtcommSessionManager); + + /* @ngInject */ + function rtcommSessionManager() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-sessionmgr.html', + controller: SessionManagerController, + controllerAs: 'sessionMgrVM', + bindToController: true + }; + + return directive; + + function linkFunc(scope, el, attr, ctrl) { + + } + } + + SessionManagerController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function SessionManagerController(RtcommService, $scope, $log) { + var vm = this; + vm.sessions = RtcommService.getSessions(); + vm.sessMgrActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.publishPresence = false; + vm.sessionPresenceData = []; + + $scope.init = function(publishPresence) { + vm.publishPresence = publishPresence; + vm.updatePresence(); + }; + + vm.activateSession = function(endpointUUID) { + $log.debug('rtcommSessionmgr: activateEndpoint =' + endpointUUID); + if (vm.sessMgrActiveEndpointUUID !== endpointUUID) { + RtcommService.setActiveEndpoint(endpointUUID); + } + }; + + vm.updatePresence = function() { + // Update the presence record if enabled + if (vm.publishPresence === true) { + RtcommService.removeFromPresenceRecord(vm.sessionPresenceData, false); + + vm.sessionPresenceData = [{ + 'name': "sessions", + 'value': String(vm.sessions.length) + }]; + + RtcommService.addToPresenceRecord(vm.sessionPresenceData); + } + } + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $log.debug('rtcommSessionmgr: endpointActivated =' + endpointUUID); + vm.sessMgrActiveEndpointUUID = endpointUUID; + }); + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('rtcommSessionmgr: session:started: uuid =' + eventObject.endpoint.id); + + vm.updatePresence(); + }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommEndpointController', RtcommEndpointController); + + RtcommEndpointController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function RtcommEndpointController(RtcommService, $scope, $log) { + $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); + $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected($scope.epCtrlActiveEndpointUUID); + $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); + + $scope.disconnect = function() { + $log.debug('Disconnecting call for endpoint: ' + $scope.epCtrlActiveEndpointUUID); + RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).disconnect(); - }], - controllerAs: 'presence' }; - }; + + $scope.toggleAV = function() { + $log.debug('Enable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); + + if ($scope.epCtrlAVConnected == false) { + RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.enable(function(value, message) { + if (!value) { + $log.debug('Enable failed: ', message); + RtcommService.alert({ + type: 'danger', + msg: message + }); + } + }); + } else { + $log.debug('Disable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); + RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.disable(); + } + }; + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + $scope.sessionState = 'session:started'; + } + }); + + $scope.$on('session:stopped', function(event, eventObject) { + $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + $scope.sessionState = 'session:stopped'; + } + }); + + $scope.$on('session:failed', function(event, eventObject) { + $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + $scope.sessionState = 'session:failed'; + } + }); + + $scope.$on('webrtc:connected', function(event, eventObject) { + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) + $scope.epCtrlAVConnected = true; + }); + + $scope.$on('webrtc:disconnected', function(event, eventObject) { + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) + $scope.epCtrlAVConnected = false; + }); + + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $scope.epCtrlActiveEndpointUUID = endpointUUID; + $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected(endpointUUID); + }); + + $scope.$on('noEndpointActivated', function(event) { + $scope.epCtrlAVConnected = false; + }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive manages the chat portion of a session. The data model for chat + * is maintained in the RtcommService. This directive handles switching between + * active endpoints. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommChat', rtcommChat); + + rtcommChat.$inject = ['RtcommService', '$log']; + + /* @ngInject */ + function rtcommChat(RtcommService, $log) { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-chat.html', + link: chatLink, + controller: ChatController, + controllerAs: 'chatVM', + bindToController: true + }; + + return directive; + + function chatLink(scope, element, attr, ctrl) { + var chatPanel = angular.element(element.find('.panel-body')[0]); + + var bottom = true; + + //Chooses if the scrollbar should be forced to the bottom on the next lifecycle + ctrl.scrollToBottom = function(flag) { + bottom = flag; + scope.bottom = flag; + + } + if (chatPanel.length > 0) { + //Watch scroll events + chatPanel.bind('scroll', function() { + if (chatPanel.prop('scrollTop') + chatPanel.prop('clientHeight') == chatPanel.prop('scrollHeight')) { + ctrl.scrollToBottom(true); + } else { + ctrl.scrollToBottom(false); + } + }); + + //Watch the chat messages, if the scroll bar is in the bottom keep it on the bottom so the user can view incoming chat messages, else possibly send a notification and don't scroll down + scope.$watch(function() { + return ctrl.chats + }, function() { + $log.debug('rtcommChat - Link > $watch on chats called'); + if (bottom) { + chatPanel.scrollTop(chatPanel.prop('scrollHeight')); + } else { + //In this else, a notification could be sent + } + }, true); + + } + } + + } + + //Controller should be used to listen for events from Rtcmo + ChatController.$inject = ['$scope', 'RtcommService', '$log']; + + /* @ngInject */ + function ChatController($scope, RtcommService, $log) { + var vm = this; + + vm.chatActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.chats = RtcommService.getChats(vm.chatActiveEndpointUUID); + + vm.keySendMessage = function(keyEvent) { + if (keyEvent.which === 13) + vm.sendMessage(); + }; + + vm.sendMessage = function() { + $log.debug('rtcommChat: sendMessage() -> ' + vm.message); + var chat = { + time: new Date(), + name: RtcommService.getEndpoint(vm.chatActiveEndpointUUID).getLocalEndpointID(), + message: angular.copy(vm.message) + }; + + vm.message = ''; + vm.scrollToBottom(true); + $scope.bottom = true; + RtcommService.sendChatMessage(chat, vm.chatActiveEndpointUUID); + } + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $log.debug('rtcommChat: endpointActivated =' + endpointUUID); + + // The data model for the chat is maintained in the RtcommService. + vm.chats = RtcommService.getChats(endpointUUID); + vm.chatActiveEndpointUUID = endpointUUID; + }); + + $scope.$on('noEndpointActivated', function(event) { + vm.chats = []; + vm.chatActiveEndpointUUID = null; + }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This endpoint status controller only shows the active endpoint. The $scope.sessionState always contains the + * state of the active endpoint if one exist. It will be one of the following states: + * + * 'session:alerting' + * 'session:trying' + * 'session:ringing' + * 'session:queued' - for this one $scope.queueCount will tell you where you are in the queue. + * 'session:failed' - for this one $scope.reason will tell you why the call failed. + * 'session:started' + * 'session:stopped' + * + * You can bind to $scope.sessionState to track state in the view. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommEndpointStatus', rtcommEndpointStatus); + + /* @ngInject */ + function rtcommEndpointStatus() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-endpoint-status.html', + controller: EndpointStatusController, + controllerAs: 'endpointStatusVM', + bindToController: true + }; + + return directive; + } + + EndpointStatusController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function EndpointStatusController(RtcommService, $scope, $log) { + var vm = this; + vm.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint(vm.epCtrlActiveEndpointUUID); + vm.sessionState = RtcommService.getSessionState(vm.epCtrlActiveEndpointUUID); + vm.failureReason = ''; + vm.queueCount = 0; //TODO FIX: Currently not implemented! + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID === eventObject.endpoint.id) { + vm.sessionState = 'session:started'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:stopped', function(event, eventObject) { + $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:stopped'; + vm.epCtrlRemoteEndpointID = null; + } + }); + + $scope.$on('session:failed', function(event, eventObject) { + $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:failed'; + vm.failureReason = eventObject.reason; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:alerting', function(event, eventObject) { + $log.debug('session:alerting received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID != eventObject.endpoint.id) { + vm.sessionState = 'session:alerting'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:connecting', function(event, eventObject) { + $log.debug('session:connecting received: endpointID = ' + eventObject.endpoint.id); + // if ($scope.epCtrlActiveEndpointUUID != eventObject.endpoint.id){ + vm.sessionState = 'session:connecting'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + // } + }); + + + $scope.$on('session:queued', function(event, eventObject) { + $log.debug('session:queued received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:queued'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:trying', function(event, eventObject) { + $log.debug('session:trying received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:trying'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:ringing', function(event, eventObject) { + $log.debug('session:ringing received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:ringing'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('endpointActivated', function(event, endpointUUID) { + vm.epCtrlActiveEndpointUUID = endpointUUID; + vm.epCtrlRemoteEndpointID = RtcommService.getEndpoint(endpointUUID).getRemoteEndpointID(); + vm.sessionState = RtcommService.getSessionState(endpointUUID); + }); + + $scope.$on('noEndpointActivated', function(event) { + vm.epCtrlRemoteEndpointID = null; + vm.sessionState = 'session:stopped'; + }); + + $scope.$on('rtcomm::init', function(event, success, details) { + if (success === true) { + vm.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint(vm.epCtrlActiveEndpointUUID); + vm.sessionState = RtcommService.getSessionState(vm.epCtrlActiveEndpointUUID); + vm.failureReason = ''; + } + if (success == false) { + vm.sessionState = 'session:stopped'; + vm.epCtrlRemoteEndpointID = null; + } + }); + } + +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommIframe', rtcommIframe); + + /* @ngInject */ + function rtcommIframe() { + var directive = { + restrict: 'E', + templateUrl: "templates/rtcomm/rtcomm-iframe.html", + controller: IFrameController, + controllerAs: 'iframeVM', + bindToController: true + }; + + return directive; + } + + IFrameController.$inject = ['RtcommService', '$sce', '$location', '$window','$scope', '$log']; + + /* @ngInject */ + function IFrameController(RtcommService, $sce, $location, $window, $scope, $log) { + var vm = this; + vm.iframeActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.iframeURL = null; + vm.initiframeURL = null; + vm.syncSource = false; + + /* + * syncSourcing means you a providing the URL source but no UI. Typically used in + * customer/agent scenarios. + */ + $scope.init = function(syncSource) { + if (syncSource === true) { + vm.syncSource = true; + vm.initiframeURL = $location.absUrl(); // init to current URL + } + }; + + + vm.setURL = function(newURL) { + $log.debug('rtcommIframe: setURL: newURL: ' + newURL); + RtcommService.putIframeURL(vm.iframeActiveEndpointUUID, newURL); + vm.iframeURL = $sce.trustAsResourceUrl(newURL); + }; + + vm.forward = function() {}; + + vm.backward = function() {}; + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); + + if (vm.syncSource == true) { + RtcommService.putIframeURL(eventObject.endpoint.id, vm.initiframeURL); //Update on the current or next endpoint to be activated. + } + }); + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $log.debug('rtcommIframe: endpointActivated =' + endpointUUID); + + if (vm.syncSource == false) { + vm.iframeURL = $sce.trustAsResourceUrl(RtcommService.getIframeURL(endpointUUID)); + vm.iframeActiveEndpointUUID = endpointUUID; + } + }); + + $scope.$on('noEndpointActivated', function(event) { + if (vm.syncSource == false) { + vm.iframeURL = $sce.trustAsResourceUrl('about:blank'); + vm.iframeActiveEndpointUUID = null; + } + }); + + $scope.$on('rtcomm::iframeUpdate', function(eventType, endpointUUID, url) { + if (vm.syncSource === false) { + $log.debug('rtcomm::iframeUpdate: ' + url); + // This is needed to prevent rtcomm from logging in when the page is loaded in the iFrame. + url = url + "?disableRtcomm=true"; + vm.iframeURL = $sce.trustAsResourceUrl(url); + } else { + $log.debug('rtcomm::iframeUpdate: load this url in a new tab: ' + url); + // In this case we'll open the pushed URL in a new tab. + $window.open($sce.trustAsResourceUrl(url), '_blank'); + } + }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive manages the WebRTC video screen, including both the self view and the remote view. It + * also takes care of switching state between endpoints based on which endpoint is "actively" being viewed. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommVideo', rtcommVideo) + .controller('RtcommVideoController', VideoController); + /* @ngInject */ + function rtcommVideo() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-video.html', + controller: VideoController, + controllerAs: 'videoVM', + bindToController: true + }; + + return directive; + } + + VideoController.$inject = ['RtcommService', '$scope', '$log']; + + // /* @ngInject */ + function VideoController(RtcommService, $scope, $log) { + var vm = this; + $log.debug('VideoController Starting'); + vm.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); + // $scope.init = function(selfView, remoteView) { + // RtcommService.setViewSelector(selfView, remoteView); + // + // var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); + // if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null) + // RtcommService.setVideoView(videoActiveEndpointUUID); + // }; + + // Go ahead and initialize the local media here if an endpoint already exist. + var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); + if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null){ + RtcommService.setVideoView(videoActiveEndpointUUID); + + } + + $scope.$on('endpointActivated', function(event, endpointUUID) { + // Not to do something here to show that this button is live. + $log.debug('rtcommVideo: endpointActivated =' + endpointUUID); + RtcommService.setVideoView(endpointUUID); + vm.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); + }); + // // + // $scope.$on('noEndpointActivated', function(event) { + // vm.avConnected = false; + // }); + // + // $scope.$on('webrtc:connected', function(event, eventObject) { + // if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) + // vm.avConnected = true; + // }); + // + // $scope.$on('webrtc:disconnected', function(event, eventObject) { + // if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) + // vm.avConnected = false; + // }); + } +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This modal is displayed on receiving an inbound call. It handles the alerting event. + * Note that it can also auto accept requests for enabling A/V. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommAlertModalController', RtcommAlertModalController) + .controller('RtcommAlertModalInstanceController', RtcommAlertModalInstanceController); + + RtcommAlertModalController.$inject = ['RtcommService', '$uibModal', '$rootScope', '$scope', '$log']; + + /* @ngInject */ + function RtcommAlertModalController(RtcommService, $uibModal, $rootScope, $scope, $log) { + var vm = this; + vm.alertingEndpointUUID = null; + vm.autoAnswerNewMedia = false; + vm.alertActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.caller = null; + + vm.showAlerting = function(size) { + + var modalInstance = $uibModal.open({ + templateUrl: 'templates/rtcomm/rtcomm-modal-alert.html', + controller: 'RtcommAlertModalInstanceController', + size: size, + backdrop: 'static', + resolve: { + caller: function() { + return vm.caller; + } + } + }); + + modalInstance.result.then( + function() { + var alertingEndpointObject = RtcommService.getEndpoint(vm.alertingEndpointUUID); + + if (alertingEndpointObject) { + $log.debug('Accepting call from: ' + vm.caller + ' for endpoint: ' + vm.alertingEndpointUUID); + alertingEndpointObject.accept(); + $rootScope.$broadcast('rtcomm::alert-success'); + alertingEndpointObject = null; + } + }, + function() { + var alertingEndpointObject = RtcommService.getEndpoint(vm.alertingEndpointUUID); + if (alertingEndpointObject) { + $log.debug('Rejecting call from: ' + vm.caller + ' for endpoint: ' + vm.alertingEndpointUUID); + alertingEndpointObject.reject(); + alertingEndpointObject = null; + } + }); + }; + + $scope.init = function(autoAnswerNewMedia) { + $log.debug('rtcommAlert: autoAnswerNewMedia = ' + autoAnswerNewMedia); + vm.autoAnswerNewMedia = autoAnswerNewMedia; + }; + + $scope.$on('endpointActivated', function(event, endpointUUID) { + vm.alertActiveEndpointUUID = endpointUUID; + }); + + $scope.$on('session:alerting', function(event, eventObject) { + + if ((vm.alertActiveEndpointUUID == eventObject.endpoint.id && vm.autoAnswerNewMedia == false) || + (vm.alertActiveEndpointUUID != eventObject.endpoint.id)) { + $log.debug('rtcommAlert: display alterting model: alertActiveEndpointUUID = ' + eventObject.endpoint + ' autoAnswerNewMedia = ' + vm.autoAnswerNewMedia); + vm.caller = eventObject.endpoint.getRemoteEndpointID(); + vm.alertingEndpointUUID = eventObject.endpoint.id; + vm.showAlerting(); + } else { + $log.debug('Accepting media from: ' + eventObject.endpoint.getRemoteEndpointID() + ' for endpoint: ' + eventObject.endpoint.id); + eventObject.endpoint.accept(); + } + }); + + } + + RtcommAlertModalInstanceController.$inject = ['$scope', '$uibModalInstance', '$log', 'caller']; + + function RtcommAlertModalInstanceController($scope, $uibModalInstance, $log, caller) { + $scope.caller = caller; + $scope.ok = function () { + $log.debug('Accepting alerting call'); + $uibModalInstance.close(); + }; + + $scope.cancel = function () { + $log.debug('Rejecting alerting call'); + $uibModalInstance.dismiss('cancel'); + + }; + }; +})(); + +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a modal controller for placing an outbound call to a static callee such as a queue. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommCallModalController', RtcommCallModalController) + .controller('RtcommCallModalInstanceController', RtcommCallModalInstanceController); + + RtcommCallModalController.$inject = ['RtcommService', '$uibModal', '$scope', '$log']; + + /* @ngInject */ + function RtcommCallModalController(RtcommService, $uibModal, $scope, $log){ + var vm = this; + vm.calleeID = null; + vm.callerID = null; + + vm.enableCallModel = false; + vm.mediaToEnable = ['chat']; + + vm.init = function(calleeID, mediaToEnable) { + vm.calleeID = calleeID; + + if (typeof mediaToEnable !== "undefined") + vm.mediaToEnable = mediaToEnable; + }; + + vm.placeCall = function(size) { + + var modalInstance = $uibModal.open({ + templateUrl: 'templates/rtcomm/rtcomm-modal-call.html', + controller: 'RtcommCallModalInstanceController', + size: size, + resolve: {} + }); + + modalInstance.result.then( + function(resultName) { + $log.debug('rtcommCallModal: Calling calleeID: ' + vm.calleeID); + $log.debug('rtcommCallModal: CallerID: ' + resultName); + + // This is used to set an alias when the endoint is not defined. + if (vm.callerID == null && (typeof resultName !== "undefined") && resultName != '') { + vm.callerID = resultName; + RtcommService.setAlias(resultName); + } + + RtcommService.placeCall(vm.calleeID, vm.mediaToEnable); + }, + function() { + $log.info('Modal dismissed at: ' + new Date()); + }); + }; + + $scope.$on('rtcomm::init', function(event, success, details) { + $log.debug('RtcommCallModalController: rtcomm::init: success = ' + success); + if (success == true) + vm.enableCallModel = true; + else + vm.enableCallModel = false; + }); + + $scope.$on('session:started', function(event, eventObject) { + vm.enableCallModel = false; + }); + + $scope.$on('session:stopped', function(event, eventObject) { + vm.enableCallModel = true; + }); + + } + + function RtcommCallModalInstanceController($scope, $uibModalInstance, RtcommService) { + $scope.endpointAlias = ''; + $scope.ok = function() { + $uibModalInstance.close($scope.endpointAlias); + }; + $scope.cancel = function() { + $uibModalInstance.dismiss('cancel'); + }; + } + RtcommCallModalInstanceController.$inject = ["$scope", "$uibModalInstance", "RtcommService"];; + })(); angular.module('angular-rtcomm-ui').run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('templates/rtcomm/rtcomm-alert.html', - "
{{alert.msg}}
" + "
{{alert.msg}}
" ); $templateCache.put('templates/rtcomm/rtcomm-chat.html', - "
Chat
  • {{chat.name}} {{chat.time | date:'HH:mm:ss'}}

    {{chat.message}}

" + "
Chat
  • {{chat.name}} {{chat.time | date:'HH:mm:ss'}}

    {{chat.message}}

" ); $templateCache.put('templates/rtcomm/rtcomm-endpoint-status.html', - "

Connected to {{epCtrlRemoteEndpointID}} No active sessions, waiting... Inbound call from {{epCtrlRemoteEndpointID}} Attempting to call {{epCtrlRemoteEndpointID}} Call to {{epCtrlRemoteEndpointID}} is ringing Waiting in queue at: {{queueCount}} Call failed with reason: {{failureReason}} Connecting to {{epCtrlRemoteEndpointID}} ...

" + "

Connected to {{endpointStatusVM.epCtrlRemoteEndpointID}} No active sessions, waiting... Inbound call from {{endpointStatusVM.epCtrlRemoteEndpointID}} Attempting to call {{endpointStatusVM.epCtrlRemoteEndpointID}} Call to {{endpointStatusVM.epCtrlRemoteEndpointID}} is ringing Waiting in queue at: {{endpointStatusVM.queueCount}} Call failed with reason: {{endpointStatusVM.failureReason}} Connecting to {{endpointStatusVM.epCtrlRemoteEndpointID}} ...

" ); $templateCache.put('templates/rtcomm/rtcomm-iframe.html', - "
URL Sharing
" + "
URL Sharing
" ); @@ -2009,22 +2540,22 @@ angular.module('angular-rtcomm-ui').run(['$templateCache', function($templateCac $templateCache.put('templates/rtcomm/rtcomm-queues.html', - "
Queues
" + "
Queues
" ); $templateCache.put('templates/rtcomm/rtcomm-register.html', - "
" + "
" ); $templateCache.put('templates/rtcomm/rtcomm-sessionmgr.html', - "

Sessions

" + "

Sessions

" ); $templateCache.put('templates/rtcomm/rtcomm-video.html', - "
" + "
" ); }]); diff --git a/dist/angular-rtcomm.min.js b/dist/angular-rtcomm.min.js index a888892..6f51c0a 100644 --- a/dist/angular-rtcomm.min.js +++ b/dist/angular-rtcomm.min.js @@ -14,9 +14,9 @@ * limitations under the License. * * Angular module for Rtcomm - * @version v1.0.3 - 2016-02-18 + * @version v1.0.3 - 2016-03-29 * @link https://github.com/WASdev/lib.angular-rtcomm * @author Brian Pulito (https://github.com/bpulito) */ -!function(){angular.module("angular-rtcomm",["ui.bootstrap","treeControl","angular-rtcomm-ui","angular-rtcomm-presence","angular-rtcomm-service"])}(),function(){function a(a,b,c){b.debug("RtcommConfigService: Abs URL: "+a.absUrl());var d=a.search().disableRtcomm;d="undefined"==typeof d||null===d?!1:"true"===d?!0:!1,b.debug("RtcommConfigService: _disableRtcomm = "+d);var e={server:a.host(),port:a.port(),rtcommTopicPath:"/rtcomm/",createEndpoint:!1,appContext:"default",userid:"",presence:{topic:""}};b.debug("providerConfig.server: "+e.server),b.debug("providerConfig.port: "+e.port);var f={chat:!0,webrtc:!0},g=!0,h=!0,i="DEBUG",j=null,k=null,l=!0,m=function(a){e.server="undefined"!=typeof a.server?a.server:e.server,e.port="undefined"!=typeof a.port?a.port:e.port,e.rtcommTopicPath="undefined"!=typeof a.rtcommTopicPath?a.rtcommTopicPath:e.rtcommTopicPath,e.createEndpoint="undefined"!=typeof a.createEndpoint?a.createEndpoint:e.createEndpoint,e.appContext="undefined"!=typeof a.appContext?a.appContext:e.appContext,e.presence.topic="undefined"!=typeof a.presenceTopic?a.presenceTopic:e.presence.topic,f.chat="undefined"!=typeof a.chat?a.chat:f.chat,f.webrtc="undefined"!=typeof a.webrtc?a.webrtc:f.webrtc,g="undefined"!=typeof a.broadcastAudio?a.broadcastAudio:g,h="undefined"!=typeof a.broadcastVideo?a.broadcastVideo:h,l="undefined"!=typeof a.trickleICE?a.trickleICE:l,k="undefined"!=typeof a.ringbacktone?a.ringbacktone:k,j="undefined"!=typeof a.ringtone?a.ringtone:j,i="undefined"!=typeof a.rtcommDebug?a.rtcommDebug:i,b.debug("rtcommDebug from config is: "+a.rtcommDebug),"undefined"!=typeof a.userid&&(e.userid=a.userid),b.debug("providerConfig is now: ",e)};return{setProviderConfig:function(a){m(a)},getProviderConfig:function(){return e},getWebRTCEnabled:function(){return f.webrtc},getChatEnabled:function(){return f.chat},getBroadcastAudio:function(){return g},getBroadcastVideo:function(){return h},getRingTone:function(){return j},getRingBackTone:function(){return k},getRtcommDebug:function(){return i},isRtcommDisabled:function(){return d},getTrickleICE:function(){return l}}}function b(a,b,c,d){var e=new rtcomm.EndpointProvider,f=!1,g=null,h=[],i=null,j=!1,k="selfView",l="remoteView";e.setLogLevel(d.getRtcommDebug()),b.debug("rtcomm-service - endpointProvider log level is: "+e.getLogLevel()),b.debug("rtcomm-service - endpointProvider log level should be: "+d.getRtcommDebug()),e.setAppContext(d.getProviderConfig().appContext);var m=function(){return null==i&&(i={state:"available",userDefines:[]}),i},n=function(){var a={ringbacktone:d.getRingBackTone(),ringtone:d.getRingTone(),webrtcConfig:{broadcast:{audio:d.getBroadcastAudio(),video:d.getBroadcastVideo()},trickleICE:d.getTrickleICE()},webrtc:d.getWebRTCEnabled(),chat:d.getChatEnabled()};return a};e.on("reset",function(a){f=!1,x({type:"danger",msg:a.reason})}),e.on("queueupdate",function(c){b.debug("<<------rtcomm-service------>> - Event: queueupdate"),b.debug("queueupdate",c),a.$evalAsync(function(){a.$broadcast("queueupdate",c)})}),e.on("newendpoint",function(c){b.debug("<<------rtcomm-service------>> - Event: newendpoint remoteEndpointID: "+c.getRemoteEndpointID()),c.on("onetimemessage",function(c){if(b.debug("<<------rtcomm-onetimemessage------>> - Event: ",c),"undefined"!=c.onetimemessage.type&&"iFrameURL"==c.onetimemessage.type){var d=s(c.endpoint.id);d.iFrameURL=c.onetimemessage.iFrameURL,a.$evalAsync(function(){a.$broadcast("rtcomm::iframeUpdate",c.endpoint.id,c.onetimemessage.iFrameURL)})}}),a.$evalAsync(function(){a.$broadcast("newendpoint",c)})});var o=function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){if(c.eventName.indexOf("session:")>-1){var b=s(c.endpoint.id);b.sessionState=c.eventName}a.$broadcast(c.eventName,c)}),1==j&&a.$digest()};e.setRtcommEndpointConfig({ringtone:d.getRingTone(),ringbacktone:d.getRingBackTone(),"session:started":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){var b=s(c.endpoint.id);v(c.endpoint.id),b.sessionStarted=!0,b.remoteEndpointID=c.endpoint.getRemoteEndpointID(),a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},"session:alerting":o,"session:trying":o,"session:ringing":o,"session:queued":o,"session:failed":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){t(c.endpoint.id),a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},"session:stopped":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){t(c.endpoint.id),a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},"session:connecting":o,"webrtc:connected":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){s(c.endpoint.id).webrtcConnected=!0,a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},"webrtc:remotemuted":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},"webrtc:disconnected":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){var b=r(c.endpoint.id);null!=b&&(b.webrtcConnected=!1),a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},"chat:connected":o,"chat:disconnected":o,"chat:message":function(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){var b={time:new Date,name:c.message.from,message:angular.copy(c.message.message)};s(c.endpoint.id).chats.push(b),a.$broadcast(c.eventName,c)}),1==j&&a.$digest()},destroyed:o});var p=function(c){b.debug("<<------rtcomm-service------>> - Event: Provider init succeeded"),null!=i&&(b.debug("RtcommService: initSuccess: updating presence record"),e.publishPresence(i)),a.$evalAsync(function(){var b={ready:c.ready,registered:c.registered,endpoint:c.endpoint,userid:d.getProviderConfig().userid};a.$broadcast("rtcomm::init",!0,b)}),1==j&&a.$digest()},q=function(c){b.debug("<<------rtcomm-service------>> - Event: Provider init failed: error: ",c),a.$evalAsync(function(){a.$broadcast("rtcomm::init",!1,c)}),1==j&&a.$digest()},r=function(a){for(var b=null,c=0;c> - Event: ",c),"undefined"!=c.onetimemessage.type&&"iFrameURL"==c.onetimemessage.type){var d=s(c.endpoint.id);d.iFrameURL=c.onetimemessage.iFrameURL,a.$evalAsync(function(){a.$broadcast("rtcomm::iframeUpdate",c.endpoint.id,c.onetimemessage.iFrameURL)})}})):d=e.getRtcommEndpoint(c),d},v=function(b){var c=w();if(null!=c&&c!=b){var d=r(c);null!=d&&(d.activated=!1)}var d=s(b);d.activated=!0,a.$broadcast("endpointActivated",b)},w=function(){for(var a=null,b=0;b-1&&c.chat.enable(),b.indexOf("webrtc")>-1){var d=!0;b.indexOf("disableTrickleICE")>-1&&(d=!1),c.webrtc.enable({trickleICE:d})}return v(c.id),c.connect(a),c.id},getSessions:function(){return h},endCall:function(a){a.disconnect()},setActiveEndpoint:function(a){v(a)},getActiveEndpoint:function(){return w()},getRemoteEndpoint:function(a){var b=null;if(null!=a){var c=r(a);null!=c&&(b=c.remoteEndpointID)}return b},setDefaultViewSelector:function(){k="selfView",l="remoteView"},setViewSelector:function(a,b){k=a,l=b},setVideoView:function(a){b.debug("rtcommVideo: setting local media");var c=null;"undefined"!=typeof a&&null!=a?c=u(a):null!=w()&&(c=u(w())),null!=c&&c.webrtc.setLocalMedia({mediaOut:document.querySelector("#"+k),mediaIn:document.querySelector("#"+l)})}}}angular.module("angular-rtcomm-service",[]).config(["$logProvider",function(a){a.debugEnabled(!0)}]).factory("RtcommConfigService",a).factory("RtcommService",b),a.$inject=["$location","$log","$window"],b.$inject=["$rootScope","$log","$http","RtcommConfigService"]}(),function(){function a(a,b){return{restrict:"E",templateUrl:"templates/rtcomm/rtcomm-sessionmgr.html",controller:["$scope",function(c){c.sessions=a.getSessions(),c.sessMgrActiveEndpointUUID=a.getActiveEndpoint(),c.publishPresence=!1,c.sessionPresenceData=[],c.init=function(a){c.publishPresence=a,c.updatePresence()},c.$on("endpointActivated",function(a,d){b.debug("rtcommSessionmgr: endpointActivated ="+d),c.sessMgrActiveEndpointUUID=d}),c.$on("session:started",function(a,d){b.debug("rtcommSessionmgr: session:started: uuid ="+d.endpoint.id),c.updatePresence()}),c.activateSession=function(d){b.debug("rtcommSessionmgr: activateEndpoint ="+d),c.sessMgrActiveEndpointUUID!=d&&a.setActiveEndpoint(d)},c.updatePresence=function(){1==c.publishPresence&&(a.removeFromPresenceRecord(c.sessionPresenceData,!1),c.sessionPresenceData=[{name:"sessions",value:String(c.sessions.length)}],a.addToPresenceRecord(c.sessionPresenceData))}}],controllerAs:"sessionmgr"}}function b(a,b){return{restrict:"E",templateUrl:"templates/rtcomm/rtcomm-register.html",controller:["$scope",function(c){c.nextAction="Register",c.reguserid="",c.invalid=!1;var d=/(\$|#|\+|\/|\\)+/i;c.$watch("reguserid",function(){c.reguserid.length<1||d.test(c.reguserid)?c.invalid=!0:c.invalid=!1}),c.onRegClick=function(){"Register"!==c.nextAction||d.test(c.reguserid)?(b.debug("Unregister: reguserid ="+c.reguserid),a.unregister()):(b.debug("Register: reguserid ="+c.reguserid),a.register(c.reguserid))},c.$on("rtcomm::init",function(a,b,d){1==b?(c.nextAction="Unregister",c.reguserid=d.userid):(c.nextAction="Register","destroyed"==d?c.reguserid="":c.reguserid="Init failed:"+d)})}],controllerAs:"register"}}function c(a,b){return{restrict:"E",templateUrl:"templates/rtcomm/rtcomm-queues.html",controller:["$scope",function(c){c.rQueues=[],c.autoJoinQueues=!1,c.queuePresenceData=[],c.queuePublishPresence=!1,c.queueFilter=null,c.init=function(a,d,e){b.debug("rtcommQueues: autoJoinQueues = "+a),c.autoJoinQueues=a,c.queuePublishPresence=d,"undefined"!=typeof e&&(c.queueFilter=e)},c.$on("queueupdate",function(a,d){b.debug("rtcommQueues: scope queues",c.rQueues),Object.keys(d).forEach(function(a){b.debug("rtcommQueues: Push queue: "+d[a]),b.debug("rtcommQueues: autoJoinQueues: "+c.autoJoinQueues),0==c.filterOutQueue(d[a])&&(c.rQueues.push(d[a]),1==c.autoJoinQueues&&c.onQueueClick(d[a]))}),c.updateQueuePresence()}),c.$on("rtcomm::init",function(a,d,e){0==d&&(b.debug("rtcommQueues: init: clear queues"),c.rQueues=[])}),c.filterOutQueue=function(a){var b=!0;if(null!=c.queueFilter)for(var d=0;d0?(d.bind("scroll",function(){d.prop("scrollTop")+d.prop("clientHeight")==d.prop("scrollHeight")?a.scrollToBottom(!0):a.scrollToBottom(!1)}),a.$watch("chats",function(){e&&d.scrollTop(d.prop("scrollHeight"))},!0)):b.warn("chatPanel not found: most likely you need to load jquery prior to angular")}}}function h(a,b,c,d,e){return{restrict:"E",templateUrl:"templates/rtcomm/rtcomm-iframe.html",controller:["$scope",function(f){f.iframeActiveEndpointUUID=a.getActiveEndpoint(),f.iframeURL=null,f.initiframeURL=null,f.syncSource=!1,f.init=function(a){1==a&&(f.syncSource=!0,f.initiframeURL=d.absUrl())},f.$on("session:started",function(c,d){b.debug("session:started received: endpointID = "+d.endpoint.id),1==f.syncSource&&a.putIframeURL(d.endpoint.id,f.initiframeURL)}),f.$on("endpointActivated",function(d,e){b.debug("rtcommIframe: endpointActivated ="+e),0==f.syncSource&&(f.iframeURL=c.trustAsResourceUrl(a.getIframeURL(e)),f.iframeActiveEndpointUUID=e)}),f.$on("noEndpointActivated",function(a){0==f.syncSource&&(f.iframeURL=c.trustAsResourceUrl("about:blank"),f.iframeActiveEndpointUUID=null)}),f.$on("rtcomm::iframeUpdate",function(a,d,g){0==f.syncSource?(b.debug("rtcomm::iframeUpdate: "+g),g+="?disableRtcomm=true",f.iframeURL=c.trustAsResourceUrl(g)):(b.debug("rtcomm::iframeUpdate: load this url in a new tab: "+g),e.open(c.trustAsResourceUrl(g),"_blank"))}),f.setURL=function(d){b.debug("rtcommIframe: setURL: newURL: "+d),a.putIframeURL(f.iframeActiveEndpointUUID,d),f.iframeURL=c.trustAsResourceUrl(d)},f.forward=function(){},f.backward=function(){}}],controllerAs:"rtcommiframe"}}function i(a,b,c,d,e){b.alertingEndpointUUID=null,b.autoAnswerNewMedia=!1,b.alertActiveEndpointUUID=c.getActiveEndpoint(),b.caller=null,b.init=function(a){e.debug("rtcommAlert: autoAnswerNewMedia = "+a),b.autoAnswerNewMedia=a},b.$on("endpointActivated",function(a,c){b.alertActiveEndpointUUID=c}),b.$on("session:alerting",function(a,c){b.alertActiveEndpointUUID==c.endpoint.id&&0==b.autoAnswerNewMedia||b.alertActiveEndpointUUID!=c.endpoint.id?(e.debug("rtcommAlert: display alterting model: alertActiveEndpointUUID = "+c.endpoint+" autoAnswerNewMedia = "+b.autoAnswerNewMedia),b.caller=c.endpoint.getRemoteEndpointID(),b.alertingEndpointUUID=c.endpoint.id,b.showAlerting()):(e.debug("Accepting media from: "+c.endpoint.getRemoteEndpointID()+" for endpoint: "+c.endpoint.id),c.endpoint.accept())}),b.showAlerting=function(f){var g=d.open({templateUrl:"templates/rtcomm/rtcomm-modal-alert.html",controller:"RtcommAlertModalInstanceController",size:f,backdrop:"static",resolve:{caller:function(){return b.caller}}});g.result.then(function(){var d=c.getEndpoint(b.alertingEndpointUUID);d&&(e.debug("Accepting call from: "+b.caller+" for endpoint: "+b.alertingEndpointUUID),d.accept(),a.$broadcast("rtcomm::alert-success"),d=null)},function(){var a=c.getEndpoint(b.alertingEndpointUUID);a&&(e.debug("Rejecting call from: "+b.caller+" for endpoint: "+b.alertingEndpointUUID),a.reject(),a=null)})}}function j(a,b,c,d){a.caller=d,a.ok=function(){c.debug("Accepting alerting call"),b.close()},a.cancel=function(){c.debug("Rejecting alerting call"),b.dismiss("cancel")}}function k(a,b,c,d){a.calleeID=null,a.callerID=null,a.enableCallModel=!1,a.mediaToEnable=["chat"],a.init=function(b,c){a.calleeID=b,"undefined"!=typeof c&&(a.mediaToEnable=c)},a.$on("rtcomm::init",function(b,c,e){d.debug("RtcommCallModalController: rtcomm::init: success = "+c),1==c?a.enableCallModel=!0:a.enableCallModel=!1}),a.$on("session:started",function(b,c){a.enableCallModel=!1}),a.$on("session:stopped",function(b,c){a.enableCallModel=!0}),a.placeCall=function(e){var f=c.open({templateUrl:"templates/rtcomm/rtcomm-modal-call.html",controller:"RtcommCallModalInstanceController",size:e,resolve:{}});f.result.then(function(c){d.debug("rtcommCallModal: Calling calleeID: "+a.calleeID),d.debug("rtcommCallModal: CallerID: "+c),null==a.callerID&&"undefined"!=typeof c&&""!=c&&(a.callerID=c,b.setAlias(c)),b.placeCall(a.calleeID,a.mediaToEnable)},function(){d.info("Modal dismissed at: "+new Date)})}}function l(a,b,c){a.endpointAlias="",a.ok=function(){b.close(a.endpointAlias)},a.cancel=function(){b.dismiss("cancel")}}function m(a,b,c,d){a.extendedConfig=null,d.debug("RtcommConfigController: configURL = "+a.configURL),a.setConfig=function(a){d.debug("RtcommConfigController: setting config data:"+a),c.setConfig(a)},a.init=function(b,c){d.debug("RtcommConfigController: initing configURL = "+b),a.configURL=b,"undefined"!=typeof c&&(a.extendedConfig=c),a.getConfig()},a.getConfig=function(){b.get(a.configURL).success(function(b){null!=a.extendedConfig&&(angular.extend(b,a.extendedConfig),d.debug("RtcommConfigController: extended config object: "+b)),c.setConfig(b)}).error(function(a,b,c,e){d.debug("RtcommConfigController: error accessing config: "+b)})}}function n(a,b,c,d){a.avConnected=c.isWebrtcConnected(c.getActiveEndpoint()),a.init=function(a,b){c.setViewSelector(a,b);var d=c.getActiveEndpoint();"undefined"!=typeof d&&null!=d&&c.setVideoView(d)};var e=c.getActiveEndpoint();"undefined"!=typeof e&&null!=e&&c.setVideoView(e),a.$on("endpointActivated",function(b,e){d.debug("rtcommVideo: endpointActivated ="+e),c.setVideoView(e),a.avConnected=c.isWebrtcConnected(c.getActiveEndpoint())}),a.$on("noEndpointActivated",function(b){a.avConnected=!1}),a.$on("webrtc:connected",function(b,d){c.getActiveEndpoint()==d.endpoint.id&&(a.avConnected=!0)}),a.$on("webrtc:disconnected",function(b,d){c.getActiveEndpoint()==d.endpoint.id&&(a.avConnected=!1)})}function o(a,b,c,d,e){a.epCtrlActiveEndpointUUID=d.getActiveEndpoint(),a.epCtrlAVConnected=d.isWebrtcConnected(a.epCtrlActiveEndpointUUID),a.sessionState=d.getSessionState(a.epCtrlActiveEndpointUUID),a.disconnect=function(){e.debug("Disconnecting call for endpoint: "+a.epCtrlActiveEndpointUUID),d.getEndpoint(a.epCtrlActiveEndpointUUID).disconnect()},a.toggleAV=function(){e.debug("Enable AV for endpoint: "+a.epCtrlActiveEndpointUUID),0==a.epCtrlAVConnected?d.getEndpoint(a.epCtrlActiveEndpointUUID).webrtc.enable(function(a,b){a||(e.debug("Enable failed: ",b),d.alert({type:"danger",msg:b}))}):(e.debug("Disable AV for endpoint: "+a.epCtrlActiveEndpointUUID),d.getEndpoint(a.epCtrlActiveEndpointUUID).webrtc.disable())},a.$on("session:started",function(b,c){e.debug("session:started received: endpointID = "+c.endpoint.id),a.epCtrlActiveEndpointUUID==c.endpoint.id&&(a.sessionState="session:started")}),a.$on("session:stopped",function(b,c){e.debug("session:stopped received: endpointID = "+c.endpoint.id),a.epCtrlActiveEndpointUUID==c.endpoint.id&&(a.sessionState="session:stopped")}),a.$on("session:failed",function(b,c){e.debug("session:failed received: endpointID = "+c.endpoint.id),a.epCtrlActiveEndpointUUID==c.endpoint.id&&(a.sessionState="session:failed")}),a.$on("webrtc:connected",function(b,c){a.epCtrlActiveEndpointUUID==c.endpoint.id&&(a.epCtrlAVConnected=!0)}),a.$on("webrtc:disconnected",function(b,c){a.epCtrlActiveEndpointUUID==c.endpoint.id&&(a.epCtrlAVConnected=!1)}),a.$on("endpointActivated",function(b,c){a.epCtrlActiveEndpointUUID=c,a.epCtrlAVConnected=d.isWebrtcConnected(c)}),a.$on("noEndpointActivated",function(b){a.epCtrlAVConnected=!1})}angular.module("angular-rtcomm-ui",["ui.bootstrap","angular-rtcomm-service"]).directive("rtcommSessionManager",a).directive("rtcommRegister",b).directive("rtcommQueues",c).directive("rtcommAlert",d).directive("rtcommEndpointStatus",e).directive("rtcommVideo",f).directive("rtcommChat",g).directive("rtcommIframe",h).controller("RtcommAlertModalController",i).controller("RtcommAlertModalInstanceController",j).controller("RtcommCallModalController",k).controller("RtcommCallModalInstanceController",l).controller("RtcommConfigController",m).controller("RtcommVideoController",n).controller("RtcommEndpointController",o),a.$inject=["RtcommService","$log"],b.$inject=["RtcommService","$log"],c.$inject=["RtcommService","$log"],d.$inject=["$log"],e.$inject=["RtcommService","$log"],f.$inject=["RtcommService","$log"],g.$inject=["RtcommService","$log"],h.$inject=["RtcommService","$log","$sce","$location","$window"],i.$inject=["$rootScope","$scope","RtcommService","$modal","$log"],j.$inject=["$scope","$modalInstance","$log","caller"],k.$inject=["$scope","RtcommService","$modal","$log"],l.$inject=["$scope","$modalInstance","RtcommService"],m.$inject=["$scope","$http","RtcommService","$log"],n.$inject=["$scope","$http","RtcommService","$log"],o.$inject=["$scope","$rootScope","$http","RtcommService","$log"]}(),function(){function a(a,b){return{restrict:"E",templateUrl:"templates/rtcomm/rtcomm-presence.html",controller:["$scope","$rootScope",function(c,d){c.monitorTopics=[],c.presenceData=[],c.expandedNodes=[],c.protocolList={chat:!0,webrtc:!1},c.flatten=!1,c.treeOptions={nodeChildren:"nodes",dirSelectable:!0,injectClasses:{ul:"a1",li:"a2",liSelected:"a7",iExpanded:"a3",iCollapsed:"a4",iLeaf:"a5",label:"a6",labelSelected:"a8"}},c.init=function(a){c.protocolList.chat="boolean"==typeof a.chat?a.chat:c.protocolList.chat,c.protocolList.webrtc="boolean"==typeof a.webrtc?a.webrtc:c.protocolList.webrtc,c.flatten="boolean"==typeof a.flatten?a.flatten:c.flatten},c.onCallClick=function(b){var e=a.getEndpoint();a.setActiveEndpoint(e.id),1==c.protocolList.chat&&e.chat.enable(),1==c.protocolList.webrtc&&e.webrtc.enable(function(b,c){b||a.alert({type:"danger",msg:c})}),e.connect(b),d.$broadcast("rtcomm::presence-click")},c.$on("rtcomm::init",function(d,e,f){a.publishPresence();var g=a.getPresenceMonitor();g.on("updated",function(a){b.debug("<<------rtcommPresence: updated------>>"),c.flatten&&(b.debug("<<------rtcommPresence: updated using flattened data ------>>"),c.presenceData=a[0].flatten()),c.$apply()}),c.flatten||(c.presenceData=g.getPresenceData()),c.presenceData.length>=1&&c.expandedNodes.push(c.presenceData[0]);for(var h=0;h{{alert.msg}}'),a.put("templates/rtcomm/rtcomm-chat.html",'
Chat
  • {{chat.name}} {{chat.time | date:\'HH:mm:ss\'}}

    {{chat.message}}

'),a.put("templates/rtcomm/rtcomm-endpoint-status.html",'
'), -a.put("templates/rtcomm/rtcomm-iframe.html",'
URL Sharing
'),a.put("templates/rtcomm/rtcomm-modal-alert.html",''),a.put("templates/rtcomm/rtcomm-modal-call.html",''),a.put("templates/rtcomm/rtcomm-queues.html",'
Queues
'),a.put("templates/rtcomm/rtcomm-register.html",'
'),a.put("templates/rtcomm/rtcomm-sessionmgr.html",'
'),a.put("templates/rtcomm/rtcomm-video.html",'
')}]),angular.module("angular-rtcomm-presence").run(["$templateCache",function(a){"use strict";a.put("templates/rtcomm/rtcomm-presence.html",'
{{node.name}} {{node.value ? \': \' + node.value : \'\'}}
')}]); \ No newline at end of file +!function(){angular.module("angular-rtcomm",["ui.bootstrap","treeControl","angular-rtcomm-ui","angular-rtcomm-presence","angular-rtcomm-service"])}(),function(){"use strict";angular.module("angular-rtcomm-service",[])}(),function(){angular.module("angular-rtcomm-ui",["ui.bootstrap","angular-rtcomm-service"])}(),function(){function a(a,b){return{restrict:"E",templateUrl:"templates/rtcomm/rtcomm-presence.html",controller:["$scope","$rootScope",function(c,d){c.monitorTopics=[],c.presenceData=[],c.expandedNodes=[],c.protocolList={chat:!0,webrtc:!1},c.flatten=!1,c.treeOptions={nodeChildren:"nodes",dirSelectable:!0,injectClasses:{ul:"a1",li:"a2",liSelected:"a7",iExpanded:"a3",iCollapsed:"a4",iLeaf:"a5",label:"a6",labelSelected:"a8"}},c.init=function(a){c.protocolList.chat="boolean"==typeof a.chat?a.chat:c.protocolList.chat,c.protocolList.webrtc="boolean"==typeof a.webrtc?a.webrtc:c.protocolList.webrtc,c.flatten="boolean"==typeof a.flatten?a.flatten:c.flatten},c.onCallClick=function(b){var e=a.getEndpoint();a.setActiveEndpoint(e.id),1==c.protocolList.chat&&e.chat.enable(),1==c.protocolList.webrtc&&e.webrtc.enable(function(b,c){b||a.alert({type:"danger",msg:c})}),e.connect(b),d.$broadcast("rtcomm::presence-click")},c.$on("rtcomm::init",function(d,e,f){a.publishPresence();var g=a.getPresenceMonitor();g.on("updated",function(a){b.debug("<<------rtcommPresence: updated------>>"),c.flatten&&(b.debug("<<------rtcommPresence: updated using flattened data ------>>"),c.presenceData=a[0].flatten()),c.$apply()}),c.flatten||(c.presenceData=g.getPresenceData()),c.presenceData.length>=1&&c.expandedNodes.push(c.presenceData[0]);for(var h=0;h> - Event: queueupdate"),b.debug("queueupdate",c),a.$evalAsync(function(){a.$broadcast("queueupdate",c)})}),_.on("newendpoint",function(c){b.debug("<<------rtcomm-service------>> - Event: newendpoint remoteEndpointID: "+c.getRemoteEndpointID()),a.$evalAsync(function(){a.$broadcast("newendpoint",c)})}),_.setRtcommEndpointConfig({onetimemessage:function(c){if(b.debug("<<------- rtcomm-service ----->> - Event: "+c),"undefined"!==c.onetimemessage.type&&"iFrameURL"===c.onetimemessage.type){var e=c.endpoint.id,f=d.getSession(e);null===f&&(f=d.createSession(e)),f.iFrameURL=c.onetimemessage.iFrameURL,a.$evalAsync(function(){a.$broadcast("rtcomm::iframeUpdate",c.endpoint.id,c.onetimemessage.iFrameURL)})}},"session:started":function(a){b.debug("<<------rtcomm-service------>> - Event: "+a.eventName+" remoteEndpointID: "+a.endpoint.getRemoteEndpointID());var c=a.endpoint.id,e=a.endpoint,f=d.getSession(c);null===f?b.error("Session:started but a previous session hasn't been created!"):(m(c),f.started=!0,f.remoteEndpointID=e.getRemoteEndpointID(),h(a))},"session:alerting":f,"session:trying":f,"session:ringing":f,"session:queued":f,"session:failed":function(a){d.removeSession(a.endpoint.id),h(a)},"session:stopped":function(a){d.removeSession(a.endpoint.id),h(a)},"webrtc:connected":function(a){var b=d.getSession(a.endpoint.id);null!==b&&(b.webrtcConnected=!0,h(a))},"webrtc:remotemuted":function(a){h(a)},"webrtc:disconnected":function(a){var b=d.getSession(a.endpoint.id);null!==b&&(b.webrtcConnected=!1),h(a)},"chat:connected":h,"chat:disconnected":h,"chat:message":function(a){var b={time:new Date,name:a.message.from,message:angular.copy(a.message.message)},c=d.getSession(a.endpoint.id);null!==c&&(c.chats.push(b),h(a))},destroyed:h})}function h(c){b.debug("<<------rtcomm-service------>> - Event: "+c.eventName+" remoteEndpointID: "+c.endpoint.getRemoteEndpointID()),a.$evalAsync(function(){a.$broadcast(c.eventName,c)})}function i(){return null==Y&&(Y={state:"available",userDefines:[]}),Y}function j(d){b.debug("<<------rtcomm-service------>> - Event: Provider init succeeded"),null!=Y&&(b.debug("RtcommService: initSuccess: updating presence record"),_.publishPresence(Y)),a.$evalAsync(function(){var b={ready:d.ready,registered:d.registered,endpoint:d.endpoint,userid:c.getProviderConfig().userid};a.$broadcast("rtcomm::init",!0,b)})}function k(c){b.debug("<<------rtcomm-service------>> - Event: Provider init failed: error: ",c),a.$evalAsync(function(){a.$broadcast("rtcomm::init",!1,c)})}function l(a){var c=null;return"undefined"==typeof a||null===a?(b.debug("getEndpoint: create new endpoint"),c=_.createRtcommEndpoint()):(b.debug("getEndpoint: get an endpoint with id -> "+a),c=_.getRtcommEndpoint(a)),c}function m(b){var c=n();if(null!==c&&c!==b){var e=d.getSession(c);null!==e&&(e.activated=!1)}var e=d.getSession(b);null===e&&(e=d.createSession(b)),e.activated=!0,a.$broadcast("endpointActivated",b)}function n(){for(var a=null,b=d.getAllSessions(),c=0;c-1&&c.chat.enable(),b.indexOf("webrtc")>-1){var d=!0;b.indexOf("disableTrickleICE")>-1&&(d=!1),c.webrtc.enable({trickleICE:d})}return m(c.id),c.connect(a),c.id}function N(){return d.getAllSessions()}function O(a){a.disconnect()}function P(a){m(a)}function Q(){return n()}function R(a){var b=null;if(null!=a){var c=d.getSession(a);null!=c&&(b=c.remoteEndpointID)}return b}function S(){Z="selfView",$="remoteView"}function T(a,b){Z=a,$=b}function U(a){b.debug("rtcommVideo: setting local media");var c=null;"undefined"!=typeof a&&null!==a?c=l(a):null!=n()&&(c=l(n())),null!=c&&(b.debug(c),c.webrtc.setLocalMedia({mediaOut:document.querySelector("#"+Z),mediaIn:document.querySelector("#"+$)}))}var V={alert:o,isInitialized:p,setConfig:q,getPresenceMonitor:r,publishPresence:s,addToPresenceRecord:t,removeFromPresenceRecord:u,setPresenceRecordState:v,getEndpoint:w,destroyEndpoint:x,register:y,unregister:z,joinQueue:A,leaveQueue:B,getQueues:C,sendChatMessage:D,getChats:E,isWebrtcConnected:F,getSessionState:G,setAlias:H,setUserID:I,setPresenceTopic:J,getIframeURL:K,putIframeURL:L,placeCall:M,getSessions:N,endCall:O,setActiveEndpoint:P,getActiveEndpoint:Q,getRemoteEndpoint:R,setDefaultViewSelector:S,setViewSelector:T,setVideoView:U},W=!1,X=null,Y=null,Z="selfView",$="remoteView",_=null;return g(),V}angular.module("angular-rtcomm-service").config(["$logProvider",function(a){a.debugEnabled(!0)}]).constant("rtcomm",rtcomm).factory("RtcommService",a),a.$inject=["$rootScope","$log","RtcommConfigService","RtcommSessions","rtcomm","$http"]}(),function(){"use strict";function a(a){function b(){return h}function c(b){a.debug("Retrieving session linked to EndpointUUID: "+b);var c=null;return h.forEach(function(a){a.endpointUUID===b&&(c=a)}),c}function d(b){a.debug("Creating a session for EndpointUUID: "+b);var c;return c={endpointUUID:b,remoteEndpointID:null,chats:[],webrtcConnected:!1,started:!1,state:"session:stopped",activated:!0,iFrameURL:"about:blank"},h.push(c),c}function e(b,d){a.debug("Updating session for EndpointUUID: "+b);var e=c(b);if("undefined"==typeof e)a.debug("Unable to update endpoint due to it not existing");else for(var f in e)e.hasOwnProperty(f)&&(e[f]="undefined"!=typeof d[f]?d[f]:e[f]);return e}function f(b){a.debug("Destroy session for EndpointUUID: "+b);for(var c,d=0;d0&&(f.bind("scroll",function(){f.prop("scrollTop")+f.prop("clientHeight")==f.prop("scrollHeight")?e.scrollToBottom(!0):e.scrollToBottom(!1)}),a.$watch(function(){return e.chats},function(){c.debug("rtcommChat - Link > $watch on chats called"),g&&f.scrollTop(f.prop("scrollHeight"))},!0))}var e={restrict:"E",templateUrl:"templates/rtcomm/rtcomm-chat.html",link:d,controller:b,controllerAs:"chatVM",bindToController:!0};return e}function b(a,b,c){var d=this;d.chatActiveEndpointUUID=b.getActiveEndpoint(),d.chats=b.getChats(d.chatActiveEndpointUUID),d.keySendMessage=function(a){13===a.which&&d.sendMessage()},d.sendMessage=function(){c.debug("rtcommChat: sendMessage() -> "+d.message);var e={time:new Date,name:b.getEndpoint(d.chatActiveEndpointUUID).getLocalEndpointID(),message:angular.copy(d.message)};d.message="",d.scrollToBottom(!0),a.bottom=!0,b.sendChatMessage(e,d.chatActiveEndpointUUID)},a.$on("endpointActivated",function(a,e){c.debug("rtcommChat: endpointActivated ="+e),d.chats=b.getChats(e),d.chatActiveEndpointUUID=e}),a.$on("noEndpointActivated",function(a){d.chats=[],d.chatActiveEndpointUUID=null})}angular.module("angular-rtcomm-ui").directive("rtcommChat",a),a.$inject=["RtcommService","$log"],b.$inject=["$scope","RtcommService","$log"]}(),function(){"use strict";function a(){var a={restrict:"E",templateUrl:"templates/rtcomm/rtcomm-endpoint-status.html",controller:b,controllerAs:"endpointStatusVM",bindToController:!0};return a}function b(a,b,c){var d=this;d.epCtrlActiveEndpointUUID=a.getActiveEndpoint(),d.epCtrlRemoteEndpointID=a.getRemoteEndpoint(d.epCtrlActiveEndpointUUID),d.sessionState=a.getSessionState(d.epCtrlActiveEndpointUUID),d.failureReason="",d.queueCount=0,b.$on("session:started",function(a,b){c.debug("session:started received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID===b.endpoint.id&&(d.sessionState="session:started",d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID())}),b.$on("session:stopped",function(a,b){c.debug("session:stopped received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID==b.endpoint.id&&(d.sessionState="session:stopped",d.epCtrlRemoteEndpointID=null)}),b.$on("session:failed",function(a,b){c.debug("session:failed received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID==b.endpoint.id&&(d.sessionState="session:failed",d.failureReason=b.reason,d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID())}),b.$on("session:alerting",function(a,b){c.debug("session:alerting received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID!=b.endpoint.id&&(d.sessionState="session:alerting",d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID())}),b.$on("session:connecting",function(a,b){c.debug("session:connecting received: endpointID = "+b.endpoint.id),d.sessionState="session:connecting",d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID()}),b.$on("session:queued",function(a,b){c.debug("session:queued received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID==b.endpoint.id&&(d.sessionState="session:queued",d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID())}),b.$on("session:trying",function(a,b){c.debug("session:trying received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID==b.endpoint.id&&(d.sessionState="session:trying",d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID())}),b.$on("session:ringing",function(a,b){c.debug("session:ringing received: endpointID = "+b.endpoint.id),d.epCtrlActiveEndpointUUID==b.endpoint.id&&(d.sessionState="session:ringing",d.epCtrlRemoteEndpointID=b.endpoint.getRemoteEndpointID())}),b.$on("endpointActivated",function(b,c){d.epCtrlActiveEndpointUUID=c,d.epCtrlRemoteEndpointID=a.getEndpoint(c).getRemoteEndpointID(),d.sessionState=a.getSessionState(c)}),b.$on("noEndpointActivated",function(a){d.epCtrlRemoteEndpointID=null,d.sessionState="session:stopped"}),b.$on("rtcomm::init",function(b,c,e){c===!0&&(d.epCtrlActiveEndpointUUID=a.getActiveEndpoint(),d.epCtrlRemoteEndpointID=a.getRemoteEndpoint(d.epCtrlActiveEndpointUUID),d.sessionState=a.getSessionState(d.epCtrlActiveEndpointUUID),d.failureReason=""),0==c&&(d.sessionState="session:stopped",d.epCtrlRemoteEndpointID=null)})}angular.module("angular-rtcomm-ui").directive("rtcommEndpointStatus",a),b.$inject=["RtcommService","$scope","$log"]}(),function(){"use strict";function a(){var a={restrict:"E",templateUrl:"templates/rtcomm/rtcomm-iframe.html",controller:b,controllerAs:"iframeVM",bindToController:!0};return a}function b(a,b,c,d,e,f){var g=this;g.iframeActiveEndpointUUID=a.getActiveEndpoint(),g.iframeURL=null,g.initiframeURL=null,g.syncSource=!1,e.init=function(a){a===!0&&(g.syncSource=!0,g.initiframeURL=c.absUrl())},g.setURL=function(c){f.debug("rtcommIframe: setURL: newURL: "+c),a.putIframeURL(g.iframeActiveEndpointUUID,c),g.iframeURL=b.trustAsResourceUrl(c)},g.forward=function(){},g.backward=function(){},e.$on("session:started",function(b,c){f.debug("session:started received: endpointID = "+c.endpoint.id),1==g.syncSource&&a.putIframeURL(c.endpoint.id,g.initiframeURL)}),e.$on("endpointActivated",function(c,d){f.debug("rtcommIframe: endpointActivated ="+d),0==g.syncSource&&(g.iframeURL=b.trustAsResourceUrl(a.getIframeURL(d)),g.iframeActiveEndpointUUID=d)}),e.$on("noEndpointActivated",function(a){0==g.syncSource&&(g.iframeURL=b.trustAsResourceUrl("about:blank"),g.iframeActiveEndpointUUID=null)}),e.$on("rtcomm::iframeUpdate",function(a,c,e){g.syncSource===!1?(f.debug("rtcomm::iframeUpdate: "+e),e+="?disableRtcomm=true",g.iframeURL=b.trustAsResourceUrl(e)):(f.debug("rtcomm::iframeUpdate: load this url in a new tab: "+e),d.open(b.trustAsResourceUrl(e),"_blank"))})}angular.module("angular-rtcomm-ui").directive("rtcommIframe",a),b.$inject=["RtcommService","$sce","$location","$window","$scope","$log"]}(),function(){"use strict";function a(){var a={restrict:"E",templateUrl:"templates/rtcomm/rtcomm-video.html",controller:b,controllerAs:"videoVM",bindToController:!0};return a}function b(a,b,c){var d=this;c.debug("VideoController Starting"),d.avConnected=a.isWebrtcConnected(a.getActiveEndpoint());var e=a.getActiveEndpoint();"undefined"!=typeof e&&null!=e&&a.setVideoView(e),b.$on("endpointActivated",function(b,e){c.debug("rtcommVideo: endpointActivated ="+e),a.setVideoView(e),d.avConnected=a.isWebrtcConnected(a.getActiveEndpoint())})}angular.module("angular-rtcomm-ui").directive("rtcommVideo",a).controller("RtcommVideoController",b),b.$inject=["RtcommService","$scope","$log"]}(),function(){"use strict";function a(a,b,c,d,e){var f=this;f.alertingEndpointUUID=null,f.autoAnswerNewMedia=!1,f.alertActiveEndpointUUID=a.getActiveEndpoint(),f.caller=null,f.showAlerting=function(d){var g=b.open({templateUrl:"templates/rtcomm/rtcomm-modal-alert.html",controller:"RtcommAlertModalInstanceController",size:d,backdrop:"static",resolve:{caller:function(){return f.caller}}});g.result.then(function(){var b=a.getEndpoint(f.alertingEndpointUUID);b&&(e.debug("Accepting call from: "+f.caller+" for endpoint: "+f.alertingEndpointUUID),b.accept(),c.$broadcast("rtcomm::alert-success"),b=null)},function(){var b=a.getEndpoint(f.alertingEndpointUUID);b&&(e.debug("Rejecting call from: "+f.caller+" for endpoint: "+f.alertingEndpointUUID),b.reject(),b=null)})},d.init=function(a){e.debug("rtcommAlert: autoAnswerNewMedia = "+a),f.autoAnswerNewMedia=a},d.$on("endpointActivated",function(a,b){f.alertActiveEndpointUUID=b}),d.$on("session:alerting",function(a,b){f.alertActiveEndpointUUID==b.endpoint.id&&0==f.autoAnswerNewMedia||f.alertActiveEndpointUUID!=b.endpoint.id?(e.debug("rtcommAlert: display alterting model: alertActiveEndpointUUID = "+b.endpoint+" autoAnswerNewMedia = "+f.autoAnswerNewMedia),f.caller=b.endpoint.getRemoteEndpointID(),f.alertingEndpointUUID=b.endpoint.id,f.showAlerting()):(e.debug("Accepting media from: "+b.endpoint.getRemoteEndpointID()+" for endpoint: "+b.endpoint.id),b.endpoint.accept())})}function b(a,b,c,d){a.caller=d,a.ok=function(){c.debug("Accepting alerting call"),b.close()},a.cancel=function(){c.debug("Rejecting alerting call"),b.dismiss("cancel")}}angular.module("angular-rtcomm-ui").controller("RtcommAlertModalController",a).controller("RtcommAlertModalInstanceController",b),a.$inject=["RtcommService","$uibModal","$rootScope","$scope","$log"],b.$inject=["$scope","$uibModalInstance","$log","caller"]}(),function(){"use strict";function a(a,b,c,d){var e=this;e.calleeID=null,e.callerID=null,e.enableCallModel=!1,e.mediaToEnable=["chat"],e.init=function(a,b){e.calleeID=a,"undefined"!=typeof b&&(e.mediaToEnable=b)},e.placeCall=function(c){var f=b.open({templateUrl:"templates/rtcomm/rtcomm-modal-call.html",controller:"RtcommCallModalInstanceController",size:c,resolve:{}});f.result.then(function(b){d.debug("rtcommCallModal: Calling calleeID: "+e.calleeID),d.debug("rtcommCallModal: CallerID: "+b),null==e.callerID&&"undefined"!=typeof b&&""!=b&&(e.callerID=b,a.setAlias(b)),a.placeCall(e.calleeID,e.mediaToEnable)},function(){d.info("Modal dismissed at: "+new Date)})},c.$on("rtcomm::init",function(a,b,c){d.debug("RtcommCallModalController: rtcomm::init: success = "+b),1==b?e.enableCallModel=!0:e.enableCallModel=!1}),c.$on("session:started",function(a,b){e.enableCallModel=!1}),c.$on("session:stopped",function(a,b){e.enableCallModel=!0})}function b(a,b,c){a.endpointAlias="",a.ok=function(){b.close(a.endpointAlias)},a.cancel=function(){b.dismiss("cancel")}}angular.module("angular-rtcomm-ui").controller("RtcommCallModalController",a).controller("RtcommCallModalInstanceController",b),a.$inject=["RtcommService","$uibModal","$scope","$log"],b.$inject=["$scope","$uibModalInstance","RtcommService"]}(),angular.module("angular-rtcomm-ui").run(["$templateCache",function(a){"use strict";a.put("templates/rtcomm/rtcomm-alert.html",'
{{alert.msg}}
'),a.put("templates/rtcomm/rtcomm-chat.html",'
Chat
  • {{chat.name}} {{chat.time | date:\'HH:mm:ss\'}}

    {{chat.message}}

'),a.put("templates/rtcomm/rtcomm-endpoint-status.html",'
'), +a.put("templates/rtcomm/rtcomm-iframe.html",'
URL Sharing
'),a.put("templates/rtcomm/rtcomm-modal-alert.html",''),a.put("templates/rtcomm/rtcomm-modal-call.html",''),a.put("templates/rtcomm/rtcomm-queues.html",'
Queues
'),a.put("templates/rtcomm/rtcomm-register.html",'
'),a.put("templates/rtcomm/rtcomm-sessionmgr.html",'
'),a.put("templates/rtcomm/rtcomm-video.html",'
')}]),angular.module("angular-rtcomm-presence").run(["$templateCache",function(a){"use strict";a.put("templates/rtcomm/rtcomm-presence.html",'
{{node.name}} {{node.value ? \': \' + node.value : \'\'}}
')}]); \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index 55b7799..1790c5c 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -9,45 +9,50 @@ module.exports = function(config) { // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine', 'mocha', 'chai'], - + frameworks: ['mocha', 'chai', 'sinon'], + reporters: ['progress', 'coverage'], // list of files / patterns to load in the browser files: [ - 'node_modules/angular/angular.js', - 'node_modules/angular-mocks/angular-mocks.js', 'bower_components/jquery/dist/jquery.js', + 'bower_components/bootstrap/dist/js/bootstrap.js', + 'bower_components/angular/angular.js', + 'bower_components/angular-mocks/angular-mocks.js', 'bower_components/angular-bootstrap/ui-bootstrap-tpls.js', - 'bower_components/angular-modal-service/dst/angular-modal-service.js', 'bower_components/angular-tree-control/angular-tree-control.js', 'bower_components/bower-mqttws/mqttws31.js', 'bower_components/rtcomm/dist/rtcomm.js', - 'src/js/rtcomm-services.js', - 'src/js/rtcomm-directives.js', - 'test/*Spec.js' + 'src/templates/**/*.html', + 'src/js/**/*.spec.js', + 'src/js/**/*.module.js', + 'src/js/**/*.js', ], // list of files to exclude - exclude: [ - ], + exclude: [], // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - 'src/templates/*.html': 'ng-html2js' + 'src/templates/**/*.html': ['ng-html2js'], + 'src/js/**/!(*.spec).js': ['coverage'] + }, + coverageReporter: { + type: 'html', + dir: 'coverage/' }, - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], - + ngHtml2JsPreprocessor: { + stripPrefix: 'src/', + moduleName: 'rtcomm.templates' + }, // web server port port: 9876, + // plugins: ["karma-spec-reporter"], + // enable / disable colors in the output (reporters and logs) colors: true, @@ -55,21 +60,21 @@ module.exports = function(config) { // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_DEBUG, + logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, + autoWatch: true, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher //browsers: ['Chrome', 'Firefox'], - browsers: ['Chrome'], + browsers: ['Chrome', 'Firefox'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits - singleRun: true + singleRun: false }); }; diff --git a/package.json b/package.json index 0984c7c..1d9690f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Angular module for Rtcomm", "main": "Gruntfile.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "start": "node test/server.js", + "test": "node_modules/.bin/protractor protractor.conf.js" }, "repository": { "type": "git", @@ -21,9 +22,9 @@ }, "homepage": "https://github.com/WASdev/lib.angular-rtcomm", "devDependencies": { - "angular": "^1.3.5", - "angular-mocks": "^1.3.5", - "chai": "^1.10.0", + "chai": "^3.5.0", + "chai-as-promised": "^5.3.0", + "firefox-profile": "^0.3.11", "grunt": "^0.4.5", "grunt-angular-templates": "^0.5.7", "grunt-contrib-concat": "^0.5.0", @@ -35,15 +36,23 @@ "grunt-karma": "^0.9.0", "grunt-ng-annotate": "^0.8.0", "grunt-serve": "^0.1.6", + "grunt-wiredep": "^2.0.0", + "istanbul": "^0.4.2", "karma": "^0.12.28", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^0.1.7", + "karma-coverage": "^0.5.5", "karma-firefox-launcher": "^0.1.3", "karma-ie-launcher": "^0.1.5", "karma-jasmine": "^0.3.2", "karma-mocha": "^0.1.10", - "karma-ng-html2js-preprocessor": "^0.1.2", + "karma-ng-html2js-preprocessor": "^0.2.1", + "karma-sinon": "^1.0.4", + "karma-spec-reporter": "0.0.24", "load-grunt-tasks": "^1.0.0", - "mocha": "^2.0.1" + "mocha": "^2.0.1", + "mosca": "^1.1.2", + "protractor": "^3.1.1", + "q": "^1.4.1" } } diff --git a/protractor.conf.js b/protractor.conf.js new file mode 100644 index 0000000..8f85392 --- /dev/null +++ b/protractor.conf.js @@ -0,0 +1,46 @@ +//Required to use Mocha in Protractor +var chai = require('chai'); +var chaiAsPromised = require('chai-as-promised'); +chai.use(chaiAsPromised); +var expect = chai.expect; +var q = require('q'); +var RtcommHelper = require('./test/lib/browser-config-generator.js'); + +///Define the users in the session +var session = [{ + browserName: process.env.BROWSER || 'chrome', + caller: true +}]; + + +function establishSessionMeta(capabilities) { + var promises = []; + + capabilities.forEach(function(cap) { + promises.push(RtcommHelper.generateBrowserProfile(cap)); + }); + return q.all(promises); +} + +exports.config = { + seleniumAddress: process.env.SELENIUM_ADDRESS || 'http://localhost:4444/wd/hub', + specs: ['test/**/*.spec.js'], + baseUrl: process.env.BASE_URL || 'http://localhost:8083/test/', + getMultiCapabilities: function() { + return establishSessionMeta(session); + }, + onPrepare: function() { + + global.EC = protractor.ExpectedConditions; + global.expect = expect; + browser.driver.manage().window().maximize(); + + }, + + framework: 'mocha', + + mochaOpts: { + reporter: 'spec', + timeout: 60000 + } +}; diff --git a/src/js/angular-rtcomm.js b/src/js/angular-rtcomm.js deleted file mode 100644 index aa3958e..0000000 --- a/src/js/angular-rtcomm.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * This is the main angular-rtcomm module. - */ -(function() { - angular.module('angular-rtcomm', [ - 'ui.bootstrap', - 'treeControl', - 'angular-rtcomm-ui', - 'angular-rtcomm-presence', - 'angular-rtcomm-service' - ]); -})(); diff --git a/src/js/angular-rtcomm.module.js b/src/js/angular-rtcomm.module.js new file mode 100644 index 0000000..4e7338e --- /dev/null +++ b/src/js/angular-rtcomm.module.js @@ -0,0 +1,24 @@ +/** + * (C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + angular.module('angular-rtcomm', [ + 'ui.bootstrap', + 'treeControl', + 'angular-rtcomm-ui', + 'angular-rtcomm-presence', + 'angular-rtcomm-service' + ]); +})(); diff --git a/src/js/rtcomm-presence.js b/src/js/presence/rtcomm-presence.js similarity index 87% rename from src/js/rtcomm-presence.js rename to src/js/presence/rtcomm-presence.js index e54ebc6..93e0be3 100644 --- a/src/js/rtcomm-presence.js +++ b/src/js/presence/rtcomm-presence.js @@ -1,3 +1,18 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /* * The angular-rtcomm-presence module * This has controllers and directives in it. @@ -5,7 +20,7 @@ (function(){ angular .module('angular-rtcomm-presence', [ - 'ui.bootstrap', + 'ui.bootstrap', 'treeControl', 'angular-rtcomm-service']) .directive('rtcommPresence', rtcommPresence); diff --git a/src/js/rtcomm-directives.js b/src/js/rtcomm-directives.js deleted file mode 100644 index e2459de..0000000 --- a/src/js/rtcomm-directives.js +++ /dev/null @@ -1,942 +0,0 @@ -/* - * The angular-rtcomm-ui module - * This has controllers and directives in it. - */ -(function(){ - -angular - .module('angular-rtcomm-ui', [ - 'ui.bootstrap', - 'angular-rtcomm-service']) - .directive('rtcommSessionManager', rtcommSessionManager) - .directive('rtcommRegister', rtcommRegister) - .directive('rtcommQueues', rtcommQueues) - .directive('rtcommAlert', rtcommAlert) - .directive('rtcommEndpointStatus', rtcommEndpointStatus) - .directive('rtcommVideo', rtcommVideo) - .directive('rtcommChat', rtcommChat) - .directive('rtcommIframe', rtcommIframe) - .controller('RtcommAlertModalController', RtcommAlertModalController) - .controller('RtcommAlertModalInstanceController', RtcommAlertModalInstanceController) - .controller('RtcommCallModalController', RtcommCallModalController) - .controller('RtcommCallModalInstanceController', RtcommCallModalInstanceController) - .controller('RtcommConfigController', RtcommConfigController) - .controller('RtcommVideoController', RtcommVideoController) - .controller('RtcommEndpointController', RtcommEndpointController); - -/************* Endpoint Provider Directives *******************************/ -/** - * This directive is used to manage multiple sessions. If you are only supporting at most one session you wont need - * this directive. The associated template provides a way to switch between active sessions. The session must be in - * the started state to be managed by this directive and is removed when the session stops. - */ - -rtcommSessionManager.$inject=['RtcommService', '$log']; -function rtcommSessionManager (RtcommService, $log) { - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-sessionmgr.html', - controller: function ($scope) { - $scope.sessions = RtcommService.getSessions(); - $scope.sessMgrActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.publishPresence = false; - $scope.sessionPresenceData = []; - - $scope.init = function(publishPresence) { - $scope.publishPresence = publishPresence; - $scope.updatePresence(); - }; - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $log.debug('rtcommSessionmgr: endpointActivated =' + endpointUUID); - $scope.sessMgrActiveEndpointUUID = endpointUUID; - }); - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('rtcommSessionmgr: session:started: uuid =' + eventObject.endpoint.id); - - $scope.updatePresence(); - }); - - $scope.activateSession = function(endpointUUID) { - $log.debug('rtcommSessionmgr: activateEndpoint =' + endpointUUID); - if ($scope.sessMgrActiveEndpointUUID != endpointUUID){ - RtcommService.setActiveEndpoint(endpointUUID); - } - }; - - $scope.updatePresence = function(){ - // Update the presence record if enabled - if ($scope.publishPresence == true){ - RtcommService.removeFromPresenceRecord ($scope.sessionPresenceData, false); - - $scope.sessionPresenceData = [{ - 'name' : "sessions", - 'value' : String($scope.sessions.length)}]; - - RtcommService.addToPresenceRecord ($scope.sessionPresenceData); - } - }; - - }, - controllerAs: 'sessionmgr' - }; -}; - -/** - * This directive is used to manage the registration of an endpoint provider. Since the registered name can only - * be set on initialization of the endpoint provider, this directive actually controls the initialization of the - * provider. Note that the endpoint provider must be initialized before any sessions can be created or received. - */ -rtcommRegister.$inject=['RtcommService', '$log']; -function rtcommRegister(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-register.html', - controller: function ($scope) { - - $scope.nextAction = 'Register'; - - $scope.reguserid = ''; - - $scope.invalid = false; - - var invalidCharacters = /(\$|#|\+|\/|\\)+/i; //Invalid characters for MQTT Topic Path - - //Watch for changes in reguserid - $scope.$watch('reguserid', function(){ - - if($scope.reguserid.length < 1 || invalidCharacters.test($scope.reguserid)){ - - $scope.invalid = true; - } - else{ - $scope.invalid = false; - } - }); - - - $scope.onRegClick = function() { - if ($scope.nextAction === 'Register' && !invalidCharacters.test($scope.reguserid)){ - - $log.debug('Register: reguserid =' + $scope.reguserid); - RtcommService.register($scope.reguserid); - } - else { - $log.debug('Unregister: reguserid =' + $scope.reguserid); - RtcommService.unregister(); - } - }; - - $scope.$on('rtcomm::init', function (event, success, details) { - - if (success == true){ - $scope.nextAction = 'Unregister'; - $scope.reguserid = details.userid; - } - else{ - $scope.nextAction = 'Register'; - - if (details == 'destroyed') - $scope.reguserid = ''; - else - $scope.reguserid = 'Init failed:' + details; - } - }); - }, - controllerAs: 'register' - }; -}; - -/** - * This directive manages call queues. It provides the ability to display all the available queues - * (along with their descriptions) and by clicking on a queue, allows an agent (or any type of user) - * to subscribe on that queue. - */ -rtcommQueues.$inject = ['RtcommService', '$log']; -function rtcommQueues(RtcommService, $log) { - return { - restrict : 'E', - templateUrl : 'templates/rtcomm/rtcomm-queues.html', - controller : function($scope) { - $scope.rQueues = []; - $scope.autoJoinQueues = false; - $scope.queuePresenceData = []; - $scope.queuePublishPresence = false; - $scope.queueFilter = null; - - /** - * autoJoinQueues - automatically join any queues that are not filtered out - * queuePublishedPresence - will add to the presence document information about what queues this person joins. - * queueFilter - If defined, this specifies which queues should be joined. All others will be ignored. - */ - $scope.init = function(autoJoinQueues, queuePublishPresence, queueFilter) { - $log.debug('rtcommQueues: autoJoinQueues = ' + autoJoinQueues); - $scope.autoJoinQueues = autoJoinQueues; - $scope.queuePublishPresence = queuePublishPresence; - - if (typeof queueFilter !== "undefined") - $scope.queueFilter = queueFilter; - }; - - $scope.$on('queueupdate', function(event, queues) { - $log.debug('rtcommQueues: scope queues', $scope.rQueues); - - Object.keys(queues).forEach(function(key) { - $log.debug('rtcommQueues: Push queue: ' + queues[key]); - $log.debug('rtcommQueues: autoJoinQueues: ' + $scope.autoJoinQueues); - - // Check to make sure queue is not filteres out before adding it. - if ($scope.filterOutQueue(queues[key]) == false){ - $scope.rQueues.push(queues[key]); - - // If autoJoin we go ahead and join the queue as soon as we get the queue update. - if ($scope.autoJoinQueues == true){ - $scope.onQueueClick(queues[key]); - } - } - }); - - $scope.updateQueuePresence(); - }); - - $scope.$on('rtcomm::init', function (event, success, details) { - if (success == false){ - $log.debug('rtcommQueues: init: clear queues'); - $scope.rQueues = []; - } - }); - - // - $scope.filterOutQueue = function(queue){ - var returnValue = true; - - if ($scope.queueFilter != null){ - - for (var index = 0; index < $scope.queueFilter.length; ++index) { - var entry = $scope.queueFilter[index]; - if (entry == queue.endpointID) { - returnValue = false; - break; - } - } - } - else - returnValue = false; - - return (returnValue); - }; - - $scope.onQueueClick = function(queue){ - $log.debug('rtcommQueues: onClick: TOP'); - for (var index = 0; index < $scope.rQueues.length; index++) { - if($scope.rQueues[index].endpointID === queue.endpointID) - { - $log.debug('rtcommQueues: onClick: queue.endpointID = ' + queue.endpointID); - - if (queue.active == false){ - RtcommService.joinQueue(queue.endpointID); - $scope.rQueues[index].active = true; - } - else{ - RtcommService.leaveQueue(queue.endpointID); - $scope.rQueues[index].active = false; - } - } - else if (index == ($scope.rQueues.length - 1)){ - $log.debug('rtcommQueues: ERROR: queue.endpointID: ' + queue.endpointID + ' not found in list of queues'); - - } - } - - $scope.updateQueuePresence(); - }; - - $scope.updateQueuePresence = function(){ - // Update the presence record if enabled - if ($scope.queuePublishPresence == true){ - RtcommService.removeFromPresenceRecord ($scope.queuePresenceData, false); - - $scope.queuePresenceData = []; - - for (var index = 0; index < $scope.rQueues.length; index++) { - if($scope.rQueues[index].active === true){ - $scope.queuePresenceData.push ( - { - 'name' : "queue", - 'value' : $scope.rQueues[index].endpointID - }); - } - } - - RtcommService.addToPresenceRecord ($scope.queuePresenceData); - } - }; - }, - controllerAs : 'queues' - }; -}; - -//rtcommModule.controller('RtcommAlertController', ['$scope', '$log', function($scope, $log){ -rtcommAlert.$inject = ['$log']; -function rtcommAlert($log) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-alert.html", - controller: function ($scope) { - $scope.alerts = []; - $scope.addAlert = function(alert) { - $scope.alerts.push(alert); - }; - $scope.closeAlert = function(index) { - $scope.alerts.splice(index, 1); - }; - $scope.$on('rtcomm::alert', function(event, eventObject) { - $scope.addAlert(eventObject); - }); - } - } -}; - -/********************** Endpoint Directives *******************************/ - -/** - * This endpoint status controller only shows the active endpoint. The $scope.sessionState always contains the - * state of the active endpoint if one exist. It will be one of the following states: - * - * 'session:alerting' - * 'session:trying' - * 'session:ringing' - * 'session:queued' - for this one $scope.queueCount will tell you where you are in the queue. - * 'session:failed' - for this one $scope.reason will tell you why the call failed. - * 'session:started' - * 'session:stopped' - * - * You can bind to $scope.sessionState to track state in the view. - */ -rtcommEndpointStatus.$inject = ['RtcommService', '$log']; -function rtcommEndpointStatus(RtcommService, $log){ - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-endpoint-status.html', - controller: function ($scope) { - - // Session states. - $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint($scope.epCtrlActiveEndpointUUID); - $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); - $scope.failureReason = ''; - $scope.queueCount = 0; // FIX: Currently not implemented! - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:started'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:stopped', function (event, eventObject) { - $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:stopped'; - $scope.epCtrlRemoteEndpointID = null; - } - }); - - $scope.$on('session:failed', function (event, eventObject) { - $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:failed'; - $scope.failureReason = eventObject.reason; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:alerting', function (event, eventObject) { - $log.debug('session:alerting received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID != eventObject.endpoint.id){ - $scope.sessionState = 'session:alerting'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:connecting', function (event, eventObject) { - $log.debug('session:connecting received: endpointID = ' + eventObject.endpoint.id); - // if ($scope.epCtrlActiveEndpointUUID != eventObject.endpoint.id){ - $scope.sessionState = 'session:connecting'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - // } - }); - - - $scope.$on('session:queued', function (event, eventObject) { - $log.debug('session:queued received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:queued'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:trying', function (event, eventObject) { - $log.debug('session:trying received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:trying'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('session:ringing', function (event, eventObject) { - $log.debug('session:ringing received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:ringing'; - $scope.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - } - }); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $scope.epCtrlActiveEndpointUUID = endpointUUID; - $scope.epCtrlRemoteEndpointID = RtcommService.getEndpoint(endpointUUID).getRemoteEndpointID(); - $scope.sessionState = RtcommService.getSessionState(endpointUUID); - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.epCtrlRemoteEndpointID = null; - $scope.sessionState = 'session:stopped'; - }); - - $scope.$on('rtcomm::init', function(event, success, details){ - if(success === true){ - $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint($scope.epCtrlActiveEndpointUUID); - $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); - $scope.failureReason = ''; - } - if(success == false){ - $scope.sessionState = 'session:stopped'; - $scope.epCtrlRemoteEndpointID = null; - } - }); - - - - } - }; -}; - -/** - * This directive manages the WebRTC video screen, including both the self view and the remote view. It - * also takes care of switching state between endpoints based on which endpoint is "actively" being viewed. - */ -rtcommVideo.$inject = ['RtcommService', '$log']; -function rtcommVideo(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: 'templates/rtcomm/rtcomm-video.html', - controller: 'RtcommVideoController' - }; -}; - -/** - * This directive manages the chat portion of a session. The data model for chat - * is maintained in the RtcommService. This directive handles switching between - * active endpoints. - */ -rtcommChat.$inject = ['RtcommService', '$log']; -function rtcommChat(RtcommService, $log) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-chat.html", - controller: function ($scope) { - $scope.chatActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.chats = RtcommService.getChats($scope.chatActiveEndpointUUID); - // This forces the scroll bar to the bottom and watches the $location.hash - //$anchorScroll(); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $log.debug('rtcommChat: endpointActivated =' + endpointUUID); - - // The data model for the chat is maintained in the RtcommService. - $scope.chats = RtcommService.getChats(endpointUUID); - $scope.chatActiveEndpointUUID = endpointUUID; - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.chats = []; - $scope.chatActiveEndpointUUID = null; - }); - - $scope.keySendMessage = function(keyEvent){ - if (keyEvent.which === 13) - $scope.sendMessage(); - }; - - $scope.sendMessage = function() { - var chat = { - time : new Date(), - name : RtcommService.getEndpoint($scope.chatActiveEndpointUUID).getLocalEndpointID(), - message : angular.copy($scope.message) - }; - - $scope.message = ''; - $scope.scrollToBottom(true); - RtcommService.sendChatMessage(chat, $scope.chatActiveEndpointUUID); - }; - - }, - controllerAs: 'chat', - link: function(scope, element){ - var chatPanel = angular.element(element.find('.panel-body')[0]); - - var bottom = true; - - //Chooses if the scrollbar should be forced to the bottom on the next lifecycle - scope.scrollToBottom = function(flag){ - bottom = flag; - } - - if (chatPanel.length > 0) { - //Watch scroll events - chatPanel.bind('scroll', function(){ - if(chatPanel.prop('scrollTop') + chatPanel.prop('clientHeight') == chatPanel.prop('scrollHeight')){ - scope.scrollToBottom(true); - } - else { - scope.scrollToBottom(false); - } - }); - //Watch the chat messages, if the scroll bar is in the bottom keep it on the bottom so the user can view incoming chat messages, else possibly send a notification and don't scroll down - scope.$watch('chats', function(){ - if(bottom){ - chatPanel.scrollTop(chatPanel.prop('scrollHeight')); - } - else { - //In this else, a notification could be sent - } - },true); - } - else { - $log.warn('chatPanel not found: most likely you need to load jquery prior to angular'); - } - } - }; - -}; - -/** - * This directive manages the shared iFrame. - */ -rtcommIframe.$inject = ['RtcommService', '$log', '$sce', '$location', '$window']; -function rtcommIframe(RtcommService, $log, $sce, $location, $window) { - return { - restrict: 'E', - templateUrl: "templates/rtcomm/rtcomm-iframe.html", - controller: ["$scope", function ($scope) { - $scope.iframeActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.iframeURL = null; - $scope.initiframeURL = null; - $scope.syncSource = false; - - /* - * syncSourcing means you a providing the URL source but no UI. Typically used in - * customer/agent scenarios. - */ - $scope.init = function(syncSource) { - if (syncSource == true){ - $scope.syncSource = true; - $scope.initiframeURL = $location.absUrl(); // init to current URL - } - }; - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); - - if ($scope.syncSource == true){ - RtcommService.putIframeURL(eventObject.endpoint.id,$scope.initiframeURL); //Update on the current or next endpoint to be activated. - } - }); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $log.debug('rtcommIframe: endpointActivated =' + endpointUUID); - - if ($scope.syncSource == false){ - $scope.iframeURL = $sce.trustAsResourceUrl(RtcommService.getIframeURL(endpointUUID)); - $scope.iframeActiveEndpointUUID = endpointUUID; - } - }); - - $scope.$on('noEndpointActivated', function (event) { - if ($scope.syncSource == false){ - $scope.iframeURL = $sce.trustAsResourceUrl('about:blank'); - $scope.iframeActiveEndpointUUID = null; - } - }); - - $scope.$on('rtcomm::iframeUpdate', function (eventType, endpointUUID, url) { - if ($scope.syncSource == false){ - $log.debug('rtcomm::iframeUpdate: ' + url); - // This is needed to prevent rtcomm from logging in when the page is loaded in the iFrame. - url = url + "?disableRtcomm=true"; - $scope.iframeURL = $sce.trustAsResourceUrl(url); - } - else{ - $log.debug('rtcomm::iframeUpdate: load this url in a new tab: ' + url); - // In this case we'll open the pushed URL in a new tab. - $window.open($sce.trustAsResourceUrl(url), '_blank'); - } - }); - - $scope.setURL = function(newURL){ - $log.debug('rtcommIframe: setURL: newURL: ' + newURL); - RtcommService.putIframeURL($scope.iframeActiveEndpointUUID, newURL); - $scope.iframeURL = $sce.trustAsResourceUrl(newURL); - }; - - $scope.forward = function() { - }; - - $scope.backward = function() { - }; - }], - controllerAs: 'rtcommiframe' - }; -}; - - - -/******************************** Rtcomm Modals ************************************************/ - -/** - * This modal is displayed on receiving an inbound call. It handles the alerting event. - * Note that it can also auto accept requests for enabling A/V. - */ - -RtcommAlertModalController.$inject=['$rootScope', '$scope', 'RtcommService', '$modal', '$log']; -function RtcommAlertModalController($rootScope, $scope, RtcommService, $modal, $log) { - - $scope.alertingEndpointUUID = null; - $scope.autoAnswerNewMedia = false; - $scope.alertActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.caller = null; - - $scope.init = function(autoAnswerNewMedia) { - $log.debug('rtcommAlert: autoAnswerNewMedia = ' + autoAnswerNewMedia); - $scope.autoAnswerNewMedia = autoAnswerNewMedia; - }; - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $scope.alertActiveEndpointUUID = endpointUUID; - }); - - $scope.$on('session:alerting', function (event, eventObject) { - - if (($scope.alertActiveEndpointUUID == eventObject.endpoint.id && $scope.autoAnswerNewMedia == false) || - ($scope.alertActiveEndpointUUID != eventObject.endpoint.id)) - { - $log.debug('rtcommAlert: display alterting model: alertActiveEndpointUUID = ' + eventObject.endpoint + ' autoAnswerNewMedia = ' + $scope.autoAnswerNewMedia); - $scope.caller = eventObject.endpoint.getRemoteEndpointID(); - $scope.alertingEndpointUUID = eventObject.endpoint.id; - $scope.showAlerting(); - } - else{ - $log.debug('Accepting media from: ' + eventObject.endpoint.getRemoteEndpointID() + ' for endpoint: ' + eventObject.endpoint.id); - eventObject.endpoint.accept(); - } - }); - - $scope.showAlerting = function (size) { - - var modalInstance = $modal.open({ - templateUrl: 'templates/rtcomm/rtcomm-modal-alert.html', - controller: 'RtcommAlertModalInstanceController', - size: size, - backdrop: 'static', - resolve: { - caller: function () { - return $scope.caller; - }} - }); - - modalInstance.result.then( - function() { - var alertingEndpointObject = RtcommService.getEndpoint($scope.alertingEndpointUUID); - - if(alertingEndpointObject){ - $log.debug('Accepting call from: ' + $scope.caller + ' for endpoint: ' + $scope.alertingEndpointUUID); - alertingEndpointObject.accept(); - $rootScope.$broadcast('rtcomm::alert-success'); - alertingEndpointObject = null; - } - }, - function () { - var alertingEndpointObject = RtcommService.getEndpoint($scope.alertingEndpointUUID); - if(alertingEndpointObject){ - $log.debug('Rejecting call from: ' + $scope.caller + ' for endpoint: ' + $scope.alertingEndpointUUID); - alertingEndpointObject.reject(); - alertingEndpointObject = null; - } - }); - }; -}; - -RtcommAlertModalInstanceController.$inject = ['$scope', '$modalInstance', '$log', 'caller']; - -function RtcommAlertModalInstanceController($scope, $modalInstance, $log, caller) { - $scope.caller = caller; - $scope.ok = function () { - $log.debug('Accepting alerting call'); - $modalInstance.close(); - }; - - $scope.cancel = function () { - $log.debug('Rejecting alerting call'); - $modalInstance.dismiss('cancel'); - }; -}; - -/** - * This is a modal controller for placing an outbound call to a static callee such as a queue. - */ -RtcommCallModalController.$inject = ['$scope', 'RtcommService', '$modal', '$log']; -function RtcommCallModalController($scope, RtcommService, $modal, $log) { - $scope.calleeID = null; - $scope.callerID = null; - - $scope.enableCallModel = false; - $scope.mediaToEnable = ['chat']; - - $scope.init = function(calleeID, mediaToEnable) { - $scope.calleeID = calleeID; - - if (typeof mediaToEnable !== "undefined") - $scope.mediaToEnable = mediaToEnable; - }; - - $scope.$on('rtcomm::init', function (event, success, details) { - $log.debug('RtcommCallModalController: rtcomm::init: success = ' + success); - if (success == true) - $scope.enableCallModel = true; - else - $scope.enableCallModel = false; - }); - - $scope.$on('session:started', function (event, eventObject) { - $scope.enableCallModel = false; - }); - - $scope.$on('session:stopped', function (event, eventObject) { - $scope.enableCallModel = true; - }); - - $scope.placeCall = function (size) { - - var modalInstance = $modal.open({ - templateUrl: 'templates/rtcomm/rtcomm-modal-call.html', - controller: 'RtcommCallModalInstanceController', - size: size, - resolve: {} - }); - - modalInstance.result.then( - function (resultName) { - $log.debug('rtcommCallModal: Calling calleeID: ' + $scope.calleeID); - $log.debug('rtcommCallModal: CallerID: ' + resultName); - - // This is used to set an alias when the endoint is not defined. - if ($scope.callerID == null && (typeof resultName !== "undefined") && resultName != ''){ - $scope.callerID = resultName; - RtcommService.setAlias(resultName); - } - - RtcommService.placeCall($scope.calleeID, $scope.mediaToEnable); - }, - function () { - $log.info('Modal dismissed at: ' + new Date()); - }); - }; -}; - -RtcommCallModalInstanceController.$inject = ['$scope', '$modalInstance', 'RtcommService']; -function RtcommCallModalInstanceController($scope, $modalInstance, RtcommService) { - $scope.endpointAlias = ''; - $scope.ok = function () { - $modalInstance.close($scope.endpointAlias); - }; - $scope.cancel = function () { - $modalInstance.dismiss('cancel'); - }; -}; - -/********************************************* Rtcomm Controllers ******************************************************/ - -/** - * This is the controller for config loader. It reads a JSON object and utilizes the RtcommService to set the configuration. - * This can also result in the initialization of the endpoint provider if the config JSON object includes a registration name. - * - * Here is an example of the config object: - * - * { - * "server" : "server address", - * "port" : 1883, - * "rtcommTopicPath" : "/rtcomm-helpdesk/", - * "createEndpoint" : false, - * "userid" : "registration name", - * "broadcastAudio" : true, - * "broadcastVideo" : true - * } - * - * NOTE: If the user does not specify a userid, that says one will never be specified so go ahead - * and initialize the endpoint provider and let the provider assign a name. If a defined empty - * string is passed in, that means to wait until the end user registers a name before initializing - * the endpoint provider. - */ - -RtcommConfigController.$inject = ['$scope','$http', 'RtcommService', '$log']; -function RtcommConfigController($scope, $http, RtcommService, $log) { - $scope.extendedConfig = null; - - $log.debug('RtcommConfigController: configURL = ' + $scope.configURL); - - $scope.setConfig = function(data) { - $log.debug('RtcommConfigController: setting config data:' + data); - RtcommService.setConfig(data); - }; - - $scope.init = function(configURL,extendedConfig) { - $log.debug('RtcommConfigController: initing configURL = ' + configURL); - $scope.configURL = configURL; - - if (typeof extendedConfig !== "undefined") - $scope.extendedConfig = extendedConfig; - - $scope.getConfig(); - }; - - $scope.getConfig = function() { - $http.get($scope.configURL).success (function(config){ - - // Now we need to update the config with any extensions passed in on init. - if ($scope.extendedConfig != null){ - angular.extend(config, $scope.extendedConfig); - $log.debug('RtcommConfigController: extended config object: ' + config); - } - - RtcommService.setConfig(config); - }).error(function(data, status, headers, config) { - $log.debug('RtcommConfigController: error accessing config: ' + status); - }); - }; -}; - - -RtcommVideoController.$inject= ['$scope','$http', 'RtcommService', '$log']; -function RtcommVideoController($scope, $http, RtcommService, $log) { - $scope.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); - $scope.init = function(selfView,remoteView) { - RtcommService.setViewSelector(selfView,remoteView); - - var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); - if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null) - RtcommService.setVideoView(videoActiveEndpointUUID); - }; - - // Go ahead and initialize the local media here if an endpoint already exist. - var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); - if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null) - RtcommService.setVideoView(videoActiveEndpointUUID); - - $scope.$on('endpointActivated', function (event, endpointUUID) { - // Not to do something here to show that this button is live. - $log.debug('rtcommVideo: endpointActivated =' + endpointUUID); - RtcommService.setVideoView(endpointUUID); - $scope.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.avConnected = false; - }); - - $scope.$on('webrtc:connected', function (event, eventObject) { - if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) - $scope.avConnected = true; - }); - - $scope.$on('webrtc:disconnected', function (event, eventObject) { - if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) - $scope.avConnected = false; - }); -}; - - -RtcommEndpointController.$inject = ['$scope', '$rootScope', '$http', 'RtcommService', '$log']; -function RtcommEndpointController($scope, $rootScope, $http, RtcommService, $log) { - // Session states. - $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); - $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected($scope.epCtrlActiveEndpointUUID); - $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); - - $scope.disconnect = function() { - $log.debug('Disconnecting call for endpoint: ' + $scope.epCtrlActiveEndpointUUID); - RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).disconnect(); - }; - - $scope.toggleAV = function() { - $log.debug('Enable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); - - if ($scope.epCtrlAVConnected == false){ - RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.enable(function(value, message) { - if (!value) { - $log.debug('Enable failed: ',message); - RtcommService.alert({type: 'danger', msg: message}); - } - }); - } - else{ - $log.debug('Disable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); - RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.disable(); - } - }; - - $scope.$on('session:started', function (event, eventObject) { - $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:started'; - } - }); - - $scope.$on('session:stopped', function (event, eventObject) { - $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:stopped'; - } - }); - - $scope.$on('session:failed', function (event, eventObject) { - $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id){ - $scope.sessionState = 'session:failed'; - } - }); - - $scope.$on('webrtc:connected', function (event, eventObject) { - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) - $scope.epCtrlAVConnected = true; - }); - - $scope.$on('webrtc:disconnected', function (event, eventObject) { - if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) - $scope.epCtrlAVConnected = false; - }); - - - $scope.$on('endpointActivated', function (event, endpointUUID) { - $scope.epCtrlActiveEndpointUUID = endpointUUID; - $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected(endpointUUID); - }); - - $scope.$on('noEndpointActivated', function (event) { - $scope.epCtrlAVConnected = false; - }); -}; - -})(); diff --git a/src/js/rtcomm-services.js b/src/js/rtcomm-services.js deleted file mode 100644 index ccffb61..0000000 --- a/src/js/rtcomm-services.js +++ /dev/null @@ -1,869 +0,0 @@ -/** - * Definition for the rtcommModule - */ - -(function() { - angular.module('angular-rtcomm-service', []) - /** - * Set debugEnabled to true to enable the debug messages in this rtcomm angular module. - */ - .config(function($logProvider){ - $logProvider.debugEnabled(true); - }) - /* This causes a problem in ionic/iosrtc - .config(function($locationProvider) { - $locationProvider.html5Mode( {enabled: true, - requireBase: false}); - }) */ - .factory('RtcommConfigService', RtcommConfigService) - .factory('RtcommService', RtcommService); - /** - * - */ - RtcommConfigService.$inject = ['$location', '$log', '$window']; - function RtcommConfigService($location, $log, $window) { - // First we check to see if the URL includes the query string disableRtcomm=true. - // This is typically done when a URL is being shared vian an iFrame that includes Rtcomm directives. - // If it is set we just return without setting up Rtcomm. - $log.debug('RtcommConfigService: Abs URL: ' + $location.absUrl()); - var _disableRtcomm = $location.search().disableRtcomm; - if (typeof _disableRtcomm === "undefined" || _disableRtcomm === null) { - _disableRtcomm = false; - } else if (_disableRtcomm === "true") { - _disableRtcomm = true; - } else { - _disableRtcomm = false; - } - - $log.debug('RtcommConfigService: _disableRtcomm = ' + _disableRtcomm); - - var providerConfig = { - server : $location.host(), - port : $location.port(), - rtcommTopicPath : "/rtcomm/", - createEndpoint : false, - appContext: 'default', - userid: "", - presence : {topic : ""} - }; - - $log.debug('providerConfig.server: ' + providerConfig.server); - $log.debug('providerConfig.port: ' + providerConfig.port); - - var endpointConfig = { - chat: true, - webrtc: true - }; - - // Default to enabling audio and video. It must be disabled through config. - var broadcastAudio = true; - var broadcastVideo = true; - var rtcommDebug = "DEBUG"; - var ringtone = null; - var ringbacktone = null; - var trickleICE = true; - - var setConfig = function(config){ - providerConfig.server = (typeof config.server !== "undefined")? config.server : providerConfig.server; - providerConfig.port = (typeof config.port !== "undefined")? config.port : providerConfig.port; - providerConfig.rtcommTopicPath = (typeof config.rtcommTopicPath !== "undefined")? config.rtcommTopicPath : providerConfig.rtcommTopicPath; - providerConfig.createEndpoint = (typeof config.createEndpoint !== "undefined")? config.createEndpoint : providerConfig.createEndpoint; - providerConfig.appContext = (typeof config.appContext !== "undefined")? config.appContext : providerConfig.appContext; - providerConfig.presence.topic = (typeof config.presenceTopic !== "undefined")? config.presenceTopic : providerConfig.presence.topic; - - // We no longer need to set 'useSSL' This will be set based on how page is served. -// providerConfig.useSSL = (typeof config.useSSL !== "undefined")? config.useSSL : providerConfig.useSSL; - // Protocol related booleans - endpointConfig.chat= (typeof config.chat!== "undefined")? config.chat: endpointConfig.chat; - endpointConfig.webrtc = (typeof config.webrtc!== "undefined")? config.webrtc: endpointConfig.webrtc; - - broadcastAudio = (typeof config.broadcastAudio !== "undefined")? config.broadcastAudio: broadcastAudio; - broadcastVideo = (typeof config.broadcastVideo !== "undefined")? config.broadcastVideo: broadcastVideo; - trickleICE = (typeof config.trickleICE !== "undefined")? config.trickleICE: trickleICE; - - ringbacktone = (typeof config.ringbacktone !== "undefined")? config.ringbacktone: ringbacktone; - ringtone = (typeof config.ringtone !== "undefined")? config.ringtone : ringtone; - - rtcommDebug = (typeof config.rtcommDebug !== "undefined")? config.rtcommDebug: rtcommDebug; - - $log.debug('rtcommDebug from config is: ' + config.rtcommDebug); - - if (typeof config.userid !== "undefined") - providerConfig.userid = config.userid; - - $log.debug('providerConfig is now: ', providerConfig); - - }; - - return { - setProviderConfig : function(config){setConfig(config);}, - - getProviderConfig : function(){return providerConfig;}, - - getWebRTCEnabled : function(){return endpointConfig.webrtc;}, - - getChatEnabled : function(){return endpointConfig.chat;}, - - getBroadcastAudio : function(){return broadcastAudio;}, - - getBroadcastVideo : function(){return broadcastVideo;}, - - getRingTone : function(){return ringtone;}, - - getRingBackTone : function(){return ringbacktone;}, - - getRtcommDebug: function(){return rtcommDebug;}, - - isRtcommDisabled : function(){return _disableRtcomm;}, - - getTrickleICE: function(){return trickleICE;} - }; - }; - - RtcommService.$inject=['$rootScope', '$log', '$http', 'RtcommConfigService']; - function RtcommService($rootScope, $log, $http, RtcommConfigService) { - /** Setup the endpoint provider first **/ - var myEndpointProvider = new rtcomm.EndpointProvider(); - var endpointProviderInitialized = false; - var queueList = null; - var sessions = []; - var presenceRecord = null; - var karmaTesting = false; - var _selfView = "selfView"; // Default self view - var _remoteView = "remoteView"; // Default remote view - - myEndpointProvider.setLogLevel(RtcommConfigService.getRtcommDebug()); - $log.debug('rtcomm-service - endpointProvider log level is: '+myEndpointProvider.getLogLevel()); - $log.debug('rtcomm-service - endpointProvider log level should be: '+RtcommConfigService.getRtcommDebug()); - myEndpointProvider.setAppContext(RtcommConfigService.getProviderConfig().appContext); - - var getPresenceRecord = function(){ - if (presenceRecord == null) - presenceRecord = {'state': 'available', userDefines: []}; - - return (presenceRecord); - }; - - // This defines all the media related configuration and is controlled through external config. - var getMediaConfig = function() { - - var mediaConfig = { - ringbacktone: RtcommConfigService.getRingBackTone(), - ringtone: RtcommConfigService.getRingTone(), - webrtcConfig: { - broadcast : { - audio : RtcommConfigService.getBroadcastAudio(), - video : RtcommConfigService.getBroadcastVideo() - }, - trickleICE: RtcommConfigService.getTrickleICE() - }, - webrtc : RtcommConfigService.getWebRTCEnabled(), - chat : RtcommConfigService.getChatEnabled(), - }; - - return (mediaConfig); - }; - - myEndpointProvider.on('reset', function(event_object) { - //The Endpoint provider is destroyed on reset - endpointProviderInitialized = false; - _alert({type:'danger', msg: event_object.reason}); - }); - - - myEndpointProvider.on('queueupdate', function(queuelist) { - $log.debug('<<------rtcomm-service------>> - Event: queueupdate'); - $log.debug('queueupdate', queuelist); - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('queueupdate', queuelist); - } - ); - }); - - myEndpointProvider.on('newendpoint', function(endpoint) { - $log.debug('<<------rtcomm-service------>> - Event: newendpoint remoteEndpointID: ' + endpoint.getRemoteEndpointID()); - - endpoint.on('onetimemessage',function(event){ - $log.debug('<<------rtcomm-onetimemessage------>> - Event: ', event); - if (event.onetimemessage.type != "undefined" && event.onetimemessage.type == 'iFrameURL'){ - var session = _createSession(event.endpoint.id); - session.iFrameURL = event.onetimemessage.iFrameURL; - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::iframeUpdate', event.endpoint.id, event.onetimemessage.iFrameURL); - } - ); - } - }); - - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('newendpoint', endpoint); - } - ); - }); - - var callback = function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - if (eventObject.eventName.indexOf("session:") > -1){ - var session = _createSession(eventObject.endpoint.id); - session.sessionState = eventObject.eventName; - } - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - - }; - - // Setup all the callbacks here because they are all static. - myEndpointProvider.setRtcommEndpointConfig ({ - ringtone: RtcommConfigService.getRingTone(), - ringbacktone: RtcommConfigService.getRingBackTone(), - // These are all the session related events. - 'session:started' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - var session = _createSession(eventObject.endpoint.id); - _setActiveEndpoint(eventObject.endpoint.id); - - session.sessionStarted = true; - session.remoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - - }, - - 'session:alerting' : callback, - 'session:trying' : callback, - 'session:ringing' : callback, - 'session:queued' : callback, - - 'session:failed' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - _removeSession(eventObject.endpoint.id); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - - }, - - 'session:stopped' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - _removeSession(eventObject.endpoint.id); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - - }, - - 'session:connecting' : callback, - - // These are all the WebRTC related events. - 'webrtc:connected' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - - $rootScope.$evalAsync( - function () { - _createSession(eventObject.endpoint.id).webrtcConnected = true; - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, - // These are all the WebRTC related events. - 'webrtc:remotemuted' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, - - 'webrtc:disconnected' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - - $rootScope.$evalAsync( - function () { - var session = _getSession(eventObject.endpoint.id); - if (session != null) - session.webrtcConnected = false; - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, - - // These are all the chat related events. - 'chat:connected' : callback, - 'chat:disconnected' : callback, - - 'chat:message' : function(eventObject) { - $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); - $rootScope.$evalAsync( - function () { - var chat = { - time : new Date(), - name : eventObject.message.from, - message : angular.copy(eventObject.message.message) - }; - - _createSession(eventObject.endpoint.id).chats.push(chat); - $rootScope.$broadcast(eventObject.eventName, eventObject); - } - ); - - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }, - - // Endpoint destroyed - 'destroyed' : callback - }); - - var initSuccess = function(event) { - $log.debug('<<------rtcomm-service------>> - Event: Provider init succeeded'); - - if (presenceRecord != null){ - $log.debug('RtcommService: initSuccess: updating presence record'); - myEndpointProvider.publishPresence(presenceRecord); - } - - $rootScope.$evalAsync( - function () { - var broadcastEvent = { - 'ready': event.ready, - 'registered': event.registered, - 'endpoint': event.endpoint, - 'userid' : RtcommConfigService.getProviderConfig().userid - }; - - $rootScope.$broadcast('rtcomm::init', true, broadcastEvent); - } - ); - - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }; - - var initFailure = function(error) { - $log.debug('<<------rtcomm-service------>> - Event: Provider init failed: error: ',error); - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::init', false, error); - } - ); - // This is required in karma to get the evalAsync to fire. Ugly but necessary... - if (karmaTesting == true) - $rootScope.$digest(); - }; - - /* - * Get session from local endpoint ID - */ - var _getSession = function(endpointUUID){ - - var session = null; - - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].endpointUUID === endpointUUID){ - session = sessions[index]; - break; - } - } - - return (session); - }; - - /* - * Get session from local endpoint ID - */ - var _createSession = function(endpointUUID){ - - var session = null; - - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].endpointUUID === endpointUUID){ - session = sessions[index]; - break; - } - } - - if (session == null){ - session = { - endpointUUID : endpointUUID, - chats : [], - webrtcConnected : false, - sessionStarted : false, - iFrameURL : 'about:blank', - remoteEndpointID : null, - activated : true, - sessionState : 'session:stopped' - }; - sessions[sessions.length] = session; - } - - return (session); - }; - - var _removeSession = function(endpointUUID){ - - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].endpointUUID === endpointUUID){ - - var endpoint = _getEndpoint(endpointUUID); - if(typeof endpoint !== 'undefined') - endpoint.destroy(); - - // Remove the disconnected endpoint from the list. - sessions.splice(index, 1); - - // Now we need to set the active endpoint to someone else or to no endpoint if none are left. - if (sessions.length == 0){ - $rootScope.$broadcast('noEndpointActivated'); - } - else{ - _setActiveEndpoint(sessions[0].endpointUUID); - } - break; - } - } - }; - - - var _getEndpoint = function(uuid) { - var endpoint = null; - - if ((typeof uuid === "undefined") || uuid == null){ - $log.debug('getEndpoint: create new endpoint and setup onetimemessage event'); - endpoint = myEndpointProvider.createRtcommEndpoint(); - endpoint.on('onetimemessage',function(event){ - $log.debug('<<------rtcomm-onetimemessage------>> - Event: ', event); - if (event.onetimemessage.type != "undefined" && event.onetimemessage.type == 'iFrameURL'){ - var session = _createSession(event.endpoint.id); - - session.iFrameURL = event.onetimemessage.iFrameURL; - - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::iframeUpdate', event.endpoint.id, event.onetimemessage.iFrameURL); - } - ); - } - }); - } - else - endpoint = myEndpointProvider.getRtcommEndpoint(uuid); - - return (endpoint); - }; - - var _setActiveEndpoint = function(endpointID){ - - // First get the old active endpoint - var activeEndpoint = _getActiveEndpointUUID(); - if ((activeEndpoint != null) && (activeEndpoint != endpointID)){ - var session = _getSession(activeEndpoint); - if (session != null) - session.activated = false; - } - - var session = _createSession(endpointID); - session.activated = true; - - $rootScope.$broadcast('endpointActivated', endpointID); - }; - - var _getActiveEndpointUUID = function(){ - var activeEndpoint = null; - - for (var index = 0; index < sessions.length; index++) { - if(sessions[index].activated == true){ - activeEndpoint = sessions[index].endpointUUID; - break; - } - } - return (activeEndpoint); - }; - var _alert = function _alert(alertObject) { - var a = { type: 'info', - msg: 'default message'}; - if (typeof alertObject === 'string') { - a.msg = alertObject; - } else { - a = alertObject; - } - $rootScope.$evalAsync( - function () { - $rootScope.$broadcast('rtcomm::alert', a); - } - ); - }; - - - return { - - alert: _alert, - - setKarmaTesting : function(){ - karmaTesting = true; - }, - - isInitialized : function(){ - return(endpointProviderInitialized); - }, - - setConfig : function(config){ - if (RtcommConfigService.isRtcommDisabled() == true){ - $log.debug('RtcommService:setConfig: isRtcommDisabled = true; return with no setup'); - return; - } - - - $log.debug('rtcomm-services: setConfig: config: ', config); - - RtcommConfigService.setProviderConfig(config); - myEndpointProvider.setRtcommEndpointConfig(getMediaConfig()); - - if (endpointProviderInitialized == false){ - // If an identityServlet is defined we will get the User ID from the servlet. - // This is used when the user ID needs to be derived from an SSO token like LTPA. - if (typeof config.identityServlet !== "undefined" && config.identityServlet != null){ - $http.get(config.identityServlet).success (function(data){ - - if (typeof data.userid !== "undefined"){ - RtcommConfigService.setProviderConfig(data); - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - endpointProviderInitialized = true; - } - else - $log.error('RtcommService: setConfig promise: Invalid JSON object return from identityServlet: ', data); - }).error(function(data, status, headers, config) { - $log.debug('RtcommService: setConfig promise: error accessing userid from identityServlet: ' + status); - }); - } - else{ - // If the user does not specify a userid, that says one will never be specified so go ahead - // and initialize the endpoint provider and let the provider assign a name. If a defined empty - // string is passed in, that means to wait until the end user registers a name. - if (typeof config.userid == "undefined" || RtcommConfigService.getProviderConfig().userid != ''){ - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - endpointProviderInitialized = true; - } - } - } - }, - - // Presence related methods - getPresenceMonitor:function(topic) { - return myEndpointProvider.getPresenceMonitor(topic); - }, - - publishPresence:function() { - if (endpointProviderInitialized == true) - myEndpointProvider.publishPresence(getPresenceRecord()); - }, - - /** - * userDefines is an array of JSON objects that look like: - * - * { - * name : "some name", - * value : "some value" - * } - * - * The only rule is that some name and some value have to both be strings. - */ - addToPresenceRecord:function(userDefines) { - - for (var index = 0; index < userDefines.length; index++) { - getPresenceRecord().userDefines.push(userDefines[index]); - } - - if (endpointProviderInitialized == true){ - $log.debug('RtcommService: addToPresenceRecord: updating presence record to: ', getPresenceRecord()); - myEndpointProvider.publishPresence(getPresenceRecord()); - } - }, - - /** - * userDefines is an array of JSON objects that look like: - * - * { - * name : "some name", - * value : "some value" - * } - * - * The only rule is that some name and some value have to both be strings. - */ - removeFromPresenceRecord:function(userDefines, doPublish) { - - for (var i = 0; i < userDefines.length; i++) { - for (var j = 0; j < getPresenceRecord().userDefines.length; j++) { - - if (getPresenceRecord().userDefines[j].name == userDefines[i].name){ - getPresenceRecord().userDefines.splice(j,1); - break; - } - } - } - - if ((endpointProviderInitialized == true) && doPublish){ - $log.debug('RtcommService: removeFromPresenceRecord: updating presence record to: ', getPresenceRecord()); - myEndpointProvider.publishPresence(getPresenceRecord()); - } - }, - - setPresenceRecordState:function(state) { - getPresenceRecord().state = state; - return myEndpointProvider.publishPresence(getPresenceRecord()); - }, - - // Endpoint related methods - getEndpoint : function(uuid) { - return(_getEndpoint(uuid)); - }, - - destroyEndpoint : function(uuid) { - myEndpointProvider.getRtcommEndpoint(uuid).destroy(); - }, - - // Registration related methods. - register : function(userid) { - if (endpointProviderInitialized == false){ - RtcommConfigService.getProviderConfig().userid = userid; - - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - endpointProviderInitialized = true; - } - else - $log.error('rtcomm-services: register: ERROR: endpoint provider already initialized'); - }, - - unregister : function() { - if (endpointProviderInitialized == true){ - myEndpointProvider.destroy(); - endpointProviderInitialized = false; - initFailure("destroyed"); - } - else - $log.error('rtcomm-services: unregister: ERROR: endpoint provider not initialized'); - }, - - // Queue related methods - joinQueue : function(queueID) { - myEndpointProvider.joinQueue(queueID); - }, - - leaveQueue : function(queueID) { - myEndpointProvider.leaveQueue(queueID); - }, - - getQueues : function() { - return(queueList); - }, - - /** - * Chat related methods - */ - sendChatMessage : function(chat, endpointUUID){ - // Save this chat in the local session store - var session = _createSession(endpointUUID); - session.chats.push(chat); - - myEndpointProvider.getRtcommEndpoint(endpointUUID).chat.send(chat.message); - }, - - getChats : function(endpointUUID) { - if (typeof endpointUUID !== "undefined" && endpointUUID != null){ - var session = _getSession(endpointUUID); - if (session != null) - return (session.chats); - else - return(null); - } - else - return(null); - }, - - isWebrtcConnected : function(endpointUUID) { - if (typeof endpointUUID !== 'undefined' && endpointUUID != null){ - var session = _getSession(endpointUUID); - if (session != null) - return (session.webrtcConnected); - else - return(false); - } - else - return(false); - }, - - getSessionState : function(endpointUUID) { - if (typeof endpointUUID !== "undefined" && endpointUUID != null) - return (myEndpointProvider.getRtcommEndpoint(endpointUUID).getState()); - else - return ("session:stopped"); - }, - - setAlias : function(aliasID) { - if ((typeof aliasID !== "undefined") && aliasID != '') - myEndpointProvider.setUserID(aliasID); - }, - - setUserID : function(userID) { - if ((typeof userID !== "undefined") && userID != ''){ - RtcommConfigService.setProviderConfig({userid: userID}); - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - } - }, - - setPresenceTopic : function(presenceTopic) { - if ((typeof presenceTopic !== "undefined") && presenceTopic != ''){ - RtcommConfigService.setProviderConfig({presenceTopic : presenceTopic}); - myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); - } - }, - - getIframeURL : function(endpointUUID){ - if (typeof endpointUUID !== "undefined" && endpointUUID != null){ - var session = _getSession(endpointUUID); - if (session != null) - return (session.iFrameURL); - else - return(null); - } - else - return(null); - }, - - putIframeURL : function(endpointUUID, newUrl){ - $log.debug('RtcommService: putIframeURL: endpointUUID: ' + endpointUUID + ' newURL: ' + newUrl); - var endpoint = myEndpointProvider.getRtcommEndpoint(endpointUUID); - - if (endpoint != null){ - var session = _createSession(endpointUUID); - session.iFrameURL = newUrl; - - var message = { type : 'iFrameURL', - iFrameURL : newUrl}; - - $log.debug('RtcommService: putIframeURL: sending new iFrame URL'); - endpoint.sendOneTimeMessage(message); - } - }, - - placeCall : function(calleeID, mediaToEnable){ - var endpoint = _getEndpoint(); - - if (mediaToEnable.indexOf('chat') > -1) - endpoint.chat.enable(); - - if (mediaToEnable.indexOf('webrtc') > -1) { - // Support turning off trickle ICE - var trickleICE = true; - if (mediaToEnable.indexOf('disableTrickleICE') > -1) { - trickleICE = false; - } - endpoint.webrtc.enable({'trickleICE': trickleICE}); - } - _setActiveEndpoint(endpoint.id); - - endpoint.connect(calleeID); - return(endpoint.id); - }, - - getSessions : function(){ - return(sessions); - }, - - endCall : function(endpoint) { - endpoint.disconnect(); - }, - - setActiveEndpoint : function(endpointID){ - _setActiveEndpoint(endpointID); - }, - - getActiveEndpoint : function(){ - return(_getActiveEndpointUUID()); - }, - - getRemoteEndpoint : function(localEndpointID){ - var remoteEndpointID = null; - - if (localEndpointID != null){ - var session = _getSession(localEndpointID); - - if (session != null){ - remoteEndpointID = session.remoteEndpointID; - } - } - - return (remoteEndpointID); - }, - - setDefaultViewSelector : function() { - _selfView = "selfView"; - _remoteView = "remoteView"; - }, - - setViewSelector : function(selfView, remoteView) { - _selfView = selfView; - _remoteView = remoteView; - }, - - setVideoView : function(endpointUUID){ - $log.debug('rtcommVideo: setting local media'); - var endpoint = null; - - if (typeof endpointUUID != "undefined" && endpointUUID != null) - endpoint = _getEndpoint(endpointUUID); - else if (_getActiveEndpointUUID() != null) - endpoint = _getEndpoint(_getActiveEndpointUUID()); - - if (endpoint != null){ - - endpoint.webrtc.setLocalMedia( - { - mediaOut: document.querySelector('#' + _selfView), - mediaIn: document.querySelector('#' + _remoteView) - }); - } - }, - }; - }; - -})(); diff --git a/src/js/services/config/config.service.js b/src/js/services/config/config.service.js new file mode 100644 index 0000000..ba08587 --- /dev/null +++ b/src/js/services/config/config.service.js @@ -0,0 +1,155 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-service') + .factory('RtcommConfigService', RtcommConfigService); + + /* @ngInject */ + function RtcommConfigService($location, $log, $window) { + var service = { + setProviderConfig: setProviderConfig, + getProviderConfig: getProviderConfig, + getWebRTCEnabled: getWebRTCEnabled, + getChatEnabled: getChatEnabled, + getBroadcastAudio: getBroadcastAudio, + getBroadcastVideo: getBroadcastVideo, + getRingTone: getRingTone, + getRingBackTone: getRingBackTone, + getRtcommDebug: getRtcommDebug, + isRtcommDisabled: isRtcommDisabled, + getMediaConfig: getMediaConfig + }; + + //Default provider + var providerConfig = { + server: $location.host(), + port: $location.port(), + rtcommTopicPath: '/rtcomm/', + createEndpoint: false, + appContext: 'default', + userid: '', + presence: { + topic: '' + } + }; + + //Rtcomm Endpoint Config Defaults + var mediaConfig = { + chat: true, + webrtc: true, + webrtcConfig: { + broadcast: { + audio: true, + video: true + }, + trickleICE: true + }, + ringbacktone: null, + ringtone: null + }; + + //Rtcomm Debug + var rtcommDebug = 'DEBUG'; + + $log.debug('RtcommConfigService: Abs Url: ' + $location.absUrl()); + $log.debug('providerConfig.server: ' + providerConfig.server); + $log.debug('providerConfig.port: ' + providerConfig.port); + + return service; + + function setProviderConfig(config) { + + //Provider Config + providerConfig = { + + server: (typeof config.server !== 'undefined') ? config.server : providerConfig.server, + port: (typeof config.port !== 'undefined') ? config.port : providerConfig.port, + rtcommTopicPath: (typeof config.rtcommTopicPath !== 'undefined') ? config.rtcommTopicPath : providerConfig.rtcommTopicPath, + createEndpoint: (typeof config.createEndpoint !== 'undefined') ? config.createEndpoint : providerConfig.createEndpoint, + appContext: (typeof config.appContext !== 'undefined') ? config.appContext : providerConfig.appContext, + presence: { + topic: (typeof config.presenceTopic !== 'undefined') ? config.presenceTopic : providerConfig.presence.topic, + }, + userid: (typeof config.userid !== 'undefined') ? config.userid : providerConfig.userid + }; + + //Media Configuration + mediaConfig = { + chat: (typeof config.chat !== 'undefined') ? config.chat : mediaConfig.chat, + webrtc: (typeof config.video !== 'undefined') ? config.webrtc : mediaConfig.webrtc, + webrtcConfig: { + broadcast: { + video: typeof config.broadcastVideo !== 'undefined' ? config.broadcastVideo : mediaConfig.webrtcConfig.broadcast.video, + audio: typeof config.broadcastAudio !== 'undefined' ? config.broadcastAudio : mediaConfig.webrtcConfig.broadcast.audio + }, + trickleICE: typeof config.trickleICE !== 'undefined' ? config.trickleICE : mediaConfig.webrtcConfig.trickleICE + }, + ringbacktone: typeof config.ringbacktone !== 'undefined' ? config.ringbacktone : mediaConfig.ringbacktone, + ringtone: typeof config.ringtone !== 'undefined' ? config.ringtone : mediaConfig.ringtone + }; + + rtcommDebug = (typeof config.rtcommDebug !== 'undefined') ? config.rtcommDebug : rtcommDebug; + + $log.debug('rtcommDebug from config is: ' + config.rtcommDebug); + + $log.debug('providerConfig is: ' + providerConfig); + } + + function getProviderConfig() { + return providerConfig; + } + + function getWebRTCEnabled() { + return mediaConfig.webrtc; + } + + function getChatEnabled() { + return mediaConfig.chat; + } + + function getBroadcastAudio() { + return mediaConfig.webrtcConfig.broadcast.audio; + } + + function getBroadcastVideo() { + return mediaConfig.webrtcConfig.broadcast.video; + } + + function getRingTone() { + return mediaConfig.ringtone; + } + + function getRingBackTone() { + return mediaConfig.ringbacktone; + } + + function getRtcommDebug() { + return rtcommDebug; + } + + function isRtcommDisabled() { + return false; + } + + function getMediaConfig() { + return mediaConfig; + } + } +})(); diff --git a/src/js/services/config/config.service.spec.js b/src/js/services/config/config.service.spec.js new file mode 100644 index 0000000..266f1ef --- /dev/null +++ b/src/js/services/config/config.service.spec.js @@ -0,0 +1,222 @@ +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Testing: Rtcomm Config Service', function() { + + var RtcommConfigService; + + //Dependencies + var $location, $window; + + //Mock and stub + var sandbox; + + beforeEach(module('angular-rtcomm-service')); + + beforeEach(inject(['$location', '$window', + function(_$location_, _$window_) { + + $location = _$location_; + $window = _$window_; + sandbox = sinon.sandbox.create(); + //Mock the dependencies + sandbox.stub($location, 'absUrl', function() { + 'http://localhost:3000'; + }); + sandbox.stub($location, 'host', function() { + return 'localhost'; + }); + sandbox.stub($location, 'port', function() { + return 3000; + }); + sandbox.stub($location, 'search', function() { + return { + disableRtcomm: false + }; + }); + + } + ])); + + beforeEach(inject(['RtcommConfigService', + function(_RtcommConfigService_) { + RtcommConfigService = _RtcommConfigService_; + } + ])); + + afterEach(function() { + sandbox.restore(); + }); + + var defaultConfig = { + server: 'localhost', + port: 3000, + rtcommTopicPath: '/rtcomm/', + createEndpoint: false, + appContext: 'default', + userid: '', + presence: { + topic: '' + } + }; + + var defaultMediaConfig = { + + chat: true, + webrtc: true, + webrtcConfig: { + broadcast: { + audio: true, + video: true + }, + trickleICE: true + }, + ringbacktone: null, + ringtone: null + + } + it('API should be defined', function() { + expect(RtcommConfigService.setProviderConfig).to.not.be.undefined; + expect(RtcommConfigService.getProviderConfig).to.not.be.undefined; + expect(RtcommConfigService.getWebRTCEnabled).to.not.be.undefined; + expect(RtcommConfigService.getChatEnabled).to.not.be.undefined; + expect(RtcommConfigService.getBroadcastVideo).to.not.be.undefined; + expect(RtcommConfigService.getBroadcastAudio).to.not.be.undefined; + expect(RtcommConfigService.getRingTone).to.not.be.undefined; + expect(RtcommConfigService.getRingBackTone).to.not.be.undefined; + expect(RtcommConfigService.getRtcommDebug).to.not.be.undefined; + expect(RtcommConfigService.isRtcommDisabled).to.not.be.undefined; + expect(RtcommConfigService.getMediaConfig).to.not.be.undefined; + }); + + + + + describe('default configuration values', function() { + + it('should have a default provider configuration', function() { + var providerConfig = RtcommConfigService.getProviderConfig(); + expect(providerConfig).to.deep.equal(defaultConfig); + }); + + it('should have a default media configuration', function() { + var mediaConfig = RtcommConfigService.getMediaConfig(); + expect(mediaConfig).to.deep.equal(defaultMediaConfig); + }); + it('webrtc should be enabled', function() { + expect(RtcommConfigService.getWebRTCEnabled()).to.be.true; + }); + + it('chat should be enabeld', function() { + expect(RtcommConfigService.getChatEnabled()).to.be.true; + }); + + it('video broadcast should be enabled', function() { + expect(RtcommConfigService.getBroadcastVideo()).to.be.true; + }); + + it('audio broadcast should be enabled', function() { + expect(RtcommConfigService.getBroadcastAudio()).to.be.true; + }); + + it('ringtone should be null', function() { + + expect(RtcommConfigService.getRingTone()).to.be.null; + }); + + it('ringbacktone should be null', function() { + + expect(RtcommConfigService.getRingBackTone()).to.be.null; + }); + + it('rtcomm debug should be on level INFO', function() { + expect(RtcommConfigService.getRtcommDebug()).to.equal('DEBUG'); + }); + + it('rtcommdisabled should false', function() { + expect(RtcommConfigService.isRtcommDisabled()).to.not.be.true; + }); + }); + + + it('should set the server correctly', function() { + + var config = { + server: 'localhost2' + }; + + RtcommConfigService.setProviderConfig(config); + + var rtcommConfig = RtcommConfigService.getProviderConfig(); + + expect(rtcommConfig.server).to.equal(config.server); + + for (var property in rtcommConfig) { + if (property !== 'server') { + expect(rtcommConfig[property]).to.deep.equal(defaultConfig[property]); + } + } + }); + + it('should set the port correctly', function() { + var config = { + port: 8083 + }; + + RtcommConfigService.setProviderConfig(config); + + var rtcommConfig = RtcommConfigService.getProviderConfig(); + + expect(rtcommConfig.port).to.equal(config.port); + }); + + it('should correctly set broadcastAudio and broadcastVideo property', function() { + var config = { + broadcastAudio: false, + broadcastVideo: false + }; + + RtcommConfigService.setProviderConfig(config); + + expect(RtcommConfigService.getBroadcastAudio()).to.equal(false); + expect(RtcommConfigService.getBroadcastVideo()).to.equal(false); + + config.broadcastAudio = true; + + RtcommConfigService.setProviderConfig(config); + + expect(RtcommConfigService.getBroadcastAudio()).to.equal(true); + expect(RtcommConfigService.getBroadcastVideo()).to.equal(false); + + config.broadcastVideo = true; + + RtcommConfigService.setProviderConfig(config); + expect(RtcommConfigService.getBroadcastAudio()).to.equal(true); + expect(RtcommConfigService.getBroadcastVideo()).to.equal(true); + + }); + + it('should set appContext', function() { + var config = { + appContext: 'rtcommContext' + }; + + RtcommConfigService.setProviderConfig(config); + + expect(RtcommConfigService.getProviderConfig().appContext).to.be.equal(config.appContext); + }); +}); diff --git a/src/js/services/rtcomm-service/rtcomm-service.js b/src/js/services/rtcomm-service/rtcomm-service.js new file mode 100644 index 0000000..20c82f4 --- /dev/null +++ b/src/js/services/rtcomm-service/rtcomm-service.js @@ -0,0 +1,723 @@ +/** + *(C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * Definition for the rtcommModule + */ + +(function() { + angular.module('angular-rtcomm-service') + /** + * Set debugEnabled to true to enable the debug messages in this rtcomm angular module. + */ + .config(function($logProvider) { + $logProvider.debugEnabled(true); + }) + .constant('rtcomm', rtcomm) + .factory('RtcommService', RtcommService); + RtcommService.$inject = ['$rootScope', '$log', 'RtcommConfigService', 'RtcommSessions', 'rtcomm', '$http']; + + function RtcommService($rootScope, $log, RtcommConfigService, RtcommSessions, rtcomm, $http) { + /** Setup the endpoint provider first **/ + + var service = { + + alert: alert, + + isInitialized: isInitialized, + + setConfig: setConfig, + + getPresenceMonitor: getPresenceMonitor, + + publishPresence: publishPresence, + + addToPresenceRecord: addToPresenceRecord, + + removeFromPresenceRecord: removeFromPresenceRecord, + + setPresenceRecordState: setPresenceRecordState, + + getEndpoint: getEndpoint, + + destroyEndpoint: destroyEndpoint, + + register: register, + + unregister: unregister, + + joinQueue: joinQueue, + + leaveQueue: leaveQueue, + + getQueues: getQueues, + + sendChatMessage: sendChatMessage, + + getChats: getChats, + + isWebrtcConnected: isWebrtcConnected, + + getSessionState: getSessionState, + + setAlias: setAlias, + + setUserID: setUserID, + + setPresenceTopic: setPresenceTopic, + + getIframeURL: getIframeURL, + + putIframeURL: putIframeURL, + + placeCall: placeCall, + + getSessions: getSessions, + + endCall: endCall, + + setActiveEndpoint: setActiveEndpoint, + + getActiveEndpoint: getActiveEndpoint, + + getRemoteEndpoint: getRemoteEndpoint, + + setDefaultViewSelector: setDefaultViewSelector, + + setViewSelector: setViewSelector, + + setVideoView: setVideoView + }; + + + var endpointProviderInitialized = false; + var queueList = null; + var presenceRecord = null; + var _selfView = 'selfView'; // Default self view + var _remoteView = 'remoteView'; // Default remote view + var myEndpointProvider = null; + activate(); + return service; + + function activate() { + myEndpointProvider = new rtcomm.EndpointProvider(); + + myEndpointProvider.setLogLevel(RtcommConfigService.getRtcommDebug()); + + $log.debug('rtcomm-service - endpointProvider log level is: ' + myEndpointProvider.getLogLevel()); + $log.debug('rtcomm-service - endpointProvider log level should be: ' + RtcommConfigService.getRtcommDebug()); + myEndpointProvider.setAppContext(RtcommConfigService.getProviderConfig().appContext); + + + myEndpointProvider.on('reset', function(event_object) { + // Should have a reason. + alert({ + type: 'danger', + msg: event_object.reason + }); + }); + + + myEndpointProvider.on('queueupdate', function(queuelist) { + $log.debug('<<------rtcomm-service------>> - Event: queueupdate'); + $log.debug('queueupdate', queuelist); + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('queueupdate', queuelist); + } + ); + }); + + myEndpointProvider.on('newendpoint', function(endpoint) { + $log.debug('<<------rtcomm-service------>> - Event: newendpoint remoteEndpointID: ' + endpoint.getRemoteEndpointID()); + + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('newendpoint', endpoint); + } + ); + }); + + function sessionEstablishmentCallback(eventObject) { + var id = eventObject.endpoint.id; + + var session = RtcommSessions.getSession(id); + if (session === null) session = RtcommSessions.createSession(id); + + + session.state = eventObject.eventName; + broadcastRtcommEvent(eventObject); + }; + + + /** + * Setup all the callbacks here because they are all static. + */ + myEndpointProvider.setRtcommEndpointConfig({ + // These are all the session related events. + + 'onetimemessage': function(eventObject) { + $log.debug('<<------- rtcomm-service ----->> - Event: ' + eventObject); + + if (eventObject.onetimemessage.type !== 'undefined' && eventObject.onetimemessage.type === 'iFrameURL') { + var id = eventObject.endpoint.id; + + var session = RtcommSessions.getSession(id); + if (session === null) { + session = RtcommSessions.createSession(id); + } + session.iFrameURL = eventObject.onetimemessage.iFrameURL; + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('rtcomm::iframeUpdate', eventObject.endpoint.id, eventObject.onetimemessage.iFrameURL); + } + ); + } + }, + 'session:started': function(eventObject) { + $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); + var id = eventObject.endpoint.id; + var endpoint = eventObject.endpoint; + var session = RtcommSessions.getSession(id); + + if (session === null) $log.error('Session:started but a previous session hasn\'t been created!'); + else { + _setActiveEndpoint(id); + session.started = true; + session.remoteEndpointID = endpoint.getRemoteEndpointID(); + broadcastRtcommEvent(eventObject); + } + }, + 'session:alerting': sessionEstablishmentCallback, + + 'session:trying': sessionEstablishmentCallback, + + 'session:ringing': sessionEstablishmentCallback, + + 'session:queued': sessionEstablishmentCallback, + + 'session:failed': function(eventObject) { + + RtcommSessions.removeSession(eventObject.endpoint.id); + broadcastRtcommEvent(eventObject); + }, + + /** + * Handle when the endpoint stops the session + */ + 'session:stopped': function(eventObject) { + //Remove the session + RtcommSessions.removeSession(eventObject.endpoint.id); + + broadcastRtcommEvent(eventObject); + }, + + // These are all the WebRTC related events. + 'webrtc:connected': function(eventObject) { + + var session = RtcommSessions.getSession(eventObject.endpoint.id); + if (session !== null) { + session.webrtcConnected = true; + broadcastRtcommEvent(eventObject); + } + }, + 'webrtc:remotemuted': function(eventObject) { + broadcastRtcommEvent(eventObject); + }, + + 'webrtc:disconnected': function(eventObject) { + + var session = RtcommSessions.getSession(eventObject.endpoint.id); + if (session !== null) + session.webrtcConnected = false; + broadcastRtcommEvent(eventObject); + }, + + // These are all the chat related events. + 'chat:connected': broadcastRtcommEvent, + 'chat:disconnected': broadcastRtcommEvent, + + 'chat:message': function(eventObject) { + + //Create a message object + + var chat = { + time: new Date(), + name: eventObject.message.from, + message: angular.copy(eventObject.message.message) + }; + + var session = RtcommSessions.getSession(eventObject.endpoint.id); + + if (session !== null) { + session.chats.push(chat); + broadcastRtcommEvent(eventObject); + } + }, + + // Endpoint destroyed + 'destroyed': broadcastRtcommEvent + }); + } + + function broadcastRtcommEvent(eventObject) { + + $log.debug('<<------rtcomm-service------>> - Event: ' + eventObject.eventName + ' remoteEndpointID: ' + eventObject.endpoint.getRemoteEndpointID()); + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast(eventObject.eventName, eventObject); + } + ); + } + + function getPresenceRecord() { + if (presenceRecord == null) + presenceRecord = { + 'state': 'available', + userDefines: [] + }; + + return (presenceRecord); + }; + + function initSuccess(event) { + $log.debug('<<------rtcomm-service------>> - Event: Provider init succeeded'); + + if (presenceRecord != null) { + $log.debug('RtcommService: initSuccess: updating presence record'); + myEndpointProvider.publishPresence(presenceRecord); + } + + $rootScope.$evalAsync( + function() { + var broadcastEvent = { + 'ready': event.ready, + 'registered': event.registered, + 'endpoint': event.endpoint, + 'userid': RtcommConfigService.getProviderConfig().userid + }; + + $rootScope.$broadcast('rtcomm::init', true, broadcastEvent); + } + ); + }; + + function initFailure(error) { + $log.debug('<<------rtcomm-service------>> - Event: Provider init failed: error: ', error); + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('rtcomm::init', false, error); + } + ); + }; + + function _getEndpoint(uuid) { + var endpoint = null; + + if (typeof uuid === 'undefined' || uuid === null) { + $log.debug('getEndpoint: create new endpoint'); + endpoint = myEndpointProvider.createRtcommEndpoint(); + } else { + $log.debug('getEndpoint: get an endpoint with id -> ' + uuid); + endpoint = myEndpointProvider.getRtcommEndpoint(uuid); + } + + return (endpoint); + }; + + function _setActiveEndpoint(endpointID) { + + var activeEndpoint = _getActiveEndpointUUID(); + + if ((activeEndpoint !== null) && (activeEndpoint !== endpointID)) { + var session = RtcommSessions.getSession(activeEndpoint); + if (session !== null) + session.activated = false; + } + var session = RtcommSessions.getSession(endpointID); + + if (session === null) session = RtcommSessions.createSession(endpointID); + session.activated = true; + + + $rootScope.$broadcast('endpointActivated', endpointID); + }; + + function _getActiveEndpointUUID() { + var activeEndpoint = null; + var sessions = RtcommSessions.getAllSessions(); + + for (var index = 0; index < sessions.length; index++) { + if (sessions[index].activated === true) { + activeEndpoint = sessions[index].endpointUUID; + break; + } + } + return (activeEndpoint); + }; + + function alert(alertObject) { + var a = { + type: 'info', + msg: 'default message' + }; + if (typeof alertObject === 'string') { + a.msg = alertObject; + } else { + a = alertObject; + } + $rootScope.$evalAsync( + function() { + $rootScope.$broadcast('rtcomm::alert', a); + } + ); + }; + + /** External functionalities fror the RtcommService API */ + function isInitialized() { + return endpointProviderInitialized; + } + + function setConfig(config) { + + if (RtcommConfigService.isRtcommDisabled() == true) { + $log.debug('RtcommService:setConfig: isRtcommDisabled = true; return with no setup'); + return; + } + + if (config.rtcommDebug === 'INFO' || config.rtcommDebug === 'DEBUG') { + myEndpointProvider.setLogLevel(config.rtcommDebug); + } + $log.debug('rtcomm-services: setConfig: config: ', config); + + RtcommConfigService.setProviderConfig(config); + myEndpointProvider.setRtcommEndpointConfig(RtcommConfigService.getMediaConfig()); + + if (endpointProviderInitialized === false) { + + if (typeof config.identityServlet !== "undefined" && config.identityServlet != null) { + $http.get(config.identityServlet).success(function(data) { + + if (typeof data.userid !== "undefined") { + RtcommConfigService.setProviderConfig(data); + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + endpointProviderInitialized = true; + } else + $log.error('RtcommService: setConfig promise: Invalid JSON object return from identityServlet: ', data); + }).error(function(data, status, headers, config) { + $log.debug('RtcommService: setConfig promise: error accessing userid from identityServlet: ' + status); + }); + } else { + // If the user does not specify a userid, that says one will never be specified so go ahead + // and initialize the endpoint provider and let the provider assign a name. If a defined empty + // string is passed in, that means to wait until the end user registers a name. + if (typeof config.userid === 'undefined' || RtcommConfigService.getProviderConfig().userid !== '') { + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + endpointProviderInitialized = true; + } + } + } + } + + + function getPresenceMonitor(topic) { + return myEndpointProvider.getPresenceMonitor(topic); + } + + function publishPresence() { + + if (endpointProviderInitialized === true) + myEndpointProvider.publishPresence(getPresenceRecord()); + } + + function addToPresenceRecord(userDefines) { + + for (var index = 0; index < userDefines.length; index++) { + getPresenceRecord().userDefines.push(userDefines[index]); + } + + if (endpointProviderInitialized === true) { + $log.debug('RtcommService: addToPresenceRecord: updating presence record to: ', getPresenceRecord()); + myEndpointProvider.publishPresence(getPresenceRecord()); + } + } + + function removeFromPresenceRecord(userDefines, doPublish) { + + for (var i = 0; i < userDefines.length; i++) { + for (var j = 0; j < getPresenceRecord().userDefines.length; j++) { + + if (getPresenceRecord().userDefines[j].name === userDefines[i].name) { + getPresenceRecord().userDefines.splice(j, 1); + break; + } + } + } + + if ((endpointProviderInitialized === true) && doPublish) { + $log.debug('RtcommService: removeFromPresenceRecord: updating presence record to: ', getPresenceRecord()); + myEndpointProvider.publishPresence(getPresenceRecord()); + } + } + + function setPresenceRecordState(state) { + + getPresenceRecord().state = state; + return myEndpointProvider.publishPresence(getPresenceRecord()); + } + + function getEndpoint(uuid) { + return _getEndpoint(uuid); + } + + function destroyEndpoint(uuid) { + myEndpointProvider.getRtcommEndpoint(uuid).destroy(); + } + + function register(userid) { + + if (endpointProviderInitialized === false) { + RtcommConfigService.getProviderConfig().userid = userid; + + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + endpointProviderInitialized = true; + } else + $log.error('rtcomm-services: register: ERROR: endpoint provider already initialized'); + } + + function unregister() { + + if (endpointProviderInitialized == true) { + myEndpointProvider.destroy(); + endpointProviderInitialized = false; + initFailure('destroyed'); + } else + $log.error('rtcomm-services: unregister: ERROR: endpoint provider not initialized'); + } + + + /** + * Queue API + */ + function joinQueue(queueID) { + myEndpointProvider.joinQueue(queueID); + } + + function leaveQueue(queueID) { + myEndpointProvider.leaveQueue(queueID); + } + + function getQueues() { + return queueList; + } + + /** + * Chat API + */ + function sendChatMessage(chat, endpointUUID) { + + var session; + // Save this chat in the local session store + session = RtcommSessions.getSession(endpointUUID); + if (session === null) session = RtcommSessions.createSession(endpointUUID); + + session.chats.push(chat); + + myEndpointProvider.getRtcommEndpoint(endpointUUID).chat.send(chat.message); + + } + + function getChats(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) { + var session = RtcommSessions.getSession(endpointUUID); + if (session !== null) + return (session.chats); + else + return (null); + } else + return (null); + + } + + function isWebrtcConnected(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) { + var session = RtcommSessions.getSession(endpointUUID); + if (session != null) + return (session.webrtcConnected); + else + return (false); + } else + return (false); + } + + function getSessionState(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) + return (myEndpointProvider.getRtcommEndpoint(endpointUUID).getState()); + else + return ('session:stopped'); + } + + function setAlias(aliasID) { + + if ((typeof aliasID !== 'undefined') && aliasID !== '') + myEndpointProvider.setUserID(aliasID); + } + + function setUserID(userID) { + + if ((typeof userID !== 'undefined') && userID !== '') { + RtcommConfigService.setProviderConfig({ + userid: userID + }); + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + } + } + + function setPresenceTopic(presenceTopic) { + + if ((typeof presenceTopic !== 'undefined') && presenceTopic !== '') { + RtcommConfigService.setProviderConfig({ + presenceTopic: presenceTopic + }); + myEndpointProvider.init(RtcommConfigService.getProviderConfig(), initSuccess, initFailure); + } + + } + + function getIframeURL(endpointUUID) { + + if (typeof endpointUUID !== 'undefined' && endpointUUID != null) { + var session = RtcommSessions.getSession(endpointUUID); + if (session != null) + return (session.iFrameURL); + else + return (null); + } else + return (null); + } + + function putIframeURL(endpointUUID, newUrl) { + + + $log.debug('RtcommService: putIframeURL: endpointUUID: ' + endpointUUID + ' newURL: ' + newUrl); + var endpoint = myEndpointProvider.getRtcommEndpoint(endpointUUID); + + if (endpoint != null) { + var session = RtcommSessions.getSession(endpointUUID); + + if (session === null) session = RtcommSessions.createSession(endpointUUID); + session.iFrameURL = newUrl; + + var message = { + type: 'iFrameURL', + iFrameURL: newUrl + }; + + $log.debug('RtcommService: putIframeURL: sending new iFrame URL'); + endpoint.sendOneTimeMessage(message); + } + } + + function placeCall(calleeID, mediaToEnable) { + + //Create new endpoint + var endpoint = _getEndpoint(); + + if (mediaToEnable.indexOf('chat') > -1) + endpoint.chat.enable(); + + if (mediaToEnable.indexOf('webrtc') > -1) { + // Support turning off trickle ICE + var trickleICE = true; + if (mediaToEnable.indexOf('disableTrickleICE') > -1) { + trickleICE = false; + } + endpoint.webrtc.enable({ + 'trickleICE': trickleICE + }); + } + _setActiveEndpoint(endpoint.id); + endpoint.connect(calleeID); + return (endpoint.id); + } + + function getSessions() { + return RtcommSessions.getAllSessions(); + } + + function endCall(endpoint) { + endpoint.disconnect(); + } + + function setActiveEndpoint(endpointID) { + _setActiveEndpoint(endpointID); + } + + function getActiveEndpoint() { + return _getActiveEndpointUUID(); + } + + function getRemoteEndpoint(localEndpointID) { + + + var remoteEndpointID = null; + + if (localEndpointID != null) { + var session = RtcommSessions.getSession(localEndpointID); + + if (session != null) { + remoteEndpointID = session.remoteEndpointID; + } + } + + return (remoteEndpointID); + } + + function setDefaultViewSelector() { + + _selfView = 'selfView'; + _remoteView = 'remoteView'; + } + + function setViewSelector(selfView, remoteView) { + _selfView = selfView; + _remoteView = remoteView; + } + + function setVideoView(endpointUUID) { + + $log.debug('rtcommVideo: setting local media'); + var endpoint = null; + + if (typeof endpointUUID !== 'undefined' && endpointUUID !== null) + endpoint = _getEndpoint(endpointUUID); + else if (_getActiveEndpointUUID() != null) + endpoint = _getEndpoint(_getActiveEndpointUUID()); + + if (endpoint != null) { + $log.debug(endpoint); + endpoint.webrtc.setLocalMedia({ + mediaOut: document.querySelector('#' + _selfView), + mediaIn: document.querySelector('#' + _remoteView) + }); + } + } + } +})(); diff --git a/src/js/services/rtcomm-service/rtcomm-service.spec.js b/src/js/services/rtcomm-service/rtcomm-service.spec.js new file mode 100644 index 0000000..4f4f01e --- /dev/null +++ b/src/js/services/rtcomm-service/rtcomm-service.spec.js @@ -0,0 +1,205 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('Unit Testing: RtcommService', function(){ + //Dependencies + var $rootScope, $httpBackend, RtcommConfigService, rtcomm; + + //Mock and stubbing sandbox + var sandbox; + + var RtcommService; + + + beforeEach(function(){ + module('angular-rtcomm-service'); + }); + + beforeEach(function(){ + + var rtcomm = generateMockRtcomm(); + module(function($provide){ + $provide.constant('rtcomm', rtcomm); + }); + }); + + beforeEach(inject(['$rootScope', 'RtcommConfigService', 'rtcomm', '$httpBackend', 'RtcommService', + function(_$rootScope_, _RtcommConfigService_, _rtcomm_, _$httpBackend_, _RtcommService_){ + + $rootScope = _$rootScope_; + RtcommConfigService = _RtcommConfigService_; + rtcomm = _rtcomm_; + $httpBackend = _$httpBackend_; + RtcommService = _RtcommService_; + sandbox = sinon.sandbox.create(); + }])); + + afterEach(function(){ + sandbox.restore(); + }); + describe('initialization without user id', function(){ + + it('check state before init', function(){ + expect(RtcommService.isInitialized()).to.be.false; + }); + + it('should still not initialize without a userid defined', function(){ + var config = { + userid: '' + }; + sandbox.stub(RtcommConfigService, 'setProviderConfig', function(config){}); + sandbox.stub(RtcommConfigService, 'getMediaConfig', function(){}); + RtcommService.setConfig(config); + + expect(RtcommConfigService.setProviderConfig.calledWith(config)).to.be.true; + expect(RtcommConfigService.getMediaConfig.calledOnce).to.be.true; + expect(RtcommService.isInitialized()).to.be.false; + }); + }); + + describe('setConfig functionalities', function(){ + var sampleConfig = { + server: 'localhost', + port: '80', + rtcommTopicPath: '/rtcomm/', + userid: '' + }; + it('should do nothing if isRtcommDisabled', function(){ + sandbox.stub(RtcommConfigService, 'isRtcommDisabled', function(){ return true;}); + + RtcommService.setConfig({}); + expect(RtcommConfigService.isRtcommDisabled.calledOnce).to.be.true; + + expect(RtcommService.isInitialized()).to.be.false; + }); + + it('should setConfiguration but not initialize if the userid is not set', function(){ + + sandbox.stub(RtcommConfigService, 'setProviderConfig', function(config){}); + sandbox.stub(RtcommConfigService, 'getMediaConfig', function(){}); + sandbox.stub(RtcommConfigService, 'getProviderConfig', function(){return sampleConfig}); + + RtcommService.setConfig(sampleConfig); + + expect(RtcommConfigService.setProviderConfig.calledWith(sampleConfig)).to.be.true; + expect(RtcommService.isInitialized()).to.be.false; + }); + + it('should initialize if a userid is defined', function(){ + sandbox.stub(RtcommConfigService, 'setProviderConfig', function(config){}); + sandbox.stub(RtcommConfigService, 'getMediaConfig', function(){}); + sandbox.stub(RtcommConfigService, 'getProviderConfig', function(){return sampleConfig}); + sampleConfig.userid = 'MockUser'; + RtcommService.setConfig(sampleConfig); + + expect(RtcommService.isInitialized()).to.be.true; + }); + + + }); + //TODO Need better presence test methods + describe('presence related events', function(){ + it('should get an empty presence monitor', function(){ + expect(RtcommService.getPresenceMonitor).to.not.be.undefined; + var presenceMonitor = RtcommService.getPresenceMonitor('someTopic'); + + expect(presenceMonitor).to.be.empty; + + }); + + it('should be able to publish a presence', function(){ + expect(RtcommService.publishPresence).to.not.be.undefined; + + //Initialize first + RtcommService.publishPresence(); + }); + + }); + + it('should have the API defined for backward compability', function(){ + + expect(RtcommService.alert).to.not.be.undefined; + expect(RtcommService.isInitialized).to.not.be.undefined; + expect(RtcommService.setConfig).to.not.be.undefined; + expect(RtcommService.getPresenceMonitor).to.not.be.undefined; + expect(RtcommService.publishPresence).to.not.be.undefined; + expect(RtcommService.addToPresenceRecord).to.not.be.undefined; + expect(RtcommService.removeFromPresenceRecord).to.not.be.undefined; + expect(RtcommService.setPresenceRecordState).to.not.be.undefined; + expect(RtcommService.getEndpoint).to.not.be.undefined; + expect(RtcommService.destroyEndpoint).to.not.be.undefined; + expect(RtcommService.register).to.not.be.undefined; + expect(RtcommService.unregister).to.not.be.undefined; + expect(RtcommService.joinQueue).to.not.be.undefined; + expect(RtcommService.leaveQueue).to.not.be.undefined; + expect(RtcommService.getQueues).to.not.be.undefined; + expect(RtcommService.sendChatMessage).to.not.be.undefined; + expect(RtcommService.getChats).to.not.be.undefined; + expect(RtcommService.isWebrtcConnected).to.not.be.undefined; + expect(RtcommService.getSessionState).to.not.be.undefined; + expect(RtcommService.setAlias).to.not.be.undefined; + expect(RtcommService.setUserID).to.not.be.undefined; + expect(RtcommService.setPresenceTopic).to.not.be.undefined; + expect(RtcommService.getIframeURL).to.not.be.undefined; + expect(RtcommService.putIframeURL).to.not.be.undefined; + expect(RtcommService.placeCall).to.not.be.undefined; + expect(RtcommService.getSessions).to.not.be.undefined; + expect(RtcommService.endCall).to.not.be.undefined; + expect(RtcommService.setActiveEndpoint).to.not.be.undefined; + expect(RtcommService.getActiveEndpoint).to.not.be.undefined; + expect(RtcommService.getRemoteEndpoint).to.not.be.undefined; + expect(RtcommService.setDefaultViewSelector).to.not.be.undefined; + expect(RtcommService.setViewSelector).to.not.be.undefined; + expect(RtcommService.setVideoView).to.not.be.undefined; + }); + //Helper functions + function generateMockRtcomm(){ + + return { + EndpointProvider: MockEndpointProvider + + }; + + + } + + function MockEndpointProvider(){ + this.setLogLevel = function(level){ + }; + this.getLogLevel = function(){ + return 'DEBUG';}; + + this.setAppContext = function(appContext){}; + + this.on = function(eventName, func){}; + + this.setRtcommEndpointConfig = function(configurationCallbacks){}; + + this.getPresenceMonitor = function(topic){ return {}}; + + this.publishPresence = function(record){}; + + this.createRtcommEndpoint = function() { return null; }; + + this.getRtcommEndpoint = function(id) { return null; }; + + this.init = function(providerConfig, successCallback, failureCallback){}; + + } + + +}); diff --git a/src/js/services/services.module.js b/src/js/services/services.module.js new file mode 100644 index 0000000..91da229 --- /dev/null +++ b/src/js/services/services.module.js @@ -0,0 +1,24 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-service', []); +})(); diff --git a/src/js/services/sessions/sessions.service.js b/src/js/services/sessions/sessions.service.js new file mode 100644 index 0000000..f685349 --- /dev/null +++ b/src/js/services/sessions/sessions.service.js @@ -0,0 +1,115 @@ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-service') + .factory('RtcommSessions', RtcommSessions); + + /* @ngInject */ + function RtcommSessions($log) { + var service = { + getAllSessions: getAllSessions, + createSession: createSession, + getSession: getSession, + updateSession: updateSession, + removeSession: removeSession + + }; + + var sessions = []; + return service; + + //////////////// + + function getAllSessions() { + return sessions; + } + + function removeAllSessions() { + + sessions.forEach(function(session) { + removeSession(session.endpointUUID); + }); + } + + function getSession(endpointUUID) { + $log.debug('Retrieving session linked to EndpointUUID: ' + endpointUUID); + + var session = null; + sessions.forEach(function(_session) { + if (_session.endpointUUID === endpointUUID) { + session = _session; + } + }); + + return session; + } + + function createSession(endpointUUID) { + $log.debug('Creating a session for EndpointUUID: ' + endpointUUID); + + var session; + + /* Define a session */ + session = { + + endpointUUID: endpointUUID, + remoteEndpointID: null, + chats: [], + webrtcConnected: false, + started: false, + state: 'session:stopped', + activated: true, + iFrameURL: 'about:blank', + }; + sessions.push(session); + return session; + + } + + function updateSession(endpointUUID, config) { + + $log.debug('Updating session for EndpointUUID: ' + endpointUUID); + + var session = getSession(endpointUUID); + + if (typeof session === 'undefined') + $log.debug('Unable to update endpoint due to it not existing'); + else { + + for (var property in session) { + if (session.hasOwnProperty(property)) { + + session[property] = typeof config[property] !== 'undefined' ? config[property] : session[property]; + } + } + } + + return session; + + } + + function removeSession(endpointUUID) { + $log.debug('Destroy session for EndpointUUID: ' + endpointUUID); + var session; + for (var i = 0; i < sessions.length; i++) { + session = sessions[i]; + + if (session.endpointUUID === endpointUUID) { + sessions.splice(i, 1); + + $log.debug('Session with endpointUUID === ' + endpointUUID + 'has been removed'); + break; + } + } + + if (session === null) { + $log.debug('Unable to destroy session due to it not existing'); + } + return session; + + } + + + } +})(); diff --git a/src/js/services/sessions/sessions.service.spec.js b/src/js/services/sessions/sessions.service.spec.js new file mode 100644 index 0000000..c7a7643 --- /dev/null +++ b/src/js/services/sessions/sessions.service.spec.js @@ -0,0 +1,87 @@ +describe('Unit Testing: RtcommSessions', function(){ + + var RtcommSessions; + + beforeEach(module('angular-rtcomm-service')); + + beforeEach(inject(function(_RtcommSessions_){ + RtcommSessions = _RtcommSessions_; + })); + + it('should be able to create a session', function(){ + + var session = RtcommSessions.createSession('MockID'); + + expect(session.endpointUUID).to.equal('MockID'); + expect(session.remoteEndpointID).to.be.null; + expect(session.chats).to.be.empty; + expect(session.webrtcConnected).to.be.false; + expect(session.started).to.be.false; + expect(session.state).to.equal('session:stopped'); + expect(session.activated).to.equal(true); + expect(session.iFrameURL).to.equal('about:blank'); + }); + + it('should be able to retrieve created sessions', function(){ + + //Create some session + var N = 5; + for(var i = 0; i < N; i++){ RtcommSessions.createSession('MockID'+i);} + + var session; + for(var i =0; i < N; i++){ + session = RtcommSessions.getSession('MockID'+i); + expect(session.endpointUUID).to.equal('MockID'+i); + } + }); + + it('should return a null session if it wasn\'t created', function(){ + var session = RtcommSessions.getSession('MockID0'); + + expect(session).to.be.null; + }); + + it('should update an existing session', function(){ + var id = 'MockID42'; + + RtcommSessions.createSession(id); + + RtcommSessions.updateSession(id, { state: 'session:started'}); + + var session = RtcommSessions.getSession(id); + + expect(session.state).to.equal('session:started'); + }); + + it('should destroy an existing session', function(){ + var id = 'MockID45'; + var session; + + RtcommSessions.createSession(id); + + session = RtcommSessions.getSession(id); + expect(session).to.not.be.undefined; + + RtcommSessions.removeSession(id); + session = RtcommSessions.getSession(id); + + expect(session).to.be.null; + }); + + it('should update properties on returned object', function(){ + var session = RtcommSessions.createSession('ID'); + + session.state = 'session:started'; + + var _session = RtcommSessions.getSession('ID'); + expect(session.state).to.equal(_session.state); + + session.chats.push({message: 'Hello World!'}); + + _session = RtcommSessions.getSession('ID'); + expect(session.chats).to.deep.equal(_session.chats); + }); + + + +}); diff --git a/src/js/ui/config.controller.js b/src/js/ui/config.controller.js new file mode 100644 index 0000000..6ea4f8d --- /dev/null +++ b/src/js/ui/config.controller.js @@ -0,0 +1,80 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This is the controller for config loader. It reads a JSON object and utilizes the RtcommService to set the configuration. + * This can also result in the initialization of the endpoint provider if the config JSON object includes a registration name. + * + * Here is an example of the config object: + * + * { + * "server" : "server address", + * "port" : 1883, + * "rtcommTopicPath" : "/rtcomm-helpdesk/", + * "createEndpoint" : false, + * "userid" : "registration name", + * "broadcastAudio" : true, + * "broadcastVideo" : true + * } + * + * NOTE: If the user does not specify a userid, that says one will never be specified so go ahead + * and initialize the endpoint provider and let the provider assign a name. If a defined empty + * string is passed in, that means to wait until the end user registers a name before initializing + * the endpoint provider. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommConfigController', RtcommConfigController); + + RtcommConfigController.$inject = ['RtcommService', '$http', '$scope', '$log']; + + /* @ngInject */ + function RtcommConfigController(RtcommService, $http, $scope, $log) { + var vm = this; + vm.extendedConfig = null; + + $log.debug('RtcommConfigController: configURL = ' + vm.configURL); + + $scope.init = function(configURL, extendedConfig) { + + $log.debug('RtcommConfigController: initing configURL = ' + configURL); + vm.configURL = configURL; + + if (typeof extendedConfig !== 'undefined') + vm.extendedConfig = extendedConfig; + + vm.getConfig(); + }; + + vm.getConfig = function() { + $http.get(vm.configURL).success(function(config) { + + // Now we need to update the config with any extensions passed in on init. + if (vm.extendedConfig != null) { + angular.extend(config, vm.extendedConfig); + $log.debug('RtcommConfigController: extended config object: ' + config); + } + + RtcommService.setConfig(config); + }).error(function(data, status, headers, config) { + $log.debug('RtcommConfigController: error accessing config: ' + status); + }); + }; + } +})(); diff --git a/src/js/ui/config.controller.spec.js b/src/js/ui/config.controller.spec.js new file mode 100644 index 0000000..36661aa --- /dev/null +++ b/src/js/ui/config.controller.spec.js @@ -0,0 +1,103 @@ +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Testing: RtcommConfigController', function() { + + var sandbox; + + var $rootScope, RtcommService, $compile, $httpBackend, rtcommConfigGET, rtcommConfig, $log; + + beforeEach(module('rtcomm.templates')); + + beforeEach(module('angular-rtcomm-ui')); + + beforeEach(inject( + function($injector) { + + sandbox = sinon.sandbox.create(); + $rootScope = $injector.get('$rootScope'); + RtcommService = $injector.get('RtcommService'); + $compile = $injector.get('$compile'); + $httpBackend = $injector.get('$httpBackend'); + $log = $injector.get('$log'); + rtcommConfig = { + 'rtcommTopicPath': '/rtcomm/', + 'createEndpoint': true, + 'presenceTopic': 'sampleRoom', + 'broadcastVideo': true, + 'broadcastAudio': true, + 'userid': '' + }; + + rtcommConfigGET = $httpBackend.when('GET', 'rtcommConfig.json'); + rtcommConfigGET.respond(rtcommConfig); + + + } + )); + + afterEach(function() { + sandbox.restore(); + }); + + it('should initialize with a simple config', function() { + sandbox.stub(RtcommService, 'setConfig', function(data) { + expect(data).to.deep.equal(angular.extend(rtcommConfig, {})); + }); + + $httpBackend.expectGET('rtcommConfig.json'); + + var rtcommConfigDiv = compileRtcommConfigController(); + + $httpBackend.flush(); + + }); + + it('should combine the simple config and extended config', function() { + + sandbox.stub(RtcommService, 'setConfig', function(data) { + expect(data).to.deep.equal(angular.extend(rtcommConfig, { + chat: false + })); + }); + $httpBackend.expectGET('rtcommConfig.json'); + + var rtcommConfigDiv = compileRtcommConfigController({ + 'chat': false + }); + + $httpBackend.flush(); + + }); + + it('should display an error on accessing the config', function() { + rtcommConfigGET.respond(404, ''); + sandbox.spy($log, 'error'); + + var rtcommConfigDiv = compileRtcommConfigController({}); + + $httpBackend.flush(); + + expect($log.calledOnce); + }); + + function compileRtcommConfigController(extendedConfig) { + var html = '
'; + var configCtrl = $compile(html)($rootScope); + return configCtrl; + } +}); diff --git a/src/js/ui/endpoint-provider/rtcomm-alert/rtcomm-alert.js b/src/js/ui/endpoint-provider/rtcomm-alert/rtcomm-alert.js new file mode 100644 index 0000000..61ac3f0 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-alert/rtcomm-alert.js @@ -0,0 +1,53 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommAlert', rtcommAlert); + + /* @ngInject */ + function rtcommAlert() { + var directive = { + restrict: 'E', + templateUrl: "templates/rtcomm/rtcomm-alert.html", + controller: AlertController, + controllerAs: 'alertVM', + bindToController: true + }; + + return directive; + } + + AlertController.$inject = ['$scope', '$log']; + + /* @ngInject */ + function AlertController($scope, $log) { + var vm = this; + vm.alerts = []; + vm.addAlert = function(alert) { + vm.alerts.push(alert); + }; + vm.closeAlert = function(index) { + vm.alerts.splice(index, 1); + }; + $scope.$on('rtcomm::alert', function(event, eventObject) { + vm.addAlert(eventObject); + }); + } +})(); diff --git a/src/js/ui/endpoint-provider/rtcomm-alert/rtcomm-alert.spec.js b/src/js/ui/endpoint-provider/rtcomm-alert/rtcomm-alert.spec.js new file mode 100644 index 0000000..e71f6e7 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-alert/rtcomm-alert.spec.js @@ -0,0 +1,68 @@ + + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Testing: RtcommAlert directive', function(){ + var _$rootScope, element; + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); beforeEach(module("rtcomm.templates")); + + beforeEach(inject(function($compile, $rootScope) { + _$rootScope = $rootScope; + element = $compile('')(_$rootScope); + _$rootScope.$digest(); + + })); + + it('alert directive should be available', function(){ + expect(element.html()).to.include('alert in alertVM.alerts'); + }); + + it('should create an alert object on rtcomm::alert', function(){ + var type = 'error', msg = 'Disconnected from the server!'; + _$rootScope.$broadcast('rtcomm::alert', createEventObject(type, msg) ); + _$rootScope.$digest(); + + var alertElements = element.find('.alert'); + expect(angular.element(alertElements[0]).html()).to.include(msg); + }); + + it('should delete an alert object on close click', function(){ + var type = 'error', msg = 'Disconnected from the server!'; + _$rootScope.$broadcast('rtcomm::alert', createEventObject(type, msg) ); + _$rootScope.$digest(); + var alertElements = element.find('.alert'); + var alert = angular.element(alertElements[0]); + var closeBtn = alert.find('button'); + closeBtn.click(); + _$rootScope.$digest(); + + var alertElements = element.find('.alert'); + + expect(alertElements.length).to.equal(0); + }) + + function createEventObject(_type, _msg){ + return { + type: _type, + msg: _msg + } + } + // it() +}) diff --git a/src/js/ui/endpoint-provider/rtcomm-queues/rtcomm-queues.js b/src/js/ui/endpoint-provider/rtcomm-queues/rtcomm-queues.js new file mode 100644 index 0000000..f89fed1 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-queues/rtcomm-queues.js @@ -0,0 +1,156 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive manages call queues. It provides the ability to display all the available queues + * (along with their descriptions) and by clicking on a queue, allows an agent (or any type of user) + * to subscribe on that queue. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommQueues', rtcommQueues); + + /* @ngInject */ + function rtcommQueues() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-queues.html', + controller: QueuesController, + controllerAs: 'queuesVM', + bindToController: true + }; + + return directive; + + } + + QueuesController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function QueuesController(RtcommService, $scope, $log) { + var vm = this; + + vm.rQueues = []; + vm.autoJoinQueues = false; + vm.queuePresenceData = []; + vm.queuePublishPresence = false; + vm.queueFilter = null; + + /** + * autoJoinQueues - automatically join any queues that are not filtered out + * queuePublishedPresence - will add to the presence document information about what queues this person joins. + * queueFilter - If defined, this specifies which queues should be joined. All others will be ignored. + */ + $scope.init = function(autoJoinQueues, queuePublishPresence, queueFilter) { + $log.debug('rtcommQueues: autoJoinQueues = ' + autoJoinQueues); + vm.autoJoinQueues = autoJoinQueues; + vm.queuePublishPresence = queuePublishPresence; + if (typeof queueFilter !== "undefined") + vm.queueFilter = queueFilter; + }; + + // + vm.filterOutQueue = function(queue) { + var returnValue = true; + + if (vm.queueFilter != null) { + + for (var index = 0; index < vm.queueFilter.length; ++index) { + var entry = vm.queueFilter[index]; + if (entry == queue.endpointID) { + returnValue = false; + break; + } + } + } else + returnValue = false; + + return (returnValue); + }; + + vm.onQueueClick = function(queue) { + $log.debug('rtcommQueues: onClick: TOP'); + for (var index = 0; index < vm.rQueues.length; index++) { + if (vm.rQueues[index].endpointID === queue.endpointID) { + $log.debug('rtcommQueues: onClick: queue.endpointID = ' + queue.endpointID); + + if (queue.active == false) { + RtcommService.joinQueue(queue.endpointID); + vm.rQueues[index].active = true; + } else { + RtcommService.leaveQueue(queue.endpointID); + vm.rQueues[index].active = false; + } + } else if (index == (vm.rQueues.length - 1)) { + $log.debug('rtcommQueues: ERROR: queue.endpointID: ' + queue.endpointID + ' not found in list of queues'); + + } + } + + vm.updateQueuePresence(); + }; + + vm.updateQueuePresence = function() { + // Update the presence record if enabled + if (vm.queuePublishPresence == true) { + RtcommService.removeFromPresenceRecord(vm.queuePresenceData, false); + + vm.queuePresenceData = []; + + for (var index = 0; index < vm.rQueues.length; index++) { + if (vm.rQueues[index].active === true) { + vm.queuePresenceData.push({ + 'name': "queue", + 'value': vm.rQueues[index].endpointID + }); + } + } + + RtcommService.addToPresenceRecord(vm.queuePresenceData); + } + } + + $scope.$on('queueupdate', function(event, queues) { + $log.debug('rtcommQueues: scope queues', vm.rQueues); + Object.keys(queues).forEach(function(key) { + $log.debug('rtcommQueues: Push queue: ' + queues[key]); + $log.debug('rtcommQueues: autoJoinQueues: ' + vm.autoJoinQueues); + + // Check to make sure queue is not filteres out before adding it. + if (vm.filterOutQueue(queues[key]) == false) { + vm.rQueues.push(queues[key]); + // If autoJoin we go ahead and join the queue as soon as we get the queue update. + if (vm.autoJoinQueues == true) { + vm.onQueueClick(queues[key]); + } + } + }); + + vm.updateQueuePresence(); + }); + + $scope.$on('rtcomm::init', function(event, success, details) { + if (success == false) { + $log.debug('rtcommQueues: init: clear queues'); + vm.rQueues = []; + } + }); + + } +})(); diff --git a/src/js/ui/endpoint-provider/rtcomm-queues/rtcomm-queues.spec.js b/src/js/ui/endpoint-provider/rtcomm-queues/rtcomm-queues.spec.js new file mode 100644 index 0000000..9b72a83 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-queues/rtcomm-queues.spec.js @@ -0,0 +1,243 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +//TODO Finish rtcomm-queues unit test +describe('Unit Testing: RtcommQueues directive', function() { + + //Dependencies + var $rootScope, RtcommService, $scope, $log, $compile, rtcommQueues; + + var sandbox; + + beforeEach(module('rtcomm.templates')); + + beforeEach(module('angular-rtcomm-ui')); + + beforeEach(inject( + function($injector) { + sandbox = sinon.sandbox.create(); + $rootScope = $injector.get('$rootScope'); + RtcommService = $injector.get('RtcommService'); + $compile = $injector.get('$compile'); + + } + )); + afterEach(function() { + sandbox.restore(); + }); + + it('queues directive should be available', function() { + var rtcommQueue = compileRtcommQueue(false, false, false); + expect(rtcommQueue.html()).to.include('class="queueContainer"'); + }); + + it('should update the queuelist correctly on update', function() { + + var rtcommQueue = compileRtcommQueue(false, false); + + var mockQueues = [ + createMockQueue({ + active: false, + endpointID: 'Mock Queue' + }), + createMockQueue({ + active: true, + endpointID: 'Mock Queue 2' + }) + ]; + + //Emit queueupdate + $rootScope.$broadcast('queueupdate', mockQueues); + $rootScope.$digest(); + + //All Queues should be visible + var queuesElements = rtcommQueue.find('button'); + expect(queuesElements.length).to.equal(mockQueues.length); + + for (var i = 0; i < queuesElements.length; i++) { + var mockQueue = mockQueues[i]; + var actionString = mockQueue.active ? 'Leave ' : 'Join '; + expect(queuesElements[i].innerHTML).to.equal(actionString + mockQueues[i].endpointID); + } + }); + + it('should filter out queues correctly', function() { + var rtcommQueue = compileRtcommQueue(false, false, ['Mock Queue 2']); + + var mockQueues = [ + createMockQueue({ + active: false, + endpointID: 'Mock Queue' + }), + createMockQueue({ + active: true, + endpointID: 'Mock Queue 2' + }) + ]; + + //Emit queueupdate + $rootScope.$broadcast('queueupdate', mockQueues); + $rootScope.$digest(); + var queuesElements = rtcommQueue.find('button'); + expect(queuesElements.length).to.equal(1); + + expect(queuesElements[0].innerHTML).to.equal('Leave Mock Queue 2'); + }); + + it('when autojoin is enabled it should join the queues', function() { + sandbox.stub(RtcommService, 'joinQueue', function(id) {}); + + var rtcommQueue = compileRtcommQueue(true, false); + + var mockQueues = [ + createMockQueue({ + active: false, + endpointID: 'Mock Queue' + }) + ]; + + //Emite queueupdate + + $rootScope.$broadcast('queueupdate', mockQueues); + $rootScope.$digest(); + + var queueElement = rtcommQueue.find('button'); + expect(queueElement.length).to.equal(1); + expect(queueElement.html()).to.equal('Leave Mock Queue'); + // expect(RtcommService.joinQueue.called).to.be.true; + expect(RtcommService.joinQueue.calledWith('Mock Queue')).to.be.true; + + }); + + it('should be able to join and leave a queue', function() { + sandbox.stub(RtcommService, 'joinQueue', function(id) {}); + sandbox.stub(RtcommService, 'leaveQueue', function(id) {}); + var rtcommQueue = compileRtcommQueue(false, false); + + var mockQueues = [ + createMockQueue({ + active: false, + endpointID: 'Mock Queue' + }) + ]; + + //Emit queueupdate + $rootScope.$broadcast('queueupdate', mockQueues); + $rootScope.$digest(); + + var queueElement = rtcommQueue.find('button'); + expect(queueElement.length).to.equal(1); + + + expect(queueElement.html()).to.equal('Join Mock Queue'); + + queueElement.click(); + expect(RtcommService.joinQueue.calledWith('Mock Queue')).to.be.true; + + + expect(queueElement.html()).to.equal('Leave Mock Queue'); + queueElement.click(); + + expect(RtcommService.leaveQueue.calledWith('Mock Queue')).to.be.true; + + expect(queueElement.html()).to.equal('Join Mock Queue'); + + }); + + + it('should publish queue status on presence', function() { + sandbox.stub(RtcommService, 'removeFromPresenceRecord', function(id) {}); + sandbox.stub(RtcommService, 'addToPresenceRecord', function(presenceData) {}); + sandbox.stub(RtcommService, 'joinQueue', function(id) {}); + sandbox.stub(RtcommService, 'leaveQueue', function(id) {}); + + + var rtcommQueue = compileRtcommQueue(false, true); + + var mockQueues = [ + createMockQueue({ + active: false, + endpointID: 'Mock Queue' + }) + ]; + + //Emit queueupdate + $rootScope.$broadcast('queueupdate', mockQueues); + $rootScope.$digest(); + + var queueElement = rtcommQueue.find('button'); + expect(queueElement.length).to.equal(1); + + queueElement.click(); + + + expect(RtcommService.joinQueue.calledWith('Mock Queue')).to.be.true; + expect(RtcommService.removeFromPresenceRecord.calledWith([], false)).to.be.true; + + expect(RtcommService.addToPresenceRecord.calledWith([{ + name: 'queue', + value: 'Mock Queue' + }])).to.be.true; + + }); + + it('should empty queues on rtcomm::init', function() { + var rtcommQueue = compileRtcommQueue(false, false); + + var mockQueues = [ + createMockQueue({ + active: false, + endpointID: 'Mock Queue' + }) + ]; + + //Emit queueupdate + $rootScope.$broadcast('queueupdate', mockQueues); + $rootScope.$digest(); + + var queueElement = rtcommQueue.find('button'); + + expect(queueElement.length).to.equal(1); + + $rootScope.$broadcast('rtcomm::init', false); + $rootScope.$digest(); + queueElement = rtcommQueue.find('button'); + + expect(queueElement.length).to.equal(0); + + }); + + + //Helper functions + function compileRtcommQueue(autoJoinQueues, queuePublishPresence, queueFilter) { + var html = ''; + var rtcommQueue = $compile(html)($rootScope); + + $rootScope.$digest(); + return rtcommQueue; + } + + function createMockQueue(options) { + return { + active: options.active ? options.active : false, + description: options.description || 'Default description', + title: options.title || 'Default Queue Title', + endpointID: options.endpointID || 'Queue ID' + }; + } +}); diff --git a/src/js/ui/endpoint-provider/rtcomm-register/rtcomm-register.js b/src/js/ui/endpoint-provider/rtcomm-register/rtcomm-register.js new file mode 100644 index 0000000..fbb57f0 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-register/rtcomm-register.js @@ -0,0 +1,89 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive is used to manage the registration of an endpoint provider. Since the registered name can only + * be set on initialization of the endpoint provider, this directive actually controls the initialization of the + * provider. Note that the endpoint provider must be initialized before any sessions can be created or received. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommRegister', rtcommRegister); + + /* @ngInject */ + function rtcommRegister() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-register.html', + controller: RegisterController, + controllerAs: 'registerVM', + bindToController: true + }; + + return directive; + + } + + RegisterController.$inject = ['RtcommService', '$scope', '$log']; + + // /* @ngInject */ + function RegisterController(RtcommService, $scope, $log) { + var vm = this; + + vm.nextAction = 'Register'; + vm.reguserid = ''; + vm.invalid = false; + + var invalidCharacters = /(\$|#|\+|\/|\\)+/i; //Invalid characters for MQTT Topic Path + + vm.onRegClick = function() { + if (vm.nextAction === 'Register' && !invalidCharacters.test(vm.reguserid)) { + $log.debug('Register: reguserid =' + vm.reguserid); + RtcommService.register(vm.reguserid); + } else { + $log.debug('Unregister: reguserid =' + vm.reguserid); + RtcommService.unregister(); + } + }; + + //Watch for changes in reguserid + $scope.$watch(function(){ return vm.reguserid}, function() { + + if (vm.reguserid.length < 1 || invalidCharacters.test(vm.reguserid)) { + vm.invalid = true; + } else { + vm.invalid = false; + } + }); + + $scope.$on('rtcomm::init', function(event, success, details) { + + vm.nextAction = success ? 'Unregister' : 'Register'; + + if (success === true) { + vm.reguserid = details.userid; + } else { + if (details === 'destroyed') + vm.reguserid = ''; + else + vm.reguserid = 'Init failed:' + details; + } + }); + } +})(); diff --git a/src/js/ui/endpoint-provider/rtcomm-register/rtcomm-register.spec.js b/src/js/ui/endpoint-provider/rtcomm-register/rtcomm-register.spec.js new file mode 100644 index 0000000..2f8fa69 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-register/rtcomm-register.spec.js @@ -0,0 +1,189 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('Unit Testing: Register directive', function() { + var $compile, _$rootScope, sandbox, scope, ctrl, element; + + + var input, btn; + + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); + + //Mock RtcommService + beforeEach(function() { + RtcommService = { + register: function(userid) { + _$rootScope.$broadcast('rtcomm::init', true, { + userid: userid + }); + }, + unregister: function() { + _$rootScope.$broadcast('rtcomm::init', false, 'destroyed'); + } + } + + module(function($provide) { + $provide.value('RtcommService', RtcommService); + }); + }); + + //Setup Test + beforeEach(inject(function($compile, $rootScope) { + _$rootScope = $rootScope; + + + scope = $rootScope; + element = $compile('')(scope); + scope.$digest(); + + sandbox = sinon.sandbox.create(); + input = element.find('input'); + btn = element.find('button'); + + })); + + afterEach(function() { + sandbox.restore(); + + }); + + it('directive should compile', function() { + expect(element.html()).to.include('id="register-input"'); + }); + + it('initial state should be defined as nextAction = Register and userid empty', function() { + + expect(btn.html()).to.include('Register'); + expect(input.val()).to.be.empty; + + //Empty input should be disabled + expect(btn.is(':disabled')).to.be.true; + + }); + + it('should say "Unregister" when initialized and back to "Register" when uninitialized', function() { + + sandbox.spy(_$rootScope, '$broadcast'); //Spy for broadcasts called + + //Emit the 'rtcomm::init' event + _$rootScope.$broadcast('rtcomm::init', true, { + userid: 'MockUser' + }); + // Force changes on UI + _$rootScope.$digest(); + + expect(_$rootScope.$broadcast.calledOnce).to.be.true; + expect(btn.html()).to.include('Unregister'); + expect(input.val()).to.include('MockUser'); + + + _$rootScope.$broadcast('rtcomm::init', false, 'destroyed'); + _$rootScope.$digest(); + + expect(_$rootScope.$broadcast.called).to.be.true; + expect(btn.html()).to.include('Register'); + expect(input.val()).to.be.empty; + + }); + + it('should display an error with details when failure to initialize', function() { + sandbox.spy(_$rootScope, '$broadcast'); + var error = 'SERVICE_QUERY_FAILED'; + + _$rootScope.$broadcast('rtcomm::init', false, error); + + _$rootScope.$digest(); + + expect(_$rootScope.$broadcast.calledOnce).to.be.true; + expect(input.val()).to.include(error); + }); + + it('should successfully register using the input and btn -> Input should be disabled', function() { + + //Fill input + input.val('MockUser'); + input.trigger('input'); + + _$rootScope.$digest(); + expect(input.val()).to.include('MockUser'); + expect(btn.html()).to.include('Register'); + + + btn.click(); //Register + _$rootScope.$digest(); + + expect(input.val()).to.include('MockUser'); + expect(btn.html()).to.include('Unregister'); + expect(input.is(':disabled')).to.be.true; //Input field should be disabled + + }); + + it('should unregister using the "Unregister" button', function() { + input.val('MockUser'); + input.trigger('input'); + + expect(btn.html()).to.equal('Register'); + + btn.click(); + + _$rootScope.$digest(); + + expect(btn.html()).to.equal('Unregister'); + + btn.click(); + _$rootScope.$digest(); + + // _$rootScope.$digest(); + + expect(btn.html()).to.equal('Register'); + expect(input.is(':enabled')).to.be.true; + expect(input.val()).to.be.empty; + }); + + it('should disable input fields on invalid characters', function(done) { + var invalidCharacters = ['$', '#', '+', '/', '\\']; //Invalid characters for MQTT Topic Path + + + invalidCharacters.forEach(function(invalid_char) { + + inputHelper(invalid_char); + expect(btn.is(':disabled')).to.be.true; + + //Clear + inputHelper(''); + + inputHelper('MockUser' + invalid_char); + expect(btn.is(':disabled')).to.be.true; + + inputHelper(''); + + inputHelper(invalid_char + 'MockUser'); + expect(btn.is(':disabled')).to.be.true; + }); + + function inputHelper(value) { + input.val(value); + input.trigger('input'); //Trigger user input action + _$rootScope.$digest(); + } + //TODO Test permutations and combinations between all characters + + done(); + }); +}); diff --git a/src/js/ui/endpoint-provider/rtcomm-session-manager/rtcomm-session-manager.js b/src/js/ui/endpoint-provider/rtcomm-session-manager/rtcomm-session-manager.js new file mode 100644 index 0000000..63d2afc --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-session-manager/rtcomm-session-manager.js @@ -0,0 +1,94 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive is used to manage multiple sessions. If you are only supporting at most one session you wont need + * this directive. The associated template provides a way to switch between active sessions. The session must be in + * the started state to be managed by this directive and is removed when the session stops. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommSessionManager', rtcommSessionManager); + + /* @ngInject */ + function rtcommSessionManager() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-sessionmgr.html', + controller: SessionManagerController, + controllerAs: 'sessionMgrVM', + bindToController: true + }; + + return directive; + + function linkFunc(scope, el, attr, ctrl) { + + } + } + + SessionManagerController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function SessionManagerController(RtcommService, $scope, $log) { + var vm = this; + vm.sessions = RtcommService.getSessions(); + vm.sessMgrActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.publishPresence = false; + vm.sessionPresenceData = []; + + $scope.init = function(publishPresence) { + vm.publishPresence = publishPresence; + vm.updatePresence(); + }; + + vm.activateSession = function(endpointUUID) { + $log.debug('rtcommSessionmgr: activateEndpoint =' + endpointUUID); + if (vm.sessMgrActiveEndpointUUID !== endpointUUID) { + RtcommService.setActiveEndpoint(endpointUUID); + } + }; + + vm.updatePresence = function() { + // Update the presence record if enabled + if (vm.publishPresence === true) { + RtcommService.removeFromPresenceRecord(vm.sessionPresenceData, false); + + vm.sessionPresenceData = [{ + 'name': "sessions", + 'value': String(vm.sessions.length) + }]; + + RtcommService.addToPresenceRecord(vm.sessionPresenceData); + } + } + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $log.debug('rtcommSessionmgr: endpointActivated =' + endpointUUID); + vm.sessMgrActiveEndpointUUID = endpointUUID; + }); + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('rtcommSessionmgr: session:started: uuid =' + eventObject.endpoint.id); + + vm.updatePresence(); + }); + } +})(); diff --git a/src/js/ui/endpoint-provider/rtcomm-session-manager/rtcomm-session-manager.spec.js b/src/js/ui/endpoint-provider/rtcomm-session-manager/rtcomm-session-manager.spec.js new file mode 100644 index 0000000..5590218 --- /dev/null +++ b/src/js/ui/endpoint-provider/rtcomm-session-manager/rtcomm-session-manager.spec.js @@ -0,0 +1,38 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +//TODO Finish Session manager Unit Test +describe('Unit Testing: RtcommSessionManager directive', function(){ + var $compile, $rootScope; + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm')); + beforeEach(inject( + ['$compile', '$rootScope', function($c, $r){ + $compile = $c; + $rootScope = $r; + }] + )); + + it('session-manager directive should be available', function(){ + var element = $compile('')($rootScope); + $rootScope.$digest(); + // console.log(element[0]); + expect(element.html()).to.include('class="session-manager"'); + }); +}) diff --git a/src/js/ui/endpoint/endpoint-controller/endpoint.controller.js b/src/js/ui/endpoint/endpoint-controller/endpoint.controller.js new file mode 100644 index 0000000..67c0d53 --- /dev/null +++ b/src/js/ui/endpoint/endpoint-controller/endpoint.controller.js @@ -0,0 +1,97 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommEndpointController', RtcommEndpointController); + + RtcommEndpointController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function RtcommEndpointController(RtcommService, $scope, $log) { + $scope.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); + $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected($scope.epCtrlActiveEndpointUUID); + $scope.sessionState = RtcommService.getSessionState($scope.epCtrlActiveEndpointUUID); + + $scope.disconnect = function() { + $log.debug('Disconnecting call for endpoint: ' + $scope.epCtrlActiveEndpointUUID); + RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).disconnect(); + + }; + + $scope.toggleAV = function() { + $log.debug('Enable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); + + if ($scope.epCtrlAVConnected == false) { + RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.enable(function(value, message) { + if (!value) { + $log.debug('Enable failed: ', message); + RtcommService.alert({ + type: 'danger', + msg: message + }); + } + }); + } else { + $log.debug('Disable AV for endpoint: ' + $scope.epCtrlActiveEndpointUUID); + RtcommService.getEndpoint($scope.epCtrlActiveEndpointUUID).webrtc.disable(); + } + }; + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + $scope.sessionState = 'session:started'; + } + }); + + $scope.$on('session:stopped', function(event, eventObject) { + $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + $scope.sessionState = 'session:stopped'; + } + }); + + $scope.$on('session:failed', function(event, eventObject) { + $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + $scope.sessionState = 'session:failed'; + } + }); + + $scope.$on('webrtc:connected', function(event, eventObject) { + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) + $scope.epCtrlAVConnected = true; + }); + + $scope.$on('webrtc:disconnected', function(event, eventObject) { + if ($scope.epCtrlActiveEndpointUUID == eventObject.endpoint.id) + $scope.epCtrlAVConnected = false; + }); + + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $scope.epCtrlActiveEndpointUUID = endpointUUID; + $scope.epCtrlAVConnected = RtcommService.isWebrtcConnected(endpointUUID); + }); + + $scope.$on('noEndpointActivated', function(event) { + $scope.epCtrlAVConnected = false; + }); + } +})(); diff --git a/src/js/ui/endpoint/endpoint-controller/endpoint.controller.spec.js b/src/js/ui/endpoint/endpoint-controller/endpoint.controller.spec.js new file mode 100644 index 0000000..d185072 --- /dev/null +++ b/src/js/ui/endpoint/endpoint-controller/endpoint.controller.spec.js @@ -0,0 +1,234 @@ +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Testing: Endpoint Controller', function() { + //Dependency + var RtcommService; + var ctrl, scope; + //Utilities + var $compile, $rootScope, $controller; + //Mock and stubbing + var sandbox; + + var endpointEvents = ['session:started', 'session:stopped', 'session:failed']; + beforeEach(module('rtcomm.templates')); + beforeEach(module('angular-rtcomm-ui')); + + + beforeEach(inject(function($injector) { + sandbox = sinon.sandbox.create(); + RtcommService = $injector.get('RtcommService'); + $compile = $injector.get('$compile'); + $rootScope = $injector.get('$rootScope'); + $controller = $injector.get('$controller'); + + })); + + beforeEach(function() { + //Mock initial state of the controller + // + var endpoint = { + + } + sandbox.stub(RtcommService, 'getActiveEndpoint', function() { + return 'MOCK_ID'; + }); + sandbox.stub(RtcommService, 'isWebrtcConnected', function(id) { + return false; + }); + + sandbox.stub(RtcommService, 'getSessionState', function() { + return 'session:stopped'; + }); + scope = $rootScope.$new(); + ctrl = $controller('RtcommEndpointController', { + $scope: scope + }); + + compileRtcommEndpointController(); + }); + + + describe('behavior when receiving events from the same endpoint', function() { + var endpoint = null; + beforeEach(function() { + endpoint = { + id: 'MOCK_ID' + }; + }); + + it('should change state accordingly to session events', function() { + + endpointEvents.forEach(function(eventName) { + $rootScope.$broadcast(eventName, { + endpoint: endpoint + }); + $rootScope.$digest(); + + expect(scope.sessionState).to.equal(eventName); + + }); + }); + + it('should activate the AV Connected flag', function() { + + $rootScope.$broadcast('webrtc:connected', { + endpoint: endpoint + }); + + $rootScope.$digest(); + + expect(scope.epCtrlAVConnected).to.be.true; + }); + + it('should deactivate the AV Connected flag', function() { + $rootScope.$broadcast('webrtc:disconnected', { + endpoint: endpoint + }); + + $rootScope.$digest(); + + expect(scope.epCtrlAVConnected).to.be.false; + }); + + }); + + /* The controller depends readily on the events that are happening, + * need to test how its functions and states vary in each event + */ + describe('behavior when receiving events from a non-active endpoint', function() { + + var endpoint = { + id: 'WRONG_MOCK_ID' + }; + + + it('should maintain the same state if events are from a non active endpoint', function() { + + endpointEvents.forEach(function(eventName) { + $rootScope.$broadcast(eventName, { + endpoint: { + id: 'WRONG_MOCK_ID' + } + }); + $rootScope.$digest(); + + expect(scope.sessionState).to.equal('session:stopped'); + + }); + }); + + it('should not change the AV Connected flag', function() { + scope.epCtrlAVConnected = false; + $rootScope.$broadcast('webrtc:connected', { + endpoint: endpoint + }); + + $rootScope.$digest(); + expect(scope.epCtrlAVConnected).to.be.false; + + scope.epCtrlAVConnected = true; + $rootScope.$broadcast('webrtc:disconnected', { + endpoint: endpoint + }); + $rootScope.$digest(); + + expect(scope.epCtrlAVConnected).to.be.true; + }); + }); + + + it('should switch active endpoint on active endpoint event', function() { + var activeEndpoint = { + id: 'NEW_ID' + } + $rootScope.$broadcast('endpointActivated', activeEndpoint.id); + $rootScope.$digest(); + + expect(scope.epCtrlActiveEndpointUUID).to.equal(activeEndpoint.id); + expect(scope.epCtrlAVConnected).to.be.false; + + }); + + it('should disable the AV flag when no endpoint is activated', function() { + scope.epCtrlAVConnected = true; + $rootScope.$broadcast('noEndpointActivated'); + + $rootScope.$digest(); + + expect(scope.epCtrlAVConnected).to.be.false; + }); + + describe('Testing external methods', function() { + + it('should call disconnect on the active endpoint', function() { + var endpoint = { + disconnect: function() {} + } + sandbox.stub(endpoint, 'disconnect'); + sandbox.stub(RtcommService, 'getEndpoint', function() { + return endpoint; + }); + + scope.disconnect(); + + expect(RtcommService.getEndpoint.calledWith('MOCK_ID')).to.be.true; + expect(endpoint.disconnect.calledOnce).to.be.true; + + }); + + it('should toggleAV depending on the state of the connection', function(){ + var webrtc = { + enable: function(){}, + disable: function(){} + }, + endpoint = {}; + sandbox.stub(webrtc, 'enable'); + + sandbox.stub(webrtc, 'disable'); + endpoint.webrtc = webrtc; + sandbox.stub(RtcommService, 'getEndpoint', function(){ return endpoint}); + scope.epCtrlAVConnected = false; + scope.toggleAV(); + + expect(RtcommService.getEndpoint.calledWith('MOCK_ID')).to.be.true; + expect(webrtc.enable.calledOnce).to.be.true; + + //Force webrtc.enable to throw an error + webrtc.enable.restore(); + sandbox.stub(webrtc, 'enable', function(func){ func(false)}); + sandbox.stub(RtcommService, 'alert'); + scope.toggleAV(); + + expect(RtcommService.getEndpoint.calledWith('MOCK_ID')).to.be.true; + expect(webrtc.enable.called).to.be.true; + + scope.epCtrlAVConnected = true; + + scope.toggleAV(); + expect(RtcommService.getEndpoint.calledWith('MOCK_ID')).to.be.true; + expect(webrtc.disable.called).to.be.true; + + }); + }); + + function compileRtcommEndpointController() { + var html = ' < div ng - controller = "RtcommEndpointController" > < /div>'; + var configCtrl = $compile(html)($rootScope); + return configCtrl; + } +}); diff --git a/src/js/ui/endpoint/rtcomm-chat/rtcomm-chat.js b/src/js/ui/endpoint/rtcomm-chat/rtcomm-chat.js new file mode 100644 index 0000000..4e440ed --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-chat/rtcomm-chat.js @@ -0,0 +1,124 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive manages the chat portion of a session. The data model for chat + * is maintained in the RtcommService. This directive handles switching between + * active endpoints. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommChat', rtcommChat); + + rtcommChat.$inject = ['RtcommService', '$log']; + + /* @ngInject */ + function rtcommChat(RtcommService, $log) { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-chat.html', + link: chatLink, + controller: ChatController, + controllerAs: 'chatVM', + bindToController: true + }; + + return directive; + + function chatLink(scope, element, attr, ctrl) { + var chatPanel = angular.element(element.find('.panel-body')[0]); + + var bottom = true; + + //Chooses if the scrollbar should be forced to the bottom on the next lifecycle + ctrl.scrollToBottom = function(flag) { + bottom = flag; + scope.bottom = flag; + + } + if (chatPanel.length > 0) { + //Watch scroll events + chatPanel.bind('scroll', function() { + if (chatPanel.prop('scrollTop') + chatPanel.prop('clientHeight') == chatPanel.prop('scrollHeight')) { + ctrl.scrollToBottom(true); + } else { + ctrl.scrollToBottom(false); + } + }); + + //Watch the chat messages, if the scroll bar is in the bottom keep it on the bottom so the user can view incoming chat messages, else possibly send a notification and don't scroll down + scope.$watch(function() { + return ctrl.chats + }, function() { + $log.debug('rtcommChat - Link > $watch on chats called'); + if (bottom) { + chatPanel.scrollTop(chatPanel.prop('scrollHeight')); + } else { + //In this else, a notification could be sent + } + }, true); + + } + } + + } + + //Controller should be used to listen for events from Rtcmo + ChatController.$inject = ['$scope', 'RtcommService', '$log']; + + /* @ngInject */ + function ChatController($scope, RtcommService, $log) { + var vm = this; + + vm.chatActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.chats = RtcommService.getChats(vm.chatActiveEndpointUUID); + + vm.keySendMessage = function(keyEvent) { + if (keyEvent.which === 13) + vm.sendMessage(); + }; + + vm.sendMessage = function() { + $log.debug('rtcommChat: sendMessage() -> ' + vm.message); + var chat = { + time: new Date(), + name: RtcommService.getEndpoint(vm.chatActiveEndpointUUID).getLocalEndpointID(), + message: angular.copy(vm.message) + }; + + vm.message = ''; + vm.scrollToBottom(true); + $scope.bottom = true; + RtcommService.sendChatMessage(chat, vm.chatActiveEndpointUUID); + } + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $log.debug('rtcommChat: endpointActivated =' + endpointUUID); + + // The data model for the chat is maintained in the RtcommService. + vm.chats = RtcommService.getChats(endpointUUID); + vm.chatActiveEndpointUUID = endpointUUID; + }); + + $scope.$on('noEndpointActivated', function(event) { + vm.chats = []; + vm.chatActiveEndpointUUID = null; + }); + } +})(); diff --git a/src/js/ui/endpoint/rtcomm-chat/rtcomm-chat.spec.js b/src/js/ui/endpoint/rtcomm-chat/rtcomm-chat.spec.js new file mode 100644 index 0000000..959ace7 --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-chat/rtcomm-chat.spec.js @@ -0,0 +1,274 @@ +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Testing: RtcommChat directive', function() { + var $compile, _$rootScope, sandbox, scope, element; + + var chatInput, sendBtn; + + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); + + //Mock RtcommService + beforeEach(function() { + RtcommService = { + endpoints: [], + activeEndpoint: null, + getActiveEndpoint: function() { + return this.activeEndpoint; + }, + getChats: function() { + + var ep = this.getEndpoint(this.activeEndpoint); + if (ep !== null) { + return ep.chats; + } else { + return []; + } + }, + getEndpoint: function(id) { + var endpoint = null + this.endpoints.forEach(function(_endpoint) { + if (_endpoint.id === id) { + endpoint = _endpoint; + } + }); + return endpoint; + }, + sendChatMessage: function(chat, endpoint) { + //Store chats locally, RtcommService uses a session storage mechanism, since this is a + //mock we can just store teh chats on the mockendpoint itself + var endpoint = this.getEndpoint(this.activeEndpoint); + endpoint.chats.push(chat); + }, + //Interface methods for manipulating the RtcommService through the test + _MockCreateEndpoint: function(id, userid) { + var mockEP = createMockEndpoint(id, userid); + this.endpoints.push(mockEP); + }, + _setActiveEndpoint: function(id) { + this.activeEndpoint = id; + }, + _emitChatMessage: function(eventObject) { + this.endpoints.forEach(function(_endpoint) { + if (_endpoint.id === eventObject.id) { + var chatMessage = { + name: eventObject.message.from, + time: new Date(), + message: eventObject.message.message + + } + _endpoint.chats.push(chatMessage); + + } + }); + }, + _destroyEndpoint: function(id) { + // console.log(this.endpoints); + this.endpoints.forEach(function(_endpoint, index, endpoints) { + if (_endpoint.id === id) { + _endpoint.chats = []; + endpoints.splice(index, 1); + } + }); + console.log(this.endpoints); + + } + } + + module(function($provide) { + $provide.value('RtcommService', RtcommService); + }); + }); + + //Setup Test + beforeEach(inject(function($compile, $rootScope) { + _$rootScope = $rootScope; + + + scope = $rootScope; + element = $compile('')(scope); + scope.$digest(); + + sandbox = sinon.sandbox.create(); + chatInput = element.find('input'); + sendBtn = element.find('button'); + + })); + + afterEach(function() { + sandbox.restore(); + }); + + it('chat directive should be available', function() { + expect(element.html()).to.include('class="chat"'); + }); + + it('intial state send button should be disabled', function() { + expect(sendBtn.is(':disabled')).to.be.true; + }); + + + it('should activate when an endpoint session is created', function() { + sandbox.spy(_$rootScope, '$broadcast'); + sandbox.spy(RtcommService, 'getChats'); + sandbox.spy(RtcommService, 'getEndpoint'); + + RtcommService._MockCreateEndpoint('A'); + RtcommService._setActiveEndpoint('A'); + + _$rootScope.$broadcast('endpointActivated', 'A'); + _$rootScope.$digest(); + expect(_$rootScope.$broadcast.calledOnce).to.be.true; + expect(RtcommService.getChats.called).to.be.true; + expect(RtcommService.getEndpoint.called).to.be.true; + expect(sendBtn.is(':enabled')).to.be.true; + }); + + it('should display messages sent from the local user', function() { + var chatMsg = 'Hello World!'; + var userid = 'MockUser'; + RtcommService._MockCreateEndpoint('A', userid); + RtcommService._setActiveEndpoint('A'); + + var testMessages = ['Hey!', 'How\'s it going?', 'Just found out this is an amazing framework']; + + _$rootScope.$broadcast('endpointActivated', 'A'); + _$rootScope.$digest(); + + testMessages.forEach(function(testMessage) { + + sendMessage(testMessage); + + }); + + var messageElements = element.find('ul.chat > li'); + + expect(messageElements.length).to.equal(testMessages.length); + + for (var i = 0; i < messageElements.length; i++) { + var messageElement = angular.element(messageElements[i]); + + var chatMessage = messageDecomposer(messageElement); + expect(chatMessage.user).to.equal(userid); + expect(chatMessage.message).to.equal(testMessages[i]); + } + + }); + + it('should display messages from a mock remote user', function() { + + + var userid = 'MockUser'; + RtcommService._MockCreateEndpoint('A', userid); + RtcommService._setActiveEndpoint('A'); + + _$rootScope.$broadcast('endpointActivated', 'A'); + _$rootScope.$digest(); + + var eventObject = { + id: 'A', + message: { + message: 'Hello, this is me the second person', + from: 'MockUser2' + } + } + RtcommService._emitChatMessage(eventObject); + + _$rootScope.$digest(); + var messageElements = element.find('ul.chat > li'); + + var message = messageDecomposer(angular.element(messageElements[0])); + expect(message.message).to.equal(eventObject.message.message); + expect(message.user).to.equal(eventObject.message.from); + + + }); + + it('should remove all messages when endpoint is removed or destroyed', function() { + var chatMsg = 'Hello World!'; + var userid = 'MockUser'; + RtcommService._MockCreateEndpoint('A', userid); + RtcommService._setActiveEndpoint('A'); + + var testMessages = ['Hey!', 'How\'s it going?', 'Just found out this is an amazing framework']; + + _$rootScope.$broadcast('endpointActivated', 'A'); + _$rootScope.$digest(); + + testMessages.forEach(function(testMessage) { + + sendMessage(testMessage); + + }); + + var messageElements = element.find('ul.chat > li'); + + expect(messageElements.length).to.equal(testMessages.length); + + for (var i = 0; i < messageElements.length; i++) { + var messageElement = angular.element(messageElements[i]); + + var chatMessage = messageDecomposer(messageElement); + expect(chatMessage.user).to.equal(userid); + expect(chatMessage.message).to.equal(testMessages[i]); + } + + _$rootScope.$broadcast('noEndpointActivated'); + _$rootScope.$digest(); + + var messageElements = element.find('ul.chat > li'); + + expect(messageElements.length).to.equal(0); + + }); + + function createMockEndpoint(id, name) { + var endpoint = { + id: id, + chats: [], + localId: name, + getLocalEndpointID: function() { + return this.localId; + } + } + return endpoint; + } + + function messageDecomposer(chatMessageElement) { + var user = chatMessageElement.find('strong').html(); + var time = chatMessageElement.find('small').html(); + var message = chatMessageElement.find('p').html(); + + var chatMessage = { + user: user, + time: time, + message: message + + } + return chatMessage; + } + + function sendMessage(message) { + chatInput.val(message); + chatInput.trigger('input'); + sendBtn.click(); + _$rootScope.$digest(); + + } +}) diff --git a/src/js/ui/endpoint/rtcomm-endpoint-status/rtcomm-endpoint-status.js b/src/js/ui/endpoint/rtcomm-endpoint-status/rtcomm-endpoint-status.js new file mode 100644 index 0000000..2a10345 --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-endpoint-status/rtcomm-endpoint-status.js @@ -0,0 +1,154 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This endpoint status controller only shows the active endpoint. The $scope.sessionState always contains the + * state of the active endpoint if one exist. It will be one of the following states: + * + * 'session:alerting' + * 'session:trying' + * 'session:ringing' + * 'session:queued' - for this one $scope.queueCount will tell you where you are in the queue. + * 'session:failed' - for this one $scope.reason will tell you why the call failed. + * 'session:started' + * 'session:stopped' + * + * You can bind to $scope.sessionState to track state in the view. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommEndpointStatus', rtcommEndpointStatus); + + /* @ngInject */ + function rtcommEndpointStatus() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-endpoint-status.html', + controller: EndpointStatusController, + controllerAs: 'endpointStatusVM', + bindToController: true + }; + + return directive; + } + + EndpointStatusController.$inject = ['RtcommService', '$scope', '$log']; + + /* @ngInject */ + function EndpointStatusController(RtcommService, $scope, $log) { + var vm = this; + vm.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint(vm.epCtrlActiveEndpointUUID); + vm.sessionState = RtcommService.getSessionState(vm.epCtrlActiveEndpointUUID); + vm.failureReason = ''; + vm.queueCount = 0; //TODO FIX: Currently not implemented! + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID === eventObject.endpoint.id) { + vm.sessionState = 'session:started'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:stopped', function(event, eventObject) { + $log.debug('session:stopped received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:stopped'; + vm.epCtrlRemoteEndpointID = null; + } + }); + + $scope.$on('session:failed', function(event, eventObject) { + $log.debug('session:failed received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:failed'; + vm.failureReason = eventObject.reason; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:alerting', function(event, eventObject) { + $log.debug('session:alerting received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID != eventObject.endpoint.id) { + vm.sessionState = 'session:alerting'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:connecting', function(event, eventObject) { + $log.debug('session:connecting received: endpointID = ' + eventObject.endpoint.id); + // if ($scope.epCtrlActiveEndpointUUID != eventObject.endpoint.id){ + vm.sessionState = 'session:connecting'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + // } + }); + + + $scope.$on('session:queued', function(event, eventObject) { + $log.debug('session:queued received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:queued'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:trying', function(event, eventObject) { + $log.debug('session:trying received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:trying'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('session:ringing', function(event, eventObject) { + $log.debug('session:ringing received: endpointID = ' + eventObject.endpoint.id); + if (vm.epCtrlActiveEndpointUUID == eventObject.endpoint.id) { + vm.sessionState = 'session:ringing'; + vm.epCtrlRemoteEndpointID = eventObject.endpoint.getRemoteEndpointID(); + } + }); + + $scope.$on('endpointActivated', function(event, endpointUUID) { + vm.epCtrlActiveEndpointUUID = endpointUUID; + vm.epCtrlRemoteEndpointID = RtcommService.getEndpoint(endpointUUID).getRemoteEndpointID(); + vm.sessionState = RtcommService.getSessionState(endpointUUID); + }); + + $scope.$on('noEndpointActivated', function(event) { + vm.epCtrlRemoteEndpointID = null; + vm.sessionState = 'session:stopped'; + }); + + $scope.$on('rtcomm::init', function(event, success, details) { + if (success === true) { + vm.epCtrlActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.epCtrlRemoteEndpointID = RtcommService.getRemoteEndpoint(vm.epCtrlActiveEndpointUUID); + vm.sessionState = RtcommService.getSessionState(vm.epCtrlActiveEndpointUUID); + vm.failureReason = ''; + } + if (success == false) { + vm.sessionState = 'session:stopped'; + vm.epCtrlRemoteEndpointID = null; + } + }); + } + +})(); diff --git a/src/js/ui/endpoint/rtcomm-endpoint-status/rtcomm-endpoint-status.spec.js b/src/js/ui/endpoint/rtcomm-endpoint-status/rtcomm-endpoint-status.spec.js new file mode 100644 index 0000000..6c799fb --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-endpoint-status/rtcomm-endpoint-status.spec.js @@ -0,0 +1,200 @@ +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('Unit Testing: RtcommEndpointStatus directive', function() { + var $compile, _$rootScope, sandbox, scope, element, endpointStatusElement; + + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); + + beforeEach(function() { + RtcommService = { + sessions: [ + + ], + getActiveEndpoint: function(endpointUUID) { + return 'A'; + }, + getRemoteEndpoint: function(endpointUUID) { + return { + id: 'B', + localName: 'RemoteMockUser' + + } + }, + getSessionState: function(endpointUUID) { + return 'session:stopped'; + + }, + getEndpoint: function(endpointUUID) { + return { + id: 'A', + getRemoteEndpointID: function() { + return 'RemoteMockUser' + } + } + } + } + + module(function($provide) { + $provide.value('RtcommService', RtcommService); + }); + }); + + //Setup Test + beforeEach(inject(function($compile, $rootScope) { + _$rootScope = $rootScope; + + + scope = $rootScope; + element = $compile('')(scope); + scope.$digest(); + + sandbox = sinon.sandbox.create(); + endpointStatusElement = element.find('span'); //Holds the state of the endpoint + + })); + + afterEach(function() { + sandbox.restore(); + }); + + it('endpoint-status directive should be available', function() { + expect(element.html()).to.include('class="endpoint-status"'); + }); + + it('should display an initial state of the endpoint', function() { + expect(endpointStatusElement.html()).to.equal('No active sessions, waiting...'); + }); + + it('should display a "session:started" event correct', function() { + //Event object + generateEvent('session:started', { + id: 'A', + user: 'RemoteMockUser' + }); + expect(getEndpointStatus()).to.equal('Connected to RemoteMockUser'); + }); + + it('should display a "session:stopped" event correctly', function() { + + generateEvent('session:stopped', { + id: 'A', + user: 'RemoteMockUser' + }); + expect(getEndpointStatus()).to.equal('No active sessions, waiting...'); + + }); + + it('should display a "session:alerting", event correctly', function() { + //Receive event from a new endpoint different from the current active endpoint + generateEvent('session:alerting', { + id: 'B', + user: 'RemoteMockUser2' + }); + expect(getEndpointStatus()).to.equal('Inbound call from RemoteMockUser2'); + }); + + it('should display a "session:failed" event correctly', function() { + generateEvent('session:failed', { + id: 'A', + reason: 'User dropped the call', + user: 'RemoteMockUser' + }); + expect(getEndpointStatus()).to.equal('Call failed with reason: User dropped the call'); + }) + + it('should display a "session:connecting" event correctly', function() { + generateEvent('session:connecting', { + id: 'B', + user: 'RemoteMockUser2' + }); + expect(getEndpointStatus()).to.equal('Connecting to RemoteMockUser2 ...'); + }); + + it('should display a "session:queued" event correctly', function() { + generateEvent('session:queued', { + id: 'A', + user: 'RemoteMockUser' + }); + expect(getEndpointStatus()).to.equal('Waiting in queue at: 0'); + + }); + it('should display a "session:trying" event correctly', function() { + generateEvent('session:trying', { + id: 'A', + user: 'RemoteMockUser' + }); + expect(getEndpointStatus()).to.equal('Attempting to call RemoteMockUser'); + }); + + it('should display a "session:ringing" event correctly', function() { + generateEvent('session:ringing', { + id: 'A', + user: 'RemoteMockUser' + }); + expect(getEndpointStatus()).to.equal('Call to RemoteMockUser is ringing'); + }); + + it('should initialize endpoint on successful "rtcomm::init" event', function() { + _$rootScope.$broadcast('rtcomm::init', true); + _$rootScope.$digest(); + + expect(getEndpointStatus()).to.equal('No active sessions, waiting...'); + }); + + it('should deinitialize endpoint on unsuccesful "rtcomm::init" event', function() { + _$rootScope.$broadcast('rtcomm::init', false); + _$rootScope.$digest(); + expect(getEndpointStatus()).to.equal('No active sessions, waiting...'); + }); + + it('should listen to an endpointActivated event', function() { + _$rootScope.$broadcast('endpointActivated', 'A'); + _$rootScope.$digest(); + expect(getEndpointStatus()).to.equal('No active sessions, waiting...'); + }); + + it('should listen to an noEndpointActivated event', function() { + _$rootScope.$broadcast('noEndpointActivated'); + _$rootScope.$digest(); + expect(getEndpointStatus()).to.equal('No active sessions, waiting...'); + }); + + function generateEvent(eventName, endpointDetails) { + var eventObject = createEventObject(endpointDetails); + _$rootScope.$broadcast(eventName, eventObject); + _$rootScope.$digest(); + } + + function createEventObject(endpointDetails) { + return { + reason: endpointDetails.reason, + endpoint: { + id: endpointDetails.id, + getRemoteEndpointID: function() { + return endpointDetails.user; + }, + } + } + } + + function getEndpointStatus() { + var endpointStatusElement = element.find('span'); + return endpointStatusElement.html(); + } +}) diff --git a/src/js/ui/endpoint/rtcomm-iframe/rtcomm-iframe.js b/src/js/ui/endpoint/rtcomm-iframe/rtcomm-iframe.js new file mode 100644 index 0000000..675aa1c --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-iframe/rtcomm-iframe.js @@ -0,0 +1,105 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommIframe', rtcommIframe); + + /* @ngInject */ + function rtcommIframe() { + var directive = { + restrict: 'E', + templateUrl: "templates/rtcomm/rtcomm-iframe.html", + controller: IFrameController, + controllerAs: 'iframeVM', + bindToController: true + }; + + return directive; + } + + IFrameController.$inject = ['RtcommService', '$sce', '$location', '$window','$scope', '$log']; + + /* @ngInject */ + function IFrameController(RtcommService, $sce, $location, $window, $scope, $log) { + var vm = this; + vm.iframeActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.iframeURL = null; + vm.initiframeURL = null; + vm.syncSource = false; + + /* + * syncSourcing means you a providing the URL source but no UI. Typically used in + * customer/agent scenarios. + */ + $scope.init = function(syncSource) { + if (syncSource === true) { + vm.syncSource = true; + vm.initiframeURL = $location.absUrl(); // init to current URL + } + }; + + + vm.setURL = function(newURL) { + $log.debug('rtcommIframe: setURL: newURL: ' + newURL); + RtcommService.putIframeURL(vm.iframeActiveEndpointUUID, newURL); + vm.iframeURL = $sce.trustAsResourceUrl(newURL); + }; + + vm.forward = function() {}; + + vm.backward = function() {}; + + $scope.$on('session:started', function(event, eventObject) { + $log.debug('session:started received: endpointID = ' + eventObject.endpoint.id); + + if (vm.syncSource == true) { + RtcommService.putIframeURL(eventObject.endpoint.id, vm.initiframeURL); //Update on the current or next endpoint to be activated. + } + }); + + $scope.$on('endpointActivated', function(event, endpointUUID) { + $log.debug('rtcommIframe: endpointActivated =' + endpointUUID); + + if (vm.syncSource == false) { + vm.iframeURL = $sce.trustAsResourceUrl(RtcommService.getIframeURL(endpointUUID)); + vm.iframeActiveEndpointUUID = endpointUUID; + } + }); + + $scope.$on('noEndpointActivated', function(event) { + if (vm.syncSource == false) { + vm.iframeURL = $sce.trustAsResourceUrl('about:blank'); + vm.iframeActiveEndpointUUID = null; + } + }); + + $scope.$on('rtcomm::iframeUpdate', function(eventType, endpointUUID, url) { + if (vm.syncSource === false) { + $log.debug('rtcomm::iframeUpdate: ' + url); + // This is needed to prevent rtcomm from logging in when the page is loaded in the iFrame. + url = url + "?disableRtcomm=true"; + vm.iframeURL = $sce.trustAsResourceUrl(url); + } else { + $log.debug('rtcomm::iframeUpdate: load this url in a new tab: ' + url); + // In this case we'll open the pushed URL in a new tab. + $window.open($sce.trustAsResourceUrl(url), '_blank'); + } + }); + } +})(); diff --git a/src/js/ui/endpoint/rtcomm-iframe/rtcomm-iframe.spec.js b/src/js/ui/endpoint/rtcomm-iframe/rtcomm-iframe.spec.js new file mode 100644 index 0000000..3746cc5 --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-iframe/rtcomm-iframe.spec.js @@ -0,0 +1,214 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Testing: RtcommIFrame directive', function() { + + //Dependencies + var $rootScope, RtcommService, $compile, $sce, $location, $window; + + var sandbox; + + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); + + //Mock RtcommService + + beforeEach(function() { + + }) + beforeEach(inject( + function($injector) { + sandbox = sinon.sandbox.create(); + $compile = $injector.get('$compile'); + $rootScope = $injector.get('$rootScope'); + RtcommService = $injector.get('RtcommService'); + $location = $injector.get('$location'); + $sce = $injector.get('$sce'); + $window = $injector.get('$window'); + sandbox.stub(RtcommService, 'getActiveEndpoint', function() { + return 'ID'; + }); + } + )); + afterEach(function() { + sandbox.restore(); + }); + + + it('iframe directive should be available', function() { + var element = compileIFrame(); + expect(element.html()).to.include('class="rtcomm-iframe"'); + }); + + it('iframe directive should accept ng-init', function() { + var element = compileIFrame(false); + expect(element.html()).to.include('class="rtcomm-iframe"'); + }); + + it('should have its buttons disabled if the iframeUrl is null', function() { + var element = compileIFrame(); + var backwardBtn = element.find('#btnBackward'); + var forwardBtn = element.find('#btnForward'); + + expect(backwardBtn.is(':disabled')).to.be.true; + expect(forwardBtn.is(':disabled')).to.be.true; + + }); + + it('should be able to set an URL', function() { + sandbox.stub(RtcommService, 'putIframeURL'); + sandbox.stub($sce, 'trustAsResourceUrl'); + + var element = compileIFrame(); + var urlInput = element.find('#setUrl'); + var setUrlBtn = element.find('#btn-send-url'); + + urlInput.val('https://wasdev.net/webrtc'); + urlInput.trigger('input'); + $rootScope.$digest(); + + expect(urlInput.val()).to.equal('https://wasdev.net/webrtc'); + + setUrlBtn.click(); + $rootScope.$digest(); + + var iframe = angular.element(element.find('iframe')[0]); + // expect(iframe.attr('src')).to.equal('https://wasdev.net/webrtc'); + expect(RtcommService.putIframeURL.calledOnce).to.be.true; + expect(RtcommService.putIframeURL.calledWithExactly('ID', 'https://wasdev.net/webrtc')).to.be.true; + + expect($sce.trustAsResourceUrl.calledOnce).to.be.true; + }); + + it('should set the directive\'s url when the endpoint is activated', function() { + + sandbox.stub(RtcommService, 'getIframeURL', function() { + return 'https://wasdev.net/webrtc'; + }); + sandbox.stub($sce, 'trustAsResourceUrl'); + + var element = compileIFrame(); + $rootScope.$broadcast('endpointActivated', 'ID'); + $rootScope.$digest(); + + expect(RtcommService.getIframeURL.calledWith('ID')).to.be.true; + + }); + + it('should clear the iframe when endpoint is deactivated', function() { + sandbox.stub($sce, 'trustAsResourceUrl'); + var element = compileIFrame(); + + $rootScope.$broadcast('noEndpointActivated'); + $rootScope.$digest(); + + expect($sce.trustAsResourceUrl.calledOnce).to.be.true; + expect($sce.trustAsResourceUrl.calledWith('about:blank')).to.be.true; + }); + + it('should not do anything on session:started if no syncsource is active',function(){ + sandbox.stub(RtcommService, 'putIframeURL'); + + var element = compileIFrame(); + + var eventObject = { + endpoint: { + id: 'MockID' + } + }; + + $rootScope.$broadcast('session:started', eventObject); + $rootScope.$digest(); + + expect(RtcommService.putIframeURL.called).to.be.false; + }); + + it('should flag disable rtcomm inside the iframe', function(){ + sandbox.stub($sce, 'trustAsResourceUrl', function(url){return url;}); + + + var element = compileIFrame(); + $rootScope.$broadcast('rtcomm::iframeUpdate', 'MockID','https://wasdev.net/webrtc'); + // $rootScope.$digest(); + + expect($sce.trustAsResourceUrl.calledOnce).to.be.true; + expect($sce.trustAsResourceUrl.calledWith('https://wasdev.net/webrtc?disableRtcomm=true')).to.be.true; + + }); + + describe('using syncsource (providing the url but no UI):', function() { + + + it('should update iFrameURL with the new session\'s url on session:started', function() { + sandbox.stub(RtcommService, 'putIframeURL'); + sandbox.stub($location, 'absUrl', function() { + return 'localhost'; + }); + + var element = compileIFrame(true); + + expect($location.absUrl.called).to.be.true; + + var eventObject = { + endpoint: { + id: 'MockID' + } + }; + + $rootScope.$broadcast('session:started', eventObject); + $rootScope.$digest(); + + expect(RtcommService.putIframeURL.calledOnce).to.be.true; + expect(RtcommService.putIframeURL.calledWith('MockID', 'localhost')).to.be.true; + + }); + + it('should open a pushed iframe url in a new tab', function(){ + sandbox.stub($sce, 'trustAsResourceUrl', function(url){return url;}); + sandbox.stub($window, 'open'); + var element = compileIFrame(true); + + $rootScope.$broadcast('rtcomm::iframeUpdate', 'MockID','https://wasdev.net/webrtc'); + $rootScope.$digest(); + + expect($sce.trustAsResourceUrl.calledOnce).to.be.true; + + expect($sce.trustAsResourceUrl.calledWith('https://wasdev.net/webrtc')).to.be.true; + + expect($window.open.calledOnce).to.be.true; + expect($window.open.calledWith('https://wasdev.net/webrtc', '_blank')).to.be.true; + + + }); + + + + }) + + function compileIFrame(_syncSource) { + var syncSource; + if (typeof _syncSource !== 'undefined') { + syncSource = 'ng-init="(init(' + _syncSource +'))"'; + } + var element = $compile('')($rootScope); + $rootScope.$digest(); + return element; + + } +}) diff --git a/src/js/ui/endpoint/rtcomm-video/rtcomm-video.js b/src/js/ui/endpoint/rtcomm-video/rtcomm-video.js new file mode 100644 index 0000000..a788c60 --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-video/rtcomm-video.js @@ -0,0 +1,85 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This directive manages the WebRTC video screen, including both the self view and the remote view. It + * also takes care of switching state between endpoints based on which endpoint is "actively" being viewed. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .directive('rtcommVideo', rtcommVideo) + .controller('RtcommVideoController', VideoController); + /* @ngInject */ + function rtcommVideo() { + var directive = { + restrict: 'E', + templateUrl: 'templates/rtcomm/rtcomm-video.html', + controller: VideoController, + controllerAs: 'videoVM', + bindToController: true + }; + + return directive; + } + + VideoController.$inject = ['RtcommService', '$scope', '$log']; + + // /* @ngInject */ + function VideoController(RtcommService, $scope, $log) { + var vm = this; + $log.debug('VideoController Starting'); + vm.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); + // $scope.init = function(selfView, remoteView) { + // RtcommService.setViewSelector(selfView, remoteView); + // + // var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); + // if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null) + // RtcommService.setVideoView(videoActiveEndpointUUID); + // }; + + // Go ahead and initialize the local media here if an endpoint already exist. + var videoActiveEndpointUUID = RtcommService.getActiveEndpoint(); + if (typeof videoActiveEndpointUUID !== "undefined" && videoActiveEndpointUUID != null){ + RtcommService.setVideoView(videoActiveEndpointUUID); + + } + + $scope.$on('endpointActivated', function(event, endpointUUID) { + // Not to do something here to show that this button is live. + $log.debug('rtcommVideo: endpointActivated =' + endpointUUID); + RtcommService.setVideoView(endpointUUID); + vm.avConnected = RtcommService.isWebrtcConnected(RtcommService.getActiveEndpoint()); + }); + // // + // $scope.$on('noEndpointActivated', function(event) { + // vm.avConnected = false; + // }); + // + // $scope.$on('webrtc:connected', function(event, eventObject) { + // if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) + // vm.avConnected = true; + // }); + // + // $scope.$on('webrtc:disconnected', function(event, eventObject) { + // if (RtcommService.getActiveEndpoint() == eventObject.endpoint.id) + // vm.avConnected = false; + // }); + } +})(); diff --git a/src/js/ui/endpoint/rtcomm-video/rtcomm-video.spec.js b/src/js/ui/endpoint/rtcomm-video/rtcomm-video.spec.js new file mode 100644 index 0000000..7b4c6fa --- /dev/null +++ b/src/js/ui/endpoint/rtcomm-video/rtcomm-video.spec.js @@ -0,0 +1,103 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('Unit Testing: RtcommVideo directive', function() { + var $compile, _$rootScope, sandbox, scope, element; + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); + + //Mock RtcommService + beforeEach(function() { + RtcommService = { + isWebrtcConnected: function() {}, + setViewSelector: function(selfView, remoteView) {}, + + setVideoView: function(activeEndpointUUID) {}, + + getActiveEndpoint: function() {} + } + + module(function($provide) { + $provide.value('RtcommService', RtcommService); + }); + }); + + + afterEach(function() { + sandbox.restore(); + }); + + describe('when an endpoint is already initialized', function() { + //Setup Test + beforeEach(inject(function($compile, $rootScope) { + sandbox = sinon.sandbox.create(); + + sandbox.stub(RtcommService, 'getActiveEndpoint', function() { + return 'A'; + }); + sandbox.spy(RtcommService, 'setVideoView'); + _$rootScope = $rootScope; + + compileVideoElement($compile); + + + })); + + it('should call RtcommService to attach endpoint to the video elements', function() { + expect(RtcommService.setVideoView.calledOnce).to.be.true; + }) + + }); + + describe('when an endpoint not initialized', function() { + //Setup Test + beforeEach(inject(function($compile, $rootScope) { + sandbox = sinon.sandbox.create(); + + sandbox.spy(RtcommService, 'setVideoView'); + sandbox.stub(RtcommService, 'isWebrtcConnected', function(){ + return true; + }); + _$rootScope = $rootScope; + + compileVideoElement($compile); + })); + + it('should activate the video view on endpoint activated event', function(){ + _$rootScope.$broadcast('endpointActivated', 'A'); + _$rootScope.$digest(); + expect(RtcommService.setVideoView.calledOnce).to.be.true; + expect(RtcommService.isWebrtcConnected.called).to.be.true; + }); + + + }); + + + function compileVideoElement($compile){ + element = $compile('')(_$rootScope); + _$rootScope.$digest(); + + } + + // it('RtcommVideo directive should be available', function() { + // var element = $compile('')($rootScope); + // $rootScope.$digest(); + // expect(element.html()).to.include('id="videoContainer"'); + // }); +}) diff --git a/src/js/ui/modals/alert-modal/alert-modal.js b/src/js/ui/modals/alert-modal/alert-modal.js new file mode 100644 index 0000000..72cb30b --- /dev/null +++ b/src/js/ui/modals/alert-modal/alert-modal.js @@ -0,0 +1,115 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This modal is displayed on receiving an inbound call. It handles the alerting event. + * Note that it can also auto accept requests for enabling A/V. + */ + +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommAlertModalController', RtcommAlertModalController) + .controller('RtcommAlertModalInstanceController', RtcommAlertModalInstanceController); + + RtcommAlertModalController.$inject = ['RtcommService', '$uibModal', '$rootScope', '$scope', '$log']; + + /* @ngInject */ + function RtcommAlertModalController(RtcommService, $uibModal, $rootScope, $scope, $log) { + var vm = this; + vm.alertingEndpointUUID = null; + vm.autoAnswerNewMedia = false; + vm.alertActiveEndpointUUID = RtcommService.getActiveEndpoint(); + vm.caller = null; + + vm.showAlerting = function(size) { + + var modalInstance = $uibModal.open({ + templateUrl: 'templates/rtcomm/rtcomm-modal-alert.html', + controller: 'RtcommAlertModalInstanceController', + size: size, + backdrop: 'static', + resolve: { + caller: function() { + return vm.caller; + } + } + }); + + modalInstance.result.then( + function() { + var alertingEndpointObject = RtcommService.getEndpoint(vm.alertingEndpointUUID); + + if (alertingEndpointObject) { + $log.debug('Accepting call from: ' + vm.caller + ' for endpoint: ' + vm.alertingEndpointUUID); + alertingEndpointObject.accept(); + $rootScope.$broadcast('rtcomm::alert-success'); + alertingEndpointObject = null; + } + }, + function() { + var alertingEndpointObject = RtcommService.getEndpoint(vm.alertingEndpointUUID); + if (alertingEndpointObject) { + $log.debug('Rejecting call from: ' + vm.caller + ' for endpoint: ' + vm.alertingEndpointUUID); + alertingEndpointObject.reject(); + alertingEndpointObject = null; + } + }); + }; + + $scope.init = function(autoAnswerNewMedia) { + $log.debug('rtcommAlert: autoAnswerNewMedia = ' + autoAnswerNewMedia); + vm.autoAnswerNewMedia = autoAnswerNewMedia; + }; + + $scope.$on('endpointActivated', function(event, endpointUUID) { + vm.alertActiveEndpointUUID = endpointUUID; + }); + + $scope.$on('session:alerting', function(event, eventObject) { + + if ((vm.alertActiveEndpointUUID == eventObject.endpoint.id && vm.autoAnswerNewMedia == false) || + (vm.alertActiveEndpointUUID != eventObject.endpoint.id)) { + $log.debug('rtcommAlert: display alterting model: alertActiveEndpointUUID = ' + eventObject.endpoint + ' autoAnswerNewMedia = ' + vm.autoAnswerNewMedia); + vm.caller = eventObject.endpoint.getRemoteEndpointID(); + vm.alertingEndpointUUID = eventObject.endpoint.id; + vm.showAlerting(); + } else { + $log.debug('Accepting media from: ' + eventObject.endpoint.getRemoteEndpointID() + ' for endpoint: ' + eventObject.endpoint.id); + eventObject.endpoint.accept(); + } + }); + + } + + RtcommAlertModalInstanceController.$inject = ['$scope', '$uibModalInstance', '$log', 'caller']; + + function RtcommAlertModalInstanceController($scope, $uibModalInstance, $log, caller) { + $scope.caller = caller; + $scope.ok = function () { + $log.debug('Accepting alerting call'); + $uibModalInstance.close(); + }; + + $scope.cancel = function () { + $log.debug('Rejecting alerting call'); + $uibModalInstance.dismiss('cancel'); + + }; + }; +})(); diff --git a/src/js/ui/modals/alert-modal/alert-modal.spec.js b/src/js/ui/modals/alert-modal/alert-modal.spec.js new file mode 100644 index 0000000..892edb3 --- /dev/null +++ b/src/js/ui/modals/alert-modal/alert-modal.spec.js @@ -0,0 +1,171 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Controller Testing: Rtcomm Alert Modal', function() { + var $compile, $rootScope, $uibModal, element, sandbox, body; + + beforeEach(module("rtcomm.templates")); + + beforeEach(module('angular-rtcomm-ui')); + + //Setup test environment + beforeEach(inject(function($compile, $rootScope, $uibModal, RtcommService, $window) { + sandbox = sinon.sandbox.create(); + _$rootScope = $rootScope; + element = $compile('
')(_$rootScope); + _$rootScope.$digest(); + + })); + + afterEach(function() { + sandbox.restore(); + }); + it('alert modal controller should be available', function() { + expect(element.attr('ng-controller')).to.include('RtcommAlertModalController'); + }) + it('should open on sesssion:alerting and accept', inject(function($uibModal, RtcommService) { + + var mockModal = getMockModal(); + + var rtcommServiceStub = sinon.stub(RtcommService, 'getEndpoint', function() { + return { + accept: function() {} + } + }); + + var modalSpy = sinon.stub($uibModal, 'open', function() { + return mockModal; + }); + + //Emit an rtcomm-alerting event + _$rootScope.$broadcast('session:alerting', { + endpoint: { + id: 'testid', + getRemoteEndpointID: function() { + return 'temp2' + } + } + }); + + expect(modalSpy.calledOnce).to.be.true; + + mockModal.close(); + expect(rtcommServiceStub.calledOnce).to.be.true; + + modalSpy.restore(); + })); + + it('should open on session:alerting and reject correctly', inject(function(RtcommService, $uibModal) { + var mockModal = getMockModal(); + + var rtcommServiceStub = sinon.stub(RtcommService, 'getEndpoint', function() { + return { + reject: function() {} + } + }); + + var modalSpy = sinon.stub($uibModal, 'open', function() { + return mockModal; + }); + + //Emit an rtcomm-alerting event + _$rootScope.$broadcast('session:alerting', { + endpoint: { + id: 'testid', + getRemoteEndpointID: function() { + return 'temp2' + } + } + }); + + expect(modalSpy.calledOnce).to.be.true; + + mockModal.dismiss('cancel'); + expect(rtcommServiceStub.calledOnce).to.be.true; + + modalSpy.restore(); + rtcommServiceStub.restore(); + })); + + it('should listen to endpointActivated event', function(){ + _$rootScope.$broadcast('endpointActivated', 'EndpointUUID'); + _$rootScope.$digest(); + + + }); + + describe('Testing RtcommAlertModalInstanceController', function() { + var scope, ctrl; + beforeEach(inject(function($rootScope, $log, $controller) { + modalInstance = { + close: function(){}, + dismiss: function(){} + } + scope = $rootScope.$new(); + ctrl = $controller('RtcommAlertModalInstanceController', { + $scope: scope, + $uibModalInstance: modalInstance, + $log: $log, + caller: 'MockUser' + }); + })); + + it('should be defined correctly', function(){ + expect(scope.caller).to.equal('MockUser'); + }); + + it('should call "ok" on click', function(){ + var modalInstanceSpy = sinon.spy(modalInstance, 'close'); + scope.ok(); + + expect(modalInstanceSpy.called).to.be.true; + modalInstanceSpy.restore(); + }); + + it('should call "cancel" on click', function(){ + var modalInstanceSpy = sinon.spy(modalInstance, 'dismiss'); + scope.cancel(); + expect(modalInstanceSpy.called).to.be.true; + modalInstanceSpy.restore(); + + }); + + }); + describe.skip('should automatically accept calls when autoAnswerNewMedia is enabeld', function() { + + + }) + + function getMockModal() { + return { + result: { + then: function(successCallback, failureCallback) { + this.successCallback = successCallback; + this.failureCallback = failureCallback; + } + }, + close: function() { + this.result.successCallback(); + }, + + dismiss: function(type) { + this.result.failureCallback(); + } + } + } +}) diff --git a/src/js/ui/modals/call-modal/call-modal.js b/src/js/ui/modals/call-modal/call-modal.js new file mode 100644 index 0000000..86e5057 --- /dev/null +++ b/src/js/ui/modals/call-modal/call-modal.js @@ -0,0 +1,101 @@ +/** + * (C) Copyright IBM Corporation 2015. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a modal controller for placing an outbound call to a static callee such as a queue. + */ +(function() { + 'use strict'; + + angular + .module('angular-rtcomm-ui') + .controller('RtcommCallModalController', RtcommCallModalController) + .controller('RtcommCallModalInstanceController', RtcommCallModalInstanceController); + + RtcommCallModalController.$inject = ['RtcommService', '$uibModal', '$scope', '$log']; + + /* @ngInject */ + function RtcommCallModalController(RtcommService, $uibModal, $scope, $log){ + var vm = this; + vm.calleeID = null; + vm.callerID = null; + + vm.enableCallModel = false; + vm.mediaToEnable = ['chat']; + + vm.init = function(calleeID, mediaToEnable) { + vm.calleeID = calleeID; + + if (typeof mediaToEnable !== "undefined") + vm.mediaToEnable = mediaToEnable; + }; + + vm.placeCall = function(size) { + + var modalInstance = $uibModal.open({ + templateUrl: 'templates/rtcomm/rtcomm-modal-call.html', + controller: 'RtcommCallModalInstanceController', + size: size, + resolve: {} + }); + + modalInstance.result.then( + function(resultName) { + $log.debug('rtcommCallModal: Calling calleeID: ' + vm.calleeID); + $log.debug('rtcommCallModal: CallerID: ' + resultName); + + // This is used to set an alias when the endoint is not defined. + if (vm.callerID == null && (typeof resultName !== "undefined") && resultName != '') { + vm.callerID = resultName; + RtcommService.setAlias(resultName); + } + + RtcommService.placeCall(vm.calleeID, vm.mediaToEnable); + }, + function() { + $log.info('Modal dismissed at: ' + new Date()); + }); + }; + + $scope.$on('rtcomm::init', function(event, success, details) { + $log.debug('RtcommCallModalController: rtcomm::init: success = ' + success); + if (success == true) + vm.enableCallModel = true; + else + vm.enableCallModel = false; + }); + + $scope.$on('session:started', function(event, eventObject) { + vm.enableCallModel = false; + }); + + $scope.$on('session:stopped', function(event, eventObject) { + vm.enableCallModel = true; + }); + + } + + function RtcommCallModalInstanceController($scope, $uibModalInstance, RtcommService) { + $scope.endpointAlias = ''; + $scope.ok = function() { + $uibModalInstance.close($scope.endpointAlias); + }; + $scope.cancel = function() { + $uibModalInstance.dismiss('cancel'); + }; + }; + +})(); diff --git a/src/js/ui/modals/call-modal/call-modal.spec.js b/src/js/ui/modals/call-modal/call-modal.spec.js new file mode 100644 index 0000000..872861d --- /dev/null +++ b/src/js/ui/modals/call-modal/call-modal.spec.js @@ -0,0 +1,47 @@ + +/** + *(C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +describe('Unit Test: Call Modal', function(){ + //Dependencies + var RtcommService, $uibModal, $rootScope; + + //Sandbox + var sandbox; + + var RtcommCallDiv; + beforeEach(module('angular-rtcomm-ui')); + + beforeEach(inject(['$uibModal', 'RtcommService', '$compile', '$rootScope', + function(_$uibModal_, _RtcommService_, _$compile_, _$rootScope_){ + + $uibModal = _$uibModal_; + RtcommService = _RtcommService_; + $compile = _$compile_; + $rootScope = _$rootScope_; + RtcommCallDiv = $compile('
')($rootScope); + + + + } + + ])); + + it('should at least compile without errors', function(){ + + }); +}); diff --git a/src/js/ui/ui.module.js b/src/js/ui/ui.module.js new file mode 100644 index 0000000..95b80e1 --- /dev/null +++ b/src/js/ui/ui.module.js @@ -0,0 +1,27 @@ +/** + * (C) Copyright IBM Corporation 2016. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * The angular-rtcomm-ui module + * This has controllers and directives in it. + */ +(function(){ + +angular + .module('angular-rtcomm-ui', [ + 'ui.bootstrap', + 'angular-rtcomm-service']); + +})(); diff --git a/src/templates/rtcomm/rtcomm-alert.html b/src/templates/rtcomm/rtcomm-alert.html index e10be0f..60e0326 100644 --- a/src/templates/rtcomm/rtcomm-alert.html +++ b/src/templates/rtcomm/rtcomm-alert.html @@ -1,3 +1,3 @@
- {{alert.msg}} + {{alert.msg}}
diff --git a/src/templates/rtcomm/rtcomm-chat.html b/src/templates/rtcomm/rtcomm-chat.html index b57225b..e0c9fc7 100644 --- a/src/templates/rtcomm/rtcomm-chat.html +++ b/src/templates/rtcomm/rtcomm-chat.html @@ -6,10 +6,10 @@
    -
  • +
  • - {{chat.name}} - + {{chat.name}} + {{chat.time | date:'HH:mm:ss'}}
    @@ -20,9 +20,9 @@ diff --git a/src/templates/rtcomm/rtcomm-endpoint-status.html b/src/templates/rtcomm/rtcomm-endpoint-status.html index d7ca13a..65ca013 100644 --- a/src/templates/rtcomm/rtcomm-endpoint-status.html +++ b/src/templates/rtcomm/rtcomm-endpoint-status.html @@ -1,13 +1,13 @@
    -
    diff --git a/src/templates/rtcomm/rtcomm-iframe.html b/src/templates/rtcomm/rtcomm-iframe.html index dfba673..a2ac28c 100644 --- a/src/templates/rtcomm/rtcomm-iframe.html +++ b/src/templates/rtcomm/rtcomm-iframe.html @@ -4,29 +4,29 @@ URL Sharing
- +
-
-
- + - +
- \ No newline at end of file + diff --git a/src/templates/rtcomm/rtcomm-queues.html b/src/templates/rtcomm/rtcomm-queues.html index 394cc30..76b9dad 100644 --- a/src/templates/rtcomm/rtcomm-queues.html +++ b/src/templates/rtcomm/rtcomm-queues.html @@ -4,7 +4,7 @@ Queues
- +
- + diff --git a/src/templates/rtcomm/rtcomm-register.html b/src/templates/rtcomm/rtcomm-register.html index c6b2c3e..c6c3d66 100644 --- a/src/templates/rtcomm/rtcomm-register.html +++ b/src/templates/rtcomm/rtcomm-register.html @@ -2,9 +2,9 @@
+ placeholder="Enter your ID here..." type="text" ng-model="registerVM.reguserid" ng-disabled="(registerVM.nextAction=='Unregister')"> - +
diff --git a/src/templates/rtcomm/rtcomm-sessionmgr.html b/src/templates/rtcomm/rtcomm-sessionmgr.html index 9bd9955..a054eb6 100644 --- a/src/templates/rtcomm/rtcomm-sessionmgr.html +++ b/src/templates/rtcomm/rtcomm-sessionmgr.html @@ -1,7 +1,7 @@
-
-
\ No newline at end of file + diff --git a/src/templates/rtcomm/rtcomm-video.html b/src/templates/rtcomm/rtcomm-video.html index 641c8e4..50406f1 100644 --- a/src/templates/rtcomm/rtcomm-video.html +++ b/src/templates/rtcomm/rtcomm-video.html @@ -3,7 +3,5 @@ - + - - diff --git a/test/angular-rtcomm-directives.js b/test/angular-rtcomm-directives.js new file mode 100644 index 0000000..c36222d --- /dev/null +++ b/test/angular-rtcomm-directives.js @@ -0,0 +1,202 @@ +'use strict'; +/** + * This file contains all the directives represented as Selenium driver selectors + * and exposed by using functions that calls up driver functions such as click, waiting, + * etc. + */ + + +/* globals element */ +/* globals by */ +/* globals EC */ +/* globals document */ +function RtcommRegister(browser) { + var element = browser.element; + this.inputElement = element(by.model('registerVM.reguserid')); + this.button = element(by.id('btn-register')); + this.input = function(user) { + this.inputElement.sendKeys(user); + return this; + }; + + this.clickRegister = function() { + this.button.click(); + return this; + }; +} + +/** + * Represents the rtcomm-video directive + */ +function RtcommVideo(_browser) { + var browser = _browser; + var element = browser.element; + this.remoteViewID = 'remoteView'; + this.selfViewID = 'selfView'; + this.remoteView = element(by.id('remoteView')); + this.selfView = element(by.id('selfView')); + + this.waitForVideoReady = function(selector, _ms, _msg) { + var msg = _msg || 'Timed out while retrieving video state'; + var ms = _ms || 5000; + + var script = function(selector) { + var callback = arguments[arguments.length - 1]; + + try { + + var video = document.querySelector(selector); + if (video.readyState === 4) { + callback(video.readyState); + } else { + video.onloadeddata = function() { + if (video.readyState === 4) { + callback(video.readyState); + } + }; + } + + } catch (err) { + + callback(err); + } + }; + + return browser.driver.wait(browser.driver.executeAsyncScript(script, [selector]), ms, msg); + }; +} + + +/** + * Represents the rtcomm-chat directive + */ +function RtcommChat(browser) { + var element = browser.element; + + this.send = element(by.id('btn-chat')); + this.input = element(by.model('chatVM.message')); + this.sendChatMessage = function(msg) { + expect(this.send.isEnabled()).to.eventually.be.true; + + this.input.sendKeys(msg); + this.send.click(); + + }; + this.getChatMessages = function() { + this.chatElements = element.all(by.css('ul.chat > li')); + + var chats = this.chatElements.map(function(chatMessage, index) { + + return { + name: chatMessage.element(by.css('strong.ng-binding')).getText(), + message: chatMessage.element(by.css('p.ng-binding')).getText() + }; + }); + + return chats; + }; + +} + +function RtcommEndpointStatus() { + this.statusText = element(by.css('p.endpoint-controls-title > span')); +} + +/** + * Represents the rtcomm-alert-modal + */ +function RtcommAlertModal(_browser) { + var browser = _browser; + var element = browser.element; + this.ok = element(by.css('[ng-click="ok()"]')); + this.cancel = element(by.css('[ng-click="cancel()"]')); + + this.waitUntilDisplayed = function(_ms, _msg) { + var msg = _msg || 'Waited too long until alert modal was displayed...'; + var ms = _ms || 5000; + + browser.wait(EC.elementToBeClickable(this.ok), ms, msg); + + }; +} + + +/** + * Represents the rtcomm-presence directive + */ +function RtcommPresence(_browser) { + var browser = _browser; + var element = browser.element; + + this.call = function(name) { + + browser.wait(EC.visibilityOf(element(by.css('div[treecontrol]'))), 5000, + 'Rtcomm-presence tree structure not found -> Possibly not initialized correctly'); + + //Expand the presence tree + expandPresenceTree(); + + function clickNodeToCall() { + var nodes = element.all(by.css('div.tree-label')); + + var calleeNode = nodes.filter(function(node, index) { + var span = node.element(by.css('span.ng-binding')); + return span.getText().then(function(text) { + return text.indexOf(name) > -1; + }); + + }); + + calleeNode.first().element(by.css('button')).click(); + } + + function expandPresenceTree() { + //Find collapsed elements + var collapsedElements = element.all(by.css('.tree-collapsed > i.tree-branch-head')); + + + collapsedElements.count().then(function(count) { + + //If no more collapsed elements exist, you can click on the node to call + if (count === 0) { + + clickNodeToCall(); + } + //Expand the collapsed nodes found + else { + + + collapsedElements.each(function(element, index) { + element.click(); + if (index === count - 1) { + expandPresenceTree(); + } + }); + } + }); + } + }; +} +/** + * Represents the RtcommEndpointController + */ +function RtcommEndpointController(_browser) { + + var browser = _browser; + var element = browser.element; + + this.disconnectBtn = element(by.id('btnDisconnectEndpoint')); + this.toggleAVBtn = element(by.id('btnEnableAV')); + +} + + +module.exports = { + RtcommRegister: RtcommRegister, + RtcommChat: RtcommChat, + RtcommVideo: RtcommVideo, + RtcommAlertModal: RtcommAlertModal, + RtcommPresence: RtcommPresence, + RtcommEndpointController: RtcommEndpointController + +}; diff --git a/test/lib/browser-config-generator.js b/test/lib/browser-config-generator.js new file mode 100644 index 0000000..35bf471 --- /dev/null +++ b/test/lib/browser-config-generator.js @@ -0,0 +1,52 @@ +var FirefoxProfile = require('firefox-profile'); +var q = require('q'); + +module.exports = { + generateBrowserProfile: generateBrowserProfile +}; + +function generateBrowserProfile(capability) { + + if (capability.browserName === 'chrome') + return generateChromeProfile(capability); + else if (capability.browserName === 'firefox') + return generateFirefoxProfile(capability); +} + + +function generateFirefoxProfile(capability) { + var deferred = q.defer(); + + var firefoxProfile = new FirefoxProfile(); + firefoxProfile.setPreference('media.peerconnection.enabled', true); + firefoxProfile.setPreference('media.navigator.enabled', true); + firefoxProfile.setPreference("media.navigator.streams.fake", true); + firefoxProfile.setPreference('media.navigator.permission.disabled', true); + firefoxProfile.encoded(function(encodedProfile) { + capability.firefox_profile = encodedProfile; + deferred.resolve(capability); + }); + return deferred.promise; + +} + +function generateChromeProfile(capability) { + var deferred = q.defer(); + var chromeFlags = { + 'args': ['--start-maximized', + '--allow-file-access-from-files', + '--disable-gesture-requirement-for-media-playback', + '--allow-file-access', + '--use-fake-ui-for-media-stream', + '--use-fake-device-for-media-stream', + '--start-maximized' + ] + }; + + setTimeout(function(){ + capability.chromeOptions = chromeFlags; + deferred.resolve(capability); + }, 1000); + + return deferred.promise; +} diff --git a/test/rtcomm-chat/index.html b/test/rtcomm-chat/index.html new file mode 100644 index 0000000..61659eb --- /dev/null +++ b/test/rtcomm-chat/index.html @@ -0,0 +1,62 @@ + + + + + + + + + E2E: rtcomm-video + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+
+ +
+ +
+ + + diff --git a/test/rtcomm-chat/rtcomm-chat.spec.js b/test/rtcomm-chat/rtcomm-chat.spec.js new file mode 100644 index 0000000..cb514aa --- /dev/null +++ b/test/rtcomm-chat/rtcomm-chat.spec.js @@ -0,0 +1,113 @@ +/* globals browser */ +/* globals by */ +/* globals element */ + +var AngularRtcomm = require('../angular-rtcomm-directives.js'); + +var RtcommChat = AngularRtcomm.RtcommChat; +var RtcommAlertModal = AngularRtcomm.RtcommAlertModal; +var RtcommRegister = AngularRtcomm.RtcommRegister; + +describe('E2E Integration: rtcomm-chat directive with RtcommService', function() { + var newBrowser; + var userOne, userTwo; + beforeEach(function() { + browser.get('rtcomm-chat/'); + newBrowser = browser.forkNewDriverInstance(true); + userOne = createUser(browser); + userTwo = createUser(newBrowser); + }); + + afterEach(function(){ + newBrowser.quit(); + }); + it('should maintain a chat session between users', function() { + //Register User one + userOne.register('UserOne'); + + //Register user two + userTwo.register('UserTwo'); + + //UserOne places a call to UserTwo + userOne.placeCall('UserTwo'); + + //User Two should wait for alert modal + browser.wait(EC.elementToBeClickable(userTwo.rtcommAlertModal.ok), 5000, 'Waited too long for alert modal'); + + //Accept the modal + userTwo.rtcommAlertModal.ok.click(); + + //Send a message to user one + userTwo.rtcommChat.sendChatMessage('Hello World!'); + + browser.driver.sleep(500); + + userOne.rtcommChat.getChatMessages().then(function(messages) { + + expect(messages[0].message).to.equal('Hello World!', 'Should\' received a message in the chat'); + }); + + + userOne.rtcommChat.sendChatMessage('How are you doing!?'); + + userTwo.rtcommChat.sendChatMessage('Pretty good and you?'); + + userOne.rtcommChat.sendChatMessage('Great, just testing out this directive!!!'); + + var conversation = [{ + name: 'UserTwo', + message: 'Hello World!' + }, { + name: 'UserOne', + message: 'How are you doing!?' + }, { + name: 'UserTwo', + message: 'Pretty good and you?' + }, { + name: 'UserOne', + message: 'Great, just testing out this directive!!!' + }]; + + //Verify that both sides of the chats appear + userOne.rtcommChat.getChatMessages().then(function(messages) { + messages.forEach(function(message, index) { + expect(message.name).to.equal(conversation[index].name, 'Incorrect user match in chat'); + expect(message.message).to.equal(conversation[index].message, 'Incorrect message sent in chat'); + }); + }); + + //Verify user two can also see the chats + userTwo.rtcommChat.getChatMessages().then(function(messages) { + messages.forEach(function(message, index) { + expect(message.name).to.equal(conversation[index].name, 'Incorrect user match in chat'); + expect(message.message).to.equal(conversation[index].message, 'Incorrect message sent in chat'); + }); + }); + }); + + + function createUser(browser) { + var user = {}; + user.rtcommChat = new RtcommChat(browser); + user.rtcommRegister = new RtcommRegister(browser); + user.rtcommAlertModal = new RtcommAlertModal(browser); + user.register = function(name) { + + user.rtcommRegister + .input(name) + .clickRegister(); + return this; + }; + + user.placeCall = function(name) { + var input = element(by.model('vm.callee')); + var callBtn = element(by.id('place-call-btn')); + + input.sendKeys(name); + callBtn.click(); + + } + return user; + + } +}); diff --git a/test/rtcomm-chat/script.js b/test/rtcomm-chat/script.js new file mode 100644 index 0000000..75fc544 --- /dev/null +++ b/test/rtcomm-chat/script.js @@ -0,0 +1,30 @@ + 'use strict'; + angular + .module('app', [ + 'angular-rtcomm' + ]) + + .controller('MyController', RtcommController); + + function RtcommController($scope, RtcommService, $log){ + var vm = this; + var config = { + server: 'localhost', + port: 8083, + userid: '', + presenceTopic: 'rtcomm' + } + $log.debug('Activated'); + RtcommService.setConfig(config); + vm.callee = ''; + + vm.call = function(){ + $log.debug('Calling: ' + vm.callee); + RtcommService.placeCall(vm.callee, ['chat']); + + } + + } + + + diff --git a/test/rtcomm-video/index.html b/test/rtcomm-video/index.html new file mode 100644 index 0000000..84e42a0 --- /dev/null +++ b/test/rtcomm-video/index.html @@ -0,0 +1,68 @@ + + + + + + + + + E2E: rtcomm-video + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+ + + + + +
+
+ +
+ +
+ + + diff --git a/test/rtcomm-video/rtcomm-video-integration.spec.js b/test/rtcomm-video/rtcomm-video-integration.spec.js new file mode 100644 index 0000000..3ffec47 --- /dev/null +++ b/test/rtcomm-video/rtcomm-video-integration.spec.js @@ -0,0 +1,83 @@ +/* globals browser */ +/* globals expect */ +/* globals element */ +/* glboals EC */ +/* globals by */ + +var AngularRtcomm = require('../angular-rtcomm-directives.js'); + +var RtcommVideo = AngularRtcomm.RtcommVideo; +var RtcommAlertModal = AngularRtcomm.RtcommAlertModal; +var RtcommRegister = AngularRtcomm.RtcommRegister; + +describe('E2E Integration: rtcomm-video with RtcommService', function() { + + var newBrowser; + + var userOne, userTwo; + beforeEach(function() { + browser.get('rtcomm-video/'); + + newBrowser = browser.forkNewDriverInstance(true); + userOne = createUser(browser); + userTwo = createUser(newBrowser); + + }); + + afterEach(function() { + newBrowser.quit(); + }); + it('should display the video session between two users', function() { + + //Register user one + userOne.register('UserOne'); + + //Register user two + userTwo.register('UserTwo'); + + + userOne.placeCall('UserTwo'); + + browser.wait(EC.elementToBeClickable(userTwo.rtcommAlertModal.ok), 5000, 'Waited too long for alert moda'); + + userTwo.rtcommAlertModal.ok.click(); + + browser.driver.sleep(3000); + + //Video ready state is supposed to be 4 (READY_STATE ENUM === 4) + + + expect(userOne.rtcommVideo.waitForVideoReady('#selfView', 5000)).to.eventually.equal(4); + expect(userOne.rtcommVideo.waitForVideoReady('#remoteView', 5000)).to.eventually.equal(4); + + + + expect(userTwo.rtcommVideo.waitForVideoReady('#selfView', 5000)).to.eventually.equal(4); + expect(userTwo.rtcommVideo.waitForVideoReady('#remoteView', 5000)).to.eventually.equal(4); + }); + + function createUser(browser) { + + var user = {}; + + user.rtcommVideo = new RtcommVideo(browser); + user.rtcommRegister = new RtcommRegister(browser); + user.rtcommAlertModal = new RtcommAlertModal(browser); + + user.placeCall = function(name) { + var input = element(by.model('vm.callee')); + var callBtn = element(by.id('place-call-btn')); + + input.sendKeys(name); + callBtn.click(); + + } + user.register = function(name) { + user.rtcommRegister + .input(name) + .clickRegister(); + } + return user; + } + +}); diff --git a/test/rtcomm-video/script.js b/test/rtcomm-video/script.js new file mode 100644 index 0000000..1b19f8a --- /dev/null +++ b/test/rtcomm-video/script.js @@ -0,0 +1,30 @@ + 'use strict'; + angular + .module('app', [ + 'angular-rtcomm' + ]) + + .controller('MyController', RtcommController); + + function RtcommController($scope, RtcommService, $log){ + var vm = this; + var config = { + server: 'localhost', + port: 8083, + userid: '', + presenceTopic: 'rtcomm' + } + $log.debug('Activated'); + RtcommService.setConfig(config); + vm.callee = ''; + + vm.call = function(){ + $log.debug('Calling: ' + vm.callee); + RtcommService.placeCall(vm.callee, ['webrtc']); + + } + + } + + + diff --git a/test/sample.html b/test/sample.html deleted file mode 100644 index 1564a9f..0000000 --- a/test/sample.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - angular-rtcomm Sample Page - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
-
- - -
-
- -
-
-
-
-
- - -
-
- - -
-
-
-
- Video -
-
- -
-
-
-
- Presence -
-
- -
-
- -
-
- - -
-
-
-
-
- - diff --git a/test/sample/index.html b/test/sample/index.html new file mode 100644 index 0000000..7358d54 --- /dev/null +++ b/test/sample/index.html @@ -0,0 +1,111 @@ + + + + + + + + + E2E: Sample Angular-Rtcomm + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + +
+
+ +
+
+
+
+
+ + + +
+
+ + +
+
+
+
+ Video +
+
+ +
+
+
+
+ Presence +
+
+ +
+
+ +
+
+ + +
+
+
+
+
+ + + diff --git a/test/sample/integration.spec.js b/test/sample/integration.spec.js new file mode 100644 index 0000000..f74309a --- /dev/null +++ b/test/sample/integration.spec.js @@ -0,0 +1,156 @@ +/* globals browser */ +var AngularRtcomm = require('../angular-rtcomm-directives.js'); +var RtcommEndpointController = AngularRtcomm.RtcommEndpointController; +var RtcommChat = AngularRtcomm.RtcommChat; +var RtcommVideo = AngularRtcomm.RtcommVideo; +var RtcommPresence = AngularRtcomm.RtcommPresence; +var RtcommAlertModal = AngularRtcomm.RtcommAlertModal; +var RtcommRegister = AngularRtcomm.RtcommRegister; +/** + * Integration Test for the Sample + */ +describe('E2E Testing: Directives Integration Sample', function() { + + var newBrowser; + var userOne, userTwo; + /** + * Before each test retrieve the url and create a second browser window + */ + beforeEach(function() { + browser.get('sample/'); + newBrowser = browser.forkNewDriverInstance(true); + + //Create users (see below) + userOne = createUser(browser); + userTwo = createUser(newBrowser); + + }); + + //Close the second window after each test spec + afterEach(function() { + newBrowser.quit(); + }); + + + it('each user should be able to register successfully', function() { + + userOne.register('UserOne'); + + userTwo.register('UserTwo'); + + browser.driver.sleep(2000); + }); + + it('should be able to maintain a chat session between users', function() { + //Register both users + userOne.register('UserOne'); + userTwo.register('UserTwo'); + + //Define chat conversation + var conversation = [{ + name: 'UserTwo', + message: 'Hello!' + }, { + name: 'UserOne', + message: 'Hi!' + }, { + name: 'UserOne', + message: 'Do you want to start a video chat?' + }, { + name: 'UserTwo', + message: 'Sure' + } + + ]; + + //Call using the presence directive + userOne.rtcommPresence.call('UserTwo'); + + //Wait for alert modal to show + userTwo.rtcommAlertModal.waitUntilDisplayed(); + + //Click 'ok' + userTwo.rtcommAlertModal.ok.click(); + + //Send chat messages from both sides + conversation.forEach(function(message, index) { + var sendee; + + if (message.name === 'UserTwo') + sendee = userTwo; + else if (message.name === 'UserOne') + sendee = userOne; + sendee.rtcommChat.sendChatMessage(message.message); + }); + + //Expect that user one can see both chats + userOne.rtcommChat.getChatMessages().then(function(messages) { + messages.forEach(function(message, index) { + expect(message.name).to.equal(conversation[index].name, 'Incorrect user match in chat'); + expect(message.message).to.equal(conversation[index].message, 'Incorrect message sent in chat'); + }); + }); + + //Verify user two can also see the chats + userTwo.rtcommChat.getChatMessages().then(function(messages) { + messages.forEach(function(message, index) { + expect(message.name).to.equal(conversation[index].name, 'Incorrect user match in chat'); + expect(message.message).to.equal(conversation[index].message, 'Incorrect message sent in chat'); + }); + }); + + //Now we enable the video + + //Click 'Enable A/V' + userOne.browser.wait(EC.elementToBeClickable(userOne.rtcommEndpointController.toggleAVBtn), 5000, "Wait till the button is clickable"); + expect(userOne.rtcommEndpointController.toggleAVBtn.getText()).to.eventually.equal('Enable A/V', 'Verify the \'Enable A/V\' button is functioning correctly'); + userOne.rtcommEndpointController.toggleAVBtn.click(); + + userTwo.rtcommAlertModal.waitUntilDisplayed(); + + userTwo.rtcommAlertModal.ok.click(); + + browser.driver.sleep(3000); //Let the video play out for a bit + //We should expect to see the video to work + expect(userOne.rtcommVideo.waitForVideoReady('#selfView', 5000)).to.eventually.equal(4); + expect(userOne.rtcommVideo.waitForVideoReady('#remoteView', 5000)).to.eventually.equal(4); + + + + expect(userTwo.rtcommVideo.waitForVideoReady('#selfView', 5000)).to.eventually.equal(4); + expect(userTwo.rtcommVideo.waitForVideoReady('#remoteView', 5000)).to.eventually.equal(4); + }); + + function createUser(browser) { + var user = {}; + user.browser = browser; + user.rtcommChat = new RtcommChat(browser); + user.rtcommRegister = new RtcommRegister(browser); + user.rtcommAlertModal = new RtcommAlertModal(browser); + user.rtcommVideo = new RtcommVideo(browser); + user.rtcommPresence = new RtcommPresence(browser); + user.rtcommEndpointController = new RtcommEndpointController(browser); + user.register = function(name) { + + user.rtcommRegister + .input(name) + .clickRegister(); + + user.browser.wait(EC.not(EC.elementToBeClickable(user.rtcommRegister.inputElement)), 5000); + expect(user.rtcommRegister.inputElement.getAttribute('value')).to.eventually.equal(name); + return this; + }; + + + user.placeCall = function(name) { + var input = element(by.model('vm.callee')); + var callBtn = element(by.id('place-call-btn')); + + input.sendKeys(name); + callBtn.click(); + + } + return user; + + } +}); diff --git a/test/sample/sampleConfig.json b/test/sample/sampleConfig.json new file mode 100644 index 0000000..b027d31 --- /dev/null +++ b/test/sample/sampleConfig.json @@ -0,0 +1,9 @@ +{ + "server": "messagesight.demos.ibm.com", + "port": 1883, + "rtcommTopicPath": "/rtcommAngularSample/", + "userid": "", + "broadcastAudio": true, + "broadcastVideo": true, + "presenceTopic": "sampleRoom" +} diff --git a/test/sampleConfig.json b/test/sampleConfig.json deleted file mode 100644 index 00c4ab4..0000000 --- a/test/sampleConfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "server" : "messagesight.demos.ibm.com", - "port" : 1884, - "rtcommTopicPath" : "/rtcommAngularSample/", - "userid" : "", - "broadcastAudio" : true, - "broadcastVideo" : true, - "presenceTopic" : "sampleRoom" -} diff --git a/test/server.js b/test/server.js new file mode 100644 index 0000000..e508188 --- /dev/null +++ b/test/server.js @@ -0,0 +1,27 @@ +var mosca = require('mosca'); + +var settings = { + logger: { + level: 'info' + }, + persistence: { + factory: mosca.persistence.Memory + }, + port: 1883, + http: { + port: 8083, + static: './', + bundle: true + } + +}; + +var server = new mosca.Server(settings); +server.on('ready', setup); + +function setup() { + + console.log('Mosca Broker and Web Server are up and running!'); + console.log('MQTT Websocket Port: 8083'); + console.log('Hostname: localhost'); +} diff --git a/test/testChat.js b/test/testChat.js deleted file mode 100644 index c695f06..0000000 --- a/test/testChat.js +++ /dev/null @@ -1,29 +0,0 @@ -describe('Unit testing angular-rtcomm chat', function() { - var $compile, - $rootScope; - - // Load the myApp module, which contains the directive - beforeEach(module('angular-rtcomm')); - - // Store references to $rootScope and $compile - // so they are available to all tests in this describe block - beforeEach(inject(function(_$compile_, _$rootScope_){ - // The injector unwraps the underscores (_) from around the parameter names when matching - $compile = _$compile_; - $rootScope = _$rootScope_; - })); - - angular.mock.module('RtcommService', { - widgetStorage: self.widgetStorage, - widgetEditor: self.widgetEditor - }); - - it('Replaces the element with the appropriate content', function() { - // Compile a piece of HTML containing the directive - var element = $compile("")($rootScope); - // fire all the watches, so the scope expression {{1 + 1}} will be evaluated - $rootScope.$digest(); - // Check that the compiled element contains the templated content - expect(element.html()).toContain("lidless, wreathed in flame, 2 times"); - }); -}); \ No newline at end of file diff --git a/test/testRtcommServiceSpec.js b/test/testRtcommServiceSpec.js deleted file mode 100644 index e806194..0000000 --- a/test/testRtcommServiceSpec.js +++ /dev/null @@ -1,127 +0,0 @@ -describe('Unit testing angular-rtcomm service', function() { - var $rootScope, $log; - - // Load the myApp module, which contains the directive - var RtcommService; - - var rtcommTopicPath = "/testTopic/"; - //var rtcommTopicPath = "/rtcomm-karma-test-" + Math.floor((Math.random() * 1000000) + 1) + "/"; - - var testUserID = "TestID " + Math.floor((Math.random() * 1000000) + 1); - - beforeEach(module('angular-rtcomm')); - - beforeEach(module('angular-rtcomm', function($provide) { - // Output messages - $provide.value('$log', console); - })); - - beforeEach(inject(function (_RtcommService_,_$rootScope_,_$log_) { - RtcommService = _RtcommService_; - $rootScope = _$rootScope_; - $log = _$log_; - - // Required to get evalAsync to fire so that broadcasted messages are received by test code. - RtcommService.setKarmaTesting(); - } - )); - - describe('initialization - no user ID', function () { - - // Before init'ing, - it('check state before init', function () { - expect(RtcommService.isInitialized()).toEqual(false); - }); - - // When init'ing with no user ID, rtcomm.js should not be init'd - it('initialize with no user ID', function () { - var config = { - "server" : "localhost", - "port" : 9080, - "rtcommTopicPath" : "/rtcomm/", - "userid" : "", - "broadcastAudio" : true, - "broadcastVideo" : true, - "presenceTopic" : "karmaPresence" - }; - - RtcommService.setConfig(config); - - expect(RtcommService.isInitialized()).toEqual(false); - }); - }); - - describe('Run test after initialization with user ID', function () { - - var presenceData = null; - - // When init'ing with user ID, rtcomm.js should be init'd - it('initialize with user ID', function (done) { - $log.debug('Karma: initialize with user ID: top: $rootScope: ',$rootScope); - -// spyOn($rootScope, '$broadcast').and.callThrough(); - - $rootScope.$on('rtcomm::init', function (event, success, details) { - $log.debug('Karma: initialize with user ID: rtcomm::init received'); - expect(RtcommService.isInitialized()).toEqual(true); - done(); - }); - - var config = { - "server" : "localhost", - "port" : 9080, - "rtcommTopicPath" : "/rtcomm/", - "userid" : "testUserID", - "broadcastAudio" : true, - "broadcastVideo" : true, - "presenceTopic" : "karmaPresence" - }; - - RtcommService.setConfig(config); - }); - - // Here we publish presence and wait for the result to come in through a notification. - it('test pubishing presence', function (done) { - - $rootScope.$on('rtcomm::init', function (event, success, details) { - $log.debug('Karma: test pubishing presence: rtcomm::init received'); - var presenceMonitor = RtcommService.getPresenceMonitor(); - - presenceMonitor.on('updated', function(){ - - presenceData = presenceMonitor.getPresenceData(); - - $log.debug('Karma: test pubishing presence: presenceData: ',presenceData); - - assert.isArray(presenceData); - assert.lengthOf(presenceData, 1); - assert.deepProperty(presenceData[0], "name"); - assert.deepProperty(presenceData[0], "record"); - assert.deepProperty(presenceData[0], "nodes"); - assert.deepPropertyVal(presenceData[0], "name", "karmaPresence"); - - assert.isArray(presenceData[0].nodes); - assert.lengthOf(presenceData[0].nodes, 1); - assert.deepProperty(presenceData[0].nodes[0], "name"); - assert.deepPropertyVal(presenceData[0].nodes[0], "name", "testUserID"); - done(); - }); - - presenceMonitor.add("karmaPresence"); - RtcommService.publishPresence(); - }); - - var config = { - "server" : "localhost", - "port" : 9080, - "rtcommTopicPath" : "/rtcomm/", - "userid" : "testUserID", - "broadcastAudio" : true, - "broadcastVideo" : true, - "presenceTopic" : "karmaPresence" - }; - - RtcommService.setConfig(config); - }); - }); -}); \ No newline at end of file