diff --git a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java index cfd45f8f..19c84127 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java +++ b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java @@ -49,6 +49,7 @@ import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException.Code; import io.openvidu.server.cdr.CDRLoggerFile; import io.openvidu.server.cdr.CallDetailRecord; +import io.openvidu.server.config.HttpHandshakeInterceptor; import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.core.SessionEventsHandler; import io.openvidu.server.core.SessionManager; @@ -166,7 +167,8 @@ public class OpenViduServer implements JsonRpcConfigurer { @Override public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) { - registry.addHandler(rpcHandler().withPingWatchdog(true), "/openvidu"); + registry.addHandler(rpcHandler().withPingWatchdog(true).withInterceptors(new HttpHandshakeInterceptor()), + "/openvidu"); } private static String getContainerIp() throws IOException, InterruptedException { diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventEnd.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventEnd.java index 3441998b..fc9633a4 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventEnd.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventEnd.java @@ -51,4 +51,16 @@ public class CDREventEnd extends CDREvent { return json; } + public Long getStartTime() { + return startTime; + } + + public Integer getDuration() { + return duration; + } + + public String getReason() { + return reason; + } + } diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventParticipant.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventParticipant.java index a051ccd8..8bb8527a 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventParticipant.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventParticipant.java @@ -32,9 +32,9 @@ public class CDREventParticipant extends CDREventEnd { } // participantLeft - public CDREventParticipant(CDREvent event, String reason) { + public CDREventParticipant(CDREventParticipant event, String reason) { super(CDREventName.participantLeft, event.getSessionId(), event.getTimestamp(), reason); - this.participant = ((CDREventParticipant) event).participant; + this.participant = event.participant; } @Override @@ -46,4 +46,8 @@ public class CDREventParticipant extends CDREventEnd { return json; } + public Participant getParticipant() { + return this.participant; + } + } diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventRecording.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventRecording.java index 3a594af2..ec844500 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventRecording.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventRecording.java @@ -33,9 +33,9 @@ public class CDREventRecording extends CDREventEnd { } // recordingStopped - public CDREventRecording(CDREvent event, String reason) { + public CDREventRecording(CDREventRecording event, Recording recording, String reason) { super(CDREventName.recordingStopped, event.getSessionId(), event.getTimestamp(), reason); - this.recording = ((CDREventRecording) event).recording; + this.recording = recording; } @Override @@ -44,7 +44,8 @@ public class CDREventRecording extends CDREventEnd { json.addProperty("id", this.recording.getId()); json.addProperty("name", this.recording.getName()); json.addProperty("outputMode", this.recording.getOutputMode().name()); - if (io.openvidu.java.client.Recording.OutputMode.COMPOSED.equals(this.recording.getOutputMode()) && this.recording.hasVideo()) { + if (io.openvidu.java.client.Recording.OutputMode.COMPOSED.equals(this.recording.getOutputMode()) + && this.recording.hasVideo()) { json.addProperty("resolution", this.recording.getResolution()); json.addProperty("recordingLayout", this.recording.getRecordingLayout().name()); if (RecordingLayout.CUSTOM.equals(this.recording.getRecordingLayout()) @@ -59,4 +60,8 @@ public class CDREventRecording extends CDREventEnd { return json; } + public Recording getRecording() { + return this.recording; + } + } diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventSession.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventSession.java index 05843516..7e3bedd8 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventSession.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventSession.java @@ -30,8 +30,13 @@ public class CDREventSession extends CDREventEnd { } // sessionDestroyed - public CDREventSession(CDREvent event, String reason) { + public CDREventSession(CDREventSession event, String reason) { super(CDREventName.sessionDestroyed, event.getSessionId(), event.getTimestamp(), reason); + this.session = event.session; + } + + public Session getSession() { + return this.session; } } diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventWebrtcConnection.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventWebrtcConnection.java index 9cead475..adfaa3b0 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventWebrtcConnection.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventWebrtcConnection.java @@ -20,35 +20,43 @@ package io.openvidu.server.cdr; import com.google.gson.JsonObject; import io.openvidu.server.core.MediaOptions; +import io.openvidu.server.core.Participant; public class CDREventWebrtcConnection extends CDREventEnd implements Comparable { - String participantId; + String streamId; + Participant participant; MediaOptions mediaOptions; String receivingFrom; // webrtcConnectionCreated - public CDREventWebrtcConnection(String sessionId, String participantId, MediaOptions mediaOptions, - String receivingFrom, Long timestamp) { + public CDREventWebrtcConnection(String sessionId, String streamId, Participant participant, + MediaOptions mediaOptions, String receivingFrom, Long timestamp) { super(CDREventName.webrtcConnectionCreated, sessionId, timestamp); - this.participantId = participantId; + this.streamId = streamId; + this.participant = participant; this.mediaOptions = mediaOptions; this.receivingFrom = receivingFrom; } // webrtcConnectionDestroyed - public CDREventWebrtcConnection(CDREvent event, String reason) { + public CDREventWebrtcConnection(CDREventWebrtcConnection event, String reason) { super(CDREventName.webrtcConnectionDestroyed, event.getSessionId(), event.getTimestamp(), reason); - CDREventWebrtcConnection e = (CDREventWebrtcConnection) event; - this.participantId = e.participantId; - this.mediaOptions = e.mediaOptions; - this.receivingFrom = e.receivingFrom; + this.streamId = event.streamId; + this.participant = event.participant; + this.mediaOptions = event.mediaOptions; + this.receivingFrom = event.receivingFrom; + } + + public Participant getParticipant() { + return this.participant; } @Override public JsonObject toJson() { JsonObject json = super.toJson(); - json.addProperty("participantId", this.participantId); + json.addProperty("streamId", this.streamId); + json.addProperty("participantId", this.participant.getParticipantPublicId()); if (this.receivingFrom != null) { json.addProperty("connection", "INBOUND"); json.addProperty("receivingFrom", this.receivingFrom); @@ -66,7 +74,7 @@ public class CDREventWebrtcConnection extends CDREventEnd implements Comparable< } public int compareTo(CDREventWebrtcConnection other) { - if (this.participantId.equals(other.participantId)) { + if (this.participant.getParticipantPublicId().equals(other.participant.getParticipantPublicId())) { if (this.receivingFrom != null && other.receivingFrom != null) { if (this.receivingFrom.equals(other.receivingFrom)) { return 0; diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLogger.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLogger.java index 5dd70dfa..9c73dbf0 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLogger.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLogger.java @@ -18,6 +18,7 @@ package io.openvidu.server.cdr; import io.openvidu.server.kurento.endpoint.KmsEvent; +import io.openvidu.server.summary.SessionSummary; public interface CDRLogger { @@ -25,6 +26,8 @@ public interface CDRLogger { public void log(KmsEvent event); + public void log(SessionSummary sessionSummary); + public boolean canBeDisabled(); } diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLoggerFile.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLoggerFile.java index 506afe58..5856f3ca 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLoggerFile.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRLoggerFile.java @@ -21,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.openvidu.server.kurento.endpoint.KmsEvent; +import io.openvidu.server.summary.SessionSummary; public class CDRLoggerFile implements CDRLogger { @@ -35,6 +36,10 @@ public class CDRLoggerFile implements CDRLogger { public void log(KmsEvent event) { } + @Override + public void log(SessionSummary sessionSummary) { + } + @Override public boolean canBeDisabled() { return true; diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java index bdc823eb..95b572f8 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java @@ -30,9 +30,11 @@ import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.core.MediaOptions; import io.openvidu.server.core.Participant; import io.openvidu.server.core.Session; +import io.openvidu.server.core.SessionManager; import io.openvidu.server.kurento.endpoint.KmsEvent; import io.openvidu.server.recording.Recording; import io.openvidu.server.recording.service.RecordingManager; +import io.openvidu.server.summary.SessionSummary; /** * CDR logger to register all information of a Session. @@ -83,6 +85,9 @@ import io.openvidu.server.recording.service.RecordingManager; */ public class CallDetailRecord { + @Autowired + protected SessionManager sessionManager; + @Autowired protected OpenviduConfig openviduConfig; @@ -109,9 +114,14 @@ public class CallDetailRecord { } public void recordSessionDestroyed(String sessionId, String reason) { - CDREvent e = this.sessions.remove(sessionId); + CDREventSession e = this.sessions.remove(sessionId); if (e != null) { - this.log(new CDREventSession(e, RecordingManager.finalReason(reason))); + CDREventSession eventSessionEnd = new CDREventSession(e, RecordingManager.finalReason(reason)); + this.log(eventSessionEnd); + + // Summary: log closed session + this.log(new SessionSummary(eventSessionEnd, sessionManager.removeFinalUsers(sessionId), + sessionManager.removeAccumulatedRecordings(sessionId))); } } @@ -122,52 +132,63 @@ public class CallDetailRecord { } public void recordParticipantLeft(Participant participant, String sessionId, String reason) { - CDREvent e = this.participants.remove(participant.getParticipantPublicId()); - this.log(new CDREventParticipant(e, reason)); + CDREventParticipant e = this.participants.remove(participant.getParticipantPublicId()); + CDREventParticipant eventParticipantEnd = new CDREventParticipant(e, reason); + this.log(eventParticipantEnd); + + // Summary: update final user ended connection + sessionManager.getFinalUsers(sessionId).get(participant.getFinalUserId()).setConnection(eventParticipantEnd); } - public void recordNewPublisher(Participant participant, String sessionId, MediaOptions mediaOptions, - Long timestamp) { - CDREventWebrtcConnection publisher = new CDREventWebrtcConnection(sessionId, - participant.getParticipantPublicId(), mediaOptions, null, timestamp); + public void recordNewPublisher(Participant participant, String sessionId, String streamId, + MediaOptions mediaOptions, Long timestamp) { + CDREventWebrtcConnection publisher = new CDREventWebrtcConnection(sessionId, streamId, participant, + mediaOptions, null, timestamp); this.publications.put(participant.getParticipantPublicId(), publisher); this.log(publisher); } - public boolean stopPublisher(String participantPublicId, String reason) { - CDREventWebrtcConnection publisher = this.publications.remove(participantPublicId); - if (publisher != null) { - publisher = new CDREventWebrtcConnection(publisher, reason); - this.log(publisher); - return true; + public void stopPublisher(String participantPublicId, String streamId, String reason) { + CDREventWebrtcConnection eventPublisherEnd = this.publications.remove(participantPublicId); + if (eventPublisherEnd != null) { + eventPublisherEnd = new CDREventWebrtcConnection(eventPublisherEnd, reason); + this.log(eventPublisherEnd); + + // Summary: update final user ended publisher + sessionManager.getFinalUsers(eventPublisherEnd.getSessionId()) + .get(eventPublisherEnd.getParticipant().getFinalUserId()).getConnections().get(participantPublicId) + .addPublisherClosed(streamId, eventPublisherEnd); } - return false; } - public void recordNewSubscriber(Participant participant, String sessionId, String senderPublicId, Long timestamp) { + public void recordNewSubscriber(Participant participant, String sessionId, String streamId, String senderPublicId, + Long timestamp) { CDREventWebrtcConnection publisher = this.publications.get(senderPublicId); - CDREventWebrtcConnection subscriber = new CDREventWebrtcConnection(sessionId, - participant.getParticipantPublicId(), publisher.mediaOptions, senderPublicId, timestamp); + CDREventWebrtcConnection subscriber = new CDREventWebrtcConnection(sessionId, streamId, participant, + publisher.mediaOptions, senderPublicId, timestamp); this.subscriptions.putIfAbsent(participant.getParticipantPublicId(), new ConcurrentSkipListSet<>()); this.subscriptions.get(participant.getParticipantPublicId()).add(subscriber); this.log(subscriber); } - public boolean stopSubscriber(String participantPublicId, String senderPublicId, String reason) { + public void stopSubscriber(String participantPublicId, String senderPublicId, String streamId, String reason) { Set participantSubscriptions = this.subscriptions.get(participantPublicId); if (participantSubscriptions != null) { - CDREventWebrtcConnection subscription; + CDREventWebrtcConnection eventSubscriberEnd; for (Iterator it = participantSubscriptions.iterator(); it.hasNext();) { - subscription = it.next(); - if (senderPublicId.equals(subscription.receivingFrom)) { + eventSubscriberEnd = it.next(); + if (senderPublicId.equals(eventSubscriberEnd.receivingFrom)) { it.remove(); - subscription = new CDREventWebrtcConnection(subscription, reason); - this.log(subscription); - return true; + eventSubscriberEnd = new CDREventWebrtcConnection(eventSubscriberEnd, reason); + this.log(eventSubscriberEnd); + + // Summary: update final user ended subscriber + sessionManager.getFinalUsers(eventSubscriberEnd.getSessionId()) + .get(eventSubscriberEnd.getParticipant().getFinalUserId()).getConnections() + .get(participantPublicId).addSubscriberClosed(streamId, eventSubscriberEnd); } } } - return false; } public void recordRecordingStarted(String sessionId, Recording recording) { @@ -178,11 +199,12 @@ public class CallDetailRecord { public void recordRecordingStopped(String sessionId, Recording recording, String reason) { CDREventRecording recordingStartedEvent = this.recordings.remove(recording.getId()); - this.log(new CDREventRecording(recordingStartedEvent, RecordingManager.finalReason(reason))); - } + CDREventRecording recordingStoppedEvent = new CDREventRecording(recordingStartedEvent, recording, + RecordingManager.finalReason(reason)); + this.log(recordingStoppedEvent); - public void recordKmsEvent(KmsEvent event) { - this.log(event); + // Summary: update ended recording + sessionManager.getAccumulatedRecordings(sessionId).add(recordingStoppedEvent); } private void log(CDREvent event) { @@ -193,10 +215,16 @@ public class CallDetailRecord { }); } - private void log(KmsEvent event) { + public void log(KmsEvent event) { this.loggers.forEach(logger -> { logger.log(event); }); } + public void log(SessionSummary sessionSummary) { + this.loggers.forEach(logger -> { + logger.log(sessionSummary); + }); + } + } diff --git a/openvidu-server/src/main/java/io/openvidu/server/config/HttpHandshakeInterceptor.java b/openvidu-server/src/main/java/io/openvidu/server/config/HttpHandshakeInterceptor.java new file mode 100644 index 00000000..8b711d91 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/config/HttpHandshakeInterceptor.java @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2017-2019 OpenVidu (https://openvidu.io/) + * + * 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. + * + */ + +package io.openvidu.server.config; + +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeInterceptor; + +public class HttpHandshakeInterceptor implements HandshakeInterceptor { + + private static final Logger log = LoggerFactory.getLogger(HttpHandshakeInterceptor.class); + + @Override + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, + Map attributes) throws Exception { + if (request instanceof ServletServerHttpRequest) { + HttpSession session = ((ServletServerHttpRequest) request).getServletRequest().getSession(); + session.setMaxInactiveInterval(1800); // HttpSession will expire in 30 minutes + attributes.put("httpSession", session); + log.info("{} HttpSession {}", session.isNew() ? "New" : "Old", session.getId()); + } + return true; + } + + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, + Exception ex) { + } +} \ No newline at end of file diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/FinalUser.java b/openvidu-server/src/main/java/io/openvidu/server/core/FinalUser.java new file mode 100644 index 00000000..3b310c3a --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/core/FinalUser.java @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2017-2019 OpenVidu (https://openvidu.io/) + * + * 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. + * + */ + +package io.openvidu.server.core; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openvidu.server.cdr.CDREventParticipant; +import io.openvidu.server.summary.ParticipantSummary; + +public class FinalUser { + + private String id; + private String sessionId; + private String location; + private String platform; + private Map connections = new ConcurrentHashMap<>(); + + public FinalUser(String id, String sessionId, Participant firstConnection) { + this.id = id; + this.sessionId = sessionId; + this.location = firstConnection.getLocation(); + this.platform = firstConnection.getPlatform(); + this.connections.put(firstConnection.getParticipantPublicId(), + new ParticipantSummary(this.sessionId, firstConnection)); + } + + public String getId() { + return id; + } + + public String getSessionId() { + return sessionId; + } + + public String getLocation() { + return location; + } + + public String getPlatform() { + return platform; + } + + public Map getConnections() { + return connections; + } + + public void addConnection(Participant participant) { + this.connections.put(participant.getParticipantPublicId(), new ParticipantSummary(this.sessionId, participant)); + } + + public void setConnection(CDREventParticipant event) { + ParticipantSummary oldSummary = this.connections.remove(event.getParticipant().getParticipantPublicId()); + this.connections.put(event.getParticipant().getParticipantPublicId(), + new ParticipantSummary(event, oldSummary)); + } + + public JsonObject toJson() { + JsonObject json = new JsonObject(); + json.addProperty("id", id); + json.addProperty("location", location); + json.addProperty("platform", platform); + + JsonObject connectionsJson = new JsonObject(); + connectionsJson.addProperty("numberOfElements", connections.size()); + JsonArray jsonArray = new JsonArray(); + connections.values().forEach(connection -> { + jsonArray.add(connection.toJson()); + }); + connectionsJson.add("content", jsonArray); + json.add("connections", connectionsJson); + + return json; + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java b/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java index 22e64c08..76cfe229 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java @@ -21,6 +21,7 @@ import com.google.gson.JsonObject; public class Participant { + private String finalUserId; // ID to match this connection with a final user (HttpSession id) private String participantPrivatetId; // ID to identify the user on server (org.kurento.jsonrpc.Session.id) private String participantPublicId; // ID to identify the user on clients private Long createdAt; // Timestamp when this connection was established @@ -35,8 +36,9 @@ public class Participant { private final String METADATA_SEPARATOR = "%/%"; - public Participant(String participantPrivatetId, String participantPublicId, Token token, String clientMetadata, - String location, String platform, Long createdAt) { + public Participant(String finalUserId, String participantPrivatetId, String participantPublicId, Token token, + String clientMetadata, String location, String platform, Long createdAt) { + this.finalUserId = finalUserId; this.participantPrivatetId = participantPrivatetId; this.participantPublicId = participantPublicId; if (createdAt != null) { @@ -52,6 +54,10 @@ public class Participant { this.platform = platform; } + public String getFinalUserId() { + return finalUserId; + } + public String getParticipantPrivateId() { return participantPrivatetId; } diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java index cdd683bc..325abf01 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java @@ -186,6 +186,10 @@ public class SessionEventsHandler { // leaving the session rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); } + + if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(participant.getParticipantPublicId())) { + CDR.recordParticipantLeft(participant, sessionId, reason); + } } public void onPublishMedia(Participant participant, String streamId, Long createdAt, String sessionId, diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java index da6d01fe..941ef9ed 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java @@ -19,8 +19,10 @@ package io.openvidu.server.core; import java.util.Collection; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; @@ -41,6 +43,7 @@ import io.openvidu.client.internal.ProtocolElements; import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.SessionProperties; import io.openvidu.server.OpenViduServer; +import io.openvidu.server.cdr.CDREventRecording; import io.openvidu.server.cdr.CallDetailRecord; import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.coturn.CoturnCredentialsService; @@ -73,6 +76,8 @@ public abstract class SessionManager { protected ConcurrentMap sessions = new ConcurrentHashMap<>(); protected ConcurrentMap sessionsNotActive = new ConcurrentHashMap<>(); protected ConcurrentMap> sessionidParticipantpublicidParticipant = new ConcurrentHashMap<>(); + protected ConcurrentMap> sessionidFinalUsers = new ConcurrentHashMap<>(); + protected ConcurrentMap> sessionidAccumulatedRecordings = new ConcurrentHashMap<>(); protected ConcurrentMap insecureUsers = new ConcurrentHashMap<>(); public ConcurrentMap> sessionidTokenTokenobj = new ConcurrentHashMap<>(); @@ -214,6 +219,22 @@ public abstract class SessionManager { "No participant with private id '" + participantPrivateId + "' was found"); } + public Map getFinalUsers(String sessionId) { + return this.sessionidFinalUsers.get(sessionId); + } + + public Map removeFinalUsers(String sessionId) { + return this.sessionidFinalUsers.remove(sessionId); + } + + public Collection getAccumulatedRecordings(String sessionId) { + return this.sessionidAccumulatedRecordings.get(sessionId); + } + + public Collection removeAccumulatedRecordings(String sessionId) { + return this.sessionidAccumulatedRecordings.remove(sessionId); + } + public MediaOptions generateMediaOptions(Request request) { return null; } @@ -222,6 +243,10 @@ public abstract class SessionManager { Session sessionNotActive = new Session(sessionId, sessionProperties, CDR, openviduConfig, recordingManager); this.sessionsNotActive.put(sessionId, sessionNotActive); this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>()); + this.sessionidFinalUsers.putIfAbsent(sessionId, new ConcurrentHashMap<>()); + if (this.openviduConfig.isRecordingModuleEnabled()) { + this.sessionidAccumulatedRecordings.putIfAbsent(sessionId, new ConcurrentLinkedQueue<>()); + } showTokens(); return sessionNotActive; } @@ -272,6 +297,10 @@ public abstract class SessionManager { } } else { this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>()); + this.sessionidFinalUsers.putIfAbsent(sessionId, new ConcurrentHashMap<>()); + if (this.openviduConfig.isRecordingModuleEnabled()) { + this.sessionidAccumulatedRecordings.putIfAbsent(sessionId, new ConcurrentLinkedQueue<>()); + } this.sessionidTokenTokenobj.putIfAbsent(sessionId, new ConcurrentHashMap<>()); this.sessionidTokenTokenobj.get(sessionId).putIfAbsent(token, new Token(token, OpenViduRole.PUBLISHER, "", @@ -321,16 +350,30 @@ public abstract class SessionManager { } public Participant newParticipant(String sessionId, String participantPrivatetId, Token token, - String clientMetadata, String location, String platform) { + String clientMetadata, String location, String platform, String finalUserId) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { String participantPublicId = this.generateRandomChain(); - Participant p = new Participant(participantPrivatetId, participantPublicId, token, clientMetadata, location, - platform, null); + Participant p = new Participant(finalUserId, participantPrivatetId, participantPublicId, token, + clientMetadata, location, platform, null); while (this.sessionidParticipantpublicidParticipant.get(sessionId).putIfAbsent(participantPublicId, p) != null) { participantPublicId = this.generateRandomChain(); p.setParticipantPublicId(participantPublicId); } + + FinalUser finalUser = this.sessionidFinalUsers.get(sessionId).get(finalUserId); + if (finalUser == null) { + // First connection for new final user + log.info("Participant {} of session {} belongs to a new final user", p.getParticipantPublicId(), + sessionId); + this.sessionidFinalUsers.get(sessionId).put(finalUserId, new FinalUser(finalUserId, sessionId, p)); + } else { + // New connection for previously existing final user + log.info("Participant {} of session {} belongs to a previously existing user", + p.getParticipantPublicId(), sessionId); + finalUser.addConnection(p); + } + return p; } else { throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, sessionId); @@ -340,7 +383,7 @@ public abstract class SessionManager { public Participant newRecorderParticipant(String sessionId, String participantPrivatetId, Token token, String clientMetadata) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { - Participant p = new Participant(participantPrivatetId, ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, + Participant p = new Participant(null, participantPrivatetId, ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, token, clientMetadata, null, null, null); this.sessionidParticipantpublicidParticipant.get(sessionId) .put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p); @@ -445,6 +488,8 @@ public abstract class SessionManager { sessions.remove(session.getSessionId()); sessionsNotActive.remove(session.getSessionId()); sessionidParticipantpublicidParticipant.remove(session.getSessionId()); + sessionidFinalUsers.remove(session.getSessionId()); + sessionidAccumulatedRecordings.remove(session.getSessionId()); sessionidTokenTokenobj.remove(session.getSessionId()); log.warn("Session '{}' removed and closed", session.getSessionId()); diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java index e52d4a92..a7e8b66c 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java @@ -77,9 +77,9 @@ public class KurentoParticipant extends Participant { public KurentoParticipant(Participant participant, KurentoSession kurentoSession, InfoHandler infoHandler, CallDetailRecord CDR, OpenviduConfig openviduConfig, RecordingManager recordingManager) { - super(participant.getParticipantPrivateId(), participant.getParticipantPublicId(), participant.getToken(), - participant.getClientMetadata(), participant.getLocation(), participant.getPlatform(), - participant.getCreatedAt()); + super(participant.getFinalUserId(), participant.getParticipantPrivateId(), participant.getParticipantPublicId(), + participant.getToken(), participant.getClientMetadata(), participant.getLocation(), + participant.getPlatform(), participant.getCreatedAt()); this.infoHandler = infoHandler; this.CDR = CDR; this.openviduConfig = openviduConfig; @@ -185,8 +185,8 @@ public class KurentoParticipant extends Participant { this.recordingManager.startOneIndividualStreamRecording(session, null, null, this); } - CDR.recordNewPublisher(this, this.session.getSessionId(), this.publisher.getMediaOptions(), - this.publisher.createdAt()); + CDR.recordNewPublisher(this, session.getSessionId(), publisher.getStreamId(), publisher.getMediaOptions(), + publisher.createdAt()); return sdpResponse; } @@ -270,8 +270,8 @@ public class KurentoParticipant extends Participant { senderName, this.session.getSessionId()); if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(this.getParticipantPublicId())) { - CDR.recordNewSubscriber(this, this.session.getSessionId(), sender.getParticipantPublicId(), - subscriber.createdAt()); + CDR.recordNewSubscriber(this, this.session.getSessionId(), sender.getPublisherStreamId(), + sender.getParticipantPublicId(), subscriber.createdAt()); } return sdpAnswer; @@ -386,10 +386,10 @@ public class KurentoParticipant extends Participant { } releaseElement(getParticipantPublicId(), publisher.getEndpoint()); this.streaming = false; - publisher = null; this.session.deregisterPublisher(); - CDR.stopPublisher(this.getParticipantPublicId(), reason); + CDR.stopPublisher(this.getParticipantPublicId(), publisher.getStreamId(), reason); + publisher = null; } else { log.warn("PARTICIPANT {}: Trying to release publisher endpoint but is null", getParticipantPublicId()); @@ -402,7 +402,7 @@ public class KurentoParticipant extends Participant { releaseElement(senderName, subscriber.getEndpoint()); if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(this.getParticipantPublicId())) { - CDR.stopSubscriber(this.getParticipantPublicId(), senderName, reason); + CDR.stopSubscriber(this.getParticipantPublicId(), senderName, subscriber.getStreamId(), reason); } } else { @@ -442,7 +442,7 @@ public class KurentoParticipant extends Participant { KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); }); @@ -454,7 +454,7 @@ public class KurentoParticipant extends Participant { KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); }); @@ -464,7 +464,7 @@ public class KurentoParticipant extends Participant { + typeOfEndpoint + ") | timestamp: " + event.getTimestamp(); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); }); @@ -475,7 +475,7 @@ public class KurentoParticipant extends Participant { + " | timestamp: " + event.getTimestamp(); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); }); @@ -488,7 +488,7 @@ public class KurentoParticipant extends Participant { + endpoint.selectedRemoteIceCandidate + " | timestamp: " + event.getTimestamp(); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); }); @@ -500,7 +500,7 @@ public class KurentoParticipant extends Participant { KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); }); @@ -513,7 +513,7 @@ public class KurentoParticipant extends Participant { + event.getTimestamp(); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.info(msg); // } @@ -525,7 +525,7 @@ public class KurentoParticipant extends Participant { + " | timestamp: " + event.getTimestamp(); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); endpoint.kmsEvents.add(kmsEvent); - this.CDR.recordKmsEvent(kmsEvent); + this.CDR.log(kmsEvent); this.infoHandler.sendInfo(msg); log.error(msg); }); diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java index 1755555e..21c70a46 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java @@ -136,10 +136,6 @@ public class KurentoSession extends Session { this.removeParticipant(participant, reason); participant.close(reason, true); - - if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(participant.getParticipantPublicId())) { - CDR.recordParticipantLeft(participant, participant.getSession().getSessionId(), reason); - } } @Override diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java index 4b66a7cc..fe0f4e5d 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java @@ -77,9 +77,9 @@ public class KurentoSessionManager extends SessionManager { KurentoClientSessionInfo kcSessionInfo = new OpenViduKurentoClientSessionInfo( participant.getParticipantPrivateId(), sessionId); - KurentoSession session = (KurentoSession) sessions.get(sessionId); + KurentoSession kSession = (KurentoSession) sessions.get(sessionId); - if (session == null && kcSessionInfo != null) { + if (kSession == null && kcSessionInfo != null) { // First user connecting to the session Session sessionNotActive = sessionsNotActive.remove(sessionId); @@ -94,21 +94,20 @@ public class KurentoSessionManager extends SessionManager { createSession(sessionNotActive, kcSessionInfo); } - session = (KurentoSession) sessions.get(sessionId); - if (session == null) { + kSession = (KurentoSession) sessions.get(sessionId); + if (kSession == null) { log.warn("Session '{}' not found"); throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "Session '" + sessionId + "' was not found, must be created before '" + sessionId + "' can join"); } - if (session.isClosed()) { + if (kSession.isClosed()) { log.warn("'{}' is trying to join session '{}' but it is closing", participant.getParticipantPublicId(), sessionId); throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "'" + participant.getParticipantPublicId() + "' is trying to join session '" + sessionId + "' but it is closing"); } existingParticipants = getParticipants(sessionId); - session.join(participant); - + kSession.join(participant); } catch (OpenViduException e) { log.warn("PARTICIPANT {}: Error joining/creating session {}", participant.getParticipantPublicId(), sessionId, e); diff --git a/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java b/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java index b0a502a9..e9bac5ce 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java +++ b/openvidu-server/src/main/java/io/openvidu/server/rpc/RpcHandler.java @@ -24,6 +24,8 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import javax.servlet.http.HttpSession; + import org.kurento.jsonrpc.DefaultJsonRpcHandler; import org.kurento.jsonrpc.Session; import org.kurento.jsonrpc.Transaction; @@ -186,6 +188,34 @@ public class RpcHandler extends DefaultJsonRpcHandler { } } + HttpSession httpSession = (HttpSession) rpcConnection.getSession().getAttributes().get("httpSession"); + + JsonObject sessions = (JsonObject) httpSession.getAttribute("openviduSessions"); + if (sessions == null) { + // First time this final user connects to an OpenVidu session in this active + // WebSocketSession. This is a new final user connecting to OpenVidu Server + JsonObject json = new JsonObject(); + json.addProperty(sessionId, System.currentTimeMillis()); + httpSession.setAttribute("openviduSessions", json); + } else { + // This final user has already been connected to an OpenVidu session in this + // active WebSocketSession + if (sessions.has(sessionId)) { + if (sessionManager.getSession(sessionId) != null) { + // The previously existing final user is reconnecting to an OpenVidu session + log.info("Final user reconnecting"); + } else if (sessionManager.getSessionNotActive(sessionId) != null) { + // The previously existing final user is the first one connecting to a new + // OpenVidu session that shares a sessionId with a previously closed session + // (same customSessionId) + sessions.addProperty(sessionId, System.currentTimeMillis()); + } + } else { + // The previously existing final user is connecting to a new session + sessions.addProperty(sessionId, System.currentTimeMillis()); + } + } + boolean recorder = false; try { @@ -218,7 +248,7 @@ public class RpcHandler extends DefaultJsonRpcHandler { clientMetadata); } else { participant = sessionManager.newParticipant(sessionId, participantPrivatetId, tokenObj, - clientMetadata, location, platform); + clientMetadata, location, platform, httpSession.getId()); } rpcConnection.setSessionId(sessionId); @@ -555,6 +585,10 @@ public class RpcHandler extends DefaultJsonRpcHandler { address = ((WebSocketServerSession) rpcSession).getWebSocketSession().getRemoteAddress().getAddress(); } rpcSession.getAttributes().put("remoteAddress", address); + + HttpSession httpSession = (HttpSession) ((WebSocketServerSession) rpcSession).getWebSocketSession() + .getAttributes().get("httpSession"); + rpcSession.getAttributes().put("httpSession", httpSession); } } diff --git a/openvidu-server/src/main/java/io/openvidu/server/summary/ParticipantSummary.java b/openvidu-server/src/main/java/io/openvidu/server/summary/ParticipantSummary.java new file mode 100644 index 00000000..b8bece06 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/summary/ParticipantSummary.java @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2017-2019 OpenVidu (https://openvidu.io/) + * + * 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. + * + */ + +package io.openvidu.server.summary; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openvidu.server.cdr.CDREventParticipant; +import io.openvidu.server.cdr.CDREventWebrtcConnection; +import io.openvidu.server.core.Participant; + +public class ParticipantSummary { + + private CDREventParticipant eventParticipantEnd; + private Map publishers = new ConcurrentHashMap<>(); + private Map subscribers = new ConcurrentHashMap<>(); + + public ParticipantSummary(CDREventParticipant event) { + this.eventParticipantEnd = event; + } + + public ParticipantSummary(CDREventParticipant event, ParticipantSummary oldSummary) { + this.eventParticipantEnd = event; + this.publishers = oldSummary.publishers; + this.subscribers = oldSummary.subscribers; + } + + public ParticipantSummary(String sessionId, Participant participant) { + this.eventParticipantEnd = new CDREventParticipant(sessionId, participant); + } + + public void addPublisherClosed(String streamId, CDREventWebrtcConnection event) { + this.publishers.put(streamId, event); + } + + public void addSubscriberClosed(String streamId, CDREventWebrtcConnection event) { + this.subscribers.put(streamId, event); + } + + public JsonObject toJson() { + JsonObject json = new JsonObject(); + + json.addProperty("createdAt", this.eventParticipantEnd.getStartTime()); + json.addProperty("destroyedAt", this.eventParticipantEnd.getTimestamp()); + + Participant p = this.eventParticipantEnd.getParticipant(); + json.addProperty("connectionId", p.getParticipantPublicId()); + json.addProperty("clientData", p.getClientMetadata()); + json.addProperty("serverData", p.getServerMetadata()); + + long duration = (this.eventParticipantEnd.getTimestamp() - this.eventParticipantEnd.getStartTime()) / 1000; + json.addProperty("duration", duration); + + json.addProperty("reason", this.eventParticipantEnd.getReason()); + + // Publishers summary + JsonObject publishersJson = new JsonObject(); + publishersJson.addProperty("numberOfElements", publishers.size()); + JsonArray jsonArrayPublishers = new JsonArray(); + publishers.values().forEach(cdrEvent -> { + JsonObject j = cdrEvent.toJson(); + j.remove("participantId"); + j.remove("connection"); + jsonArrayPublishers.add(j); + }); + publishersJson.add("content", jsonArrayPublishers); + json.add("publishers", publishersJson); + + // Subscribers summary + JsonObject subscribersJson = new JsonObject(); + subscribersJson.addProperty("numberOfElements", subscribers.size()); + JsonArray jsonArraySubscribers = new JsonArray(); + subscribers.values().forEach(cdrEvent -> { + JsonObject j = cdrEvent.toJson(); + j.remove("participantId"); + j.remove("connection"); + jsonArraySubscribers.add(j); + }); + subscribersJson.add("content", jsonArraySubscribers); + json.add("subscribers", subscribersJson); + + return json; + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/summary/SessionSummary.java b/openvidu-server/src/main/java/io/openvidu/server/summary/SessionSummary.java new file mode 100644 index 00000000..04d363d5 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/summary/SessionSummary.java @@ -0,0 +1,82 @@ +/* + * (C) Copyright 2017-2019 OpenVidu (https://openvidu.io/) + * + * 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. + * + */ + +package io.openvidu.server.summary; + +import java.util.Collection; +import java.util.Map; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openvidu.server.cdr.CDREventRecording; +import io.openvidu.server.cdr.CDREventSession; +import io.openvidu.server.core.FinalUser; + +public class SessionSummary { + + private long totalStreamedMinutes; // Minutes + private CDREventSession eventSessionEnd; + private Map users; + private Collection recordings; + + public SessionSummary(CDREventSession event, Map users, + Collection recordings) { + this.eventSessionEnd = event; + this.users = users; + this.recordings = recordings; + } + + public JsonObject toJson() { + JsonObject json = new JsonObject(); + json.addProperty("createdAt", this.eventSessionEnd.getStartTime()); + json.addProperty("destroyedAt", this.eventSessionEnd.getTimestamp()); + json.addProperty("sessionId", this.eventSessionEnd.getSessionId()); + json.addProperty("customSessionId", this.eventSessionEnd.getSession().getSessionProperties().customSessionId()); + json.addProperty("mediaMode", this.eventSessionEnd.getSession().getSessionProperties().mediaMode().name()); + json.addProperty("recordingMode", + this.eventSessionEnd.getSession().getSessionProperties().recordingMode().name()); + + long duration = (this.eventSessionEnd.getTimestamp() - this.eventSessionEnd.getStartTime()) / 1000; + json.addProperty("duration", duration); + + json.addProperty("reason", this.eventSessionEnd.getReason()); + + // Final users + JsonObject usersJson = new JsonObject(); + usersJson.addProperty("numberOfElements", users.size()); + JsonArray jsonArray = new JsonArray(); + users.values().forEach(finalUser -> { + jsonArray.add(finalUser.toJson()); + }); + usersJson.add("content", jsonArray); + json.add("users", usersJson); + + // Accumulated recordings + JsonObject recordingsJson = new JsonObject(); + recordingsJson.addProperty("numberOfElements", recordings.size()); + JsonArray jsonRecordingsArray = new JsonArray(); + recordings.forEach(rec -> { + jsonRecordingsArray.add(rec.toJson()); + }); + recordingsJson.add("content", jsonRecordingsArray); + json.add("recordings", recordingsJson); + + return json; + } + +} diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java index f231c62a..e495aa34 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java @@ -2489,7 +2489,7 @@ public class OpenViduTestAppE2eTest { user.getEventManager().waitUntilEventReaches("recordingStarted", 2); - Thread.sleep(1000); + Thread.sleep(2000); // 409 (already recording) restClient.rest(HttpMethod.POST, "/api/recordings/start", body, HttpStatus.SC_CONFLICT);