openvidu-server: session summary

pull/255/head
pabloFuente 2019-02-28 16:11:13 +01:00
parent 84f228a0e4
commit 86cf422c2d
21 changed files with 573 additions and 86 deletions

View File

@ -49,6 +49,7 @@ import io.openvidu.client.OpenViduException;
import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.OpenViduException.Code;
import io.openvidu.server.cdr.CDRLoggerFile; import io.openvidu.server.cdr.CDRLoggerFile;
import io.openvidu.server.cdr.CallDetailRecord; import io.openvidu.server.cdr.CallDetailRecord;
import io.openvidu.server.config.HttpHandshakeInterceptor;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.core.SessionEventsHandler; import io.openvidu.server.core.SessionEventsHandler;
import io.openvidu.server.core.SessionManager; import io.openvidu.server.core.SessionManager;
@ -166,7 +167,8 @@ public class OpenViduServer implements JsonRpcConfigurer {
@Override @Override
public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) { 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 { private static String getContainerIp() throws IOException, InterruptedException {

View File

@ -51,4 +51,16 @@ public class CDREventEnd extends CDREvent {
return json; return json;
} }
public Long getStartTime() {
return startTime;
}
public Integer getDuration() {
return duration;
}
public String getReason() {
return reason;
}
} }

View File

@ -32,9 +32,9 @@ public class CDREventParticipant extends CDREventEnd {
} }
// participantLeft // participantLeft
public CDREventParticipant(CDREvent event, String reason) { public CDREventParticipant(CDREventParticipant event, String reason) {
super(CDREventName.participantLeft, event.getSessionId(), event.getTimestamp(), reason); super(CDREventName.participantLeft, event.getSessionId(), event.getTimestamp(), reason);
this.participant = ((CDREventParticipant) event).participant; this.participant = event.participant;
} }
@Override @Override
@ -46,4 +46,8 @@ public class CDREventParticipant extends CDREventEnd {
return json; return json;
} }
public Participant getParticipant() {
return this.participant;
}
} }

View File

@ -33,9 +33,9 @@ public class CDREventRecording extends CDREventEnd {
} }
// recordingStopped // recordingStopped
public CDREventRecording(CDREvent event, String reason) { public CDREventRecording(CDREventRecording event, Recording recording, String reason) {
super(CDREventName.recordingStopped, event.getSessionId(), event.getTimestamp(), reason); super(CDREventName.recordingStopped, event.getSessionId(), event.getTimestamp(), reason);
this.recording = ((CDREventRecording) event).recording; this.recording = recording;
} }
@Override @Override
@ -44,7 +44,8 @@ public class CDREventRecording extends CDREventEnd {
json.addProperty("id", this.recording.getId()); json.addProperty("id", this.recording.getId());
json.addProperty("name", this.recording.getName()); json.addProperty("name", this.recording.getName());
json.addProperty("outputMode", this.recording.getOutputMode().name()); 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("resolution", this.recording.getResolution());
json.addProperty("recordingLayout", this.recording.getRecordingLayout().name()); json.addProperty("recordingLayout", this.recording.getRecordingLayout().name());
if (RecordingLayout.CUSTOM.equals(this.recording.getRecordingLayout()) if (RecordingLayout.CUSTOM.equals(this.recording.getRecordingLayout())
@ -59,4 +60,8 @@ public class CDREventRecording extends CDREventEnd {
return json; return json;
} }
public Recording getRecording() {
return this.recording;
}
} }

View File

@ -30,8 +30,13 @@ public class CDREventSession extends CDREventEnd {
} }
// sessionDestroyed // sessionDestroyed
public CDREventSession(CDREvent event, String reason) { public CDREventSession(CDREventSession event, String reason) {
super(CDREventName.sessionDestroyed, event.getSessionId(), event.getTimestamp(), reason); super(CDREventName.sessionDestroyed, event.getSessionId(), event.getTimestamp(), reason);
this.session = event.session;
}
public Session getSession() {
return this.session;
} }
} }

View File

@ -20,35 +20,43 @@ package io.openvidu.server.cdr;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.openvidu.server.core.MediaOptions; import io.openvidu.server.core.MediaOptions;
import io.openvidu.server.core.Participant;
public class CDREventWebrtcConnection extends CDREventEnd implements Comparable<CDREventWebrtcConnection> { public class CDREventWebrtcConnection extends CDREventEnd implements Comparable<CDREventWebrtcConnection> {
String participantId; String streamId;
Participant participant;
MediaOptions mediaOptions; MediaOptions mediaOptions;
String receivingFrom; String receivingFrom;
// webrtcConnectionCreated // webrtcConnectionCreated
public CDREventWebrtcConnection(String sessionId, String participantId, MediaOptions mediaOptions, public CDREventWebrtcConnection(String sessionId, String streamId, Participant participant,
String receivingFrom, Long timestamp) { MediaOptions mediaOptions, String receivingFrom, Long timestamp) {
super(CDREventName.webrtcConnectionCreated, sessionId, timestamp); super(CDREventName.webrtcConnectionCreated, sessionId, timestamp);
this.participantId = participantId; this.streamId = streamId;
this.participant = participant;
this.mediaOptions = mediaOptions; this.mediaOptions = mediaOptions;
this.receivingFrom = receivingFrom; this.receivingFrom = receivingFrom;
} }
// webrtcConnectionDestroyed // webrtcConnectionDestroyed
public CDREventWebrtcConnection(CDREvent event, String reason) { public CDREventWebrtcConnection(CDREventWebrtcConnection event, String reason) {
super(CDREventName.webrtcConnectionDestroyed, event.getSessionId(), event.getTimestamp(), reason); super(CDREventName.webrtcConnectionDestroyed, event.getSessionId(), event.getTimestamp(), reason);
CDREventWebrtcConnection e = (CDREventWebrtcConnection) event; this.streamId = event.streamId;
this.participantId = e.participantId; this.participant = event.participant;
this.mediaOptions = e.mediaOptions; this.mediaOptions = event.mediaOptions;
this.receivingFrom = e.receivingFrom; this.receivingFrom = event.receivingFrom;
}
public Participant getParticipant() {
return this.participant;
} }
@Override @Override
public JsonObject toJson() { public JsonObject toJson() {
JsonObject json = super.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) { if (this.receivingFrom != null) {
json.addProperty("connection", "INBOUND"); json.addProperty("connection", "INBOUND");
json.addProperty("receivingFrom", this.receivingFrom); json.addProperty("receivingFrom", this.receivingFrom);
@ -66,7 +74,7 @@ public class CDREventWebrtcConnection extends CDREventEnd implements Comparable<
} }
public int compareTo(CDREventWebrtcConnection other) { 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 != null && other.receivingFrom != null) {
if (this.receivingFrom.equals(other.receivingFrom)) { if (this.receivingFrom.equals(other.receivingFrom)) {
return 0; return 0;

View File

@ -18,6 +18,7 @@
package io.openvidu.server.cdr; package io.openvidu.server.cdr;
import io.openvidu.server.kurento.endpoint.KmsEvent; import io.openvidu.server.kurento.endpoint.KmsEvent;
import io.openvidu.server.summary.SessionSummary;
public interface CDRLogger { public interface CDRLogger {
@ -25,6 +26,8 @@ public interface CDRLogger {
public void log(KmsEvent event); public void log(KmsEvent event);
public void log(SessionSummary sessionSummary);
public boolean canBeDisabled(); public boolean canBeDisabled();
} }

View File

@ -21,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.openvidu.server.kurento.endpoint.KmsEvent; import io.openvidu.server.kurento.endpoint.KmsEvent;
import io.openvidu.server.summary.SessionSummary;
public class CDRLoggerFile implements CDRLogger { public class CDRLoggerFile implements CDRLogger {
@ -35,6 +36,10 @@ public class CDRLoggerFile implements CDRLogger {
public void log(KmsEvent event) { public void log(KmsEvent event) {
} }
@Override
public void log(SessionSummary sessionSummary) {
}
@Override @Override
public boolean canBeDisabled() { public boolean canBeDisabled() {
return true; return true;

View File

@ -30,9 +30,11 @@ import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.core.MediaOptions; import io.openvidu.server.core.MediaOptions;
import io.openvidu.server.core.Participant; import io.openvidu.server.core.Participant;
import io.openvidu.server.core.Session; import io.openvidu.server.core.Session;
import io.openvidu.server.core.SessionManager;
import io.openvidu.server.kurento.endpoint.KmsEvent; import io.openvidu.server.kurento.endpoint.KmsEvent;
import io.openvidu.server.recording.Recording; import io.openvidu.server.recording.Recording;
import io.openvidu.server.recording.service.RecordingManager; import io.openvidu.server.recording.service.RecordingManager;
import io.openvidu.server.summary.SessionSummary;
/** /**
* CDR logger to register all information of a Session. * CDR logger to register all information of a Session.
@ -83,6 +85,9 @@ import io.openvidu.server.recording.service.RecordingManager;
*/ */
public class CallDetailRecord { public class CallDetailRecord {
@Autowired
protected SessionManager sessionManager;
@Autowired @Autowired
protected OpenviduConfig openviduConfig; protected OpenviduConfig openviduConfig;
@ -109,9 +114,14 @@ public class CallDetailRecord {
} }
public void recordSessionDestroyed(String sessionId, String reason) { public void recordSessionDestroyed(String sessionId, String reason) {
CDREvent e = this.sessions.remove(sessionId); CDREventSession e = this.sessions.remove(sessionId);
if (e != null) { 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) { public void recordParticipantLeft(Participant participant, String sessionId, String reason) {
CDREvent e = this.participants.remove(participant.getParticipantPublicId()); CDREventParticipant e = this.participants.remove(participant.getParticipantPublicId());
this.log(new CDREventParticipant(e, reason)); 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, public void recordNewPublisher(Participant participant, String sessionId, String streamId,
Long timestamp) { MediaOptions mediaOptions, Long timestamp) {
CDREventWebrtcConnection publisher = new CDREventWebrtcConnection(sessionId, CDREventWebrtcConnection publisher = new CDREventWebrtcConnection(sessionId, streamId, participant,
participant.getParticipantPublicId(), mediaOptions, null, timestamp); mediaOptions, null, timestamp);
this.publications.put(participant.getParticipantPublicId(), publisher); this.publications.put(participant.getParticipantPublicId(), publisher);
this.log(publisher); this.log(publisher);
} }
public boolean stopPublisher(String participantPublicId, String reason) { public void stopPublisher(String participantPublicId, String streamId, String reason) {
CDREventWebrtcConnection publisher = this.publications.remove(participantPublicId); CDREventWebrtcConnection eventPublisherEnd = this.publications.remove(participantPublicId);
if (publisher != null) { if (eventPublisherEnd != null) {
publisher = new CDREventWebrtcConnection(publisher, reason); eventPublisherEnd = new CDREventWebrtcConnection(eventPublisherEnd, reason);
this.log(publisher); this.log(eventPublisherEnd);
return true;
// 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 publisher = this.publications.get(senderPublicId);
CDREventWebrtcConnection subscriber = new CDREventWebrtcConnection(sessionId, CDREventWebrtcConnection subscriber = new CDREventWebrtcConnection(sessionId, streamId, participant,
participant.getParticipantPublicId(), publisher.mediaOptions, senderPublicId, timestamp); publisher.mediaOptions, senderPublicId, timestamp);
this.subscriptions.putIfAbsent(participant.getParticipantPublicId(), new ConcurrentSkipListSet<>()); this.subscriptions.putIfAbsent(participant.getParticipantPublicId(), new ConcurrentSkipListSet<>());
this.subscriptions.get(participant.getParticipantPublicId()).add(subscriber); this.subscriptions.get(participant.getParticipantPublicId()).add(subscriber);
this.log(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<CDREventWebrtcConnection> participantSubscriptions = this.subscriptions.get(participantPublicId); Set<CDREventWebrtcConnection> participantSubscriptions = this.subscriptions.get(participantPublicId);
if (participantSubscriptions != null) { if (participantSubscriptions != null) {
CDREventWebrtcConnection subscription; CDREventWebrtcConnection eventSubscriberEnd;
for (Iterator<CDREventWebrtcConnection> it = participantSubscriptions.iterator(); it.hasNext();) { for (Iterator<CDREventWebrtcConnection> it = participantSubscriptions.iterator(); it.hasNext();) {
subscription = it.next(); eventSubscriberEnd = it.next();
if (senderPublicId.equals(subscription.receivingFrom)) { if (senderPublicId.equals(eventSubscriberEnd.receivingFrom)) {
it.remove(); it.remove();
subscription = new CDREventWebrtcConnection(subscription, reason); eventSubscriberEnd = new CDREventWebrtcConnection(eventSubscriberEnd, reason);
this.log(subscription); this.log(eventSubscriberEnd);
return true;
// 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) { public void recordRecordingStarted(String sessionId, Recording recording) {
@ -178,11 +199,12 @@ public class CallDetailRecord {
public void recordRecordingStopped(String sessionId, Recording recording, String reason) { public void recordRecordingStopped(String sessionId, Recording recording, String reason) {
CDREventRecording recordingStartedEvent = this.recordings.remove(recording.getId()); 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) { // Summary: update ended recording
this.log(event); sessionManager.getAccumulatedRecordings(sessionId).add(recordingStoppedEvent);
} }
private void log(CDREvent event) { 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 -> { this.loggers.forEach(logger -> {
logger.log(event); logger.log(event);
}); });
} }
public void log(SessionSummary sessionSummary) {
this.loggers.forEach(logger -> {
logger.log(sessionSummary);
});
}
} }

View File

@ -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<String, Object> 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) {
}
}

View File

@ -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<String, ParticipantSummary> 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<String, ParticipantSummary> 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;
}
}

View File

@ -21,6 +21,7 @@ import com.google.gson.JsonObject;
public class Participant { 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 participantPrivatetId; // ID to identify the user on server (org.kurento.jsonrpc.Session.id)
private String participantPublicId; // ID to identify the user on clients private String participantPublicId; // ID to identify the user on clients
private Long createdAt; // Timestamp when this connection was established private Long createdAt; // Timestamp when this connection was established
@ -35,8 +36,9 @@ public class Participant {
private final String METADATA_SEPARATOR = "%/%"; private final String METADATA_SEPARATOR = "%/%";
public Participant(String participantPrivatetId, String participantPublicId, Token token, String clientMetadata, public Participant(String finalUserId, String participantPrivatetId, String participantPublicId, Token token,
String location, String platform, Long createdAt) { String clientMetadata, String location, String platform, Long createdAt) {
this.finalUserId = finalUserId;
this.participantPrivatetId = participantPrivatetId; this.participantPrivatetId = participantPrivatetId;
this.participantPublicId = participantPublicId; this.participantPublicId = participantPublicId;
if (createdAt != null) { if (createdAt != null) {
@ -52,6 +54,10 @@ public class Participant {
this.platform = platform; this.platform = platform;
} }
public String getFinalUserId() {
return finalUserId;
}
public String getParticipantPrivateId() { public String getParticipantPrivateId() {
return participantPrivatetId; return participantPrivatetId;
} }

View File

@ -186,6 +186,10 @@ public class SessionEventsHandler {
// leaving the session // leaving the session
rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); 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, public void onPublishMedia(Participant participant, String streamId, Long createdAt, String sessionId,

View File

@ -19,8 +19,10 @@ package io.openvidu.server.core;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors; 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.OpenViduRole;
import io.openvidu.java.client.SessionProperties; import io.openvidu.java.client.SessionProperties;
import io.openvidu.server.OpenViduServer; import io.openvidu.server.OpenViduServer;
import io.openvidu.server.cdr.CDREventRecording;
import io.openvidu.server.cdr.CallDetailRecord; import io.openvidu.server.cdr.CallDetailRecord;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.coturn.CoturnCredentialsService; import io.openvidu.server.coturn.CoturnCredentialsService;
@ -73,6 +76,8 @@ public abstract class SessionManager {
protected ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>(); protected ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();
protected ConcurrentMap<String, Session> sessionsNotActive = new ConcurrentHashMap<>(); protected ConcurrentMap<String, Session> sessionsNotActive = new ConcurrentHashMap<>();
protected ConcurrentMap<String, ConcurrentHashMap<String, Participant>> sessionidParticipantpublicidParticipant = new ConcurrentHashMap<>(); protected ConcurrentMap<String, ConcurrentHashMap<String, Participant>> sessionidParticipantpublicidParticipant = new ConcurrentHashMap<>();
protected ConcurrentMap<String, ConcurrentHashMap<String, FinalUser>> sessionidFinalUsers = new ConcurrentHashMap<>();
protected ConcurrentMap<String, ConcurrentLinkedQueue<CDREventRecording>> sessionidAccumulatedRecordings = new ConcurrentHashMap<>();
protected ConcurrentMap<String, Boolean> insecureUsers = new ConcurrentHashMap<>(); protected ConcurrentMap<String, Boolean> insecureUsers = new ConcurrentHashMap<>();
public ConcurrentMap<String, ConcurrentHashMap<String, Token>> sessionidTokenTokenobj = new ConcurrentHashMap<>(); public ConcurrentMap<String, ConcurrentHashMap<String, Token>> sessionidTokenTokenobj = new ConcurrentHashMap<>();
@ -214,6 +219,22 @@ public abstract class SessionManager {
"No participant with private id '" + participantPrivateId + "' was found"); "No participant with private id '" + participantPrivateId + "' was found");
} }
public Map<String, FinalUser> getFinalUsers(String sessionId) {
return this.sessionidFinalUsers.get(sessionId);
}
public Map<String, FinalUser> removeFinalUsers(String sessionId) {
return this.sessionidFinalUsers.remove(sessionId);
}
public Collection<CDREventRecording> getAccumulatedRecordings(String sessionId) {
return this.sessionidAccumulatedRecordings.get(sessionId);
}
public Collection<CDREventRecording> removeAccumulatedRecordings(String sessionId) {
return this.sessionidAccumulatedRecordings.remove(sessionId);
}
public MediaOptions generateMediaOptions(Request<JsonObject> request) { public MediaOptions generateMediaOptions(Request<JsonObject> request) {
return null; return null;
} }
@ -222,6 +243,10 @@ public abstract class SessionManager {
Session sessionNotActive = new Session(sessionId, sessionProperties, CDR, openviduConfig, recordingManager); Session sessionNotActive = new Session(sessionId, sessionProperties, CDR, openviduConfig, recordingManager);
this.sessionsNotActive.put(sessionId, sessionNotActive); this.sessionsNotActive.put(sessionId, sessionNotActive);
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>()); this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>());
this.sessionidFinalUsers.putIfAbsent(sessionId, new ConcurrentHashMap<>());
if (this.openviduConfig.isRecordingModuleEnabled()) {
this.sessionidAccumulatedRecordings.putIfAbsent(sessionId, new ConcurrentLinkedQueue<>());
}
showTokens(); showTokens();
return sessionNotActive; return sessionNotActive;
} }
@ -272,6 +297,10 @@ public abstract class SessionManager {
} }
} else { } else {
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>()); 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.putIfAbsent(sessionId, new ConcurrentHashMap<>());
this.sessionidTokenTokenobj.get(sessionId).putIfAbsent(token, this.sessionidTokenTokenobj.get(sessionId).putIfAbsent(token,
new Token(token, OpenViduRole.PUBLISHER, "", new Token(token, OpenViduRole.PUBLISHER, "",
@ -321,16 +350,30 @@ public abstract class SessionManager {
} }
public Participant newParticipant(String sessionId, String participantPrivatetId, Token token, 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) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
String participantPublicId = this.generateRandomChain(); String participantPublicId = this.generateRandomChain();
Participant p = new Participant(participantPrivatetId, participantPublicId, token, clientMetadata, location, Participant p = new Participant(finalUserId, participantPrivatetId, participantPublicId, token,
platform, null); clientMetadata, location, platform, null);
while (this.sessionidParticipantpublicidParticipant.get(sessionId).putIfAbsent(participantPublicId, while (this.sessionidParticipantpublicidParticipant.get(sessionId).putIfAbsent(participantPublicId,
p) != null) { p) != null) {
participantPublicId = this.generateRandomChain(); participantPublicId = this.generateRandomChain();
p.setParticipantPublicId(participantPublicId); 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; return p;
} else { } else {
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, sessionId); 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, public Participant newRecorderParticipant(String sessionId, String participantPrivatetId, Token token,
String clientMetadata) { String clientMetadata) {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { 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); token, clientMetadata, null, null, null);
this.sessionidParticipantpublicidParticipant.get(sessionId) this.sessionidParticipantpublicidParticipant.get(sessionId)
.put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p); .put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p);
@ -445,6 +488,8 @@ public abstract class SessionManager {
sessions.remove(session.getSessionId()); sessions.remove(session.getSessionId());
sessionsNotActive.remove(session.getSessionId()); sessionsNotActive.remove(session.getSessionId());
sessionidParticipantpublicidParticipant.remove(session.getSessionId()); sessionidParticipantpublicidParticipant.remove(session.getSessionId());
sessionidFinalUsers.remove(session.getSessionId());
sessionidAccumulatedRecordings.remove(session.getSessionId());
sessionidTokenTokenobj.remove(session.getSessionId()); sessionidTokenTokenobj.remove(session.getSessionId());
log.warn("Session '{}' removed and closed", session.getSessionId()); log.warn("Session '{}' removed and closed", session.getSessionId());

View File

@ -77,9 +77,9 @@ public class KurentoParticipant extends Participant {
public KurentoParticipant(Participant participant, KurentoSession kurentoSession, InfoHandler infoHandler, public KurentoParticipant(Participant participant, KurentoSession kurentoSession, InfoHandler infoHandler,
CallDetailRecord CDR, OpenviduConfig openviduConfig, RecordingManager recordingManager) { CallDetailRecord CDR, OpenviduConfig openviduConfig, RecordingManager recordingManager) {
super(participant.getParticipantPrivateId(), participant.getParticipantPublicId(), participant.getToken(), super(participant.getFinalUserId(), participant.getParticipantPrivateId(), participant.getParticipantPublicId(),
participant.getClientMetadata(), participant.getLocation(), participant.getPlatform(), participant.getToken(), participant.getClientMetadata(), participant.getLocation(),
participant.getCreatedAt()); participant.getPlatform(), participant.getCreatedAt());
this.infoHandler = infoHandler; this.infoHandler = infoHandler;
this.CDR = CDR; this.CDR = CDR;
this.openviduConfig = openviduConfig; this.openviduConfig = openviduConfig;
@ -185,8 +185,8 @@ public class KurentoParticipant extends Participant {
this.recordingManager.startOneIndividualStreamRecording(session, null, null, this); this.recordingManager.startOneIndividualStreamRecording(session, null, null, this);
} }
CDR.recordNewPublisher(this, this.session.getSessionId(), this.publisher.getMediaOptions(), CDR.recordNewPublisher(this, session.getSessionId(), publisher.getStreamId(), publisher.getMediaOptions(),
this.publisher.createdAt()); publisher.createdAt());
return sdpResponse; return sdpResponse;
} }
@ -270,8 +270,8 @@ public class KurentoParticipant extends Participant {
senderName, this.session.getSessionId()); senderName, this.session.getSessionId());
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(this.getParticipantPublicId())) { if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(this.getParticipantPublicId())) {
CDR.recordNewSubscriber(this, this.session.getSessionId(), sender.getParticipantPublicId(), CDR.recordNewSubscriber(this, this.session.getSessionId(), sender.getPublisherStreamId(),
subscriber.createdAt()); sender.getParticipantPublicId(), subscriber.createdAt());
} }
return sdpAnswer; return sdpAnswer;
@ -386,10 +386,10 @@ public class KurentoParticipant extends Participant {
} }
releaseElement(getParticipantPublicId(), publisher.getEndpoint()); releaseElement(getParticipantPublicId(), publisher.getEndpoint());
this.streaming = false; this.streaming = false;
publisher = null;
this.session.deregisterPublisher(); this.session.deregisterPublisher();
CDR.stopPublisher(this.getParticipantPublicId(), reason); CDR.stopPublisher(this.getParticipantPublicId(), publisher.getStreamId(), reason);
publisher = null;
} else { } else {
log.warn("PARTICIPANT {}: Trying to release publisher endpoint but is null", getParticipantPublicId()); 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()); releaseElement(senderName, subscriber.getEndpoint());
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(this.getParticipantPublicId())) { if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(this.getParticipantPublicId())) {
CDR.stopSubscriber(this.getParticipantPublicId(), senderName, reason); CDR.stopSubscriber(this.getParticipantPublicId(), senderName, subscriber.getStreamId(), reason);
} }
} else { } else {
@ -442,7 +442,7 @@ public class KurentoParticipant extends Participant {
KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(), KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(),
endpoint.createdAt()); endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
}); });
@ -454,7 +454,7 @@ public class KurentoParticipant extends Participant {
KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(), KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(),
endpoint.createdAt()); endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
}); });
@ -464,7 +464,7 @@ public class KurentoParticipant extends Participant {
+ typeOfEndpoint + ") | timestamp: " + event.getTimestamp(); + typeOfEndpoint + ") | timestamp: " + event.getTimestamp();
KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
}); });
@ -475,7 +475,7 @@ public class KurentoParticipant extends Participant {
+ " | timestamp: " + event.getTimestamp(); + " | timestamp: " + event.getTimestamp();
KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
}); });
@ -488,7 +488,7 @@ public class KurentoParticipant extends Participant {
+ endpoint.selectedRemoteIceCandidate + " | timestamp: " + event.getTimestamp(); + endpoint.selectedRemoteIceCandidate + " | timestamp: " + event.getTimestamp();
KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
}); });
@ -500,7 +500,7 @@ public class KurentoParticipant extends Participant {
KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(), KmsEvent kmsEvent = new KmsMediaEvent(event, endpoint.getEndpointName(), event.getMediaType(),
endpoint.createdAt()); endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
}); });
@ -513,7 +513,7 @@ public class KurentoParticipant extends Participant {
+ event.getTimestamp(); + event.getTimestamp();
KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.info(msg); log.info(msg);
// } // }
@ -525,7 +525,7 @@ public class KurentoParticipant extends Participant {
+ " | timestamp: " + event.getTimestamp(); + " | timestamp: " + event.getTimestamp();
KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt()); KmsEvent kmsEvent = new KmsEvent(event, endpoint.getEndpointName(), endpoint.createdAt());
endpoint.kmsEvents.add(kmsEvent); endpoint.kmsEvents.add(kmsEvent);
this.CDR.recordKmsEvent(kmsEvent); this.CDR.log(kmsEvent);
this.infoHandler.sendInfo(msg); this.infoHandler.sendInfo(msg);
log.error(msg); log.error(msg);
}); });

View File

@ -136,10 +136,6 @@ public class KurentoSession extends Session {
this.removeParticipant(participant, reason); this.removeParticipant(participant, reason);
participant.close(reason, true); participant.close(reason, true);
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(participant.getParticipantPublicId())) {
CDR.recordParticipantLeft(participant, participant.getSession().getSessionId(), reason);
}
} }
@Override @Override

View File

@ -77,9 +77,9 @@ public class KurentoSessionManager extends SessionManager {
KurentoClientSessionInfo kcSessionInfo = new OpenViduKurentoClientSessionInfo( KurentoClientSessionInfo kcSessionInfo = new OpenViduKurentoClientSessionInfo(
participant.getParticipantPrivateId(), sessionId); 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 // First user connecting to the session
Session sessionNotActive = sessionsNotActive.remove(sessionId); Session sessionNotActive = sessionsNotActive.remove(sessionId);
@ -94,21 +94,20 @@ public class KurentoSessionManager extends SessionManager {
createSession(sessionNotActive, kcSessionInfo); createSession(sessionNotActive, kcSessionInfo);
} }
session = (KurentoSession) sessions.get(sessionId); kSession = (KurentoSession) sessions.get(sessionId);
if (session == null) { if (kSession == null) {
log.warn("Session '{}' not found"); log.warn("Session '{}' not found");
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "Session '" + sessionId throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "Session '" + sessionId
+ "' was not found, must be created before '" + sessionId + "' can join"); + "' 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(), log.warn("'{}' is trying to join session '{}' but it is closing", participant.getParticipantPublicId(),
sessionId); sessionId);
throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "'" + participant.getParticipantPublicId() throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "'" + participant.getParticipantPublicId()
+ "' is trying to join session '" + sessionId + "' but it is closing"); + "' is trying to join session '" + sessionId + "' but it is closing");
} }
existingParticipants = getParticipants(sessionId); existingParticipants = getParticipants(sessionId);
session.join(participant); kSession.join(participant);
} catch (OpenViduException e) { } catch (OpenViduException e) {
log.warn("PARTICIPANT {}: Error joining/creating session {}", participant.getParticipantPublicId(), log.warn("PARTICIPANT {}: Error joining/creating session {}", participant.getParticipantPublicId(),
sessionId, e); sessionId, e);

View File

@ -24,6 +24,8 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import javax.servlet.http.HttpSession;
import org.kurento.jsonrpc.DefaultJsonRpcHandler; import org.kurento.jsonrpc.DefaultJsonRpcHandler;
import org.kurento.jsonrpc.Session; import org.kurento.jsonrpc.Session;
import org.kurento.jsonrpc.Transaction; import org.kurento.jsonrpc.Transaction;
@ -186,6 +188,34 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
} }
} }
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; boolean recorder = false;
try { try {
@ -218,7 +248,7 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
clientMetadata); clientMetadata);
} else { } else {
participant = sessionManager.newParticipant(sessionId, participantPrivatetId, tokenObj, participant = sessionManager.newParticipant(sessionId, participantPrivatetId, tokenObj,
clientMetadata, location, platform); clientMetadata, location, platform, httpSession.getId());
} }
rpcConnection.setSessionId(sessionId); rpcConnection.setSessionId(sessionId);
@ -555,6 +585,10 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
address = ((WebSocketServerSession) rpcSession).getWebSocketSession().getRemoteAddress().getAddress(); address = ((WebSocketServerSession) rpcSession).getWebSocketSession().getRemoteAddress().getAddress();
} }
rpcSession.getAttributes().put("remoteAddress", address); rpcSession.getAttributes().put("remoteAddress", address);
HttpSession httpSession = (HttpSession) ((WebSocketServerSession) rpcSession).getWebSocketSession()
.getAttributes().get("httpSession");
rpcSession.getAttributes().put("httpSession", httpSession);
} }
} }

View File

@ -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<String, CDREventWebrtcConnection> publishers = new ConcurrentHashMap<>();
private Map<String, CDREventWebrtcConnection> 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;
}
}

View File

@ -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<String, FinalUser> users;
private Collection<CDREventRecording> recordings;
public SessionSummary(CDREventSession event, Map<String, FinalUser> users,
Collection<CDREventRecording> 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;
}
}

View File

@ -2489,7 +2489,7 @@ public class OpenViduTestAppE2eTest {
user.getEventManager().waitUntilEventReaches("recordingStarted", 2); user.getEventManager().waitUntilEventReaches("recordingStarted", 2);
Thread.sleep(1000); Thread.sleep(2000);
// 409 (already recording) // 409 (already recording)
restClient.rest(HttpMethod.POST, "/api/recordings/start", body, HttpStatus.SC_CONFLICT); restClient.rest(HttpMethod.POST, "/api/recordings/start", body, HttpStatus.SC_CONFLICT);