diff --git a/appinfo/routes.php b/appinfo/routes.php
index c0aed8a5c51..11f867dd63f 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -221,6 +221,24 @@
'token' => '^[a-z0-9]{4,30}$',
],
],
+ [
+ 'name' => 'Room#joinRoom',
+ 'url' => '/api/{apiVersion}/room/{token}/participants/active',
+ 'verb' => 'POST',
+ 'requirements' => [
+ 'apiVersion' => 'v1',
+ 'token' => '^[a-z0-9]{4,30}$',
+ ],
+ ],
+ [
+ 'name' => 'Room#exitRoom',
+ 'url' => '/api/{apiVersion}/room/{token}/participants/active',
+ 'verb' => 'DELETE',
+ 'requirements' => [
+ 'apiVersion' => 'v1',
+ 'token' => '^[a-z0-9]{4,30}$',
+ ],
+ ],
[
'name' => 'Room#promoteModerator',
'url' => '/api/{apiVersion}/room/{token}/moderators',
diff --git a/docs/api-v1.md b/docs/api-v1.md
index 43f3ff295c5..d60355d08d1 100644
--- a/docs/api-v1.md
+++ b/docs/api-v1.md
@@ -278,6 +278,38 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
* Method: `DELETE`
* Endpoint: `/room/{token}/participants/self`
+* Response:
+ - Header:
+ + `200 OK`
+ + `404 Not Found` When the room could not be found for the participant
+
+### Join a room (available for call and chat)
+
+* Method: `POST`
+* Endpoint: `/room/{token}/participants/active`
+* Data:
+
+ field | type | Description
+ ------|------|------------
+ `password` | string | Optional: Password is only required for users which are of type `4` or `5` and only when the room has `hasPassword` set to true.
+
+* Response:
+ - Header:
+ + `200 OK`
+ + `403 Forbidden` When the password is required and didn't match
+ + `404 Not Found` When the room could not be found for the participant
+
+ - Data:
+
+ field | type | Description
+ ------|------|------------
+ `sessionId` | string | 512 character long string
+
+### Leave a room (not available for call and chat anymore)
+
+* Method: `DELETE`
+* Endpoint: `/room/{token}/participants/active`
+
* Response:
- Header:
+ `200 OK`
@@ -347,24 +379,12 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
* Method: `POST`
* Endpoint: `/call/{token}`
-* Data:
-
- field | type | Description
- ------|------|------------
- `password` | string | Optional: Password is only required for users which are of type `4` or `5` and only when the room has `hasPassword` set to true.
* Response:
- Header:
+ `200 OK`
- + `403 Forbidden` When the password is required and didn't match
+ `404 Not Found` When the room could not be found for the participant
- - Data:
-
- field | type | Description
- ------|------|------------
- `sessionId` | string | 512 character long string
-
### Send ping to keep the call alive
* Method: `POST`
@@ -375,7 +395,7 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
+ `200 OK`
+ `404 Not Found` When the room could not be found for the participant
-### Leave a call (but staying in the room for future calls)
+### Leave a call (but staying in the room for future calls and chat)
* Method: `DELETE`
* Endpoint: `/call/{token}`
diff --git a/js/app.js b/js/app.js
index c06f74adec2..d8f475680e8 100644
--- a/js/app.js
+++ b/js/app.js
@@ -372,7 +372,6 @@
self.setRoomMessageForGuest(self.activeRoom.get('participants'));
}
-
// Disable video when entering a room with more than 5 participants.
if (Object.keys(self.activeRoom.get('participants')).length > 5) {
self.disableVideo();
@@ -525,18 +524,10 @@
this._registerPageEvents();
this.initShareRoomClipboard();
- var token = $('#app').attr('data-token');
- if (token) {
- if (OCA.SpreedMe.webrtc.sessionReady) {
- OCA.SpreedMe.Calls.join(token);
- } else {
- OCA.SpreedMe.webrtc.once('connectionReady', function() {
- OCA.SpreedMe.Calls.join(token);
- });
- }
- }
OCA.SpreedMe.Calls.showCamera();
+ var token = $('#app').attr('data-token');
+
if (oc_current_user) {
this._showRoomList();
this.signaling.setRoomCollection(this._rooms)
@@ -557,10 +548,20 @@
}
this.initAudioVideoSettings(configuration);
+
+ if (token) {
+ if (OCA.SpreedMe.webrtc.sessionReady) {
+ OCA.SpreedMe.Calls.joinRoom(token);
+ } else {
+ OCA.SpreedMe.webrtc.once('connectionReady', function() {
+ OCA.SpreedMe.Calls.joinRoom(token);
+ });
+ }
+ }
},
_onPopState: function(params) {
if (!_.isUndefined(params.token)) {
- OCA.SpreedMe.Calls.join(params.token);
+ OCA.SpreedMe.Calls.joinRoom(params.token);
}
},
onDocumentClick: function(event) {
diff --git a/js/calls.js b/js/calls.js
index adad25d55cc..edc7b13b324 100644
--- a/js/calls.js
+++ b/js/calls.js
@@ -35,7 +35,7 @@
OC.Util.History.pushState({
token: token
}, OC.generateUrl('/call/' + token));
- this.join(token);
+ this.joinRoom(token);
},
createOneToOneVideoCall: function(recipientUserId) {
console.log("Creating one-to-one video call", recipientUserId);
@@ -81,7 +81,15 @@
success: _.bind(this._createCallSuccessHandle, this)
});
},
- join: function(token) {
+ joinRoom: function(token) {
+ if (signaling.currentRoomToken === token) {
+ return;
+ }
+
+ OCA.SpreedMe.webrtc.leaveRoom();
+ OCA.SpreedMe.webrtc.joinRoom(token);
+ },
+ joinCall: function(token) {
if (signaling.currentCallToken === token) {
return;
}
@@ -90,8 +98,12 @@
$('.videoView').addClass('hidden');
$('#app-content').addClass('icon-loading');
- OCA.SpreedMe.webrtc.leaveRoom();
- OCA.SpreedMe.webrtc.joinRoom(token);
+ OCA.SpreedMe.webrtc.leaveCall();
+ OCA.SpreedMe.webrtc.joinCall(token);
+ },
+ leaveCall: function(token) {
+ $('#app-content').removeClass('incall');
+ OCA.SpreedMe.webrtc.leaveCall();
},
leaveCurrentCall: function(deleter) {
OCA.SpreedMe.webrtc.leaveRoom();
diff --git a/js/signaling.js b/js/signaling.js
index 43782cc1171..fa84ed1ddb7 100644
--- a/js/signaling.js
+++ b/js/signaling.js
@@ -6,6 +6,7 @@
function SignalingBase(settings) {
this.settings = settings;
this.sessionId = '';
+ this.currentRoomToken = null;
this.currentCallToken = null;
this.handlers = {};
this.features = {};
@@ -61,12 +62,16 @@
SignalingBase.prototype.emit = function(ev, data) {
switch (ev) {
- case 'join':
- var callback = arguments[2];
- var token = data;
- this.joinCall(token, callback);
+ case 'joinRoom':
+ this.joinRoom(data);
break;
- case 'leave':
+ case 'joinCall':
+ this.joinCall(data, arguments[2]);
+ break;
+ case 'leaveRoom':
+ this.leaveCurrentRoom();
+ break;
+ case 'leaveCall':
this.leaveCurrentCall();
break;
case 'message':
@@ -75,6 +80,13 @@
}
};
+ SignalingBase.prototype.leaveCurrentRoom = function() {
+ if (this.currentCallToken) {
+ this.leaveRoom(this.currentCallToken);
+ this.currentCallToken = null;
+ }
+ };
+
SignalingBase.prototype.leaveCurrentCall = function() {
if (this.currentCallToken) {
this.leaveCall(this.currentCallToken);
@@ -207,9 +219,9 @@
return defer;
};
- InternalSignaling.prototype.joinCall = function(token, callback, password) {
+ InternalSignaling.prototype.joinRoom = function(token, password) {
$.ajax({
- url: OC.linkToOCS('apps/spreed/api/v1/call', 2) + token,
+ url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + token + '/participants/active',
type: 'POST',
beforeSend: function (request) {
request.setRequestHeader('Accept', 'application/json');
@@ -220,14 +232,9 @@
success: function (result) {
console.log("Joined", result);
this.sessionId = result.ocs.data.sessionId;
- this.currentCallToken = token;
+ this.currentRoomToken = token;
this._startPingCall();
this._startPullingMessages();
- // We send an empty call description to simplewebrtc since
- // usersChanged (webrtc.js) will create/remove peer connections
- // with call participants
- var callDescription = {'clients': {}};
- callback('', callDescription);
}.bind(this),
error: function (result) {
if (result.status === 404 || result.status === 503) {
@@ -243,7 +250,7 @@
t('spreed','Password required'),
function (result, password) {
if (result && password !== '') {
- this.joinCall(token, callback, password);
+ this.joinRoom(token, password);
}
}.bind(this),
true,
@@ -262,11 +269,46 @@
});
};
- InternalSignaling.prototype.leaveCall = function(token) {
- if (token === this.currentCallToken) {
+ InternalSignaling.prototype.leaveRoom = function(token) {
+ if (this.currentCallToken) {
+ this.leaveCall();
+ }
+
+ if (token === this.currentRoomToken) {
this._stopPingCall();
this._closeEventSource();
}
+
+ $.ajax({
+ url: OC.linkToOCS('apps/spreed/api/v1/room', 2) + token + '/participants/active',
+ method: 'DELETE',
+ async: false
+ });
+ };
+
+ InternalSignaling.prototype.joinCall = function(token, callback) {
+ $.ajax({
+ url: OC.linkToOCS('apps/spreed/api/v1/call', 2) + token,
+ type: 'POST',
+ beforeSend: function (request) {
+ request.setRequestHeader('Accept', 'application/json');
+ },
+ success: function () {
+ this.currentCallToken = token;
+ // We send an empty call description to simplewebrtc since
+ // usersChanged (webrtc.js) will create/remove peer connections
+ // with call participants
+ var callDescription = {'clients': {}};
+ callback('', callDescription);
+ }.bind(this),
+ error: function () {
+ // Room not found or maintenance mode
+ OC.redirect(OC.generateUrl('apps/spreed'));
+ }.bind(this)
+ });
+ };
+
+ InternalSignaling.prototype.leaveCall = function(token) {
$.ajax({
url: OC.linkToOCS('apps/spreed/api/v1/call', 2) + token,
method: 'DELETE',
diff --git a/js/simplewebrtc.js b/js/simplewebrtc.js
index 62b4d9e7ac6..89b277a6bba 100644
--- a/js/simplewebrtc.js
+++ b/js/simplewebrtc.js
@@ -18185,14 +18185,22 @@
SimpleWebRTC.prototype.leaveRoom = function () {
if (this.roomName) {
- this.connection.emit('leave');
+ this.connection.emit('leaveRoom');
+ this.emit('leftRoom', this.roomName);
+ this.roomName = undefined;
+ }
+ };
+
+ SimpleWebRTC.prototype.leaveCall = function () {
+ if (this.roomName) {
+ this.connection.emit('leaveCall');
while (this.webrtc.peers.length) {
this.webrtc.peers[0].end();
}
if (this.getLocalScreen()) {
this.stopScreenShare();
}
- this.emit('leftRoom', this.roomName);
+ this.emit('leftCall', this.roomName);
this.roomName = undefined;
}
};
@@ -18249,10 +18257,16 @@
});
};
- SimpleWebRTC.prototype.joinRoom = function (name, cb) {
+ SimpleWebRTC.prototype.joinRoom = function (name) {
+ this.connection.emit('joinRoom', name);
+ this.roomName = name;
+ this.emit('joinedRoom', name);
+ };
+
+ SimpleWebRTC.prototype.joinCall = function (name, cb) {
var self = this;
this.roomName = name;
- this.connection.emit('join', name, function (err, roomDescription) {
+ this.connection.emit('joinCall', name, function (err, roomDescription) {
console.log('join CB', err, roomDescription);
if (err) {
self.emit('error', err);
@@ -18282,7 +18296,7 @@
}
if (cb) cb(err, roomDescription);
- self.emit('joinedRoom', name);
+ self.emit('joinedCall', name);
});
};
diff --git a/js/views/callinfoview.js b/js/views/callinfoview.js
index 157f571963e..2db9becfa73 100644
--- a/js/views/callinfoview.js
+++ b/js/views/callinfoview.js
@@ -36,6 +36,15 @@
'{{#if isGuest}}' +
' ' +
'{{/if}}' +
+ '{{#if participantInCall}}' +
+ ' ' +
+ ' ' +
+ '
' +
+ '{{else}}' +
+ ' ' +
+ ' ' +
+ '
' +
+ '{{/if}}' +
'{{#if canModerate}}' +
' ' +
' ' +
@@ -76,6 +85,8 @@
'linkCheckbox': '.link-checkbox',
'guestName': 'div.guest-name',
+ 'joinCallButton': 'button.join-call',
+ 'leaveCallButton': 'button.leave-call',
'passwordOption': '.password-option',
'passwordInput': '.password-input',
@@ -91,13 +102,18 @@
'change @ui.linkCheckbox': 'toggleLinkCheckbox',
'keyup @ui.passwordInput': 'keyUpPassword',
- 'click @ui.passwordConfirm': 'confirmPassword'
+ 'click @ui.passwordConfirm': 'confirmPassword',
+ 'click @ui.joinCallButton': 'joinCall',
+ 'click @ui.leaveCallButton': 'leaveCall'
},
modelEvents: {
'change:hasPassword': function() {
this.renderWhenInactive();
},
+ 'change:participantInCall': function() {
+ this.renderWhenInactive();
+ },
'change:participantType': function() {
this._updateNameEditability();
@@ -222,6 +238,14 @@
});
},
+ joinCall: function() {
+ OCA.SpreedMe.Calls.joinCall(this.model.get('token'));
+ },
+
+ leaveCall: function() {
+ OCA.SpreedMe.Calls.leaveCall(this.model.get('token'));
+ },
+
/**
* Password
*/
diff --git a/js/views/roomlistview.js b/js/views/roomlistview.js
index 06889cab61f..a3f5679b25b 100644
--- a/js/views/roomlistview.js
+++ b/js/views/roomlistview.js
@@ -200,7 +200,7 @@
joinRoom: function(e) {
e.preventDefault();
var token = this.ui.room.attr('data-token');
- OCA.SpreedMe.Calls.join(token);
+ OCA.SpreedMe.Calls.joinRoom(token);
OC.Util.History.pushState({
token: token
diff --git a/js/webrtc.js b/js/webrtc.js
index b8de9df1ab6..4037f7adef8 100644
--- a/js/webrtc.js
+++ b/js/webrtc.js
@@ -40,6 +40,10 @@ var spreedPeerConnectionTable = [];
var currentSessionId = webrtc.connection.getSessionid();
newUsers.forEach(function(user) {
+ if (!user.inCall) {
+ return;
+ }
+
// TODO(fancycode): Adjust property name of internal PHP backend to be all lowercase.
var sessionId = user.sessionId || user.sessionid;
if (!sessionId || sessionId === currentSessionId || previousUsersInRoom.indexOf(sessionId) !== -1) {
@@ -125,9 +129,15 @@ var spreedPeerConnectionTable = [];
var currentSessionId = webrtc.connection.getSessionid();
var currentUsersInRoom = [];
var userMapping = {};
+ var selfInCall = false;
users.forEach(function(user) {
+ if (!user['inCall']) {
+ return;
+ }
+
var sessionId = user['sessionId'] || user.sessionid;
if (sessionId === currentSessionId) {
+ selfInCall = true;
return;
}
@@ -135,6 +145,10 @@ var spreedPeerConnectionTable = [];
userMapping[sessionId] = user;
});
+ if (!selfInCall) {
+ return;
+ }
+
var newSessionIds = currentUsersInRoom.diff(previousUsersInRoom);
var disconnectedSessionIds = previousUsersInRoom.diff(currentUsersInRoom);
var newUsers = [];
@@ -643,9 +657,12 @@ var spreedPeerConnectionTable = [];
}
OCA.SpreedMe.webrtc.on('joinedRoom', function(name) {
+ OCA.SpreedMe.app.syncAndSetActiveRoom(name);
+ });
+
+ OCA.SpreedMe.webrtc.on('joinedCall', function() {
$('#app-content').removeClass('icon-loading');
$('.videoView').removeClass('hidden');
- OCA.SpreedMe.app.syncAndSetActiveRoom(name);
});
OCA.SpreedMe.webrtc.on('channelOpen', function(channel) {
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 62d9c823fee..3aa1e3ec76b 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -87,6 +87,8 @@ protected function registerSignalingHooks(EventDispatcherInterface $dispatcher)
$dispatcher->addListener(Room::class . '::postRemoveUser', $listener);
$dispatcher->addListener(Room::class . '::postRemoveBySession', $listener);
$dispatcher->addListener(Room::class . '::postUserDisconnectRoom', $listener);
+ $dispatcher->addListener(Room::class . '::postSessionJoinCall', $listener);
+ $dispatcher->addListener(Room::class . '::postSessionLeaveCall', $listener);
$dispatcher->addListener(Room::class . '::postAddUsers', function(GenericEvent $event) {
/** @var BackendNotifier $notifier */
diff --git a/lib/Controller/CallController.php b/lib/Controller/CallController.php
index 00f5b3630c8..009f2fdd9e4 100644
--- a/lib/Controller/CallController.php
+++ b/lib/Controller/CallController.php
@@ -106,8 +106,8 @@ public function getPeersForCall($token) {
$participants = $room->getParticipants(time() - 30);
$result = [];
foreach ($participants['users'] as $participant => $data) {
- if ($data['sessionId'] === '0') {
- // User left the room
+ if ($data['sessionId'] === '0' || !$data['inCall']) {
+ // User is not active in call
continue;
}
@@ -136,38 +136,36 @@ public function getPeersForCall($token) {
* @UseSession
*
* @param string $token
- * @param string $password
* @return DataResponse
*/
- public function joinCall($token, $password) {
+ public function joinCall($token) {
try {
$room = $this->manager->getRoomForParticipantByToken($token, $this->userId);
} catch (RoomNotFoundException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
- try {
- if ($this->userId !== null) {
- $sessionIds = $this->manager->getSessionIdsForUser($this->userId);
- $newSessionId = $room->enterRoomAsUser($this->userId, $password, $this->session->get('spreed-password') === $room->getToken());
-
- if (!empty($sessionIds)) {
- $this->messages->deleteMessages($sessionIds);
- }
- } else {
- $newSessionId = $room->enterRoomAsGuest($password, $this->session->get('spreed-password') === $room->getToken());
+ if ($this->userId !== null) {
+ if (!$this->session->exists('spreed-session')) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ $sessionId = $this->session->get('spreed-session');
+ } else {
+ try {
+ $participant = $room->getParticipant($this->userId);
+ } catch (ParticipantNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ $sessionId = $participant->getSessionId();
+ if ($sessionId === '0') {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
}
- } catch (InvalidPasswordException $e) {
- return new DataResponse([], Http::STATUS_FORBIDDEN);
}
- $this->session->remove('spreed-password');
- $this->session->set('spreed-session', $newSessionId);
- $room->ping($this->userId, $newSessionId, time());
+ $room->changeInCall($sessionId, true);
- return new DataResponse([
- 'sessionId' => $newSessionId,
- ]);
+ return new DataResponse();
}
/**
@@ -201,23 +199,32 @@ public function pingCall($token) {
* @return DataResponse
*/
public function leaveCall($token) {
- $sessionId = $this->session->get('spreed-session');
- $this->session->remove('spreed-session');
-
try {
$room = $this->manager->getRoomForParticipantByToken($token, $this->userId);
+ } catch (RoomNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
- if ($this->userId === null) {
- $participant = $room->getParticipantBySession($sessionId);
- $room->removeParticipantBySession($participant);
- } else {
+ if ($this->userId !== null) {
+ if (!$this->session->exists('spreed-session')) {
+ return new DataResponse();
+ }
+ $sessionId = $this->session->get('spreed-session');
+ } else {
+ try {
$participant = $room->getParticipant($this->userId);
- $room->disconnectUserFromAllRooms($participant->getUser());
+ } catch (ParticipantNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ $sessionId = $participant->getSessionId();
+ if ($sessionId === '0') {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
}
- } catch (RoomNotFoundException $e) {
- } catch (ParticipantNotFoundException $e) {
}
+ $room->changeInCall($sessionId, false);
+
return new DataResponse();
}
diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php
index 27cd045d842..69a42f61c09 100644
--- a/lib/Controller/RoomController.php
+++ b/lib/Controller/RoomController.php
@@ -25,11 +25,13 @@
namespace OCA\Spreed\Controller;
+use OCA\Spreed\Exceptions\InvalidPasswordException;
use OCA\Spreed\Exceptions\ParticipantNotFoundException;
use OCA\Spreed\Exceptions\RoomNotFoundException;
use OCA\Spreed\Manager;
use OCA\Spreed\Participant;
use OCA\Spreed\Room;
+use OCA\Spreed\Signaling\Messages;
use OCP\Activity\IManager as IActivityManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
@@ -57,6 +59,8 @@ class RoomController extends OCSController {
private $logger;
/** @var Manager */
private $manager;
+ /** @var Messages */
+ private $messages;
/** @var INotificationManager */
private $notificationManager;
/** @var IActivityManager */
@@ -73,6 +77,7 @@ class RoomController extends OCSController {
* @param IGroupManager $groupManager
* @param ILogger $logger
* @param Manager $manager
+ * @param Messages $messages
* @param INotificationManager $notificationManager
* @param IActivityManager $activityManager
* @param IL10N $l10n
@@ -85,6 +90,7 @@ public function __construct($appName,
IGroupManager $groupManager,
ILogger $logger,
Manager $manager,
+ Messages $messages,
INotificationManager $notificationManager,
IActivityManager $activityManager,
IL10N $l10n) {
@@ -95,6 +101,7 @@ public function __construct($appName,
$this->groupManager = $groupManager;
$this->logger = $logger;
$this->manager = $manager;
+ $this->messages = $messages;
$this->notificationManager = $notificationManager;
$this->activityManager = $activityManager;
$this->l10n = $l10n;
@@ -158,8 +165,10 @@ protected function formatRoom(Room $room, Participant $participant = null) {
if ($participant instanceof Participant) {
$participantType = $participant->getParticipantType();
+ $participantInCall = $participant->isInCall();
} else {
$participantType = Participant::GUEST;
+ $participantInCall = false;
}
$roomData = [
@@ -169,6 +178,7 @@ protected function formatRoom(Room $room, Participant $participant = null) {
'name' => $room->getName(),
'displayName' => $room->getName(),
'participantType' => $participantType,
+ 'participantInCall' => $participantInCall,
'count' => $room->getNumberOfParticipants(time() - 30),
'hasPassword' => $room->hasPassword(),
];
@@ -766,6 +776,73 @@ public function setPassword($token, $password) {
return new DataResponse();
}
+ /**
+ * @PublicPage
+ * @UseSession
+ *
+ * @param string $token
+ * @param string $password
+ * @return DataResponse
+ */
+ public function joinRoom($token, $password) {
+ try {
+ $room = $this->manager->getRoomForParticipantByToken($token, $this->userId);
+ } catch (RoomNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ try {
+ if ($this->userId !== null) {
+ $sessionIds = $this->manager->getSessionIdsForUser($this->userId);
+ $newSessionId = $room->enterRoomAsUser($this->userId, $password, $this->session->get('spreed-password') === $room->getToken());
+
+ if (!empty($sessionIds)) {
+ $this->messages->deleteMessages($sessionIds);
+ }
+ } else {
+ $newSessionId = $room->enterRoomAsGuest($password, $this->session->get('spreed-password') === $room->getToken());
+ }
+ } catch (InvalidPasswordException $e) {
+ return new DataResponse([], Http::STATUS_FORBIDDEN);
+ }
+
+ $this->session->remove('spreed-password');
+ $this->session->set('spreed-session', $newSessionId);
+ $room->ping($this->userId, $newSessionId, time());
+
+ return new DataResponse([
+ 'sessionId' => $newSessionId,
+ ]);
+ }
+
+ /**
+ * @PublicPage
+ * @UseSession
+ *
+ * @param string $token
+ * @return DataResponse
+ */
+ public function exitRoom($token) {
+ $sessionId = $this->session->get('spreed-session');
+ $this->session->remove('spreed-session');
+
+ try {
+ $room = $this->manager->getRoomForParticipantByToken($token, $this->userId);
+
+ if ($this->userId === null) {
+ $participant = $room->getParticipantBySession($sessionId);
+ $room->removeParticipantBySession($participant);
+ } else {
+ $participant = $room->getParticipant($this->userId);
+ $room->disconnectUserFromAllRooms($participant->getUser());
+ }
+ } catch (RoomNotFoundException $e) {
+ } catch (ParticipantNotFoundException $e) {
+ }
+
+ return new DataResponse();
+ }
+
/**
* @NoAdminRequired
*
diff --git a/lib/Controller/SignalingController.php b/lib/Controller/SignalingController.php
index 0065495a8df..0752aebd2a8 100644
--- a/lib/Controller/SignalingController.php
+++ b/lib/Controller/SignalingController.php
@@ -191,7 +191,7 @@ protected function getUsersInRoom(Room $room) {
foreach ($participants['users'] as $participant => $data) {
if ($data['sessionId'] === '0') {
- // Use left the room
+ // User is not active
continue;
}
@@ -200,6 +200,7 @@ protected function getUsersInRoom(Room $room) {
'roomId' => $room->getId(),
'lastPing' => $data['lastPing'],
'sessionId' => $data['sessionId'],
+ 'inCall' => $data['inCall'],
];
}
@@ -209,6 +210,7 @@ protected function getUsersInRoom(Room $room) {
'roomId' => $room->getId(),
'lastPing' => $data['lastPing'],
'sessionId' => $data['sessionId'],
+ 'inCall' => $data['inCall'],
];
}
diff --git a/lib/Manager.php b/lib/Manager.php
index 042911d05f5..99cc14ce7f5 100644
--- a/lib/Manager.php
+++ b/lib/Manager.php
@@ -79,7 +79,7 @@ protected function createRoomObject(array $row) {
* @return Participant
*/
protected function createParticipantObject(Room $room, array $row) {
- return new Participant($this->db, $room, $row['userId'], (int) $row['participantType'], (int) $row['lastPing'], $row['sessionId']);
+ return new Participant($this->db, $room, $row['userId'], (int) $row['participantType'], (int) $row['lastPing'], $row['sessionId'], (bool) $row['inCall']);
}
/**
diff --git a/lib/Migration/Version2001Date20171031102049.php b/lib/Migration/Version2001Date20171031102049.php
new file mode 100644
index 00000000000..8cf456474f4
--- /dev/null
+++ b/lib/Migration/Version2001Date20171031102049.php
@@ -0,0 +1,51 @@
+getTable('talk_participants');
+ $table->addColumn('inCall', Type::BOOLEAN, [
+ 'default' => 0,
+ ]);
+
+ return $schema;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param \Closure $schemaClosure The `\Closure` returns a `Schema`
+ * @param array $options
+ * @since 13.0.0
+ */
+ public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
+ }
+}
diff --git a/lib/Participant.php b/lib/Participant.php
index 5b994d1486e..27a2f32a64f 100644
--- a/lib/Participant.php
+++ b/lib/Participant.php
@@ -44,6 +44,8 @@ class Participant {
protected $lastPing;
/** @var string */
protected $sessionId;
+ /** @var bool */
+ protected $inCall;
/**
* @param IDBConnection $db
@@ -52,14 +54,16 @@ class Participant {
* @param int $participantType
* @param int $lastPing
* @param string $sessionId
+ * @param bool $inCall
*/
- public function __construct(IDBConnection $db, Room $room, $user, $participantType, $lastPing, $sessionId) {
+ public function __construct(IDBConnection $db, Room $room, $user, $participantType, $lastPing, $sessionId, $inCall) {
$this->db = $db;
$this->room = $room;
$this->user = $user;
$this->participantType = $participantType;
$this->lastPing = $lastPing;
$this->sessionId = $sessionId;
+ $this->inCall = $inCall;
}
public function getUser() {
@@ -77,4 +81,8 @@ public function getLastPing() {
public function getSessionId() {
return $this->sessionId;
}
+
+ public function isInCall() {
+ return $this->inCall;
+ }
}
diff --git a/lib/Room.php b/lib/Room.php
index e4f7e257c8f..c308c946f96 100644
--- a/lib/Room.php
+++ b/lib/Room.php
@@ -547,6 +547,7 @@ public function disconnectUserFromAllRooms($userId) {
$query = $this->db->getQueryBuilder();
$query->update('talk_participants')
->set('sessionId', $query->createNamedParameter('0'))
+ ->set('inCall', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT))
->where($query->expr()->eq('userId', $query->createNamedParameter($userId)))
->andWhere($query->expr()->neq('participantType', $query->createNamedParameter(Participant::USER_SELF_JOINED, IQueryBuilder::PARAM_INT)));
$query->execute();
@@ -590,6 +591,39 @@ public function enterRoomAsGuest($password, $passedPasswordProtection = false) {
return $sessionId;
}
+ /**
+ * @param string $sessionId
+ * @param bool $active
+ */
+ public function changeInCall($sessionId, $active) {
+ if ($active) {
+ $this->dispatcher->dispatch(self::class . '::preSessionJoinCall', new GenericEvent($this, [
+ 'sessionId' => $sessionId,
+ ]));
+ } else {
+ $this->dispatcher->dispatch(self::class . '::preSessionLeaveCall', new GenericEvent($this, [
+ 'sessionId' => $sessionId,
+ ]));
+ }
+
+ $query = $this->db->getQueryBuilder();
+ $query->update('talk_participants')
+ ->set('inCall', $query->createNamedParameter((int) $active, IQueryBuilder::PARAM_INT))
+ ->where($query->expr()->eq('sessionId', $query->createNamedParameter($sessionId)))
+ ->andWhere($query->expr()->eq('roomId', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
+ $query->execute();
+
+ if ($active) {
+ $this->dispatcher->dispatch(self::class . '::postSessionJoinCall', new GenericEvent($this, [
+ 'sessionId' => $sessionId,
+ ]));
+ } else {
+ $this->dispatcher->dispatch(self::class . '::postSessionLeaveCall', new GenericEvent($this, [
+ 'sessionId' => $sessionId,
+ ]));
+ }
+ }
+
/**
* @param string $password
* @return bool
@@ -647,12 +681,14 @@ public function getParticipants($lastPing = 0) {
while ($row = $result->fetch()) {
if ($row['userId'] !== '' && $row['userId'] !== null) {
$users[$row['userId']] = [
+ 'inCall' => (bool) $row['inCall'],
'lastPing' => (int) $row['lastPing'],
'sessionId' => $row['sessionId'],
'participantType' => (int) $row['participantType'],
];
} else {
$guests[] = [
+ 'inCall' => (bool) $row['inCall'],
'lastPing' => (int) $row['lastPing'],
'sessionId' => $row['sessionId'],
];