From c75252508c5321d1d715f9550d2bc1178376cd2a Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Fri, 7 Sep 2018 09:54:38 +0200 Subject: [PATCH] openvidu-server: CDR refactoring. Session and Participant createdAt property --- .../java/io/openvidu/server/cdr/CDREvent.java | 176 ++---------------- .../io/openvidu/server/cdr/CDREventEnd.java | 37 ++++ .../server/cdr/CDREventParticipant.java | 32 ++++ .../server/cdr/CDREventRecording.java | 36 ++++ .../openvidu/server/cdr/CDREventSession.java | 20 ++ .../server/cdr/CDREventWebrtcConnection.java | 70 +++++++ .../openvidu/server/cdr/CallDetailRecord.java | 91 +++++---- .../server/config/OpenviduConfig.java | 7 + .../io/openvidu/server/core/Participant.java | 7 + .../java/io/openvidu/server/core/Session.java | 2 + .../server/core/SessionEventsHandler.java | 11 +- .../openvidu/server/core/SessionManager.java | 6 +- .../server/kurento/core/KurentoSession.java | 14 +- .../kurento/core/KurentoSessionManager.java | 7 +- .../kurento/endpoint/MediaEndpoint.java | 4 + .../server/rest/SessionRestController.java | 4 +- ...itional-spring-configuration-metadata.json | 10 +- .../src/main/resources/application.properties | 5 +- 18 files changed, 326 insertions(+), 213 deletions(-) create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventEnd.java create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventParticipant.java create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventRecording.java create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventSession.java create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventWebrtcConnection.java diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java index 9a100eab..95c3fa8e 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java @@ -19,184 +19,38 @@ package io.openvidu.server.cdr; import com.google.gson.JsonObject; -import io.openvidu.java.client.RecordingLayout; -import io.openvidu.server.core.MediaOptions; -import io.openvidu.server.core.Participant; -import io.openvidu.server.recording.Recording; +public class CDREvent { -public class CDREvent implements Comparable { - - protected CDREventName eventName; protected String sessionId; protected Long timeStamp; - private Long startTime; - private Integer duration; - private Participant participant; - private String location; - private String platform; - private MediaOptions mediaOptions; - private String receivingFrom; - private String reason; + private CDREventName eventName; - // Recording events - private Long size; - private String id; - private String name; - private Boolean hasAudio; - private Boolean hasVideo; - private RecordingLayout recordingLayout; - - public CDREvent(CDREventName eventName, CDREvent event) { - this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime, - event.reason); - this.duration = (int) (this.timeStamp - this.startTime / 1000); - } - - public CDREvent(CDREventName eventName, CDREvent event, String reason) { - this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime, - reason); - this.duration = (int) (this.timeStamp - this.startTime / 1000); - } - - public CDREvent(CDREventName eventName, String sessionId) { + public CDREvent(CDREventName eventName, String sessionId, Long timeStamp) { this.eventName = eventName; - if ((sessionId.indexOf('/')) != -1) { - this.sessionId = sessionId.substring(sessionId.lastIndexOf('/') + 1, sessionId.length()); - } else { - this.sessionId = sessionId; - } - this.timeStamp = System.currentTimeMillis(); - this.startTime = this.timeStamp; + this.sessionId = sessionId; + this.timeStamp = timeStamp; } - public CDREvent(CDREventName eventName, String sessionId, Recording recording, String reason) { - this.eventName = eventName; - if ((sessionId.indexOf('/')) != -1) { - this.sessionId = sessionId.substring(sessionId.lastIndexOf('/') + 1, sessionId.length()); - } else { - this.sessionId = sessionId; - } - this.timeStamp = System.currentTimeMillis(); - this.id = recording.getId(); - this.name = recording.getName(); - this.duration = (int) recording.getDuration(); - this.size = recording.getSize(); - this.hasAudio = recording.hasAudio(); - this.hasVideo = recording.hasVideo(); - this.recordingLayout = recording.getRecordingLayout(); - this.reason = reason; + public String getSessionId() { + return this.sessionId; } - public CDREvent(CDREventName eventName, Participant participant, String sessionId) { - this(eventName, sessionId); - this.participant = participant; - this.location = participant.getLocation(); - this.platform = participant.getPlatform(); - this.startTime = this.timeStamp; + public Long getTimestamp() { + return this.timeStamp; } - public CDREvent(CDREventName eventName, Participant participant, String sessionId, MediaOptions mediaOptions, - String receivingFrom, Long startTime, String reason) { - this(eventName, sessionId); - this.participant = participant; - this.mediaOptions = mediaOptions; - this.receivingFrom = receivingFrom; - this.startTime = startTime; - this.reason = reason; - } - - public MediaOptions getMediaOptions() { - return mediaOptions; - } - - public String getParticipantPublicId() { - return this.participant.getParticipantPublicId(); - } - - public String getReceivingFrom() { - return this.receivingFrom; + public JsonObject toJson() { + JsonObject json = new JsonObject(); + json.addProperty("sessionId", this.sessionId); + json.addProperty("timestamp", this.timeStamp); + return json; } @Override public String toString() { - JsonObject json = new JsonObject(); - json.addProperty("sessionId", this.sessionId); - json.addProperty("timestamp", this.timeStamp); - - if (this.participant != null) { - json.addProperty("participantId", this.participant.getParticipantPublicId()); - } - if (this.location != null) { - json.addProperty("location", this.location); - } - if (this.platform != null) { - json.addProperty("platform", this.platform); - } - if (this.mediaOptions != null) { - json.addProperty("connection", this.receivingFrom != null ? "INBOUND" : "OUTBOUND"); - json.addProperty("audioEnabled", this.mediaOptions.hasAudio()); - json.addProperty("videoEnabled", this.mediaOptions.hasVideo()); - if (this.mediaOptions.hasVideo()) { - json.addProperty("videoSource", this.mediaOptions.getTypeOfVideo()); - json.addProperty("videoFramerate", this.mediaOptions.getFrameRate()); - } - if (this.receivingFrom != null) { - json.addProperty("receivingFrom", this.receivingFrom); - } - } - if (this.startTime != null && this.duration != null) { - json.addProperty("startTime", this.startTime); - json.addProperty("endTime", this.timeStamp); - json.addProperty("duration", (this.timeStamp - this.startTime) / 1000); - } else if (this.duration != null) { - json.addProperty("duration", duration); - } - if (this.reason != null) { - json.addProperty("reason", this.reason); - } - if (this.id != null) { - json.addProperty("id", this.id); - } - if (this.name != null) { - json.addProperty("name", this.name); - } - if (this.size != null) { - json.addProperty("size", this.size); - } - if (this.hasAudio != null) { - json.addProperty("hasAudio", this.hasAudio); - } - if (this.hasVideo != null) { - json.addProperty("hasVideo", this.hasVideo); - } - if (this.recordingLayout != null) { - json.addProperty("recordingLayout", this.recordingLayout.name()); - } - JsonObject root = new JsonObject(); - root.add(this.eventName.name(), json); - + root.add(this.eventName.name(), this.toJson()); return root.toString(); } - @Override - public int compareTo(CDREvent other) { - if (this.participant.equals(other.participant)) { - if (this.receivingFrom != null && other.receivingFrom != null) { - if (this.receivingFrom.equals(other.receivingFrom)) { - return 0; - } else { - return 1; - } - } else { - if (this.receivingFrom == null && other.receivingFrom == null) { - return 0; - } else { - return 1; - } - } - } - return 1; - } - } 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 new file mode 100644 index 00000000..2c5e8de2 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventEnd.java @@ -0,0 +1,37 @@ +package io.openvidu.server.cdr; + +import com.google.gson.JsonObject; + +public class CDREventEnd extends CDREvent { + + protected Long startTime; + protected Integer duration; + protected String reason; + + public CDREventEnd(CDREventName eventName, String sessionId, Long timestamp) { + super(eventName, sessionId, timestamp); + } + + public CDREventEnd(CDREventName eventName, String sessionId, Long startTime, String reason) { + super(eventName, sessionId, System.currentTimeMillis()); + this.startTime = startTime; + this.duration = (int) ((this.timeStamp - this.startTime) / 1000); + this.reason = reason; + } + + @Override + public JsonObject toJson() { + JsonObject json = super.toJson(); + if (this.startTime != null) { + json.addProperty("startTime", this.startTime); + } + if (this.duration != null) { + json.addProperty("duration", this.duration); + } + if (this.reason != null) { + json.addProperty("reason", this.reason); + } + return json; + } + +} 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 new file mode 100644 index 00000000..952fb15d --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventParticipant.java @@ -0,0 +1,32 @@ +package io.openvidu.server.cdr; + +import com.google.gson.JsonObject; + +import io.openvidu.server.core.Participant; + +public class CDREventParticipant extends CDREventEnd { + + private Participant participant; + + // participantJoined + public CDREventParticipant(String sessionId, Participant participant) { + super(CDREventName.participantJoined, sessionId, participant.getCreatedAt()); + this.participant = participant; + } + + // participantLeft + public CDREventParticipant(CDREvent event, String reason) { + super(CDREventName.participantLeft, event.getSessionId(), event.getTimestamp(), reason); + this.participant = ((CDREventParticipant) event).participant; + } + + @Override + public JsonObject toJson() { + JsonObject json = super.toJson(); + json.addProperty("participantId", this.participant.getParticipantPublicId()); + json.addProperty("location", this.participant.getLocation()); + json.addProperty("platform", this.participant.getPlatform()); + return json; + } + +} 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 new file mode 100644 index 00000000..72b0800f --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventRecording.java @@ -0,0 +1,36 @@ +package io.openvidu.server.cdr; + +import com.google.gson.JsonObject; + +import io.openvidu.server.recording.Recording; + +public class CDREventRecording extends CDREventEnd { + + private Recording recording; + + // recordingStarted + public CDREventRecording(String sessionId, Recording recording) { + super(CDREventName.recordingStarted, sessionId, recording.getCreatedAt()); + this.recording = recording; + } + + // recordingStopped + public CDREventRecording(CDREvent event, String reason) { + super(CDREventName.recordingStopped, event.getSessionId(), event.getTimestamp(), reason); + this.recording = ((CDREventRecording) event).recording; + } + + @Override + public JsonObject toJson() { + JsonObject json = super.toJson(); + json.addProperty("id", this.recording.getId()); + json.addProperty("name", this.recording.getName()); + json.addProperty("recordingLayout", this.recording.getRecordingLayout().name()); + json.addProperty("hasAudio", this.recording.hasAudio()); + json.addProperty("hasVideo", this.recording.hasVideo()); + json.addProperty("size", this.recording.getSize()); + json.addProperty("duration", this.recording.getDuration()); + return json; + } + +} 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 new file mode 100644 index 00000000..987b9821 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventSession.java @@ -0,0 +1,20 @@ +package io.openvidu.server.cdr; + +import io.openvidu.server.core.Session; + +public class CDREventSession extends CDREventEnd { + + Session session; + + // sessionCreated + public CDREventSession(Session session) { + super(CDREventName.sessionCreated, session.getSessionId(), session.getStartTime()); + this.session = session; + } + + // sessionDestroyed + public CDREventSession(CDREvent event, String reason) { + super(CDREventName.sessionDestroyed, event.getSessionId(), event.getTimestamp(), reason); + } + +} 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 new file mode 100644 index 00000000..ff58122b --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREventWebrtcConnection.java @@ -0,0 +1,70 @@ +package io.openvidu.server.cdr; + +import com.google.gson.JsonObject; + +import io.openvidu.server.core.MediaOptions; + +public class CDREventWebrtcConnection extends CDREventEnd implements Comparable { + + String participantId; + MediaOptions mediaOptions; + String receivingFrom; + + // webrtcConnectionCreated + public CDREventWebrtcConnection(String sessionId, String participantId, MediaOptions mediaOptions, + String receivingFrom) { + super(CDREventName.webrtcConnectionCreated, sessionId, System.currentTimeMillis()); + this.participantId = participantId; + this.mediaOptions = mediaOptions; + this.receivingFrom = receivingFrom; + } + + // webrtcConnectionDestroyed + public CDREventWebrtcConnection(CDREvent 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; + } + + @Override + public JsonObject toJson() { + JsonObject json = super.toJson(); + json.addProperty("participantId", this.participantId); + if (this.receivingFrom != null) { + json.addProperty("connection", "INBOUND"); + json.addProperty("receivingFrom", this.receivingFrom); + } else { + json.addProperty("connection", "OUTBOUND"); + } + if (this.mediaOptions.hasVideo()) { + json.addProperty("videoSource", this.mediaOptions.getTypeOfVideo()); + json.addProperty("videoFramerate", this.mediaOptions.getFrameRate()); + json.addProperty("videoDimensions", this.mediaOptions.getVideoDimensions()); + } + json.addProperty("audioEnabled", this.mediaOptions.hasAudio()); + json.addProperty("videoEnabled", this.mediaOptions.hasVideo()); + return json; + } + + public int compareTo(CDREventWebrtcConnection other) { + if (this.participantId.equals(other.participantId)) { + if (this.receivingFrom != null && other.receivingFrom != null) { + if (this.receivingFrom.equals(other.receivingFrom)) { + return 0; + } else { + return 1; + } + } else { + if (this.receivingFrom == null && other.receivingFrom == null) { + return 0; + } else { + return 1; + } + } + } + return 1; + } + +} 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 f5c884ed..0357d3c1 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,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; 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.recording.Recording; /** @@ -37,11 +38,11 @@ import io.openvidu.server.recording.Recording; * Enabled by property 'openvidu.cdr=true' * * - 'sessionCreated': {sessionId, timestamp} - * - 'sessionDestroyed': {sessionId, timestamp, startTime, endTime, duration, reason} + * - 'sessionDestroyed': {sessionId, timestamp, startTime, duration, reason} * - 'participantJoined': {sessionId, timestamp, participantId, location, platform} - * - 'participantLeft': {sessionId, timestamp, participantId, startTime, endTime, duration, reason} + * - 'participantLeft': {sessionId, timestamp, participantId, startTime, duration, reason} * - 'webrtcConnectionCreated' {sessionId, timestamp, participantId, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate]} - * - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, endTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason} + * - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason} * - 'recordingStarted' {sessionId, timestamp, id, name, hasAudio, hasVideo, recordingLayout, size} * - 'recordingStopped' {sessionId, timestamp, id, name, hasAudio, hasVideo, recordingLayout, size} * @@ -50,7 +51,6 @@ import io.openvidu.server.recording.Recording; * - sessionId: string * - timestamp: number * - startTime: number - * - endTime: number * - duration: number * - participantId: string * - connection: "INBOUND", "OUTBOUND" @@ -59,6 +59,7 @@ import io.openvidu.server.recording.Recording; * - videoEnabled: boolean * - videoSource: "CAMERA", "SCREEN" * - videoFramerate: number + * - videoDimensions: string * - id: string * - name: string * - hasAudio: boolean @@ -73,6 +74,7 @@ import io.openvidu.server.recording.Recording; * - receivingFrom: only if connection = "INBOUND" * - videoSource: only if videoEnabled = true * - videoFramerate: only if videoEnabled = true + * - videoDimensions: only if videoEnabled = true * * @author Pablo Fuente (pablofuenteperez@gmail.com) */ @@ -83,75 +85,85 @@ public class CallDetailRecord { private CDRLogger logger; - private Map sessions = new ConcurrentHashMap<>(); - private Map participants = new ConcurrentHashMap<>(); - private Map publications = new ConcurrentHashMap<>(); - private Map> subscriptions = new ConcurrentHashMap<>(); - - private final List lastParticipantLeftReasons = Arrays.asList(new String[] {"disconnect", "forceDisconnectByUser", "forceDisconnectByServer", "networkDisconnect"}); + private Map sessions = new ConcurrentHashMap<>(); + private Map participants = new ConcurrentHashMap<>(); + private Map publications = new ConcurrentHashMap<>(); + private Map> subscriptions = new ConcurrentHashMap<>(); + private Map recordings = new ConcurrentHashMap<>(); + + private final List lastParticipantLeftReasons = Arrays.asList( + new String[] { "disconnect", "forceDisconnectByUser", "forceDisconnectByServer", "networkDisconnect" }); public CallDetailRecord(CDRLogger logger) { this.logger = logger; } - public void recordSessionCreated(String sessionId) { - CDREvent e = new CDREvent(CDREventName.sessionCreated, sessionId); - this.sessions.put(sessionId, e); - if (openviduConfig.isCdrEnabled()) this.logger.log(e); + public void recordSessionCreated(Session session) { + CDREventSession e = new CDREventSession(session); + this.sessions.put(session.getSessionId(), e); + if (openviduConfig.isCdrEnabled()) + this.logger.log(e); } public void recordSessionDestroyed(String sessionId, String reason) { CDREvent e = this.sessions.remove(sessionId); - if (openviduConfig.isCdrEnabled()) this.logger.log(new CDREvent(CDREventName.sessionDestroyed, e, this.finalReason(reason))); + if (openviduConfig.isCdrEnabled()) + this.logger.log(new CDREventSession(e, this.finalReason(reason))); } public void recordParticipantJoined(Participant participant, String sessionId) { - CDREvent e = new CDREvent(CDREventName.participantJoined, participant, sessionId); + CDREventParticipant e = new CDREventParticipant(sessionId, participant); this.participants.put(participant.getParticipantPublicId(), e); - if (openviduConfig.isCdrEnabled()) this.logger.log(e); + if (openviduConfig.isCdrEnabled()) + this.logger.log(e); } public void recordParticipantLeft(Participant participant, String sessionId, String reason) { CDREvent e = this.participants.remove(participant.getParticipantPublicId()); - if (openviduConfig.isCdrEnabled()) this.logger.log(new CDREvent(CDREventName.participantLeft, e, reason)); + if (openviduConfig.isCdrEnabled()) + this.logger.log(new CDREventParticipant(e, reason)); } public void recordNewPublisher(Participant participant, String sessionId, MediaOptions mediaOptions) { - CDREvent publisher = new CDREvent(CDREventName.webrtcConnectionCreated, participant, sessionId, mediaOptions, - null, System.currentTimeMillis(), null); + CDREventWebrtcConnection publisher = new CDREventWebrtcConnection(sessionId, + participant.getParticipantPublicId(), mediaOptions, null); this.publications.put(participant.getParticipantPublicId(), publisher); - if (openviduConfig.isCdrEnabled()) this.logger.log(publisher); + if (openviduConfig.isCdrEnabled()) + this.logger.log(publisher); } public boolean stopPublisher(String participantPublicId, String reason) { - CDREvent publisher = this.publications.remove(participantPublicId); + CDREventWebrtcConnection publisher = this.publications.remove(participantPublicId); if (publisher != null) { - publisher = new CDREvent(CDREventName.webrtcConnectionDestroyed, publisher, reason); - if (openviduConfig.isCdrEnabled()) this.logger.log(publisher); + publisher = new CDREventWebrtcConnection(publisher, reason); + if (openviduConfig.isCdrEnabled()) + this.logger.log(publisher); return true; } return false; } public void recordNewSubscriber(Participant participant, String sessionId, String senderPublicId) { - CDREvent publisher = this.publications.get(senderPublicId); - CDREvent subscriber = new CDREvent(CDREventName.webrtcConnectionCreated, participant, sessionId, - publisher.getMediaOptions(), publisher.getParticipantPublicId(), System.currentTimeMillis(), null); + CDREventWebrtcConnection publisher = this.publications.get(senderPublicId); + CDREventWebrtcConnection subscriber = new CDREventWebrtcConnection(sessionId, + participant.getParticipantPublicId(), publisher.mediaOptions, senderPublicId); this.subscriptions.putIfAbsent(participant.getParticipantPublicId(), new ConcurrentSkipListSet<>()); this.subscriptions.get(participant.getParticipantPublicId()).add(subscriber); - if (openviduConfig.isCdrEnabled()) this.logger.log(subscriber); + if (openviduConfig.isCdrEnabled()) + this.logger.log(subscriber); } public boolean stopSubscriber(String participantPublicId, String senderPublicId, String reason) { - Set participantSubscriptions = this.subscriptions.get(participantPublicId); + Set participantSubscriptions = this.subscriptions.get(participantPublicId); if (participantSubscriptions != null) { - CDREvent subscription; - for (Iterator it = participantSubscriptions.iterator(); it.hasNext();) { + CDREventWebrtcConnection subscription; + for (Iterator it = participantSubscriptions.iterator(); it.hasNext();) { subscription = it.next(); - if (subscription.getReceivingFrom().equals(senderPublicId)) { + if (senderPublicId.equals(subscription.receivingFrom)) { it.remove(); - subscription = new CDREvent(CDREventName.webrtcConnectionDestroyed, subscription, reason); - if (openviduConfig.isCdrEnabled()) this.logger.log(subscription); + subscription = new CDREventWebrtcConnection(subscription, reason); + if (openviduConfig.isCdrEnabled()) + this.logger.log(subscription); return true; } } @@ -160,13 +172,18 @@ public class CallDetailRecord { } public void recordRecordingStarted(String sessionId, Recording recording) { - if (openviduConfig.isCdrEnabled()) this.logger.log(new CDREvent(CDREventName.recordingStarted, sessionId, recording, null)); + CDREventRecording recordingStartedEvent = new CDREventRecording(sessionId, recording); + this.recordings.putIfAbsent(recording.getId(), recordingStartedEvent); + if (openviduConfig.isCdrEnabled()) + this.logger.log(new CDREventRecording(sessionId, recording)); } public void recordRecordingStopped(String sessionId, Recording recording, String reason) { - if (openviduConfig.isCdrEnabled()) this.logger.log(new CDREvent(CDREventName.recordingStopped, sessionId, recording, this.finalReason(reason))); + CDREventRecording recordingStartedEvent = this.recordings.remove(recording.getId()); + if (openviduConfig.isCdrEnabled()) + this.logger.log(new CDREventRecording(recordingStartedEvent, this.finalReason(reason))); } - + private String finalReason(String reason) { if (lastParticipantLeftReasons.contains(reason)) { return "lastParticipantLeft"; diff --git a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java index 80abae51..d4ed154c 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java +++ b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java @@ -78,6 +78,9 @@ public class OpenviduConfig { @Value("${coturn.redis.connect-timeout}") private String coturnRedisConnectTimeout; + + @Value("${kms.stats-enabled}") + private boolean kmsStatsEnabled; @Value("#{'${spring.profiles.active:}'.length() > 0 ? '${spring.profiles.active:}'.split(',') : \"default\"}") private String springProfile; @@ -168,6 +171,10 @@ public class OpenviduConfig { public String getCoturnDatabaseDbname() { return this.coturnRedisDbname; } + + public boolean isKmsStatsEnabled() { + return this.kmsStatsEnabled; + } public ParticipantRole[] getRolesFromRecordingNotification() { ParticipantRole[] roles; 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 260d38f3..cad6d39b 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 @@ -23,6 +23,7 @@ public class Participant { 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 private String clientMetadata = ""; // Metadata provided on client side private String serverMetadata = ""; // Metadata provided on server side private Token token; // Token associated to this participant @@ -38,6 +39,7 @@ public class Participant { String location, String platform) { this.participantPrivatetId = participantPrivatetId; this.participantPublicId = participantPublicId; + this.createdAt = System.currentTimeMillis(); this.token = token; this.clientMetadata = clientMetadata; if (!token.getServerMetadata().isEmpty()) @@ -62,6 +64,10 @@ public class Participant { this.participantPublicId = participantPublicId; } + public Long getCreatedAt() { + return this.createdAt; + } + public String getClientMetadata() { return clientMetadata; } @@ -187,6 +193,7 @@ public class Participant { public JsonObject toJson() { JsonObject json = new JsonObject(); json.addProperty("connectionId", this.participantPublicId); + json.addProperty("createdAt", this.createdAt); json.addProperty("location", this.location); json.addProperty("platform", this.platform); json.addProperty("token", this.token.getToken()); diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Session.java b/openvidu-server/src/main/java/io/openvidu/server/core/Session.java index 71fa6249..84dd7233 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/Session.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/Session.java @@ -49,4 +49,6 @@ public interface Session { JsonObject withStatsToJson(); + Long getStartTime(); + } 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 41d42fda..fe72c336 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 @@ -64,8 +64,8 @@ public class SessionEventsHandler { ReentrantLock lock = new ReentrantLock(); - public void onSessionCreated(String sessionId) { - CDR.recordSessionCreated(sessionId); + public void onSessionCreated(Session session) { + CDR.recordSessionCreated(session); } public void onSessionClosed(String sessionId, String reason) { @@ -501,7 +501,8 @@ public class SessionEventsHandler { } else { // Send response to every other user in the session different than the affected // participant or the moderator - if (error == null && (moderator == null || !p.getParticipantPrivateId().equals(moderator.getParticipantPrivateId()))) { + if (error == null && (moderator == null + || !p.getParticipantPrivateId().equals(moderator.getParticipantPrivateId()))) { rpcNotificationService.sendNotification(p.getParticipantPrivateId(), ProtocolElements.STREAMPROPERTYCHANGED_METHOD, params); } @@ -509,8 +510,8 @@ public class SessionEventsHandler { } } - public void onFilterEventDispatched(String connectionId, String streamId, String filterType, String eventType, Object data, - Set participants, Set subscribedParticipants) { + public void onFilterEventDispatched(String connectionId, String streamId, String filterType, String eventType, + Object data, Set participants, Set subscribedParticipants) { JsonObject params = new JsonObject(); params.addProperty(ProtocolElements.FILTEREVENTLISTENER_CONNECTIONID_PARAM, connectionId); params.addProperty(ProtocolElements.FILTEREVENTLISTENER_STREAMID_PARAM, streamId); 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 4a55350d..7323084c 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 @@ -67,6 +67,7 @@ public abstract class SessionManager { protected ConcurrentMap sessions = new ConcurrentHashMap<>(); protected ConcurrentMap sessionProperties = new ConcurrentHashMap<>(); + protected ConcurrentMap sessionCreationTime = new ConcurrentHashMap<>(); protected ConcurrentMap> sessionidParticipantpublicidParticipant = new ConcurrentHashMap<>(); protected ConcurrentMap insecureUsers = new ConcurrentHashMap<>(); public ConcurrentMap> sessionidTokenTokenobj = new ConcurrentHashMap<>(); @@ -215,9 +216,10 @@ public abstract class SessionManager { return null; } - public void storeSessionId(String sessionId, SessionProperties sessionProperties) { + public void storeSessionId(String sessionId, Long creationTime, SessionProperties sessionProperties) { this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>()); this.sessionProperties.putIfAbsent(sessionId, sessionProperties); + this.sessionCreationTime.putIfAbsent(sessionId, creationTime); showTokens(); } @@ -269,6 +271,7 @@ public abstract class SessionManager { } } else { this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>()); + this.sessionCreationTime.putIfAbsent(sessionId, System.currentTimeMillis()); this.sessionidTokenTokenobj.putIfAbsent(sessionId, new ConcurrentHashMap<>()); this.sessionidTokenTokenobj.get(sessionId).putIfAbsent(token, new Token(token, ParticipantRole.PUBLISHER, "", @@ -461,6 +464,7 @@ public abstract class SessionManager { sessions.remove(session.getSessionId()); sessionProperties.remove(session.getSessionId()); + sessionCreationTime.remove(session.getSessionId()); sessionidParticipantpublicidParticipant.remove(session.getSessionId()); sessionidTokenTokenobj.remove(session.getSessionId()); 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 ebb08f9c..cd08799a 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 @@ -61,6 +61,7 @@ public class KurentoSession implements Session { private final ConcurrentMap participants = new ConcurrentHashMap<>(); private String sessionId; private SessionProperties sessionProperties; + private Long startTime; private MediaPipeline pipeline; private CountDownLatch pipelineLatch = new CountDownLatch(1); @@ -82,7 +83,7 @@ public class KurentoSession implements Session { public final ConcurrentHashMap publishedStreamIds = new ConcurrentHashMap<>(); - public KurentoSession(String sessionId, SessionProperties sessionProperties, KurentoClient kurentoClient, + public KurentoSession(String sessionId, Long startTime, SessionProperties sessionProperties, KurentoClient kurentoClient, KurentoSessionEventsHandler kurentoSessionHandler, boolean destroyKurentoClient, CallDetailRecord CDR, OpenviduConfig openviduConfig) { this.sessionId = sessionId; @@ -92,6 +93,7 @@ public class KurentoSession implements Session { this.kurentoSessionHandler = kurentoSessionHandler; this.CDR = CDR; this.openviduConfig = openviduConfig; + this.startTime = startTime; log.debug("New SESSION instance with id '{}'", sessionId); } @@ -297,6 +299,10 @@ public class KurentoSession implements Session { @Override public void onSuccess(MediaPipeline result) throws Exception { pipeline = result; + if (openviduConfig.isKmsStatsEnabled()) { + pipeline.setLatencyStats(true); + log.debug("SESSION {}: WebRTC server stats enabled", sessionId); + } pipelineLatch.countDown(); log.debug("SESSION {}: Created MediaPipeline", sessionId); } @@ -374,6 +380,7 @@ public class KurentoSession implements Session { private JsonObject sharedJson(Function toJsonFunction) { JsonObject json = new JsonObject(); json.addProperty("sessionId", this.sessionId); + json.addProperty("createdAt", this.startTime); json.addProperty("mediaMode", this.sessionProperties.mediaMode().name()); json.addProperty("recordingMode", this.sessionProperties.recordingMode().name()); json.addProperty("defaultRecordingLayout", this.sessionProperties.defaultRecordingLayout().name()); @@ -397,4 +404,9 @@ public class KurentoSession implements Session { return this.publishedStreamIds.get(streamId); } + @Override + public Long getStartTime() { + return this.startTime; + } + } 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 b95f678d..3113e251 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 @@ -474,8 +474,9 @@ public class KurentoSessionManager extends SessionManager { "Session '" + sessionId + "' already exists"); } this.kurentoClient = kcProvider.getKurentoClient(kcSessionInfo); - session = new KurentoSession(sessionId, sessionProperties, kurentoClient, kurentoSessionEventsHandler, - kcProvider.destroyWhenUnused(), this.CDR, this.openviduConfig); + session = new KurentoSession(sessionId, this.sessionCreationTime.get(sessionId), sessionProperties, + kurentoClient, kurentoSessionEventsHandler, kcProvider.destroyWhenUnused(), this.CDR, + this.openviduConfig); KurentoSession oldSession = (KurentoSession) sessions.putIfAbsent(sessionId, session); if (oldSession != null) { @@ -488,7 +489,7 @@ public class KurentoSessionManager extends SessionManager { } log.warn("No session '{}' exists yet. Created one using KurentoClient '{}'.", sessionId, kcName); - sessionEventsHandler.onSessionCreated(sessionId); + sessionEventsHandler.onSessionCreated(session); } @Override diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/endpoint/MediaEndpoint.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/endpoint/MediaEndpoint.java index 4189bcaf..9854f624 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/endpoint/MediaEndpoint.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/endpoint/MediaEndpoint.java @@ -40,6 +40,7 @@ import org.kurento.client.WebRtcEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -495,6 +496,9 @@ public abstract class MediaEndpoint { json.add("receivedCandidates", new GsonBuilder().create().toJsonTree(this.receivedCandidateList)); json.addProperty("localCandidate", this.selectedLocalIceCandidate); json.addProperty("remoteCandidate", this.selectedRemoteIceCandidate); + if (openviduConfig.isKmsStatsEnabled()) { + json.addProperty("serverStats", new Gson().toJson(this.webEndpoint.getStats())); + } JsonArray jsonArray = new JsonArray(); for (KmsEvent event : this.kmsEvents) { diff --git a/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java b/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java index a50463db..59f649ed 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java +++ b/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java @@ -133,9 +133,11 @@ public class SessionRestController { sessionManager.sessionidTokenTokenobj.putIfAbsent(sessionId, new ConcurrentHashMap<>()); } - sessionManager.storeSessionId(sessionId, sessionProperties); + Long creationTime = System.currentTimeMillis(); + sessionManager.storeSessionId(sessionId, creationTime, sessionProperties); JsonObject responseJson = new JsonObject(); responseJson.addProperty("id", sessionId); + responseJson.addProperty("createdAt", creationTime); return new ResponseEntity<>(responseJson.toString(), getResponseHeaders(), HttpStatus.OK); } diff --git a/openvidu-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/openvidu-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1d0dda7f..cd4a3052 100644 --- a/openvidu-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/openvidu-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -6,6 +6,12 @@ "description": "KMS URL's to which OpenVidu Server will try to connect. They are tested in order until a valid one is found", "defaultValue": "[\"ws://localhost:8888/kurento\"]" }, + { + "name": "kms.stats-enabled", + "type": "java.lang.Boolean", + "description": "Whether to activate the KMS WebRTC statistics feature or not. This may increase the processor consumption", + "defaultValue": false + }, { "name": "openvidu.secret", "type": "java.lang.String", @@ -69,7 +75,7 @@ "name": "openvidu.streams.video.max-recv-bandwidth", "type": "java.lang.Integer", "description": "Maximum video bandwidth sent from clients to OpenVidu Server, in kbps. 0 means unconstrained", - "defaultValue": 600 + "defaultValue": 1000 }, { "name": "openvidu.streams.video.min-recv-bandwidth", @@ -81,7 +87,7 @@ "name": "openvidu.streams.video.max-send-bandwidth", "type": "java.lang.Integer", "description": "Maximum video bandwidth sent from OpenVidu Server to clients, in kbps. 0 means unconstrained", - "defaultValue": 600 + "defaultValue": 1000 }, { "name": "openvidu.streams.video.min-send-bandwidth", diff --git a/openvidu-server/src/main/resources/application.properties b/openvidu-server/src/main/resources/application.properties index c909cf51..676c9071 100644 --- a/openvidu-server/src/main/resources/application.properties +++ b/openvidu-server/src/main/resources/application.properties @@ -20,12 +20,13 @@ openvidu.recording.public-access: false openvidu.recording.notification: publisher_moderator openvidu.recording.custom-layout: /opt/openvidu/custom-layout -openvidu.streams.video.max-recv-bandwidth: 600 +openvidu.streams.video.max-recv-bandwidth: 1000 openvidu.streams.video.min-recv-bandwidth: 300 -openvidu.streams.video.max-send-bandwidth: 600 +openvidu.streams.video.max-send-bandwidth: 1000 openvidu.streams.video.min-send-bandwidth: 300 kms.uris: [\"ws://localhost:8888/kurento\"] +kms.stats-enabled: false coturn.redis.ip: 127.0.0.1 coturn.redis.dbname: 0