diff --git a/src/CallHandler.js b/src/CallHandler.js
new file mode 100644
index 0000000000..ce6d8906af
--- /dev/null
+++ b/src/CallHandler.js
@@ -0,0 +1,139 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+/*
+ * Manages a list of all the currently active calls.
+ *
+ * This handler dispatches when voip calls are added/removed from this list:
+ * {
+ * action: 'call_state'
+ * room_id:
+ * }
+ *
+ * To know if the call was added/removed, this handler exposes a getter to
+ * obtain the call for a room:
+ * CallHandler.getCall(roomId)
+ *
+ * This handler listens for and handles the following actions:
+ * {
+ * action: 'place_call',
+ * type: 'voice|video',
+ * room_id:
+ * }
+ *
+ * {
+ * action: 'incoming_call'
+ * call: MatrixCall
+ * }
+ *
+ * {
+ * action: 'hangup'
+ * room_id:
+ * }
+ *
+ * {
+ * action: 'answer'
+ * room_id:
+ * }
+ */
+
+var MatrixClientPeg = require("./MatrixClientPeg");
+var Matrix = require("matrix-js-sdk");
+var dis = require("./dispatcher");
+
+var calls = {
+ //room_id: MatrixCall
+};
+
+function _setCallListeners(call) {
+ call.on("error", function(err) {
+ console.error("Call error: %s", err);
+ console.error(err.stack);
+ call.hangup();
+ _setCallState(undefined, call.roomId);
+ });
+ call.on("hangup", function() {
+ _setCallState(undefined, call.roomId);
+ });
+}
+
+function _setCallState(call, roomId) {
+ console.log("_setState >>> %s >>> %s ", call, roomId);
+ calls[roomId] = call;
+ dis.dispatch({
+ action: 'call_state',
+ room_id: roomId
+ });
+}
+
+dis.register(function(payload) {
+ switch (payload.action) {
+ case 'place_call':
+ if (calls[payload.room_id]) {
+ return; // don't allow >1 call to be placed.
+ }
+ console.log("Place %s call in %s", payload.type, payload.room_id);
+ var call = Matrix.createNewMatrixCall(
+ MatrixClientPeg.get(), payload.room_id
+ );
+ _setCallListeners(call);
+ _setCallState(call, call.roomId);
+ if (payload.type === 'voice') {
+ call.placeVoiceCall();
+ }
+ else if (payload.type === 'video') {
+ call.placeVideoCall(
+ payload.remote_element,
+ payload.local_element
+ );
+ }
+ else {
+ console.error("Unknown call type: %s", payload.type);
+ }
+
+ break;
+ case 'incoming_call':
+ if (calls[payload.call.roomId]) {
+ payload.call.hangup("busy");
+ return; // don't allow >1 call to be received, hangup newer one.
+ }
+ var call = payload.call;
+ _setCallListeners(call);
+ _setCallState(call, call.roomId);
+ break;
+ case 'hangup':
+ if (!calls[payload.room_id]) {
+ return; // no call to hangup
+ }
+ calls[payload.room_id].hangup();
+ _setCallState(null, payload.room_id);
+ break;
+ case 'answer':
+ if (!calls[payload.room_id]) {
+ return; // no call to answer
+ }
+ calls[payload.room_id].answer();
+ break;
+ }
+});
+
+module.exports = {
+ getCall: function(roomId) {
+ return calls[roomId] || null;
+ }
+};
\ No newline at end of file
diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js
index 41beeadf18..c2c996e4be 100644
--- a/src/ComponentBroker.js
+++ b/src/ComponentBroker.js
@@ -96,7 +96,7 @@ require('../skins/base/views/molecules/RoomDropTarget');
require('../skins/base/views/molecules/DirectoryMenu');
require('../skins/base/views/atoms/voip/VideoFeed');
require('../skins/base/views/molecules/voip/VideoView');
-require('../skins/base/views/molecules/voip/CallHandler');
+require('../skins/base/views/molecules/voip/CallView');
}
diff --git a/src/controllers/molecules/RoomHeader.js b/src/controllers/molecules/RoomHeader.js
index 047c378997..29ddf70e6a 100644
--- a/src/controllers/molecules/RoomHeader.js
+++ b/src/controllers/molecules/RoomHeader.js
@@ -16,9 +16,40 @@ limitations under the License.
'use strict';
+/*
+ * State vars:
+ * this.state.inCall = boolean
+ */
+
var dis = require("../../dispatcher");
+var CallHandler = require("../../CallHandler");
module.exports = {
+ componentDidMount: function() {
+ this.dispatcherRef = dis.register(this.onAction);
+ this.setState({
+ inCall: false
+ });
+ },
+
+ componentWillUnmount: function() {
+ dis.unregister(this.dispatcherRef);
+ },
+
+ onAction: function(payload) {
+ // if we were given a room_id to track, don't handle anything else.
+ if (payload.room_id && this.props.room &&
+ this.props.room.roomId !== payload.room_id) {
+ return;
+ }
+ if (payload.action !== 'call_state') {
+ return;
+ }
+ this.setState({
+ inCall: (CallHandler.getCall(payload.room_id) !== null)
+ });
+ },
+
onVideoClick: function() {
dis.dispatch({
action: 'place_call',
@@ -32,6 +63,12 @@ module.exports = {
type: "voice",
room_id: this.props.room.roomId
});
+ },
+ onHangupClick: function() {
+ dis.dispatch({
+ action: 'hangup',
+ room_id: this.props.room.roomId
+ });
}
};
diff --git a/src/controllers/molecules/voip/CallHandler.js b/src/controllers/molecules/voip/CallHandler.js
deleted file mode 100644
index 0bb4685bfc..0000000000
--- a/src/controllers/molecules/voip/CallHandler.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-Copyright 2015 OpenMarket Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-'use strict';
-var MatrixClientPeg = require("../../../MatrixClientPeg");
-var Matrix = require("matrix-js-sdk");
-var dis = require("../../../dispatcher");
-
-/*
- * State vars:
- * this.state.call = MatrixCall|null
- *
- * Props:
- * this.props.room = Room (JS SDK) - can be null (for singleton views)
- */
-
-module.exports = {
-
- componentDidMount: function() {
- this.dispatcherRef = dis.register(this.onAction);
- this.setState({
- call: null
- });
- },
-
- componentWillUnmount: function() {
- dis.unregister(this.dispatcherRef);
- },
-
- onAction: function(payload) {
- // if we were given a room_id to track, don't handle anything else.
- if (payload.room_id && this.props.room &&
- this.props.room.roomId !== payload.room_id) {
- return;
- }
-
- switch (payload.action) {
- case 'place_call':
- if (this.state.call) {
- return; // don't allow >1 call to be placed.
- }
- console.log("Place %s call in %s", payload.type, payload.room_id);
- var call = Matrix.createNewMatrixCall(
- MatrixClientPeg.get(), payload.room_id
- );
- this._setCallListeners(call);
- this.setState({
- call: call
- });
- if (payload.type === 'voice') {
- call.placeVoiceCall();
- }
- else if (payload.type === 'video') {
- var videoView = this.getVideoView();
- call.placeVideoCall(
- videoView.getRemoteVideoElement(),
- videoView.getLocalVideoElement()
- );
- }
- else {
- console.error("Unknown call type: %s", payload.type);
- }
- break;
- case 'incoming_call':
- if (this.state.call) {
- payload.call.hangup("busy");
- return; // don't allow >1 call to be received.
- }
- this._setCallListeners(call);
- this.setState({
- call: call
- });
- console.log("Incoming call: %s", payload.call);
- break;
- case 'hangup':
- if (!this.state.call) {
- return; // no call to hangup
- }
- this.state.call.hangup();
- this.setState({
- call: null
- });
- break;
- case 'answer':
- if (!this.state.call) {
- return; // no call to answer
- }
- this.state.call.answer();
- break;
- }
- },
-
- _setCallListeners: function(call) {
- var self = this;
- call.on("error", function(err) {
- console.error("Call error: %s", err);
- console.error(err.stack);
- call.hangup();
- self.setState({
- call: null
- });
- });
- call.on("hangup", function() {
- self.setState({
- call: null
- });
- })
- }
-};
-
diff --git a/src/controllers/molecules/voip/CallView.js b/src/controllers/molecules/voip/CallView.js
new file mode 100644
index 0000000000..9546f885ff
--- /dev/null
+++ b/src/controllers/molecules/voip/CallView.js
@@ -0,0 +1,56 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+var dis = require("../../../dispatcher");
+var CallHandler = require("../../../CallHandler");
+
+/*
+ * State vars:
+ * this.state.call = MatrixCall|null
+ *
+ * Props:
+ * this.props.room = Room (JS SDK)
+ */
+
+module.exports = {
+
+ componentDidMount: function() {
+ this.dispatcherRef = dis.register(this.onAction);
+ this.setState({
+ call: null
+ });
+ },
+
+ componentWillUnmount: function() {
+ dis.unregister(this.dispatcherRef);
+ },
+
+ onAction: function(payload) {
+ // if we were given a room_id to track, don't handle anything else.
+ if (payload.room_id && this.props.room &&
+ this.props.room.roomId !== payload.room_id) {
+ return;
+ }
+ if (payload.action !== 'call_state') {
+ return;
+ }
+ this.setState({
+ call: CallHandler.getCall(payload.room_id)
+ });
+ }
+};
+