mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: CDR refactoring. Session and Participant createdAt property
parent
41a53c79f8
commit
c75252508c
|
@ -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<CDREvent> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<CDREventWebrtcConnection> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, CDREvent> sessions = new ConcurrentHashMap<>();
|
||||
private Map<String, CDREvent> participants = new ConcurrentHashMap<>();
|
||||
private Map<String, CDREvent> publications = new ConcurrentHashMap<>();
|
||||
private Map<String, Set<CDREvent>> subscriptions = new ConcurrentHashMap<>();
|
||||
|
||||
private final List<String> lastParticipantLeftReasons = Arrays.asList(new String[] {"disconnect", "forceDisconnectByUser", "forceDisconnectByServer", "networkDisconnect"});
|
||||
private Map<String, CDREventSession> sessions = new ConcurrentHashMap<>();
|
||||
private Map<String, CDREventParticipant> participants = new ConcurrentHashMap<>();
|
||||
private Map<String, CDREventWebrtcConnection> publications = new ConcurrentHashMap<>();
|
||||
private Map<String, Set<CDREventWebrtcConnection>> subscriptions = new ConcurrentHashMap<>();
|
||||
private Map<String, CDREventRecording> recordings = new ConcurrentHashMap<>();
|
||||
|
||||
private final List<String> 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<CDREvent> participantSubscriptions = this.subscriptions.get(participantPublicId);
|
||||
Set<CDREventWebrtcConnection> participantSubscriptions = this.subscriptions.get(participantPublicId);
|
||||
if (participantSubscriptions != null) {
|
||||
CDREvent subscription;
|
||||
for (Iterator<CDREvent> it = participantSubscriptions.iterator(); it.hasNext();) {
|
||||
CDREventWebrtcConnection subscription;
|
||||
for (Iterator<CDREventWebrtcConnection> 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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -49,4 +49,6 @@ public interface Session {
|
|||
|
||||
JsonObject withStatsToJson();
|
||||
|
||||
Long getStartTime();
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Participant> participants, Set<String> subscribedParticipants) {
|
||||
public void onFilterEventDispatched(String connectionId, String streamId, String filterType, String eventType,
|
||||
Object data, Set<Participant> participants, Set<String> subscribedParticipants) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty(ProtocolElements.FILTEREVENTLISTENER_CONNECTIONID_PARAM, connectionId);
|
||||
params.addProperty(ProtocolElements.FILTEREVENTLISTENER_STREAMID_PARAM, streamId);
|
||||
|
|
|
@ -67,6 +67,7 @@ public abstract class SessionManager {
|
|||
|
||||
protected ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();
|
||||
protected ConcurrentMap<String, SessionProperties> sessionProperties = new ConcurrentHashMap<>();
|
||||
protected ConcurrentMap<String, Long> sessionCreationTime = new ConcurrentHashMap<>();
|
||||
protected ConcurrentMap<String, ConcurrentHashMap<String, Participant>> sessionidParticipantpublicidParticipant = new ConcurrentHashMap<>();
|
||||
protected ConcurrentMap<String, Boolean> insecureUsers = new ConcurrentHashMap<>();
|
||||
public ConcurrentMap<String, ConcurrentHashMap<String, Token>> 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());
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ public class KurentoSession implements Session {
|
|||
private final ConcurrentMap<String, KurentoParticipant> 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<String, String> 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<KurentoParticipant, JsonObject> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue