Browse Source

Merge branch 'release-0.24'

pull/256/head v0.24.9
Simon Eisenmann 10 years ago
parent
commit
0da63dd9df
  1. 2
      .javascript_ignore
  2. 1
      .travis.yml
  3. 52
      Makefile.am
  4. 3
      README.md
  5. 1
      html/head.html
  6. 1
      html/sandboxes/odfcanvas_sandbox.html
  7. 1
      html/sandboxes/pdfcanvas_sandbox.html
  8. 2
      package.json
  9. 3
      src/hooks/pre-commit.hook
  10. 1
      static/js/base.js
  11. 18
      static/js/directives/buddylist.js
  12. 27
      static/js/directives/buddypicturecapture.js
  13. 24
      static/js/directives/buddypictureupload.js
  14. 32
      static/js/directives/chat.js
  15. 22
      static/js/directives/youtubevideo.js
  16. 165
      static/js/libs/webrtc.adapter.js
  17. 4
      static/js/main.js
  18. 15
      static/js/mediastream/peercall.js
  19. 8
      static/js/mediastream/peerscreenshare.js
  20. 8
      static/js/mediastream/peerxfer.js
  21. 4
      static/js/mediastream/tokens.js
  22. 3
      static/js/mediastream/utils.js
  23. 17
      static/js/mediastream/webrtc.js
  24. 2
      static/js/services/alertify.js
  25. 16
      static/js/services/animationframe.js
  26. 2
      static/js/services/desktopnotify.js
  27. 13
      static/js/services/filedownload.js
  28. 4
      static/js/services/geolocation.js
  29. 34
      static/js/services/mediadevices.js
  30. 29
      static/js/services/mediasources.js
  31. 5
      static/js/services/mediastream.js
  32. 20
      static/js/services/rooms.js
  33. 2
      static/partials/chat.html

2
.javascript_ignore

@ -1 +1 @@
static/js/libs/**.js static/js/libs/

1
.travis.yml

@ -7,6 +7,7 @@ go:
- 1.2 - 1.2
- 1.3 - 1.3
- 1.4 - 1.4
- 1.5
- tip - tip
env: env:

52
Makefile.am

@ -124,32 +124,32 @@ release: OUTPUT = $(DIST_BIN)
release: $(DIST_BIN) binary releaseassets release: $(DIST_BIN) binary releaseassets
install: install:
@echo "Installing binaries to: $(BIN)" @echo "Installing binaries to: $(DESTDIR)$(BIN)"
@echo "Installing static resources to: $(SHARE)" @echo "Installing static resources to: $(DESTDIR)$(SHARE)"
$(INSTALL) -d $(BIN) $(INSTALL) -d $(DESTDIR)$(BIN)
$(INSTALL) -d $(SHARE)/www/html $(INSTALL) -d $(DESTDIR)$(SHARE)/www/html
$(INSTALL) -d $(SHARE)/www/html/sandboxes $(INSTALL) -d $(DESTDIR)$(SHARE)/www/html/sandboxes
$(INSTALL) -d $(SHARE)/www/static $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static
$(INSTALL) -d $(SHARE)/www/static/img $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/img
$(INSTALL) -d $(SHARE)/www/static/sounds $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/sounds
$(INSTALL) -d $(SHARE)/www/static/fonts $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/fonts
$(INSTALL) -d $(SHARE)/www/static/translation $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/translation
$(INSTALL) -d $(SHARE)/www/static/css $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/css
$(INSTALL) -d $(SHARE)/www/static/js/libs/pdf $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/js/libs/pdf
$(INSTALL) -d $(SHARE)/www/static/js/sandboxes $(INSTALL) -d $(DESTDIR)$(SHARE)/www/static/js/sandboxes
$(INSTALL) bin/$(EXENAME) $(BIN) $(INSTALL) bin/$(EXENAME) $(DESTDIR)$(BIN)
$(INSTALL) html/*.html $(SHARE)/www/html $(INSTALL) html/*.html $(DESTDIR)$(SHARE)/www/html
$(INSTALL) html/sandboxes/*.html $(SHARE)/www/html/sandboxes $(INSTALL) html/sandboxes/*.html $(DESTDIR)$(SHARE)/www/html/sandboxes
$(INSTALL) static/img/* $(SHARE)/www/static/img $(INSTALL) static/img/* $(DESTDIR)$(SHARE)/www/static/img
$(INSTALL) static/sounds/* $(SHARE)/www/static/sounds $(INSTALL) static/sounds/* $(DESTDIR)$(SHARE)/www/static/sounds
$(INSTALL) static/fonts/* $(SHARE)/www/static/fonts $(INSTALL) static/fonts/* $(DESTDIR)$(SHARE)/www/static/fonts
$(INSTALL) static/translation/* $(SHARE)/www/static/translation $(INSTALL) static/translation/* $(DESTDIR)$(SHARE)/www/static/translation
$(INSTALL) static/css/* $(SHARE)/www/static/css $(INSTALL) static/css/* $(DESTDIR)$(SHARE)/www/static/css
$(INSTALL) -D static/js/libs/require/require.js $(SHARE)/www/static/js/libs/require/require.js $(INSTALL) -D static/js/libs/require/require.js $(DESTDIR)$(SHARE)/www/static/js/libs/require/require.js
$(INSTALL) $(OUTPUT_JS)/*.js $(SHARE)/www/static/js $(INSTALL) $(OUTPUT_JS)/*.js $(DESTDIR)$(SHARE)/www/static/js
$(INSTALL) $(OUTPUT_JS)/libs/pdf/*.js $(SHARE)/www/static/js/libs/pdf $(INSTALL) $(OUTPUT_JS)/libs/pdf/*.js $(DESTDIR)$(SHARE)/www/static/js/libs/pdf
$(INSTALL) -D static/js/libs/webodf.js $(SHARE)/www/static/js/libs/webodf.js $(INSTALL) -D static/js/libs/webodf.js $(DESTDIR)$(SHARE)/www/static/js/libs/webodf.js
$(INSTALL) $(OUTPUT_JS)/sandboxes/*.js $(SHARE)/www/static/js/sandboxes $(INSTALL) $(OUTPUT_JS)/sandboxes/*.js $(DESTDIR)$(SHARE)/www/static/js/sandboxes
clean: clean:
$(GO) clean -i -r app/... 2>/dev/null || true $(GO) clean -i -r app/... 2>/dev/null || true

3
README.md

@ -102,6 +102,9 @@ Styles can be found in src/styles. Translations are found in src/i18n.
Each folder has its own Makefile to build the corresponding files. Check the Each folder has its own Makefile to build the corresponding files. Check the
Makefile.am templates for available make targets. Makefile.am templates for available make targets.
Javascript console logging is automatically _disabled_ and can be enabled by
adding the query parameter `debug` to your url `https://my_url?debug`.
## Running server for development ## Running server for development

1
html/head.html

@ -4,6 +4,7 @@
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="referrer" content="no-referrer">
<base href="<%.Cfg.B%>"> <base href="<%.Cfg.B%>">
<%if.Csp%><link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/csp.min.css"><%end%> <%if.Csp%><link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/csp.min.css"><%end%>
<link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="<%.Cfg.S%>/css/bootstrap.min.css">

1
html/sandboxes/odfcanvas_sandbox.html

@ -28,6 +28,7 @@
user-select:none; user-select:none;
-webkit-user-select:none; -webkit-user-select:none;
-moz-user-select:none; -moz-user-select:none;
background:white;
} }
</style> </style>
</head> </head>

1
html/sandboxes/pdfcanvas_sandbox.html

@ -22,6 +22,7 @@
margin:0 auto; margin:0 auto;
position:relative; position:relative;
display:none; display:none;
background:white;
} }
</style> </style>
</head> </head>

2
package.json

@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"dependencies": { "dependencies": {
"autoprefixer": ">= 3.1.0", "autoprefixer": ">= 3.1.0 <= 5.2.1",
"po2json": ">= 0.4.1", "po2json": ">= 0.4.1",
"jshint": ">= 2.5.5" "jshint": ">= 2.5.5"
} }

3
src/hooks/pre-commit.hook

@ -27,7 +27,6 @@ echo "==========================================================================
fi fi
done done
for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.js$"` ; do for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.js$"` ; do
case "$file" in case "$file" in
*/libs/*) */libs/*)
@ -39,7 +38,7 @@ for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "
*) *)
echo "Checking ${file}" echo "Checking ${file}"
nf=`git checkout-index --temp ${file} | cut -f 1` nf=`git checkout-index --temp ${file} | cut -f 1`
jshint --config .jshint "${nf}" PATH="node_modules/.bin:${PATH}" jshint --config .jshint "${nf}"
r=$? r=$?
rm "${nf}" rm "${nf}"
if [ $r != 0 ] ; then if [ $r != 0 ] ; then

1
static/js/base.js

@ -19,6 +19,7 @@
* *
*/ */
"use strict";
define([ // Helper module to put non dependency base libraries together. define([ // Helper module to put non dependency base libraries together.
'modernizr', 'modernizr',
'moment', 'moment',

18
static/js/directives/buddylist.js

@ -29,10 +29,19 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) {
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var buddylist = $scope.buddylist = buddyList.buddylist($element, $scope, {});
var onJoined = _.bind(buddylist.onJoined, buddylist);
var onLeft = _.bind(buddylist.onLeft, buddylist);
var onStatus = _.bind(buddylist.onStatus, buddylist);
var onContactAdded = _.bind(buddylist.onContactAdded, buddylist);
var onContactRemoved = _.bind(buddylist.onContactRemoved, buddylist);
var onContactUpdated = _.bind(buddylist.onContactUpdated, buddylist);
var inRoom = false;
$scope.layout.buddylist = false; $scope.layout.buddylist = false;
$scope.layout.buddylistAutoHide = true; $scope.layout.buddylistAutoHide = true;
var inRoom = false;
var updateBuddyListVisibility = function() { var updateBuddyListVisibility = function() {
if (inRoom && !$scope.peer) { if (inRoom && !$scope.peer) {
$scope.layout.buddylist = true; $scope.layout.buddylist = true;
@ -87,13 +96,6 @@ define(['underscore', 'text!partials/buddylist.html'], function(_, template) {
}; };
var buddylist = $scope.buddylist = buddyList.buddylist($element, $scope, {});
var onJoined = _.bind(buddylist.onJoined, buddylist);
var onLeft = _.bind(buddylist.onLeft, buddylist);
var onStatus = _.bind(buddylist.onStatus, buddylist);
var onContactAdded = _.bind(buddylist.onContactAdded, buddylist);
var onContactRemoved = _.bind(buddylist.onContactRemoved, buddylist);
var onContactUpdated = _.bind(buddylist.onContactUpdated, buddylist);
api.e.on("received.userleftorjoined", function(event, dataType, data) { api.e.on("received.userleftorjoined", function(event, dataType, data) {
if (dataType === "Left") { if (dataType === "Left") {
onLeft(data); onLeft(data);

27
static/js/directives/buddypicturecapture.js

@ -27,6 +27,17 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct
var controller = ['$scope', 'safeApply', '$timeout', '$q', "mediaDevices", "userMedia", function($scope, safeApply, $timeout, $q, mediaDevices, userMedia) { var controller = ['$scope', 'safeApply', '$timeout', '$q', "mediaDevices", "userMedia", function($scope, safeApply, $timeout, $q, mediaDevices, userMedia) {
var localStream = null;
var delayToTakePicture = 3000;
var countDownFrom = 3;
var takePictureCountDown;
var writeVideoToCanvas;
var writePreviewPic;
var makePicture;
var videoStop;
var videoStart;
// Buddy picutre capture size. // Buddy picutre capture size.
$scope.captureSize = { $scope.captureSize = {
width: 128, width: 128,
@ -41,12 +52,8 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct
$scope.canvasPic = null; $scope.canvasPic = null;
$scope.canvasPrev = null; $scope.canvasPrev = null;
var localStream = null;
var delayToTakePicture = 3000;
var countDownFrom = 3;
// Counts down from start to 1 // Counts down from start to 1
var takePictureCountDown = function(start, delayTotal) { takePictureCountDown = function(start, delayTotal) {
$scope.countingDown = true; $scope.countingDown = true;
$scope.countdown = {}; $scope.countdown = {};
$scope.countdown.num = start; $scope.countdown.num = start;
@ -63,7 +70,7 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct
} }
}; };
var writeVideoToCanvas = function(canvas) { writeVideoToCanvas = function(canvas) {
var videoWidth = $scope.video.videoWidth; var videoWidth = $scope.video.videoWidth;
var videoHeight = $scope.video.videoHeight; var videoHeight = $scope.video.videoHeight;
@ -89,12 +96,12 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct
}; };
var writePreviewPic = function() { writePreviewPic = function() {
writeVideoToCanvas($scope.canvasPrev); writeVideoToCanvas($scope.canvasPrev);
$scope.preview = $scope.canvasPrev.toDataURL("image/jpeg"); $scope.preview = $scope.canvasPrev.toDataURL("image/jpeg");
}; };
var makePicture = function(stream, cntFrom, delayTotal) { makePicture = function(stream, cntFrom, delayTotal) {
takePictureCountDown(cntFrom, delayTotal); takePictureCountDown(cntFrom, delayTotal);
$timeout(function() { $timeout(function() {
$scope.flash.addClass("flash"); $scope.flash.addClass("flash");
@ -107,7 +114,7 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct
}, delayTotal); }, delayTotal);
}; };
var videoStop = function(stream, video) { videoStop = function(stream, video) {
if (stream) { if (stream) {
video.pause(); video.pause();
userMedia.stopUserMediaStream(stream); userMedia.stopUserMediaStream(stream);
@ -115,7 +122,7 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct
} }
}; };
var videoStart = function() { videoStart = function() {
$scope.waitingForPermission = true; $scope.waitingForPermission = true;
var videoConstraints = true; var videoConstraints = true;
var videoAllowed = $q.defer(); var videoAllowed = $q.defer();

24
static/js/directives/buddypictureupload.js

@ -39,8 +39,16 @@ define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], functi
var previewWidth = 205; var previewWidth = 205;
var previewHeight = 205; var previewHeight = 205;
$scope.maxUploadMb = 8; var maxUploadBytes = 8388608; // 8MB
var maxUploadBytes = $scope.maxUploadMb * 1024 * 1024;
var completedUpload;
var setUploadImageDimension;
var getAutoFitDimensions;
var getScaledDimensions;
var writePictureToCanvas;
var clearPicture;
$scope.maxUploadMb = maxUploadBytes / 1024 / 1024;
$scope.showUploadPicture = false; $scope.showUploadPicture = false;
$scope.previewUpload = false; $scope.previewUpload = false;
$scope.imgData = null; $scope.imgData = null;
@ -54,11 +62,11 @@ define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], functi
}; };
$scope.aspectRatio = 1; $scope.aspectRatio = 1;
var completedUpload = function() { completedUpload = function() {
$scope.upload.status = 100; $scope.upload.status = 100;
}; };
var setUploadImageDimension = function(data) { setUploadImageDimension = function(data) {
$scope.prevImage.onload = function() { $scope.prevImage.onload = function() {
// clear old dimensions // clear old dimensions
this.style.cssText = null; this.style.cssText = null;
@ -76,7 +84,7 @@ define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], functi
}; };
// Auto fit by smallest dimension // Auto fit by smallest dimension
var getAutoFitDimensions = function(from, to) { getAutoFitDimensions = function(from, to) {
if (!from.width && !from.height && !to.width && !to.height) { if (!from.width && !from.height && !to.width && !to.height) {
return null; return null;
} }
@ -94,7 +102,7 @@ define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], functi
}; };
// (image, canvas) -> object // (image, canvas) -> object
var getScaledDimensions = function(from, to) { getScaledDimensions = function(from, to) {
if (!from.style.width && !from.style.height && !to.width && !to.height) { if (!from.style.width && !from.style.height && !to.width && !to.height) {
return null; return null;
} }
@ -120,7 +128,7 @@ define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], functi
return {width: width, height: height, x: x, y: y}; return {width: width, height: height, x: x, y: y};
}; };
var writePictureToCanvas = function(canvas) { writePictureToCanvas = function(canvas) {
var img = $scope.prevImage; var img = $scope.prevImage;
var dim = getScaledDimensions(img, canvas); var dim = getScaledDimensions(img, canvas);
var context = canvas.getContext("2d"); var context = canvas.getContext("2d");
@ -129,7 +137,7 @@ define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], functi
//console.log('writeUploadToCanvas', dim); //console.log('writeUploadToCanvas', dim);
}; };
var clearPicture = function() { clearPicture = function() {
$(".file-input-name").empty(); $(".file-input-name").empty();
$scope.imgData = null; $scope.imgData = null;
$scope.prevImage.src = ""; $scope.prevImage.src = "";

32
static/js/directives/chat.js

@ -44,6 +44,7 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro
$scope.currentRoom = null; $scope.currentRoom = null;
$scope.currentRoomActive = false; $scope.currentRoomActive = false;
$scope.maxMessageSize = maxMessageSize; $scope.maxMessageSize = maxMessageSize;
$scope.autoFocusDisabled = false;
$scope.getVisibleRooms = function() { $scope.getVisibleRooms = function() {
var res = []; var res = [];
@ -415,11 +416,6 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro
pane.append(clonedElement); pane.append(clonedElement);
$scope.element = clonedElement; $scope.element = clonedElement;
$scope.visible = true; $scope.visible = true;
if (options.autofocus) {
_.defer(function() {
$scope.$broadcast("focus");
});
}
var sendFiles = function(files) { var sendFiles = function(files) {
_.each(files, function(f) { _.each(files, function(f) {
@ -461,18 +457,16 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro
subscope.enabled = true; subscope.enabled = true;
} }
} }
if (options.autofocus && subscope.visible) {
subscope.$broadcast("focus");
}
} }
if (!options.noactivate) { if (!options.noactivate) {
scope.activateRoom(subscope.id, true); scope.activateRoom(subscope.id, true, !!options.autofocus);
} }
if (options.restore && !options.noenable) { if (options.restore && !options.noenable) {
if (!scope.layout.chat) { if (!scope.layout.chat) {
scope.autoFocusDisabled = true;
scope.layout.chat = true; scope.layout.chat = true;
} }
} }
@ -524,7 +518,7 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro
scope.layout.chatMaximized = !scope.layout.chatMaximized; scope.layout.chatMaximized = !scope.layout.chatMaximized;
}; };
scope.activateRoom = function(id, active) { scope.activateRoom = function(id, active, autofocus) {
var subscope = controller.rooms[id]; var subscope = controller.rooms[id];
if (!subscope) { if (!subscope) {
return; return;
@ -555,6 +549,13 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro
if (flip) { if (flip) {
pane.toggleClass("flip"); pane.toggleClass("flip");
} }
if (active && autofocus && !scope.autoFocusDisabled) {
_.defer(function() {
if (scope.layout.chat) {
subscope.$broadcast("focus");
}
});
}
}; };
scope.deactivateRoom = function() { scope.deactivateRoom = function() {
@ -566,13 +567,22 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro
pane.removeClass("flip"); pane.removeClass("flip");
} }
scope.layout.chatMaximized = false; scope.layout.chatMaximized = false;
if (chat) {
if (!scope.autoFocusDisabled) {
if (scope.currentRoom && scope.currentRoom.active) {
scope.activateRoom(scope.currentRoom.id, true, true);
}
} else {
scope.autoFocusDisabled = false;
}
}
}); });
scope.$on("room.updated", function(event, room) { scope.$on("room.updated", function(event, room) {
var subscope = scope.showGroupRoom(null, { var subscope = scope.showGroupRoom(null, {
restore: true, restore: true,
noenable: true, noenable: true,
noactivate: true noactivate: !!scope.currentRoomActive
}); });
if (scope.currentRoomName != room.Name) { if (scope.currentRoomName != room.Name) {
var msg = $("<span>").text(translation._("You are now in room %s ...", room.Name)); var msg = $("<span>").text(translation._("You are now in room %s ...", room.Name));

22
static/js/directives/youtubevideo.js

@ -106,6 +106,16 @@ define(['require', 'jquery', 'underscore', 'moment', 'text!partials/youtubevideo
var initialState = null; var initialState = null;
var sandboxApi = null; var sandboxApi = null;
var peers = {};
var youtubevideos = [];
var youtubevideoCount = 0;
var currentToken = null;
var tokenHandler = null;
var mediaStreamSendYouTubeVideo;
var connector;
var updater;
var createSandboxApi = function(force, template) { var createSandboxApi = function(force, template) {
if (sandboxApi && force) { if (sandboxApi && force) {
sandboxApi.destroy(); sandboxApi.destroy();
@ -475,13 +485,7 @@ define(['require', 'jquery', 'underscore', 'moment', 'text!partials/youtubevideo
} }
}); });
var peers = {}; mediaStreamSendYouTubeVideo = function(peercall, token, params) {
var youtubevideos = [];
var youtubevideoCount = 0;
var currentToken = null;
var tokenHandler = null;
var mediaStreamSendYouTubeVideo = function(peercall, token, params) {
mediaStream.api.apply("sendYouTubeVideo", { mediaStream.api.apply("sendYouTubeVideo", {
send: function(type, data) { send: function(type, data) {
if (!peercall.peerconnection.datachannelReady) { if (!peercall.peerconnection.datachannelReady) {
@ -495,7 +499,7 @@ define(['require', 'jquery', 'underscore', 'moment', 'text!partials/youtubevideo
})(peercall.id, token, params); })(peercall.id, token, params);
}; };
var connector = function(token, peercall) { connector = function(token, peercall) {
if (peers.hasOwnProperty(peercall.id)) { if (peers.hasOwnProperty(peercall.id)) {
// Already got a connection. // Already got a connection.
return; return;
@ -522,7 +526,7 @@ define(['require', 'jquery', 'underscore', 'moment', 'text!partials/youtubevideo
}; };
// Updater function to bring in new calls. // Updater function to bring in new calls.
var updater = function(event, state, currentcall) { updater = function(event, state, currentcall) {
switch (state) { switch (state) {
case "completed": case "completed":
case "connected": case "connected":

165
static/js/libs/webrtc.adapter.js

@ -30,6 +30,8 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
'use strict';
var getUserMedia = null; var getUserMedia = null;
var attachMediaStream = null; var attachMediaStream = null;
var reattachMediaStream = null; var reattachMediaStream = null;
@ -39,24 +41,79 @@ var webrtcMinimumVersion = null;
var webrtcUtils = { var webrtcUtils = {
log: function() { log: function() {
// suppress console.log output when being included as a module. // suppress console.log output when being included as a module.
if (!(typeof module !== 'undefined' || if (typeof module !== 'undefined' ||
typeof require === 'function') && (typeof define === 'function')) { typeof require === 'function' && typeof define === 'function') {
console.log.apply(console, arguments); return;
} }
console.log.apply(console, arguments);
},
extractVersion: function(uastring, expr, pos) {
var match = uastring.match(expr);
return match && match.length >= pos && parseInt(match[pos], 10);
}
};
/*
function trace(text) {
// This function is used for logging.
if (text[text.length - 1] === '\n') {
text = text.substring(0, text.length - 1);
}
if (window.performance) {
var now = (window.performance.now() / 1000).toFixed(3);
webrtcUtils.log(now + ': ' + text);
} else {
webrtcUtils.log(text);
}
}
*/
if (typeof window === 'object') {
if (window.HTMLMediaElement &&
!('srcObject' in window.HTMLMediaElement.prototype)) {
// Shim the srcObject property, once, when HTMLMediaElement is found.
Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
get: function() {
// If prefixed srcObject property exists, return it.
// Otherwise use the shimmed property, _srcObject
return 'mozSrcObject' in this ? this.mozSrcObject : this._srcObject;
},
set: function(stream) {
if ('mozSrcObject' in this) {
this.mozSrcObject = stream;
} else {
// Use _srcObject as a private property for this shim
this._srcObject = stream;
// TODO: revokeObjectUrl(this.src) when !stream to release resources?
this.src = URL.createObjectURL(stream);
}
}
});
} }
// Proxy existing globals
getUserMedia = window.navigator && window.navigator.getUserMedia;
}
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
element.srcObject = stream;
};
reattachMediaStream = function(to, from) {
to.srcObject = from.srcObject;
}; };
if (typeof window === 'undefined' || !window.navigator) { if (typeof window === 'undefined' || !window.navigator) {
webrtcUtils.log('This does not appear to be a browser'); webrtcUtils.log('This does not appear to be a browser');
webrtcDetectedBrowser = 'not a browser'; webrtcDetectedBrowser = 'not a browser';
} else if (navigator.mozGetUserMedia) { } else if (navigator.mozGetUserMedia && window.mozRTCPeerConnection) {
webrtcUtils.log('This appears to be Firefox'); webrtcUtils.log('This appears to be Firefox');
webrtcDetectedBrowser = 'firefox'; webrtcDetectedBrowser = 'firefox';
// the detected firefox version. // the detected firefox version.
webrtcDetectedVersion = webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); /Firefox\/([0-9]+)\./, 1);
// the minimum firefox version still supported by adapter. // the minimum firefox version still supported by adapter.
webrtcMinimumVersion = 31; webrtcMinimumVersion = 31;
@ -88,14 +145,18 @@ if (typeof window === 'undefined' || !window.navigator) {
pcConfig.iceServers = newIceServers; pcConfig.iceServers = newIceServers;
} }
} }
return new mozRTCPeerConnection(pcConfig, pcConstraints); return new mozRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
}; };
// The RTCSessionDescription object. // The RTCSessionDescription object.
window.RTCSessionDescription = mozRTCSessionDescription; if (!window.RTCSessionDescription) {
window.RTCSessionDescription = mozRTCSessionDescription;
}
// The RTCIceCandidate object. // The RTCIceCandidate object.
window.RTCIceCandidate = mozRTCIceCandidate; if (!window.RTCIceCandidate) {
window.RTCIceCandidate = mozRTCIceCandidate;
}
// getUserMedia constraints shim. // getUserMedia constraints shim.
getUserMedia = function(constraints, onSuccess, onError) { getUserMedia = function(constraints, onSuccess, onError) {
@ -168,8 +229,8 @@ if (typeof window === 'undefined' || !window.navigator) {
navigator.mediaDevices.enumerateDevices || function() { navigator.mediaDevices.enumerateDevices || function() {
return new Promise(function(resolve) { return new Promise(function(resolve) {
var infos = [ var infos = [
{kind: 'audioinput', deviceId: 'default', label:'', groupId:''}, {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
{kind: 'videoinput', deviceId: 'default', label:'', groupId:''} {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
]; ];
resolve(infos); resolve(infos);
}); });
@ -180,7 +241,7 @@ if (typeof window === 'undefined' || !window.navigator) {
var orgEnumerateDevices = var orgEnumerateDevices =
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
navigator.mediaDevices.enumerateDevices = function() { navigator.mediaDevices.enumerateDevices = function() {
return orgEnumerateDevices().catch(function(e) { return orgEnumerateDevices().then(undefined, function(e) {
if (e.name === 'NotFoundError') { if (e.name === 'NotFoundError') {
return []; return [];
} }
@ -188,30 +249,27 @@ if (typeof window === 'undefined' || !window.navigator) {
}); });
}; };
} }
// Attach a media stream to an element. } else if (navigator.webkitGetUserMedia && window.webkitRTCPeerConnection) {
attachMediaStream = function(element, stream) {
element.mozSrcObject = stream;
};
reattachMediaStream = function(to, from) {
to.mozSrcObject = from.mozSrcObject;
};
} else if (navigator.webkitGetUserMedia) {
webrtcUtils.log('This appears to be Chrome'); webrtcUtils.log('This appears to be Chrome');
webrtcDetectedBrowser = 'chrome'; webrtcDetectedBrowser = 'chrome';
// the detected chrome version. // the detected chrome version.
webrtcDetectedVersion = webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); /Chrom(e|ium)\/([0-9]+)\./, 2);
// the minimum chrome version still supported by adapter. // the minimum chrome version still supported by adapter.
webrtcMinimumVersion = 38; webrtcMinimumVersion = 38;
// The RTCPeerConnection object. // The RTCPeerConnection object.
window.RTCPeerConnection = function(pcConfig, pcConstraints) { window.RTCPeerConnection = function(pcConfig, pcConstraints) {
var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // Translate iceTransportPolicy to iceTransports,
// see https://code.google.com/p/webrtc/issues/detail?id=4869
if (pcConfig && pcConfig.iceTransportPolicy) {
pcConfig.iceTransports = pcConfig.iceTransportPolicy;
}
var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); // jscs:ignore requireCapitalizedConstructors
var origGetStats = pc.getStats.bind(pc); var origGetStats = pc.getStats.bind(pc);
pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line
var self = this; var self = this;
@ -251,7 +309,14 @@ if (typeof window === 'undefined' || !window.navigator) {
// promise-support // promise-support
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
origGetStats.apply(self, [resolve, reject]); if (args.length === 1 && selector === null) {
origGetStats.apply(self, [
function(response) {
resolve.apply(null, [fixChromeStats(response)]);
}, reject]);
} else {
origGetStats.apply(self, [resolve, reject]);
}
}); });
}; };
@ -417,7 +482,7 @@ if (typeof window === 'undefined' || !window.navigator) {
// Attach a media stream to an element. // Attach a media stream to an element.
attachMediaStream = function(element, stream) { attachMediaStream = function(element, stream) {
if (typeof element.srcObject !== 'undefined') { if (webrtcDetectedVersion >= 43) {
element.srcObject = stream; element.srcObject = stream;
} else if (typeof element.src !== 'undefined') { } else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream); element.src = URL.createObjectURL(stream);
@ -425,9 +490,12 @@ if (typeof window === 'undefined' || !window.navigator) {
webrtcUtils.log('Error attaching stream to element.'); webrtcUtils.log('Error attaching stream to element.');
} }
}; };
reattachMediaStream = function(to, from) { reattachMediaStream = function(to, from) {
to.src = from.src; if (webrtcDetectedVersion >= 43) {
to.srcObject = from.srcObject;
} else {
to.src = from.src;
}
}; };
} else if (navigator.mediaDevices && navigator.userAgent.match( } else if (navigator.mediaDevices && navigator.userAgent.match(
@ -435,20 +503,11 @@ if (typeof window === 'undefined' || !window.navigator) {
webrtcUtils.log('This appears to be Edge'); webrtcUtils.log('This appears to be Edge');
webrtcDetectedBrowser = 'edge'; webrtcDetectedBrowser = 'edge';
webrtcDetectedVersion = webrtcDetectedVersion = webrtcUtils.extractVersion(navigator.userAgent,
parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2], 10); /Edge\/(\d+).(\d+)$/, 2);
// the minimum version still supported by adapter. // the minimum version still supported by adapter.
webrtcMinimumVersion = 12; webrtcMinimumVersion = 12;
getUserMedia = navigator.getUserMedia;
attachMediaStream = function(element, stream) {
element.srcObject = stream;
};
reattachMediaStream = function(to, from) {
to.srcObject = from.srcObject;
};
} else { } else {
webrtcUtils.log('Browser does not appear to be WebRTC-capable'); webrtcUtils.log('Browser does not appear to be WebRTC-capable');
} }
@ -461,26 +520,35 @@ function requestUserMedia(constraints) {
} }
var webrtcTesting = {}; var webrtcTesting = {};
Object.defineProperty(webrtcTesting, 'version', { try {
set: function(version) { Object.defineProperty(webrtcTesting, 'version', {
webrtcDetectedVersion = version; set: function(version) {
} webrtcDetectedVersion = version;
}); }
});
} catch (e) {}
if (typeof module !== 'undefined') { if (typeof module !== 'undefined') {
var RTCPeerConnection; var RTCPeerConnection;
var RTCIceCandidate;
var RTCSessionDescription;
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
RTCPeerConnection = window.RTCPeerConnection; RTCPeerConnection = window.RTCPeerConnection;
RTCIceCandidate = window.RTCIceCandidate;
RTCSessionDescription = window.RTCSessionDescription;
} }
module.exports = { module.exports = {
RTCPeerConnection: RTCPeerConnection, RTCPeerConnection: RTCPeerConnection,
RTCIceCandidate: RTCIceCandidate,
RTCSessionDescription: RTCSessionDescription,
getUserMedia: getUserMedia, getUserMedia: getUserMedia,
attachMediaStream: attachMediaStream, attachMediaStream: attachMediaStream,
reattachMediaStream: reattachMediaStream, reattachMediaStream: reattachMediaStream,
webrtcDetectedBrowser: webrtcDetectedBrowser, webrtcDetectedBrowser: webrtcDetectedBrowser,
webrtcDetectedVersion: webrtcDetectedVersion, webrtcDetectedVersion: webrtcDetectedVersion,
webrtcMinimumVersion: webrtcMinimumVersion, webrtcMinimumVersion: webrtcMinimumVersion,
webrtcTesting: webrtcTesting webrtcTesting: webrtcTesting,
webrtcUtils: webrtcUtils
//requestUserMedia: not exposed on purpose. //requestUserMedia: not exposed on purpose.
//trace: not exposed on purpose. //trace: not exposed on purpose.
}; };
@ -489,13 +557,16 @@ if (typeof module !== 'undefined') {
define([], function() { define([], function() {
return { return {
RTCPeerConnection: window.RTCPeerConnection, RTCPeerConnection: window.RTCPeerConnection,
RTCIceCandidate: window.RTCIceCandidate,
RTCSessionDescription: window.RTCSessionDescription,
getUserMedia: getUserMedia, getUserMedia: getUserMedia,
attachMediaStream: attachMediaStream, attachMediaStream: attachMediaStream,
reattachMediaStream: reattachMediaStream, reattachMediaStream: reattachMediaStream,
webrtcDetectedBrowser: webrtcDetectedBrowser, webrtcDetectedBrowser: webrtcDetectedBrowser,
webrtcDetectedVersion: webrtcDetectedVersion, webrtcDetectedVersion: webrtcDetectedVersion,
webrtcMinimumVersion: webrtcMinimumVersion, webrtcMinimumVersion: webrtcMinimumVersion,
webrtcTesting: webrtcTesting webrtcTesting: webrtcTesting,
webrtcUtils: webrtcUtils
//requestUserMedia: not exposed on purpose. //requestUserMedia: not exposed on purpose.
//trace: not exposed on purpose. //trace: not exposed on purpose.
}; };

4
static/js/main.js

@ -181,8 +181,8 @@ if (Object.create) {
custom: { custom: {
families: ["FontAwesome"], families: ["FontAwesome"],
testStrings: { testStrings: {
"FontAwesome": '\uf004\uf005' "FontAwesome": '\uf004\uf005'
} }
}, },
active: function() { active: function() {
console.log("Web fonts loaded."); console.log("Web fonts loaded.");

15
static/js/mediastream/peercall.js

@ -34,9 +34,8 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
this.mediaConstraints = $.extend(true, {}, this.webrtc.settings.mediaConstraints); this.mediaConstraints = $.extend(true, {}, this.webrtc.settings.mediaConstraints);
this.pcConfig = $.extend(true, {}, this.webrtc.settings.pcConfig); this.pcConfig = $.extend(true, {}, this.webrtc.settings.pcConfig);
this.pcConstraints = $.extend(true, {}, this.webrtc.settings.pcConstraints); this.pcConstraints = $.extend(true, {}, this.webrtc.settings.pcConstraints);
this.sdpConstraints = $.extend(true, {}, this.webrtc.settings.sdpConstraints);
this.offerConstraints = $.extend(true, {}, this.webrtc.settings.offerConstraints);
this.sdpParams = $.extend(true, {}, this.webrtc.settings.sdpParams); this.sdpParams = $.extend(true, {}, this.webrtc.settings.sdpParams);
this.offerOptions = $.extend(true, {}, this.webrtc.settings.offerOptions);
this.peerconnection = null; this.peerconnection = null;
this.datachannels = {}; this.datachannels = {};
@ -69,17 +68,17 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
PeerCall.prototype.createOffer = function(cb) { PeerCall.prototype.createOffer = function(cb) {
var constraints = utils.mergeConstraints(this.offerConstraints, this.sdpConstraints); var options = this.offerOptions;
console.log('Creating offer with constraints: \n' + console.log('Creating offer with options: \n' +
' \'' + JSON.stringify(constraints, null, '\t') + '\'.', this.negotiationNeeded); ' \'' + JSON.stringify(options, null, '\t') + '\'.', this.negotiationNeeded);
this.peerconnection.createOffer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), constraints); this.peerconnection.createOffer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), options);
}; };
PeerCall.prototype.createAnswer = function(cb) { PeerCall.prototype.createAnswer = function(cb) {
console.log("Creating answer.", this.negotiationNeeded); console.log("Creating answer.", this.negotiationNeeded);
this.peerconnection.createAnswer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this), this.peerconnection.sdpConstraints); this.peerconnection.createAnswer(_.bind(this.onCreateAnswerOffer, this, cb), _.bind(this.onErrorAnswerOffer, this));
}; };
@ -151,7 +150,7 @@ define(['jquery', 'underscore', 'mediastream/utils', 'mediastream/peerconnection
streams++; streams++;
} }
}, this)); }, this));
if (streams === 0 && this.sdpConstraints.mandatory && (this.sdpConstraints.mandatory.OfferToReceiveAudio || this.sdpConstraints.mandatory.OfferToReceiveVideo)) { if (streams === 0 && (this.offerOptions.offerToReceiveAudio || this.offerOptions.offerToReceiveVideo)) {
// We assume that we will eventually receive a stream, so we trigger the event to let the UI prepare for it. // We assume that we will eventually receive a stream, so we trigger the event to let the UI prepare for it.
this.e.triggerHandler("remoteStreamAdded", [null, this]); this.e.triggerHandler("remoteStreamAdded", [null, this]);
} }

8
static/js/mediastream/peerscreenshare.js

@ -23,6 +23,7 @@
define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens'], function($, _, PeerCall, tokens) { define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens'], function($, _, PeerCall, tokens) {
var screenshareIds = 0; var screenshareIds = 0;
var PeerScreenshare;
// Register ourselves for tokens. // Register ourselves for tokens.
tokens.registerHandler("screenshare", function(webrtc, id, token, from) { tokens.registerHandler("screenshare", function(webrtc, id, token, from) {
@ -32,7 +33,7 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens'], f
}); });
// PeerScreenshare inherits from PeerCall. // PeerScreenshare inherits from PeerCall.
var PeerScreenshare = function(webrtc, id, token, to) { PeerScreenshare = function(webrtc, id, token, to) {
if (id === null) { if (id === null) {
id = screenshareIds++; id = screenshareIds++;
@ -50,9 +51,6 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens'], f
audio: false, audio: false,
video: false video: false
} }
this.sdpConstraints.mandatory.OfferToReceiveAudio = false;
this.sdpConstraints.mandatory.OfferToReceiveVideo = true;
// SCTP is supported from Chrome M31. // SCTP is supported from Chrome M31.
// No need to pass DTLS constraint as it is on by default in Chrome M31. // No need to pass DTLS constraint as it is on by default in Chrome M31.
// For SCTP, reliable and ordered is true by default. // For SCTP, reliable and ordered is true by default.
@ -60,6 +58,8 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens'], f
mandatory: {}, mandatory: {},
optional: [] optional: []
}; };
this.offerOptions.offerToReceiveAudio = false;
this.offerOptions.offerToReceiveVideo = true;
// Inject token into sessiondescription and ice candidate data. // Inject token into sessiondescription and ice candidate data.
this.e.on("sessiondescription icecandidate", _.bind(function(event, data) { this.e.on("sessiondescription icecandidate", _.bind(function(event, data) {

8
static/js/mediastream/peerxfer.js

@ -23,6 +23,7 @@
define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens', 'webrtc.adapter'], function($, _, PeerCall, tokens) { define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens', 'webrtc.adapter'], function($, _, PeerCall, tokens) {
var xfersIds = 0; var xfersIds = 0;
var PeerXfer;
// Register ourselves for tokens. // Register ourselves for tokens.
tokens.registerHandler("xfer", function(webrtc, id, token, from) { tokens.registerHandler("xfer", function(webrtc, id, token, from) {
@ -32,7 +33,7 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens', 'w
}); });
// PeerXfer inherits from PeerCall. // PeerXfer inherits from PeerCall.
var PeerXfer = function(webrtc, id, token, to) { PeerXfer = function(webrtc, id, token, to) {
if (id === null) { if (id === null) {
id = xfersIds++; id = xfersIds++;
@ -48,10 +49,6 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens', 'w
audio: false, audio: false,
video: false video: false
}; };
this.sdpConstraints = {
mandatory: {},
optional: []
};
// SCTP is supported from Chrome M31. // SCTP is supported from Chrome M31.
// No need to pass DTLS constraint as it is on by default in Chrome M31. // No need to pass DTLS constraint as it is on by default in Chrome M31.
// For SCTP, reliable and ordered is true by default. // For SCTP, reliable and ordered is true by default.
@ -59,6 +56,7 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens', 'w
mandatory: {}, mandatory: {},
optional: [] optional: []
}; };
this.offerOptions = {};
// Inject token into sessiondescription and ice candidate data. // Inject token into sessiondescription and ice candidate data.
this.e.on("sessiondescription icecandidate", _.bind(function(event, data) { this.e.on("sessiondescription icecandidate", _.bind(function(event, data) {

4
static/js/mediastream/tokens.js

@ -22,6 +22,8 @@
"use strict"; "use strict";
define(['jquery', 'underscore'], function($, _) { define(['jquery', 'underscore'], function($, _) {
var tokens;
var Token = function(handlerKey) { var Token = function(handlerKey) {
this.e = $({}); this.e = $({});
this.count = 0; this.count = 0;
@ -179,7 +181,7 @@ define(['jquery', 'underscore'], function($, _) {
}; };
var tokens = new Tokens(); tokens = new Tokens();
return tokens; return tokens;
}); });

3
static/js/mediastream/utils.js

@ -41,6 +41,7 @@
"use strict"; "use strict";
define([], function() { define([], function() {
/*jshint strict: true, latedef: false */
function trace(text) { function trace(text) {
// noop // noop
@ -232,7 +233,7 @@ define([], function() {
// The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'. // The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'.
function maybePreferCodec(sdp, type, dir, codec) { function maybePreferCodec(sdp, type, dir, codec) {
var str = type + ' ' + dir + ' codec'; var str = type + ' ' + dir + ' codec';
if (codec === '') { if (!codec) {
trace('No preference on ' + str + '.'); trace('No preference on ' + str + '.');
return sdp; return sdp;
} }

17
static/js/mediastream/webrtc.js

@ -80,18 +80,6 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
mandatory: {}, mandatory: {},
optional: [] optional: []
}, },
// Set up audio and video regardless of what devices are present.
sdpConstraints: {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
},
optional: []
},
offerConstraints: {
mandatory: {},
optional: []
},
screensharing: { screensharing: {
mediaConstraints: { mediaConstraints: {
audio: false, audio: false,
@ -115,6 +103,11 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u
//videoRecvBitrate: , //videoRecvBitrate: ,
//videoRecvCodec //videoRecvCodec
}, },
// Set up audio and video regardless of what devices are present.
offerOptions: {
offerToReceiveAudio: true,
offerToReceiveVideo: true
},
renegotiation: true renegotiation: true
}; };

2
static/js/services/alertify.js

@ -108,7 +108,7 @@ define(["angular"], function(angular) {
if (!conf || if (!conf ||
conf && !conf.type || conf && !conf.type ||
conf && !conf.baseType) { conf && !conf.baseType) {
throw Error("Custom template not configured correctly."); throw new Error("Custom template not configured correctly.");
} }
var templateUrl = '/dialogs/' + conf.type + '.html'; var templateUrl = '/dialogs/' + conf.type + '.html';
if (conf.template) { if (conf.template) {

16
static/js/services/animationframe.js

@ -28,20 +28,26 @@ define(["underscore", "rAF"], function(_) {
var requestAnimationFrame = $window.requestAnimationFrame; var requestAnimationFrame = $window.requestAnimationFrame;
var registry = []; var registry = [];
var caller = function(f) { var caller;
var runner;
var timer;
var worker;
var animationFrame;
caller = function(f) {
f(); f();
}; };
var runner = function(c) { runner = function(c) {
registry.forEach(caller); registry.forEach(caller);
requestAnimationFrame(worker) requestAnimationFrame(worker)
} }
var timer = $window.setTimeout; timer = $window.setTimeout;
var worker = function() { worker = function() {
timer(runner, 100); timer(runner, 100);
}; };
// Public api. // Public api.
var animationFrame = { animationFrame = {
register: function(f) { register: function(f) {
registry.push(f); registry.push(f);
} }

2
static/js/services/desktopnotify.js

@ -74,7 +74,7 @@ define(['jquery', 'underscore', 'desktop-notify', 'webrtc.adapter'], function($,
// on Android, where Notifications raise an exception. // on Android, where Notifications raise an exception.
// See https://code.google.com/p/chromium/issues/detail?id=481856 // See https://code.google.com/p/chromium/issues/detail?id=481856
try { try {
/*jshint nonew: false */ /*jshint strict: true, nonew: false */
new $window.Notification(''); new $window.Notification('');
} catch(e) { } catch(e) {
if (e.name == 'TypeError') { if (e.name == 'TypeError') {

13
static/js/services/filedownload.js

@ -26,8 +26,9 @@ define(["jquery", "underscore"], function($, _) {
var downloads = 0; var downloads = 0;
var Session = function(id, token, scope) { var Session = function(fileDownload, id, token, scope) {
this.fileDownload = fileDownload;
this.id = id; this.id = id;
this.token = token; this.token = token;
this.scope = scope; this.scope = scope;
@ -175,7 +176,7 @@ define(["jquery", "underscore"], function($, _) {
session.done(this); session.done(this);
return; return;
} }
fileDownload.sendRequest(xfer, this.chunk++); session.fileDownload.sendRequest(xfer, this.chunk++);
}, job); }, job);
//console.log("Starting new job", job, this.fragments, xfer.id); //console.log("Starting new job", job, this.fragments, xfer.id);
xfer.e.on("sessionData", _.bind(this.handleData, this, job)); xfer.e.on("sessionData", _.bind(this.handleData, this, job));
@ -287,7 +288,7 @@ define(["jquery", "underscore"], function($, _) {
FileDownload.prototype.createSession = function(scope, token) { FileDownload.prototype.createSession = function(scope, token) {
var id = Session.makeId(token, this.downloads++); var id = Session.makeId(token, this.downloads++);
var session = this.sessions[id] = new Session(id, token, scope); var session = this.sessions[id] = new Session(this, id, token, scope);
//console.log("Created new file download session", id, session); //console.log("Created new file download session", id, session);
return session; return session;
}; };
@ -330,11 +331,7 @@ define(["jquery", "underscore"], function($, _) {
}; };
return new FileDownload();
// Create signleton.
var fileDownload = new FileDownload();
return fileDownload;
}]; }];

4
static/js/services/geolocation.js

@ -29,8 +29,8 @@ define(['underscore', 'modernizr'], function(_, Modernizr) {
var defaults = { var defaults = {
enableHighAccuracy: true, enableHighAccuracy: true,
timeout: 5000, timeout: 5000,
maximumAge: 0 maximumAge: 0
}; };
return { return {

34
static/js/services/mediadevices.js

@ -19,44 +19,12 @@
* *
*/ */
/* global Promise */
"use strict"; "use strict";
define(['webrtc.adapter'], function() { define(['webrtc.adapter'], function() {
// mediaDevices // mediaDevices
return ["$window", function($window) { return ["$window", function($window) {
return $window.navigator.mediaDevices;
var mediaDevices = $window.navigator.mediaDevices || {};
var getUserMedia = (function() {
// Implement a Promise based wrapper around getUserMedia.
if (mediaDevices.getUserMedia) {
// mediaDevices calls return Promise native.
return mediaDevices.getUserMedia.bind(mediaDevices);
} else {
return function getUserMedia(constraints) {
return new Promise(function(resolve, reject) {
var onSuccess = function(stream) {
resolve(stream)
};
var onError = function(error) {
reject(error);
};
try {
$window.getUserMedia(constraints, onSuccess, onError);
} catch(err) {
onError(err);
}
});
}
}
})();
// Public api.
return {
shim: mediaDevices.getUserMedia ? false : true,
getUserMedia: getUserMedia
}
}]; }];
}); });

29
static/js/services/mediasources.js

@ -20,13 +20,14 @@
*/ */
"use strict"; "use strict";
define(['jquery', 'underscore'], function($, _) { define(['jquery', 'underscore', 'webrtc.adapter'], function($, _, adapter) {
return ["$window", function($window) { return ["$window", "mediaDevices", function($window, mediaDevices) {
var MediaSources = function() { var MediaSources = function() {
this.supported = $window.MediaStreamTrack && $window.MediaStreamTrack.getSources // For now enable media sources only in Chrome until other browsers have some use for it.
this.supported = $window.navigator.mediaDevices.enumerateDevices && adapter.webrtcDetectedBrowser === "chrome";
this.audio = []; this.audio = [];
this.video = []; this.video = [];
@ -57,25 +58,29 @@ define(['jquery', 'underscore'], function($, _) {
MediaSources.prototype._refresh = function(cb) { MediaSources.prototype._refresh = function(cb) {
$window.MediaStreamTrack.getSources(_.bind(function(sources) { mediaDevices.enumerateDevices().then(_.bind(function(devices) {
var audio = this.audio = []; var audio = this.audio = [];
var video = this.video = []; var video = this.video = [];
_.each(sources, function(source) { _.each(devices, function(device) {
var o = { var o = {
id: source.id, id: device.deviceId,
facing: source.facing }
}; if (device.kind === "audioinput") {
if (source.kind === "audio") { o.label = device.label ? device.label : "Microphone " + (audio.length + 1);
o.label = source.label ? source.label : "Microphone " + (audio.length + 1);
audio.push(o); audio.push(o);
} else if (source.kind === "video") { } else if (device.kind === "videoinput") {
o.label = source.label ? source.label : "Camera " + (video.length + 1); o.label = device.label ? device.label : "Camera " + (video.length + 1);
video.push(o); video.push(o);
} }
}); });
if (cb) { if (cb) {
cb(audio, video); cb(audio, video);
} }
}, this), _.bind(function(error) {
console.error("failed to get media devices: " + error);
if (cb) {
cb([], []);
}
}, this)); }, this));
}; };

5
static/js/services/mediastream.js

@ -252,8 +252,9 @@ define([
}, 1000); }, 1000);
if (context.Cfg.Tokens) { if (context.Cfg.Tokens) {
var prompt, check;
var storedCode = localStorage.getItem("mediastream-access-code"); var storedCode = localStorage.getItem("mediastream-access-code");
var prompt = function() { prompt = function() {
alertify.dialog.prompt(translation._("Access code required"), function(code) { alertify.dialog.prompt(translation._("Access code required"), function(code) {
if (!code) { if (!code) {
prompt(); prompt();
@ -264,7 +265,7 @@ define([
}, prompt); }, prompt);
}; };
var url = restURL.api("tokens"); var url = restURL.api("tokens");
var check = function(code) { check = function(code) {
$http({ $http({
method: "POST", method: "POST",
url: url, url: url,

20
static/js/services/rooms.js

@ -37,7 +37,14 @@ define([
var canJoinRooms = !mediaStream.config.AuthorizeRoomJoin; var canJoinRooms = !mediaStream.config.AuthorizeRoomJoin;
var canCreateRooms = canJoinRooms ? !mediaStream.config.AuthorizeRoomCreation : false; var canCreateRooms = canJoinRooms ? !mediaStream.config.AuthorizeRoomCreation : false;
var joinFailed = function(error) { var rooms;
var joinFailed;
var joinRequestedRoom;
var setCurrentRoom;
var updateRoom;
var applyRoomUpdate;
joinFailed = function(error) {
setCurrentRoom(null); setCurrentRoom(null);
switch(error.Code) { switch(error.Code) {
@ -70,7 +77,7 @@ define([
} }
}; };
var joinRequestedRoom = function() { joinRequestedRoom = function() {
if (!connector.connected || appData.authorizing()) { if (!connector.connected || appData.authorizing()) {
// Do nothing while not connected or authorizing. // Do nothing while not connected or authorizing.
return; return;
@ -95,7 +102,7 @@ define([
} }
}; };
var setCurrentRoom = function(room) { setCurrentRoom = function(room) {
if (room === currentRoom) { if (room === currentRoom) {
return; return;
} }
@ -112,13 +119,13 @@ define([
} }
}; };
var updateRoom = function(room) { updateRoom = function(room) {
var response = $q.defer(); var response = $q.defer();
api.requestRoomUpdate(room, response.resolve, response.reject); api.requestRoomUpdate(room, response.resolve, response.reject);
return response.promise.then(applyRoomUpdate); return response.promise.then(applyRoomUpdate);
}; };
var applyRoomUpdate = function(room) { applyRoomUpdate = function(room) {
if (room.Credentials) { if (room.Credentials) {
roompin.update(currentRoom.Name, room.Credentials.PIN); roompin.update(currentRoom.Name, room.Credentials.PIN);
delete room.Credentials; delete room.Credentials;
@ -169,7 +176,8 @@ define([
} }
}); });
var rooms = { // Public API.
rooms = {
inDefaultRoom: function() { inDefaultRoom: function() {
return (currentRoom !== null ? currentRoom.Name : requestedRoomName) === ""; return (currentRoom !== null ? currentRoom.Name : requestedRoomName) === "";
}, },

2
static/partials/chat.html

@ -5,7 +5,7 @@
<div class="chatheader"><div class="chatstatusicon" ng-click="activateRoom(currentRoom.id, true)"><i class="fa fa-angle-right"></i> <i class="fa fa fa-comments-o"></i></div><div class="chatheadertitle"><span>{{_("Chat sessions")}}</span></div> <div class="ctrl"><i ng-show="layout.chatMaximized" ng-click="toggleMax()" class="fa fa-compress"></i></div></div> <div class="chatheader"><div class="chatstatusicon" ng-click="activateRoom(currentRoom.id, true)"><i class="fa fa-angle-right"></i> <i class="fa fa fa-comments-o"></i></div><div class="chatheadertitle"><span>{{_("Chat sessions")}}</span></div> <div class="ctrl"><i ng-show="layout.chatMaximized" ng-click="toggleMax()" class="fa fa-compress"></i></div></div>
<div class="chatbody"> <div class="chatbody">
<div class="list-group nicescroll"> <div class="list-group nicescroll">
<a ng-repeat="room in getVisibleRooms()" ng-click="activateRoom(room.id, true)" class="list-group-item" ng-class="{newmessage: room.pending, disabled: !room.enabled}"> <a ng-repeat="room in getVisibleRooms()" ng-click="activateRoom(room.id, true, true)" class="list-group-item" ng-class="{newmessage: room.pending, disabled: !room.enabled}">
<span class="badge" ng-show="room.pending">{{room.pending}}</span> <span class="badge" ng-show="room.pending">{{room.pending}}</span>
<span ng-if="room.id !== ''">{{room.id|displayName}}</span> <span ng-if="room.id !== ''">{{room.id|displayName}}</span>
<span ng-if="room.id === ''">{{_("Room chat")}} {{currentRoomName}}</span> <span ng-if="room.id === ''">{{_("Room chat")}} {{currentRoomName}}</span>

Loading…
Cancel
Save