diff --git a/webclient/components/matrix/matrix-call.js b/webclient/components/matrix/matrix-call.js
index 1bed843c44..a5f2529b87 100644
--- a/webclient/components/matrix/matrix-call.js
+++ b/webclient/components/matrix/matrix-call.js
@@ -21,6 +21,7 @@ angular.module('MatrixCall', [])
var MatrixCall = function(room_id) {
this.room_id = room_id;
this.call_id = "c" + new Date().getTime();
+ this.state = 'fledgling';
}
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
@@ -30,19 +31,75 @@ angular.module('MatrixCall', [])
MatrixCall.prototype.placeCall = function() {
self = this;
matrixPhoneService.callPlaced(this);
- navigator.getUserMedia({audio: true, video: false}, function(s) { self.gotUserMedia(s); }, function(e) { self.getUserMediaFailed(e); });
+ navigator.getUserMedia({audio: true, video: false}, function(s) { self.gotUserMediaForInvite(s); }, function(e) { self.getUserMediaFailed(e); });
+ self.state = 'wait_local_media';
};
- MatrixCall.prototype.gotUserMedia = function(stream) {
+ MatrixCall.prototype.initWithInvite = function(msg) {
+ this.msg = msg;
this.peerConn = new window.RTCPeerConnection({"iceServers":[{"urls":"stun:stun.l.google.com:19302"}]})
- this.peerConn.addStream(stream);
+ self= this;
+ this.peerConn.oniceconnectionstatechange = function() { self.onIceConnectionStateChanged(); };
+ this.peerConn.onicecandidate = function(c) { self.gotLocalIceCandidate(c); };
+ this.peerConn.onsignalingstatechange = function() { self.onSignallingStateChanged(); };
+ this.peerConn.onaddstream = function(s) { self.onAddStream(s); };
+ this.peerConn.setRemoteDescription(new RTCSessionDescription(this.msg.offer), self.onSetRemoteDescriptionSuccess, self.onSetRemoteDescriptionError);
+ this.state = 'ringing';
+ };
+
+ MatrixCall.prototype.answer = function() {
+ console.trace("Answering call "+this.call_id);
self = this;
+ navigator.getUserMedia({audio: true, video: false}, function(s) { self.gotUserMediaForAnswer(s); }, function(e) { self.getUserMediaFailed(e); });
+ this.state = 'wait_local_media';
+ };
+
+ MatrixCall.prototype.hangup = function() {
+ console.trace("Rejecting call "+this.call_id);
+ var content = {
+ msgtype: "m.call.hangup",
+ version: 0,
+ call_id: this.call_id,
+ };
+ matrixService.sendMessage(this.room_id, undefined, content).then(this.messageSent, this.messageSendFailed);
+ this.state = 'ended';
+ };
+
+ MatrixCall.prototype.gotUserMediaForInvite = function(stream) {
+ var audioTracks = stream.getAudioTracks();
+ for (var i = 0; i < audioTracks.length; i++) {
+ audioTracks[i].enabled = true;
+ }
+ this.peerConn = new window.RTCPeerConnection({"iceServers":[{"urls":"stun:stun.l.google.com:19302"}]})
+ self = this;
+ this.peerConn.oniceconnectionstatechange = function() { self.onIceConnectionStateChanged(); };
+ this.peerConn.onsignalingstatechange = function() { self.onSignallingStateChanged(); };
this.peerConn.onicecandidate = function(c) { self.gotLocalIceCandidate(c); };
+ this.peerConn.onaddstream = function(s) { self.onAddStream(s); };
+ this.peerConn.addStream(stream);
this.peerConn.createOffer(function(d) {
self.gotLocalOffer(d);
}, function(e) {
self.getLocalOfferFailed(e);
});
+ this.state = 'create_offer';
+ };
+
+ MatrixCall.prototype.gotUserMediaForAnswer = function(stream) {
+ var audioTracks = stream.getAudioTracks();
+ for (var i = 0; i < audioTracks.length; i++) {
+ audioTracks[i].enabled = true;
+ }
+ this.peerConn.addStream(stream);
+ self = this;
+ var constraints = {
+ 'mandatory': {
+ 'OfferToReceiveAudio': true,
+ 'OfferToReceiveVideo': false
+ },
+ };
+ this.peerConn.createAnswer(function(d) { self.createdAnswer(d); }, function(e) {}, constraints);
+ this.state = 'create_answer';
};
MatrixCall.prototype.gotLocalIceCandidate = function(event) {
@@ -59,11 +116,21 @@ angular.module('MatrixCall', [])
}
MatrixCall.prototype.gotRemoteIceCandidate = function(cand) {
- this.peerConn.addIceCandidate(cand);
+ console.trace("Got ICE candidate from remote: "+cand);
+ var candidateObject = new RTCIceCandidate({
+ sdpMLineIndex: cand.label,
+ candidate: cand.candidate
+ });
+ this.peerConn.addIceCandidate(candidateObject, function() {}, function(e) {});
+ };
+
+ MatrixCall.prototype.receivedAnswer = function(msg) {
+ this.peerConn.setRemoteDescription(new RTCSessionDescription(msg.answer), self.onSetRemoteDescriptionSuccess, self.onSetRemoteDescriptionError);
+ this.state = 'connecting';
};
MatrixCall.prototype.gotLocalOffer = function(description) {
- console.trace(description);
+ console.trace("Created offer: "+description);
this.peerConn.setLocalDescription(description);
var content = {
@@ -73,6 +140,20 @@ angular.module('MatrixCall', [])
offer: description
};
matrixService.sendMessage(this.room_id, undefined, content).then(this.messageSent, this.messageSendFailed);
+ this.state = 'invite_sent';
+ };
+
+ MatrixCall.prototype.createdAnswer = function(description) {
+ console.trace("Created answer: "+description);
+ this.peerConn.setLocalDescription(description);
+ var content = {
+ msgtype: "m.call.answer",
+ version: 0,
+ call_id: this.call_id,
+ answer: description
+ };
+ matrixService.sendMessage(this.room_id, undefined, content).then(this.messageSent, this.messageSendFailed);
+ this.state = 'connecting';
};
MatrixCall.prototype.messageSent = function() {
@@ -88,6 +169,32 @@ angular.module('MatrixCall', [])
MatrixCall.prototype.getUserMediaFailed = function() {
this.onError("Couldn't start capturing audio! Is your microphone set up?");
};
+
+ MatrixCall.prototype.onIceConnectionStateChanged = function() {
+ console.trace("Ice connection state changed to: "+this.peerConn.iceConnectionState);
+ if (this.peerConn.iceConnectionState == 'completed') {
+ this.state = 'connected';
+ }
+ };
+
+ MatrixCall.prototype.onSignallingStateChanged = function() {
+ console.trace("Signalling state changed to: "+this.peerConn.signalingState);
+ };
+
+ MatrixCall.prototype.onSetRemoteDescriptionSuccess = function() {
+ console.trace("Set remote description");
+ };
+ MatrixCall.prototype.onSetRemoteDescriptionError = function(e) {
+ console.trace("Failed to set remote description"+e);
+ };
+
+ MatrixCall.prototype.onAddStream = function(event) {
+ console.trace("Stream added"+event);
+ var player = new Audio();
+ player.src = URL.createObjectURL(event.stream);
+ player.play();
+ };
+
return MatrixCall;
}]);
diff --git a/webclient/components/matrix/matrix-phone-service.js b/webclient/components/matrix/matrix-phone-service.js
index 9e296f6939..6f96875103 100644
--- a/webclient/components/matrix/matrix-phone-service.js
+++ b/webclient/components/matrix/matrix-phone-service.js
@@ -17,19 +17,14 @@ limitations under the License.
'use strict';
angular.module('matrixPhoneService', [])
-.factory('matrixPhoneService', ['$rootScope', 'matrixService', 'MatrixCall', 'eventHandlerService', function MatrixCallFactory($rootScope, matrixService, MatrixCall, eventHandlerService) {
+.factory('matrixPhoneService', ['$rootScope', '$injector', 'matrixService', 'eventHandlerService', function MatrixPhoneService($rootScope, $injector, matrixService, eventHandlerService) {
var matrixPhoneService = function() {
- }
+ };
matrixPhoneService.CALL_EVENT = "CALL_EVENT";
matrixPhoneService.allCalls = {};
- MatrixCall.prototype.placeCall = function() {
- self = this;
- navigator.getUserMedia({audio: true, video: false}, function(s) { self.gotUserMedia(s); }, function(e) { self.getUserMediaFailed(e); });
- };
-
- matrixPhoneService.prototype.callPlaced = function(call) {
+ matrixPhoneService.callPlaced = function(call) {
matrixPhoneService.allCalls[call.call_id] = call;
};
@@ -38,17 +33,34 @@ angular.module('matrixPhoneService', [])
if (event.user_id == matrixService.config().user_id) return;
var msg = event.content;
if (msg.msgtype == 'm.call.invite') {
+ var MatrixCall = $injector.get('MatrixCall');
var call = new MatrixCall(event.room_id);
call.call_id = msg.call_id;
- $rootScope.$broadcast(matrixPhoneService.CALL_EVENT, call);
+ call.initWithInvite(msg);
matrixPhoneService.allCalls[call.call_id] = call;
+ $rootScope.$broadcast(matrixPhoneService.CALL_EVENT, call);
+ } else if (msg.msgtype == 'm.call.answer') {
+ var call = matrixPhoneService.allCalls[msg.call_id];
+ if (!call) {
+ console.trace("Got answer for unknown call ID "+msg.call_id);
+ return;
+ }
+ call.receivedAnswer(msg);
} else if (msg.msgtype == 'm.call.candidate') {
- call = matrixPhoneService.allCalls[msg.call_id];
+ var call = matrixPhoneService.allCalls[msg.call_id];
if (!call) {
console.trace("Got candidate for unknown call ID "+msg.call_id);
return;
}
call.gotRemoteIceCandidate(msg.candidate);
+ } else if (msg.msgtype == 'm.call.hangup') {
+ var call = matrixPhoneService.allCalls[msg.call_id];
+ if (!call) {
+ console.trace("Got hangup for unknown call ID "+msg.call_id);
+ return;
+ }
+ call.onHangup();
+ matrixPhoneService.allCalls[msg.call_id] = undefined;
}
});
|