diff --git a/static/js/app.js b/static/js/app.js index 80bcefe0..749b37ac 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -184,6 +184,9 @@ define([ var deferred = $.Deferred(); var globalContext = JSON.parse($("#globalcontext").text()); + if (!globalContext.Cfg.Version) { + globalContext.Cfg.Version = "unknown"; + } app.constant("globalContext", globalContext); // Configure language. diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index 23fe08a8..5f80b865 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -20,7 +20,7 @@ */ define(['underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'webrtc.adapter'], function(_, BigScreen, moment, sjcl, Modernizr) { - return ["$scope", "$rootScope", "$element", "$window", "$timeout", "safeDisplayName", "safeApply", "mediaStream", "appData", "playSound", "desktopNotify", "alertify", "toastr", "translation", "fileDownload", "localStorage", "screensharing", "userSettingsData", "localStatus", "dialogs", function($scope, $rootScope, $element, $window, $timeout, safeDisplayName, safeApply, mediaStream, appData, playSound, desktopNotify, alertify, toastr, translation, fileDownload, localStorage, screensharing, userSettingsData, localStatus, dialogs) { + return ["$scope", "$rootScope", "$element", "$window", "$timeout", "safeDisplayName", "safeApply", "mediaStream", "appData", "playSound", "desktopNotify", "alertify", "toastr", "translation", "fileDownload", "localStorage", "screensharing", "userSettingsData", "localStatus", "dialogs", "rooms", function($scope, $rootScope, $element, $window, $timeout, safeDisplayName, safeApply, mediaStream, appData, playSound, desktopNotify, alertify, toastr, translation, fileDownload, localStorage, screensharing, userSettingsData, localStatus, dialogs, rooms) { /*console.log("route", $route, $routeParams, $location);*/ @@ -544,20 +544,16 @@ define(['underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'webrtc.adapte // Unmark authorization process. if (data.Userid) { - mediaStream.users.authorizing(false); - } else if (!mediaStream.users.authorizing()) { + $rootScope.authorizing(false); + } else if (!$rootScope.authorizing()) { // Trigger user data load when not in authorizing phase. $scope.loadUserSettings(); } - if (!$rootScope.roomid && $scope.master.settings.defaultRoom) { + if (rooms.inDefaultRoom() && $scope.master.settings.defaultRoom) { console.log("Selecting default room from settings:", [$scope.master.settings.defaultRoom]); - mediaStream.changeRoom($scope.master.settings.defaultRoom, true); + rooms.joinByName($scope.master.settings.defaultRoom, true); } - - // Always apply room after self received to avoid double stuff. - mediaStream.applyRoom(); - }); mediaStream.webrtc.e.on("peercall", function(event, peercall) { @@ -660,36 +656,36 @@ define(['underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'webrtc.adapte } }; - mediaStream.connector.e.on("open error close", function(event, options) { - var t = event.type; - var opts = $.extend({}, options); + $scope.$on("room.joined", function(ev) { + // TODO(lcooper): Is it really needful to do this stuff? $timeout.cancel(ttlTimeout); - if (!opts.soft) { - // Reset login information for anything not soft. - $scope.userid = $scope.suserid = null; - } - switch (t) { + connected = true; + reconnecting = false; + $scope.updateStatus(true); + }); + + mediaStream.connector.e.on("open error close", function(event) { + $timeout.cancel(ttlTimeout); + $scope.userid = $scope.suserid = null; + switch (event.type) { case "open": - t = "waiting"; connected = true; reconnecting = false; $scope.updateStatus(true); - if (opts.soft) { - return; - } + $scope.setStatus("waiting"); break; case "error": if (reconnecting || connected) { reconnecting = false; reconnect(); - return; + } else { + $scope.setStatus(event.type); } break; case "close": reconnect(); - return; + break; } - $scope.setStatus(t); }); mediaStream.webrtc.e.on("waitforusermedia connecting", function(event, currentcall) { @@ -797,23 +793,6 @@ define(['underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'webrtc.adapte if (mediaStream.connector.connected) { $scope.setStatus("waiting"); } - if ($scope.roomstatus) { - $scope.layout.buddylist = true; - $scope.layout.buddylistAutoHide = false; - } else { - $scope.layout.buddylist = false; - $scope.layout.buddylistAutoHide = true; - } - }); - - $scope.$watch("roomstatus", function(roomstatus) { - if (roomstatus && !$scope.peer) { - $scope.layout.buddylist = true; - $scope.layout.buddylistAutoHide = false; - } else if (!$scope.layout.buddylistAutoHide) { - $scope.layout.buddylist = false; - $scope.layout.buddylistAutoHide = true; - } }); mediaStream.webrtc.e.on("busy", function(event, from) { diff --git a/static/js/controllers/roomchangecontroller.js b/static/js/controllers/roomchangecontroller.js index 084f4a80..16943cd4 100644 --- a/static/js/controllers/roomchangecontroller.js +++ b/static/js/controllers/roomchangecontroller.js @@ -19,72 +19,7 @@ * */ define([], function() { - - // RoomchangeController - return ["$scope", "$element", "$window", "mediaStream", "$http", "$timeout", function($scope, $element, $window, mediaStream, $http, $timeout) { - - //console.log("Room change controller", $element, $scope.roomdata); - - var url = mediaStream.url.api("rooms"); - - var ctrl = this; - ctrl.enabled = true; - - ctrl.getRoom = function(cb) { - $http({ - method: "POST", - url: url, - data: $.param({}), - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - }). - success(function(data, status) { - cb(data); - }). - error(function() { - console.error("Failed to retrieve room link."); - cb({}); - }); - }; - - $scope.changeRoomToId = function(id) { - return mediaStream.changeRoom(id); - }; - - $scope.refreshRoom = function() { - if (ctrl.enabled) { - ctrl.getRoom(function(roomdata) { - console.info("Retrieved room data", roomdata); - $scope.roomdata = roomdata; - $element.find(".btn-roomcreate").get(0).focus(); - }); - } - }; - - $scope.$on("$destroy", function() { - //console.log("Room change controller destroyed"); - ctrl.enabled = false; - }); - - $scope.roomdata = {}; - $scope.$watch("roomdata.name", function(n) { - //console.log("roomdata.name changed", n); - if (!n) { - n = ""; - } - var u = encodeURIComponent(n); - $scope.roomdata.url = "/" + u; - $scope.roomdata.link = mediaStream.url.room(n); - }); - - var roomDataLinkInput = $element.find(".roomdata-link-input"); - if (roomDataLinkInput.length) { - $timeout(function() { - $scope.refreshRoom(); - }, 100); - } - + return ["$scope", "rooms", function($scope, rooms) { + $scope.joinRoomByName = rooms.joinByName; }]; - }); diff --git a/static/js/directives/buddylist.js b/static/js/directives/buddylist.js index b458d768..1c73eb85 100644 --- a/static/js/directives/buddylist.js +++ b/static/js/directives/buddylist.js @@ -21,7 +21,7 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) { // buddyList - return ["$compile", "buddyList", "mediaStream", "contacts", function($compile, buddyList, mediaStream, contacts) { + return ["buddyList", "api", "webrtc", "contacts", function(buddyList, api, webrtc, contacts) { //console.log("buddyList directive"); @@ -30,10 +30,34 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) { $scope.layout.buddylist = false; $scope.layout.buddylistAutoHide = true; - $scope.doCall = function(id) { + var inRoom = false; + var updateBuddyListVisibility = function() { + if (inRoom && !$scope.peer) { + $scope.layout.buddylist = true; + $scope.layout.buddylistAutoHide = false; + } else if (!$scope.layout.buddylistAutoHide) { + $scope.layout.buddylist = false; + $scope.layout.buddylistAutoHide = true; + } + }; + + webrtc.e.on("done", function() { + updateBuddyListVisibility(); + }); - mediaStream.webrtc.doCall(id); + $scope.$on("room.joined", function(ev, room) { + inRoom = true; + updateBuddyListVisibility(); + }); + $scope.$on("room.left", function(ev) { + inRoom = false; + buddylist.onClosed(); + updateBuddyListVisibility(); + }); + + $scope.doCall = function(id) { + webrtc.doCall(id); }; $scope.doChat = function(id) { @@ -61,23 +85,6 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) { }; - /* - $scope.doAudioConference = function(id) { - - $scope.updateAutoAccept(id); - mediaStream.api.sendChat(id, null, { - AutoCall: { - Type: "conference", - Id: mediaStream.connector.roomid - } - }) - - };*/ - - $scope.setRoomStatus = function(status) { - $scope.$emit("roomStatus", status); - }; - var buddylist = $scope.buddylist = buddyList.buddylist($element, $scope, {}); var onJoined = _.bind(buddylist.onJoined, buddylist); var onLeft = _.bind(buddylist.onLeft, buddylist); @@ -85,15 +92,14 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) { var onContactAdded = _.bind(buddylist.onContactAdded, buddylist); var onContactRemoved = _.bind(buddylist.onContactRemoved, buddylist); var onContactUpdated = _.bind(buddylist.onContactUpdated, buddylist); - mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) { + api.e.on("received.userleftorjoined", function(event, dataType, data) { if (dataType === "Left") { onLeft(data); } else { onJoined(data); } }); - mediaStream.api.e.on("received.users", function(event, data) { - $scope.setRoomStatus(true); + api.e.on("received.users", function(event, data) { var selfId = $scope.id; _.each(data, function(p) { if (p.Id !== selfId) { @@ -102,17 +108,10 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) { }); $scope.$apply(); }); - mediaStream.api.e.on("received.status", function(event, data) { + api.e.on("received.status", function(event, data) { onStatus(data); }); - mediaStream.connector.e.on("closed error", function() { - $scope.setRoomStatus(false); - buddylist.onClosed(); - }); - // Request user list whenever the connection comes ready. - mediaStream.connector.ready(function() { - mediaStream.api.requestUsers(); - }); + // Contacts. contacts.e.on("contactadded", function(event, data) { onContactAdded(data); diff --git a/static/js/directives/chat.js b/static/js/directives/chat.js index 1b35c6ec..cae72dee 100644 --- a/static/js/directives/chat.js +++ b/static/js/directives/chat.js @@ -44,16 +44,13 @@ define(['underscore', 'text!partials/chat.html', 'text!partials/chatroom.html'], var res = []; for (var i = 0; i < ctrl.visibleRooms.length; i++) { var r = rooms[ctrl.visibleRooms[i]]; - if (!r || r.id === ctrl.group) { + if (!r) { continue; } res.push(r); } return res; }; - $scope.getGroupRoom = function() { - return rooms[ctrl.group]; - }; mediaStream.api.e.on("received.chat", function(event, id, from, data, p2p) { @@ -182,22 +179,31 @@ define(['underscore', 'text!partials/chat.html', 'text!partials/chatroom.html'], scope.showGroupRoom = function(settings, options) { var stngs = $.extend({ - title: translation._("Room chat") + title: translation._("Room chat"), + group: true }, settings); return scope.showRoom(controller.group, stngs, options); }; + scope.hideGroupRoom = function(settings, options) { + return scope.hideRoom(controller.group); + }; + scope.showRoom = function(id, settings, opts) { var options = $.extend({}, opts); var subscope = controller.rooms[id]; var index = controller.visibleRooms.length; if (!subscope) { console.log("Create new chatroom", [id]); - controller.visibleRooms.push(id); + if (settings.group) { + controller.visibleRooms.unshift(id); + } else { + controller.visibleRooms.push(id); + } subscope = controller.rooms[id] = scope.$new(); translation.inject(subscope); subscope.id = id; - subscope.isgroupchat = id === controller.group ? true : false; + subscope.isgroupchat = !!settings.group; subscope.index = index; subscope.settings = settings; subscope.visible = false; @@ -474,11 +480,6 @@ define(['underscore', 'text!partials/chat.html', 'text!partials/chatroom.html'], scope.currentRoomActive = false; } if (!controller.visibleRooms.length) { - scope.showGroupRoom(null, { - restore: true, - noenable: true, - noactivate: true - }); // If last visible room was removed, hide chat. scope.layout.chat = false; } @@ -544,18 +545,21 @@ define(['underscore', 'text!partials/chat.html', 'text!partials/chatroom.html'], scope.layout.chatMaximized = false; }); - scope.$on("room", function(event, room) { + scope.$on("room.joined", function(event, room) { var subscope = scope.showGroupRoom(null, { restore: true, noenable: true, noactivate: true }); - if (room) { - var msg = $("").text(translation._("You are now in room %s ...", room)); - subscope.$broadcast("display", null, $("").append(msg)); - } + scope.currentRoomName = room.name; + var msg = $("").text(translation._("You are now in room %s ...", room.name)); + subscope.$broadcast("display", null, $("").append(msg)); }); + scope.$on("room.left", function(event) { + scope.hideGroupRoom(); + scope.currentRoomName = null; + }); }; }; diff --git a/static/js/directives/directives.js b/static/js/directives/directives.js index fea45f1b..5c60c194 100644 --- a/static/js/directives/directives.js +++ b/static/js/directives/directives.js @@ -43,7 +43,8 @@ define([ 'directives/odfcanvas', 'directives/presentation', 'directives/youtubevideo', - 'directives/bfi'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPictureCapture, buddyPictureUpload, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, odfcanvas, presentation, youtubevideo, bfi) { + 'directives/bfi', + 'directives/title'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPictureCapture, buddyPictureUpload, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, odfcanvas, presentation, youtubevideo, bfi, title) { var directives = { onEnter: onEnter, @@ -68,13 +69,14 @@ define([ odfcanvas: odfcanvas, presentation: presentation, youtubevideo: youtubevideo, - bfi: bfi + bfi: bfi, + title: title }; var initialize = function(angModule) { _.each(directives, function(directive, name) { angModule.directive(name, directive); - }) + }); }; return { diff --git a/static/js/directives/page.js b/static/js/directives/page.js index 90f4dcd1..e24261b5 100644 --- a/static/js/directives/page.js +++ b/static/js/directives/page.js @@ -20,55 +20,37 @@ */ define(['text!partials/page.html', 'text!partials/page/welcome.html'], function(template, welcome) { - return ["$templateCache", "mediaStream", function($templateCache, mediaStream) { - + return ["$templateCache", "$timeout", "rooms", function($templateCache, $timeout, rooms) { $templateCache.put('page/welcome.html', welcome); - var link = function(scope, element, attrs) { - - scope.room = false; - scope.page = null; - - if (mediaStream.config.DefaultRoomEnabled !== true) { - - scope.$on("welcome", function() { - if (!scope.initialized) { - scope.initialized = true; - scope.refresh(); - } - }); + var link = function($scope, $element, attrs) { + $scope.randomRoom = rooms.randomRoom; - scope.$on("room", function(event, room) { - scope.initialized = true; - scope.room = room !== null ? true : false; - scope.refresh(); - }); + $scope.$on("room.joined", function(event, name) { + $scope.page = null; + }); - scope.$watch("status", function(event) { - if (scope.initialized) { - scope.refresh(); - } + $scope.$on("room.random", function(ev, roomdata) { + $scope.page = "page/welcome.html"; + $scope.roomdata = roomdata; + $timeout(function() { + $element.find(".btn-roomcreate:visible:enabled:first").focus(); }); + }); - scope.refresh = function() { - if (scope.roomid || scope.room || scope.status !== "waiting") { - scope.page = null; - } else { - scope.page = "page/welcome.html"; - } - }; - - } - + $scope.roomdata = {}; + $scope.$watch("roomdata.name", function(name) { + $scope.roomdata.link = rooms.link($scope.roomdata); + }); }; return { restrict: 'E', replace: true, template: template, + controller: "RoomchangeController", link: link - } - + }; }]; }); diff --git a/static/js/directives/roombar.js b/static/js/directives/roombar.js index 8cccef52..37bc4f0b 100644 --- a/static/js/directives/roombar.js +++ b/static/js/directives/roombar.js @@ -21,17 +21,16 @@ define(['underscore', 'text!partials/roombar.html'], function(_, template) { // roomBar - return ["$window", "$rootScope", "mediaStream", function($window, $rootScope, mediaStream) { + return ["$window", "rooms", function($window, rooms) { var link = function($scope) { //console.log("roomBar directive link", arguments); - $scope.newroomid = $rootScope.roomid; $scope.layout.roombar = false; $scope.save = function() { - var roomid = mediaStream.changeRoom($scope.newroomid); - if (roomid !== $rootScope.roomid) { + var roomName = rooms.joinByName($scope.newRoomName); + if (roomName !== $scope.currentRoomName) { $scope.roombarform.$setPristine(); } $scope.layout.roombar = false; @@ -44,19 +43,20 @@ define(['underscore', 'text!partials/roombar.html'], function(_, template) { }; $scope.exit = function() { - $scope.newroomid = ""; + $scope.newRoomName = ""; $scope.save(); }; - $rootScope.$watch("roomid", function(newroomid, roomid) { - if (!newroomid) { - newroomid = ""; - } - $scope.newroomid = newroomid; + $scope.$on("room.joined", function(ev, room) { + $scope.currentRoomName = $scope.newRoomName = room.name; + }); + + $scope.$on("room.left", function(ev) { + $scope.currentRoomName = $scope.newRoomName = ""; }); - $scope.$watch("newroomid", function(newroomid) { - if (newroomid === $rootScope.roomid) { + $scope.$watch("newRoomName", function(name) { + if (name === $scope.currentRoomName) { $scope.roombarform.$setPristine(); } }); diff --git a/static/js/directives/socialshare.js b/static/js/directives/socialshare.js index 6da365af..99765570 100644 --- a/static/js/directives/socialshare.js +++ b/static/js/directives/socialshare.js @@ -29,7 +29,7 @@ define(['jquery', 'text!partials/socialshare.html'], function($, template) { }; // socialShare - return ["$window", "translation", function($window, translation) { + return ["$window", "translation", "rooms", function($window, translation, rooms) { var title = $window.encodeURIComponent($window.document.title); var makeUrl = function(nw, target) { @@ -46,6 +46,14 @@ define(['jquery', 'text!partials/socialshare.html'], function($, template) { template: template, replace: true, link: function($scope, $element, $attr) { + $scope.$on("room.joined", function(ev, room) { + $scope.roomlink = rooms.link(room); + }); + + $scope.$on("room.left", function(ev, name) { + $scope.roomlink = null; + }); + $element.on("click", "a", function(event) { var nw = $(event.currentTarget).data("nw"); var url = makeUrl(nw, $scope.roomlink); diff --git a/static/js/directives/title.js b/static/js/directives/title.js new file mode 100644 index 00000000..e05b7f17 --- /dev/null +++ b/static/js/directives/title.js @@ -0,0 +1,48 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define([], function() { + return [function() { + var link = function($scope, $element, attrs) { + var originalText = $element.text(); + var updateTitle = function(roomName) { + if (roomName) { + $element.text(roomName+ " - " + originalText); + } else { + $element.text(originalText); + } + }; + + $scope.$on("room.joined", function(ev, room) { + updateTitle(room.name); + }); + + $scope.$on("room.left", function(ev) { + updateTitle(); + }); + }; + + return { + restrict: 'E', + replace: false, + link: link + }; + }]; +}); diff --git a/static/js/directives/usability.js b/static/js/directives/usability.js index 470aa7e7..d9a9194f 100644 --- a/static/js/directives/usability.js +++ b/static/js/directives/usability.js @@ -22,15 +22,13 @@ define(['jquery', 'underscore', 'text!partials/usability.html'], function($, _, var MEDIA_CHECK = "1" // First version of media check flag. - return ["mediaStream", function(mediaStream) { + return [function() { - var controller = ['$scope', "mediaStream", "safeApply", "$timeout", "localStorage", "continueConnector", function($scope, mediaStream, safeApply, $timeout, localStorage, continueConnector) { + var controller = ['$scope', "webrtc", "safeApply", "$timeout", "localStorage", "continueConnector", function($scope, webrtc, safeApply, $timeout, localStorage, continueConnector) { var pending = true; var complete = false; - var initializer = null; - var ctrl = this; ctrl.setInfo = function(info) { $scope.usabilityInfo = info; @@ -46,16 +44,7 @@ define(['jquery', 'underscore', 'text!partials/usability.html'], function($, _, localStorage.setItem("mediastream-mediacheck", MEDIA_CHECK) console.log("Continue with connect after media check ..."); continueDeferred.resolve(); - if (mediaStream.config.DefaultRoomEnabled !== true) { - ctrl.setInfo("initializing"); - initializer = $timeout(function() { - ctrl.setInfo("ok"); - $scope.layout.settings = false; - $scope.$emit("welcome"); - }, 1000); - } else { - ctrl.setInfo("ok"); - } + ctrl.setInfo("ok"); complete = true; } else { ctrl.setInfo("denied"); @@ -70,7 +59,7 @@ define(['jquery', 'underscore', 'text!partials/usability.html'], function($, _, // NOTE(longsleep): Checkin for media access makes only sense on // Chrome for now, as its the only one which remembers this // decision permanently for https. - mediaStream.webrtc.testMediaAccess($scope.continueConnect); + webrtc.testMediaAccess($scope.continueConnect); } else { $scope.continueConnect(true); } @@ -97,19 +86,16 @@ define(['jquery', 'underscore', 'text!partials/usability.html'], function($, _, } }); - $scope.$on("room", function(event, room) { - //console.log("roomStatus", room !== null ? true : false); + $scope.$on("room.joined", function(event) { if (complete) { - if (initializer !== null) { - $timeout.cancel(initializer); - initializer = null; - } - // Check if we should show settings per default when in a room. - if(room && !$scope.loadedUser) { - $scope.layout.settings = true; - } else { - $scope.layout.settings = false; - } + $scope.layout.settings = !$scope.loadedUser; + ctrl.setInfo("ok"); + } + }); + + $scope.$on("room.left", function(event) { + if (complete) { + $scope.layout.settings = false; ctrl.setInfo("ok"); } }); diff --git a/static/js/mediastream/api.js b/static/js/mediastream/api.js index 5164f4ae..99adde88 100644 --- a/static/js/mediastream/api.js +++ b/static/js/mediastream/api.js @@ -18,13 +18,13 @@ * along with this program. If not, see . * */ -define(['jquery', 'underscore'], function($, _) { +define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { var alive_check_timeout = 5000; var alive_check_timeout_2 = 10000; - var Api = function(connector) { - + var Api = function(version, connector) { + this.version = version; this.id = null; this.sid = null; this.session = {}; @@ -33,6 +33,15 @@ define(['jquery', 'underscore'], function($, _) { this.e = $({}); + var ua = uaparser(); + if (ua.os.name && /Spreed Desktop Caller/i.test(ua.ua)) { + this.userAgent = ua.ua.match(/Spreed Desktop Caller\/([\d.]+)/i)[1] + " (" + ua.os.name + ")"; + } else if (ua.browser.name) { + this.userAgent = ua.browser.name + " " + ua.browser.major; + } else { + this.userAgent = ua.ua; + } + connector.e.on("received", _.bind(function(event, data) { this.received(data); }, this)); @@ -217,6 +226,15 @@ define(['jquery', 'underscore'], function($, _) { }; + Api.prototype.sendHello = function(name) { + var data = { + Version: this.version, + Ua: this.userAgent, + Id: name + }; + this.send("Hello", data, true); + }; + Api.prototype.sendOffer = function(to, payload) { var data = { diff --git a/static/js/mediastream/connector.js b/static/js/mediastream/connector.js index 3718106a..d216dc9d 100644 --- a/static/js/mediastream/connector.js +++ b/static/js/mediastream/connector.js @@ -18,14 +18,12 @@ * along with this program. If not, see . * */ -define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { +define(['jquery', 'underscore'], function($, _, uaparser) { var timeout = 5000; var timeout_max = 20000; - var Connector = function(version) { - - this.version = version; + var Connector = function() { this.e = $({}); this.error = false; this.connected = false; @@ -35,18 +33,6 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { this.token = null; this.queue = []; - - this.roomid = null; - - var ua = uaparser(); - if (ua.os.name && /Spreed Desktop Caller/i.test(ua.ua)) { - this.userAgent = ua.ua.match(/Spreed Desktop Caller\/([\d.]+)/i)[1] + " (" + ua.os.name + ")"; - } else if (ua.browser.name) { - this.userAgent = ua.browser.name + " " + ua.browser.major; - } else { - this.userAgent = ua.ua; - } - }; Connector.prototype.connect = function(url) { @@ -110,7 +96,6 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { Connector.prototype.close = function() { this.connected = false; - this.roomid = null; if (this.conn) { var conn = this.conn; this.conn = null; @@ -131,42 +116,7 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { }; - Connector.prototype.room = function(roomid) { - - var was_connected = this.connected; - - if (was_connected) { - if (this.roomid === roomid) { - return; - } - this.e.triggerHandler("closed", [{ - soft: true - }]); - } - - this.roomid = roomid; - roomid = this.roomid ? this.roomid : ""; - - this.send({ - Type: "Hello", - Hello: { - Version: this.version, - Ua: this.userAgent, - Id: roomid - } - }, true); - this.e.triggerHandler("helloed", [roomid]); - - if (was_connected) { - this.e.triggerHandler("open", [{ - soft: true - }]); - } - - }; - Connector.prototype.onopen = function(event) { - window.clearTimeout(this.connecting); this.connecting_timeout = timeout; @@ -181,9 +131,6 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { data = this.queue.shift(); this.send(data); } - - this.e.triggerHandler("opened"); - }; Connector.prototype.onerror = function(event) { @@ -210,8 +157,6 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { if (!this.error) { this.e.triggerHandler("close", [null, event]); } - this.e.triggerHandler("closed", [null, event]); - }; Connector.prototype.onmessage = function(event) { diff --git a/static/js/services/api.js b/static/js/services/api.js new file mode 100644 index 00000000..cadd1cb3 --- /dev/null +++ b/static/js/services/api.js @@ -0,0 +1,27 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define([ + 'mediastream/api' +], function(Api) { + return ["globalContext", "connector", function(context, connector) { + return new Api(context.Cfg.Version, connector); + }]; +}); diff --git a/static/js/services/buddypicture.js b/static/js/services/buddypicture.js index 907ee489..b426ac46 100644 --- a/static/js/services/buddypicture.js +++ b/static/js/services/buddypicture.js @@ -22,7 +22,7 @@ define(['underscore'], function(underscore) { // buddyPicture - return ["mediaStream", "$window", function(mediaStream, $window) { + return ["$window", "restURL", function($window, restURL) { var buddyPicture = { @@ -38,7 +38,7 @@ } if (url.indexOf("img:") === 0) { - data.buddyPicture = data.buddyPictureLocalUrl = mediaStream.url.buddy(url.substr(4)); + data.buddyPicture = data.buddyPictureLocalUrl = restURL.buddy(url.substr(4)); } }, @@ -83,4 +83,4 @@ }]; - }); \ No newline at end of file + }); diff --git a/static/js/services/connector.js b/static/js/services/connector.js new file mode 100644 index 00000000..e475b052 --- /dev/null +++ b/static/js/services/connector.js @@ -0,0 +1,27 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define([ + 'mediastream/connector' +], function(Connector) { + return [function() { + return new Connector(); + }]; +}); diff --git a/static/js/services/mediastream.js b/static/js/services/mediastream.js index dc5ec571..517cad6c 100644 --- a/static/js/services/mediastream.js +++ b/static/js/services/mediastream.js @@ -23,29 +23,31 @@ define([ 'underscore', 'ua-parser', 'modernizr', - 'mediastream/connector', - 'mediastream/api', - 'mediastream/webrtc', 'mediastream/tokens' -], function($, _, uaparser, Modernizr, Connector, Api, WebRTC, tokens) { +], function($, _, uaparser, Modernizr, tokens) { - return ["globalContext", "$rootScope", "$route", "$location", "$window", "visibility", "alertify", "$http", "safeApply", "$timeout", "$sce", "localStorage", "continueConnector", function(context, $rootScope, $route, $location, $window, visibility, alertify, $http, safeApply, $timeout, $sce, localStorage, continueConnector) { + return ["globalContext", "connector", "api", "webrtc", "$rootScope", "$route", "$location", "$window", "visibility", "alertify", "$http", "safeApply", "$timeout", "$sce", "localStorage", "continueConnector", "restURL", function(context, connector, api, webrtc, $rootScope, $route, $location, $window, visibility, alertify, $http, safeApply, $timeout, $sce, localStorage, continueConnector, restURL) { var url = (context.Ssl ? "wss" : "ws") + "://" + context.Host + (context.Cfg.B || "/") + "ws"; - var version = context.Cfg.Version || "unknown"; + var version = context.Cfg.Version; console.log("Service version: " + version); console.log("Ws URL: " + url); console.log("Secure Contextual Escaping: " + $sce.isEnabled()); - var connector = new Connector(version); - var api = new Api(connector); - var webrtc = new WebRTC(api); var connectMarker = null; // Create encryption key from server token and browser name. var secureKey = sjcl.codec.base64.fromBits(sjcl.hash.sha256.hash(context.Cfg.Token + uaparser().browser.name)); + var authorizing = false; + $rootScope.authorizing = function(value) { + // Boolean flag to indicate that an authentication is currently in progress. + if (typeof(value) !== "undefined") { + authorizing = !!value; + } + return authorizing; + }; var mediaStream = { version: version, @@ -55,21 +57,9 @@ define([ connector: connector, api: api, tokens: tokens, - url: { - room: function(id) { - id = $window.encodeURIComponent(id); - return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + id; - }, - buddy: function(id) { - return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + "static/img/buddy/s46/" + id; - }, - api: function(path) { - return (context.Cfg.B || "/") + "api/v1/" + path; - } - }, users: { register: function(form, success_cb, error_cb) { - var url = mediaStream.url.api("users"); + var url = restURL.api("users"); if (form) { // Form submit mode. $(form).attr("action", url).attr("method", "POST"); @@ -135,16 +125,9 @@ define([ }); } }, - authorizing: function(value) { - // Boolean flag to indicate that an authentication is currently in progress. - if (typeof(value) !== "undefined") { - authorizing = !!value; - } - return authorizing; - }, authorize: function(data, success_cb, error_cb) { - mediaStream.users.authorizing(true); - var url = mediaStream.url.api("sessions") + "/" + mediaStream.api.id + "/"; + $rootScope.authorizing(true); + var url = restURL.api("sessions") + "/" + mediaStream.api.id + "/"; var login = _.clone(data); login.id = mediaStream.api.id; login.sid = mediaStream.api.sid; @@ -160,14 +143,14 @@ define([ if (data.nonce !== "" && data.success) { success_cb(data, status); } else { - mediaStream.users.authorizing(false); + $rootScope.authorizing(false); if (error_cb) { error_cb(data, status); } } }). error(function(data, status) { - mediaStream.users.authorizing(false); + $rootScope.authorizing(false); if (error_cb) { error_cb(data, status) } @@ -226,40 +209,12 @@ define([ } }); }, - changeRoom: function(id, replace) { - id = $window.encodeURIComponent(id); - // Allow room ids to start with @,$ and + without quoting. - id = id.replace(/^%40/, "@"); - id = id.replace(/^%24/, "$"); - id = id.replace(/^%2B/, "+"); - safeApply($rootScope, function(scope) { - $location.path("/" + id); - if (replace) { - $location.replace(); - } - }); - return id; - }, - applyRoom: function() { - if (authorizing) { - // Do nothing while authorizing. - return; - } - var roomid = $rootScope.roomid; - if (roomid !== connector.roomid) { - console.log("Apply room", roomid); - connector.room(roomid); - } - }, initialize: function($rootScope, translation) { var cont = false; var ready = false; $rootScope.version = version; - $rootScope.roomid = null; - $rootScope.roomlink = null; - $rootScope.roomstatus = false; $rootScope.connect = false; var connect = function() { @@ -278,61 +233,10 @@ define([ } }; - var title = (function(e) { - return { - element: e, - text: e.text() - } - }($("title"))); - - // Room selector. - $rootScope.$on("$locationChangeSuccess", function(event) { - - var room; - if ($route.current) { - room = $route.current.params.room; - room = $window.decodeURIComponent(room); - } else { - room = ""; - } - console.info("Selected room is:", [room], ready, cont); - $rootScope.roomid = room; - - if (!ready || !cont) { - ready = true; - connect(); - } else { - // Auto apply room when already connected. - mediaStream.applyRoom(); - } - - $rootScope.roomlink = room ? mediaStream.url.room(room) : null; - if ($rootScope.roomlink) { - title.element.text(room + " - " + title.text); - } else { - title.element.text(title.text); - } - - }); - - // Cache events, to avoid ui flicker during quick room changes. - var roomStatusCache = $rootScope.roomstatus; - var roomCache = null; - var roomCache2 = null; - $rootScope.$on("roomStatus", function(event, status) { - // roomStatus is triggered by the buddylist when received.users. - roomStatusCache = status ? true : false; - roomCache = status ? $rootScope.roomid : null; - $timeout(function() { - if ($rootScope.roomstatus !== roomStatusCache) { - $rootScope.roomstatus = roomStatusCache; - } - if (roomCache !== roomCache2) { - // Let every one know about the new room. - $rootScope.$broadcast("room", roomCache); - roomCache2 = roomCache; - } - }, 100); + $rootScope.$on("rooms.ready", function(event) { + console.info("Initial room path set, continuing to connect ..."); + ready = true; + connect(); }); visibility.afterPrerendering(function() { @@ -356,7 +260,7 @@ define([ } }, prompt); }; - var url = mediaStream.url.api("tokens"); + var url = restURL.api("tokens"); var check = function(code) { $http({ method: "POST", @@ -406,9 +310,6 @@ define([ } }; - // For debugging. - $window.changeRoom = mediaStream.changeRoom; - return mediaStream; }]; diff --git a/static/js/services/resturl.js b/static/js/services/resturl.js new file mode 100644 index 00000000..fdc9e22d --- /dev/null +++ b/static/js/services/resturl.js @@ -0,0 +1,38 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define([ +], function() { + + return ["globalContext", "$window", function(context, $window) { + return { + room: function(id) { + id = $window.encodeURIComponent(id); + return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + id; + }, + buddy: function(id) { + return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + "static/img/buddy/s46/" + id; + }, + api: function(path) { + return (context.Cfg.B || "/") + "api/v1/" + path; + } + }; + }]; +}); diff --git a/static/js/services/rooms.js b/static/js/services/rooms.js new file mode 100644 index 00000000..eab1820f --- /dev/null +++ b/static/js/services/rooms.js @@ -0,0 +1,152 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define([ + 'jquery' +], function($) { + + return ["$window", "$location", "$timeout", "$route", "$rootScope", "$http", "globalContext", "safeApply", "connector", "api", "restURL", function($window, $location, $timeout, $route, $rootScope, $http, globalContext, safeApply, connector, api, restURL) { + var url = restURL.api("rooms"); + var requestedRoomName = ""; + var currentRoom = null; + + var joinRequestedRoom = function() { + if ($rootScope.authorizing()) { + // Do nothing while authorizing. + return; + } + + if (!connector.connected || requestedRoomName !== currentRoom) { + if (requestedRoomName !== "" || globalContext.Cfg.DefaultRoomEnabled) { + console.log("Joining room", requestedRoomName); + requestedRoomName = requestedRoomName ? requestedRoomName : ""; + api.sendHello(requestedRoomName); + api.requestUsers(); + } else { + console.log("Default room disabled, requesting a random room."); + setCurrentRoom(null); + rooms.randomRoom(); + } + } + }; + + // Cache events, to avoid ui flicker during quick room changes. + var nextRoom = null; + var setCurrentRoom = function(room) { + nextRoom = room; + + $timeout(function() { + if (nextRoom !== currentRoom) { + var priorRoom = currentRoom; + currentRoom = nextRoom; + if (priorRoom) { + console.log("Left room", priorRoom.name); + $rootScope.$broadcast("room.left", priorRoom); + } + if (currentRoom) { + console.log("Joined room", currentRoom.name); + $rootScope.$broadcast("room.joined", currentRoom); + } + } + }, 100); + }; + + connector.e.on("close error", function() { + setCurrentRoom(null); + }); + + api.e.on("received.self", function(event, data) { + joinRequestedRoom(); + }); + + api.e.on("received.users", function() { + setCurrentRoom({ + name: requestedRoomName + }); + }); + + $rootScope.$on("$locationChangeSuccess", function(event) { + var roomName; + if ($route.current) { + roomName = $route.current.params.room; + roomName = $window.decodeURIComponent(roomName); + } else { + roomName = ""; + } + + requestedRoomName = roomName; + if (connector.connected) { + joinRequestedRoom(); + } else { + $rootScope.$broadcast("rooms.ready"); + } + }); + + var rooms = { + inDefaultRoom: function() { + return (currentRoom !== null ? currentRoom.name : requestedRoomName) === ""; + }, + randomRoom: function() { + $http({ + method: "POST", + url: url, + data: $.param({}), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }). + success(function(data, status) { + console.info("Retrieved random room data", data); + if (!data.name) { + data.name = ""; + } + $rootScope.$broadcast('room.random', {name: data.name}); + }). + error(function() { + console.error("Failed to retrieve random room data."); + $rootScope.$broadcast('room.random', {}); + }); + }, + joinByName: function(name, replace) { + name = $window.encodeURIComponent(name); + name = name.replace(/^%40/, "@"); + name = name.replace(/^%24/, "$"); + name = name.replace(/^%2B/, "+"); + + safeApply($rootScope, function(scope) { + $location.path("/" + name); + if (replace) { + $location.replace(); + } + }); + return name; + }, + link: function(room) { + var name = room ? room.name : null; + if (!name) { + name = ""; + } + return restURL.room(name); + } + }; + + return rooms; + }]; +}); diff --git a/static/js/services/services.js b/static/js/services/services.js index 0657fafe..1e49d89e 100644 --- a/static/js/services/services.js +++ b/static/js/services/services.js @@ -24,6 +24,9 @@ define([ 'services/desktopnotify', 'services/playsound', 'services/safeapply', + 'services/connector', + 'services/api', + 'services/webrtc', 'services/mediastream', 'services/appdata', 'services/buddydata', @@ -56,10 +59,15 @@ define([ 'services/continueconnector', 'services/chromeextension', 'services/usersettingsdata', - 'services/localstatus'], function(_, + 'services/localstatus', + 'services/rooms', + 'services/resturl'], function(_, desktopNotify, playSound, safeApply, +connector, +api, +webrtc, mediaStream, appData, buddyData, @@ -92,12 +100,17 @@ screensharing, continueConnector, chromeExtension, userSettingsData, -localStatus) { +localStatus, +rooms, +restURL) { var services = { desktopNotify: desktopNotify, playSound: playSound, safeApply: safeApply, + connector: connector, + api: api, + webrtc: webrtc, mediaStream: mediaStream, appData: appData, buddyData: buddyData, @@ -130,13 +143,15 @@ localStatus) { continueConnector: continueConnector, chromeExtension: chromeExtension, userSettingsData: userSettingsData, - localStatus: localStatus + localStatus: localStatus, + rooms: rooms, + restURL: restURL }; var initialize = function(angModule) { _.each(services, function(service, name) { angModule.factory(name, service); - }) + }); }; return { diff --git a/static/js/services/webrtc.js b/static/js/services/webrtc.js new file mode 100644 index 00000000..f54742d5 --- /dev/null +++ b/static/js/services/webrtc.js @@ -0,0 +1,27 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define([ + 'mediastream/webrtc' +], function(WebRTC) { + return ["api", function(api) { + return new WebRTC(api); + }]; +}); diff --git a/static/partials/chat.html b/static/partials/chat.html index bd850c32..da150439 100644 --- a/static/partials/chat.html +++ b/static/partials/chat.html @@ -5,12 +5,14 @@
{{_("Chat sessions")}}
diff --git a/static/partials/page/welcome.html b/static/partials/page/welcome.html index a28a6097..6ad5958f 100644 --- a/static/partials/page/welcome.html +++ b/static/partials/page/welcome.html @@ -1,4 +1,4 @@ -
+

{{_("Create a room and talk together")}}

@@ -6,13 +6,13 @@
- - + +

-

{{roomdata.link}}

+

{{roomdata.link}}

diff --git a/static/partials/roombar.html b/static/partials/roombar.html index 4f6ce8ec..e180adea 100644 --- a/static/partials/roombar.html +++ b/static/partials/roombar.html @@ -4,12 +4,12 @@
- +
- +
diff --git a/static/partials/usability.html b/static/partials/usability.html index 65d79300..8f57cd65 100644 --- a/static/partials/usability.html +++ b/static/partials/usability.html @@ -1,7 +1,6 @@
-
{{_("Checking camera and microphone access.")}}
{{_("Please allow access to your camera and microphone.")}}
{{_("Camera / microphone access required.")}}