diff --git a/webclient/app-controller.js b/webclient/app-controller.js
index f63bb32f4f..7f48148aaa 100644
--- a/webclient/app-controller.js
+++ b/webclient/app-controller.js
@@ -93,7 +93,13 @@ angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'even
};
$rootScope.$watch('currentCall', function(newVal, oldVal) {
- if (!$rootScope.currentCall) return;
+ if (!$rootScope.currentCall) {
+ // This causes the still frame to be flushed out of the video elements,
+ // avoiding a flash of the last frame of the previous call when starting the next
+ angular.element('#localVideo')[0].load();
+ angular.element('#remoteVideo')[0].load();
+ return;
+ }
var roomMembers = angular.copy($rootScope.events.rooms[$rootScope.currentCall.room_id].members);
delete roomMembers[matrixService.config().user_id];
@@ -140,7 +146,19 @@ angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'even
} else if (oldVal == 'ringing') {
angular.element('#ringAudio')[0].pause();
} else if (newVal == 'connected') {
- $scope.videoMode = 'large';
+ $timeout(function() {
+ //if ($scope.currentCall.type == 'video') $scope.videoMode = 'large';
+ }, 5000);
+ }
+
+ if ($rootScope.currentCall && $rootScope.currentCall.type == 'video' && $rootScope.currentCall.state != 'connected') {
+ $scope.videoMode = 'mini';
+ }
+ });
+ $rootScope.$watch('currentCall.type', function(newVal, oldVal) {
+ // need to listen for this too as the type of the call won't be know when it's created
+ if ($rootScope.currentCall && $rootScope.currentCall.type == 'video' && $rootScope.currentCall.state != 'connected') {
+ $scope.videoMode = 'mini';
}
});
diff --git a/webclient/app.css b/webclient/app.css
index 69e608287e..7b6051e0b9 100755
--- a/webclient/app.css
+++ b/webclient/app.css
@@ -97,30 +97,44 @@ a:active { color: #000; }
left: 0px;
z-index: 1;
background-color: rgba(0,0,0,0.0);
+ pointer-events: none;
transition: background-color linear 300ms;
}
#videoBackground.large {
background-color: rgba(0,0,0,0.85);
+ pointer-events: auto;
}
-#localVideo {
- position: absolute;
+#videoContainer {
+ max-width: 1280px;
+ margin: auto;
top: 32px;
- left: 160px;
+}
+
+#videoContainer.large {
+}
+
+#localVideo.mini {
+ position: relative;
+ left: 120px;
width: 128px;
height: 72px;
- z-index: 2;
+}
+
+#localVideo.ended {
+ -webkit-filter: grayscale(1);
}
#remoteVideo {
- position: absolute;
- top: 32px;
- left: 300px;
+ transition: all linear 300ms;
+}
+
+#remoteVideo.mini {
+ position: relative;
+ left: 120px;
width: 128px;
height: 72px;
- z-index: 2;
- transition: all linear 300ms;
}
#remoteVideo.large {
diff --git a/webclient/components/matrix/matrix-call.js b/webclient/components/matrix/matrix-call.js
index 636259297e..5ba782bac8 100644
--- a/webclient/components/matrix/matrix-call.js
+++ b/webclient/components/matrix/matrix-call.js
@@ -65,7 +65,7 @@ angular.module('MatrixCall', [])
var stunServer = 'stun:stun.l.google.com:19302';
var pc;
if (window.mozRTCPeerConnection) {
- pc = window.mozRTCPeerConnection({'url': stunServer});
+ pc = new window.mozRTCPeerConnection({'url': stunServer});
} else {
pc = new window.RTCPeerConnection({"iceServers":[{"urls":"stun:stun.l.google.com:19302"}]});
}
@@ -118,6 +118,17 @@ angular.module('MatrixCall', [])
this.peerConn.setRemoteDescription(new RTCSessionDescription(this.msg.offer), this.onSetRemoteDescriptionSuccess, this.onSetRemoteDescriptionError);
this.state = 'ringing';
this.direction = 'inbound';
+
+ if (window.mozRTCPeerConnection) {
+ // firefox's RTCPeerConnection doesn't add streams until it starts getting media on them
+ // so we need to figure out whether a video channel has been offered by ourselves.
+ if (this.msg.offer.sdp.indexOf('m=video') > -1) {
+ this.type = 'video';
+ } else {
+ this.type = 'voice';
+ }
+ }
+
var self = this;
$timeout(function() {
if (self.state == 'ringing') {
@@ -167,7 +178,10 @@ angular.module('MatrixCall', [])
MatrixCall.prototype.hangup = function(suppressEvent) {
console.log("Ending call "+this.call_id);
- this.remoteVideoElement.pause();
+ // pausing now keeps the last frame (ish) of the video call in the video element
+ // rather than it just turning black straight away
+ if (this.remoteVideoElement) this.remoteVideoElement.pause();
+ if (this.localVideoElement) this.localVideoElement.pause();
this.stopAllMedia();
if (this.peerConn) this.peerConn.close();
@@ -318,7 +332,7 @@ angular.module('MatrixCall', [])
};
MatrixCall.prototype.getUserMediaFailed = function() {
- this.onError("Couldn't start capturing audio! Is your microphone set up?");
+ this.onError("Couldn't start capturing! Is your microphone set up?");
this.hangup();
};
@@ -411,6 +425,8 @@ angular.module('MatrixCall', [])
MatrixCall.prototype.onHangupReceived = function() {
console.log("Hangup received");
+ if (this.remoteVideoElement) this.remoteVideoElement.pause();
+ if (this.localVideoElement) this.localVideoElement.pause();
this.state = 'ended';
this.hangupParty = 'remote';
this.stopAllMedia();
diff --git a/webclient/index.html b/webclient/index.html
index 05801a93bc..78a68753d4 100644
--- a/webclient/index.html
+++ b/webclient/index.html
@@ -45,7 +45,12 @@
</head>
<body>
- <div id="videoBackground" ng-class="videoMode" ng-show="videoMode == 'large' || videoMode == 'fullscreen'"></div>
+ <div id="videoBackground" ng-class="videoMode">
+ <div id="videoContainer" ng-class="videoMode">
+ <video id="localVideo" ng-class="[videoMode, currentCall.state]" ng-show="currentCall && currentCall.type == 'video' && (currentCall.state == 'connected' || currentCall.state == 'connecting' || currentCall.state == 'invite_sent' || currentCall.state == 'ended')"></video>
+ <video id="remoteVideo" ng-class="[videoMode, currentCall.state]" ng-show="currentCall && currentCall.type == 'video' && (currentCall.state == 'connected' || currentCall.state == 'ended')"></video>
+ </div>
+ </div>
<div id="header">
<!-- Do not show buttons on the login page -->
@@ -59,8 +64,8 @@
<br />
<span id="callState">
<span ng-show="currentCall.state == 'invite_sent'">Calling...</span>
- <span ng-show="currentCall.state == 'ringing' && currentCall.type == 'video'">Incoming Video Call</span>
- <span ng-show="currentCall.state == 'ringing' && currentCall.type == 'voice'">Incoming Voice Call</span>
+ <span ng-show="currentCall.state == 'ringing' && currentCall && currentCall.type == 'video'">Incoming Video Call</span>
+ <span ng-show="currentCall.state == 'ringing' && currentCall && currentCall.type == 'voice'">Incoming Voice Call</span>
<span ng-show="currentCall.state == 'connecting'">Call Connecting...</span>
<span ng-show="currentCall.state == 'connected'">Call Connected</span>
<span ng-show="currentCall.state == 'ended' && !currentCall.didConnect && currentCall.direction == 'outbound' && currentCall.hangupParty == 'remote'">Call Rejected</span>
@@ -94,8 +99,6 @@
<source src="media/busy.mp3" type="audio/mpeg" />
</audio>
</div>
- <video id="localVideo" ng-class="videoMode" ng-show="currentCall && currentCall.type == 'video' && (currentCall.state == 'connected' || currentCall.state == 'connecting' || currentCall.state == 'invite_sent')"></video>
- <video id="remoteVideo" ng-class="[videoMode, currentCall.state]" ng-show="currentCall && currentCall.type == 'video' && currentCall.state == 'connected' || currentCall.state == 'ended'"></video>
<a href id="headerUserId" ng-click='goToUserPage(user_id)'>{{ user_id }}</a>
|