mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: important refactoring (Session from interface to class)
parent
b2ec5ccb10
commit
1b47b9f2fa
|
@ -17,38 +17,162 @@
|
||||||
|
|
||||||
package io.openvidu.server.core;
|
package io.openvidu.server.core;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import io.openvidu.client.OpenViduException;
|
||||||
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
|
import io.openvidu.client.internal.ProtocolElements;
|
||||||
|
import io.openvidu.java.client.Recording;
|
||||||
|
import io.openvidu.java.client.RecordingLayout;
|
||||||
import io.openvidu.java.client.SessionProperties;
|
import io.openvidu.java.client.SessionProperties;
|
||||||
|
import io.openvidu.server.cdr.CallDetailRecord;
|
||||||
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
|
import io.openvidu.server.kurento.core.KurentoParticipant;
|
||||||
|
import io.openvidu.server.recording.service.RecordingManager;
|
||||||
|
|
||||||
public interface Session {
|
public class Session implements SessionInterface {
|
||||||
|
|
||||||
String getSessionId();
|
protected OpenviduConfig openviduConfig;
|
||||||
|
protected RecordingManager recordingManager;
|
||||||
|
protected CallDetailRecord CDR;
|
||||||
|
|
||||||
SessionProperties getSessionProperties();
|
protected final ConcurrentMap<String, Participant> participants = new ConcurrentHashMap<>();
|
||||||
|
protected String sessionId;
|
||||||
|
protected SessionProperties sessionProperties;
|
||||||
|
protected Long startTime;
|
||||||
|
|
||||||
void join(Participant participant);
|
protected volatile boolean closed = false;
|
||||||
|
protected AtomicInteger activePublishers = new AtomicInteger(0);
|
||||||
|
|
||||||
void leave(String participantPrivateId, String reason);
|
public Session(Session previousSession) {
|
||||||
|
this.sessionId = previousSession.getSessionId();
|
||||||
|
this.startTime = previousSession.getStartTime();
|
||||||
|
this.sessionProperties = previousSession.getSessionProperties();
|
||||||
|
this.CDR = previousSession.CDR;
|
||||||
|
this.openviduConfig = previousSession.openviduConfig;
|
||||||
|
this.recordingManager = previousSession.recordingManager;
|
||||||
|
}
|
||||||
|
|
||||||
boolean close(String reason);
|
public Session(String sessionId, SessionProperties sessionProperties, CallDetailRecord CDR,
|
||||||
|
OpenviduConfig openviduConfig, RecordingManager recordingManager) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.startTime = System.currentTimeMillis();
|
||||||
|
this.sessionProperties = sessionProperties;
|
||||||
|
this.CDR = CDR;
|
||||||
|
this.openviduConfig = openviduConfig;
|
||||||
|
this.recordingManager = recordingManager;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isClosed();
|
public String getSessionId() {
|
||||||
|
return this.sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
Set<Participant> getParticipants();
|
public SessionProperties getSessionProperties() {
|
||||||
|
return this.sessionProperties;
|
||||||
|
}
|
||||||
|
|
||||||
Participant getParticipantByPrivateId(String participantPrivateId);
|
public Long getStartTime() {
|
||||||
|
return this.startTime;
|
||||||
|
}
|
||||||
|
|
||||||
Participant getParticipantByPublicId(String participantPublicId);
|
public Set<Participant> getParticipants() {
|
||||||
|
checkClosed();
|
||||||
|
return new HashSet<Participant>(this.participants.values());
|
||||||
|
}
|
||||||
|
|
||||||
int getActivePublishers();
|
public Participant getParticipantByPrivateId(String participantPrivateId) {
|
||||||
|
checkClosed();
|
||||||
|
return participants.get(participantPrivateId);
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject toJson();
|
public Participant getParticipantByPublicId(String participantPublicId) {
|
||||||
|
checkClosed();
|
||||||
|
for (Participant p : participants.values()) {
|
||||||
|
if (p.getParticipantPublicId().equals(participantPublicId)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject withStatsToJson();
|
public int getActivePublishers() {
|
||||||
|
return activePublishers.get();
|
||||||
|
}
|
||||||
|
|
||||||
Long getStartTime();
|
public void registerPublisher() {
|
||||||
|
this.activePublishers.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deregisterPublisher() {
|
||||||
|
this.activePublishers.decrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkClosed() {
|
||||||
|
if (isClosed()) {
|
||||||
|
throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "The session '" + sessionId + "' is closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
return this.sharedJson(KurentoParticipant::toJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject withStatsToJson() {
|
||||||
|
return this.sharedJson(KurentoParticipant::withStatsToJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
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("defaultOutputMode", this.sessionProperties.defaultOutputMode().name());
|
||||||
|
if (Recording.OutputMode.COMPOSED.equals(this.sessionProperties.defaultOutputMode())) {
|
||||||
|
json.addProperty("defaultRecordingLayout", this.sessionProperties.defaultRecordingLayout().name());
|
||||||
|
if (RecordingLayout.CUSTOM.equals(this.sessionProperties.defaultRecordingLayout())) {
|
||||||
|
json.addProperty("defaultCustomLayout", this.sessionProperties.defaultCustomLayout());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.sessionProperties.customSessionId() != null) {
|
||||||
|
json.addProperty("customSessionId", this.sessionProperties.customSessionId());
|
||||||
|
}
|
||||||
|
JsonObject connections = new JsonObject();
|
||||||
|
JsonArray participants = new JsonArray();
|
||||||
|
this.participants.values().forEach(p -> {
|
||||||
|
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(p.getParticipantPublicId())) {
|
||||||
|
participants.add(toJsonFunction.apply((KurentoParticipant) p));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connections.addProperty("numberOfElements", participants.size());
|
||||||
|
connections.add("content", participants);
|
||||||
|
json.add("connections", connections);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void join(Participant participant) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void leave(String participantPrivateId, String reason) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean close(String reason) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* (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.Set;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import io.openvidu.java.client.SessionProperties;
|
||||||
|
|
||||||
|
public interface SessionInterface {
|
||||||
|
|
||||||
|
String getSessionId();
|
||||||
|
|
||||||
|
SessionProperties getSessionProperties();
|
||||||
|
|
||||||
|
void join(Participant participant);
|
||||||
|
|
||||||
|
void leave(String participantPrivateId, String reason);
|
||||||
|
|
||||||
|
boolean close(String reason);
|
||||||
|
|
||||||
|
boolean isClosed();
|
||||||
|
|
||||||
|
Set<Participant> getParticipants();
|
||||||
|
|
||||||
|
Participant getParticipantByPrivateId(String participantPrivateId);
|
||||||
|
|
||||||
|
Participant getParticipantByPublicId(String participantPublicId);
|
||||||
|
|
||||||
|
int getActivePublishers();
|
||||||
|
|
||||||
|
JsonObject toJson();
|
||||||
|
|
||||||
|
JsonObject withStatsToJson();
|
||||||
|
|
||||||
|
Long getStartTime();
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
|
@ -69,9 +70,9 @@ public abstract class SessionManager {
|
||||||
public FormatChecker formatChecker = new FormatChecker();
|
public FormatChecker formatChecker = new FormatChecker();
|
||||||
|
|
||||||
protected ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();
|
protected ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();
|
||||||
protected ConcurrentMap<String, SessionProperties> sessionProperties = new ConcurrentHashMap<>();
|
protected ConcurrentMap<String, Session> sessionsNotActive = new ConcurrentHashMap<>();
|
||||||
protected ConcurrentMap<String, Long> sessionCreationTime = new ConcurrentHashMap<>();
|
|
||||||
protected ConcurrentMap<String, ConcurrentHashMap<String, Participant>> sessionidParticipantpublicidParticipant = new ConcurrentHashMap<>();
|
protected ConcurrentMap<String, ConcurrentHashMap<String, Participant>> sessionidParticipantpublicidParticipant = 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<>();
|
||||||
|
|
||||||
|
@ -137,17 +138,21 @@ public abstract class SessionManager {
|
||||||
*
|
*
|
||||||
* @return set of the session's identifiers
|
* @return set of the session's identifiers
|
||||||
*/
|
*/
|
||||||
public Set<String> getSessions() {
|
public Collection<Session> getSessions() {
|
||||||
return new HashSet<String>(sessions.keySet());
|
return sessions.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Session getSessionNotActive(String sessionId) {
|
||||||
* Returns all currently active (opened) sessions.
|
return this.sessionsNotActive.get(sessionId);
|
||||||
*
|
}
|
||||||
* @return set of the session's identifiers
|
|
||||||
*/
|
public Collection<Session> getSessionsWithNotActive() {
|
||||||
public Collection<Session> getSessionObjects() {
|
Collection<Session> allSessions = new HashSet<>();
|
||||||
return sessions.values();
|
allSessions.addAll(this.sessionsNotActive.values().stream()
|
||||||
|
.filter(sessionNotActive -> !sessions.containsKey(sessionNotActive.getSessionId()))
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
allSessions.addAll(this.getSessions());
|
||||||
|
return allSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,11 +217,12 @@ public abstract class SessionManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void storeSessionId(String sessionId, Long creationTime, SessionProperties sessionProperties) {
|
public Session storeSessionNotActive(String sessionId, SessionProperties sessionProperties) {
|
||||||
|
Session sessionNotActive = new Session(sessionId, sessionProperties, CDR, openviduConfig, recordingManager);
|
||||||
|
this.sessionsNotActive.put(sessionId, sessionNotActive);
|
||||||
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>());
|
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>());
|
||||||
this.sessionProperties.putIfAbsent(sessionId, sessionProperties);
|
|
||||||
this.sessionCreationTime.putIfAbsent(sessionId, creationTime);
|
|
||||||
showTokens();
|
showTokens();
|
||||||
|
return sessionNotActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String newToken(String sessionId, ParticipantRole role, String serverMetadata,
|
public String newToken(String sessionId, ParticipantRole role, String serverMetadata,
|
||||||
|
@ -254,7 +260,6 @@ public abstract class SessionManager {
|
||||||
log.error("sessionId [" + sessionId + "] was not found");
|
log.error("sessionId [" + sessionId + "] was not found");
|
||||||
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "sessionId [" + sessionId + "] not found");
|
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "sessionId [" + sessionId + "] not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTokenValidInSession(String token, String sessionId, String participanPrivatetId) {
|
public boolean isTokenValidInSession(String token, String sessionId, String participanPrivatetId) {
|
||||||
|
@ -266,7 +271,6 @@ public abstract class SessionManager {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>());
|
this.sessionidParticipantpublicidParticipant.putIfAbsent(sessionId, new ConcurrentHashMap<>());
|
||||||
this.sessionCreationTime.putIfAbsent(sessionId, System.currentTimeMillis());
|
|
||||||
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, ParticipantRole.PUBLISHER, "",
|
new Token(token, ParticipantRole.PUBLISHER, "",
|
||||||
|
@ -278,15 +282,6 @@ public abstract class SessionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isParticipantInSession(String sessionId, Participant participant) {
|
|
||||||
Session session = this.sessions.get(sessionId);
|
|
||||||
if (session != null) {
|
|
||||||
return (session.getParticipantByPrivateId(participant.getParticipantPrivateId()) != null);
|
|
||||||
} else {
|
|
||||||
throw new OpenViduException(Code.ROOM_NOT_FOUND_ERROR_CODE, "[" + sessionId + "] is not a valid sessionId");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPublisherInSession(String sessionId, Participant participant) {
|
public boolean isPublisherInSession(String sessionId, Participant participant) {
|
||||||
if (!this.isInsecureParticipant(participant.getParticipantPrivateId())) {
|
if (!this.isInsecureParticipant(participant.getParticipantPrivateId())) {
|
||||||
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
|
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
|
||||||
|
@ -371,14 +366,6 @@ public abstract class SessionManager {
|
||||||
log.info("<SESSIONID, TOKENS>: {}", this.sessionidTokenTokenobj.toString());
|
log.info("<SESSIONID, TOKENS>: {}", this.sessionidTokenTokenobj.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showInsecureParticipants() {
|
|
||||||
log.info("<INSECURE_PARTICIPANTS>: {}", this.insecureUsers.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showAllParticipants() {
|
|
||||||
log.info("<SESSIONID, PARTICIPANTS>: {}", this.sessionidParticipantpublicidParticipant.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateRandomChain() {
|
public String generateRandomChain() {
|
||||||
return RandomStringUtils.randomAlphanumeric(16).toLowerCase();
|
return RandomStringUtils.randomAlphanumeric(16).toLowerCase();
|
||||||
}
|
}
|
||||||
|
@ -454,8 +441,7 @@ public abstract class SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
sessions.remove(session.getSessionId());
|
sessions.remove(session.getSessionId());
|
||||||
sessionProperties.remove(session.getSessionId());
|
sessionsNotActive.remove(session.getSessionId());
|
||||||
sessionCreationTime.remove(session.getSessionId());
|
|
||||||
sessionidParticipantpublicidParticipant.remove(session.getSessionId());
|
sessionidParticipantpublicidParticipant.remove(session.getSessionId());
|
||||||
sessionidTokenTokenobj.remove(session.getSessionId());
|
sessionidTokenTokenobj.remove(session.getSessionId());
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,9 @@
|
||||||
|
|
||||||
package io.openvidu.server.kurento.core;
|
package io.openvidu.server.kurento.core;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.kurento.client.Continuation;
|
import org.kurento.client.Continuation;
|
||||||
import org.kurento.client.ErrorEvent;
|
import org.kurento.client.ErrorEvent;
|
||||||
|
@ -35,83 +30,44 @@ import org.kurento.client.MediaPipeline;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
import io.openvidu.client.internal.ProtocolElements;
|
import io.openvidu.client.internal.ProtocolElements;
|
||||||
import io.openvidu.java.client.Recording;
|
|
||||||
import io.openvidu.java.client.RecordingLayout;
|
|
||||||
import io.openvidu.java.client.SessionProperties;
|
|
||||||
import io.openvidu.server.cdr.CallDetailRecord;
|
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
|
||||||
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.recording.service.RecordingManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pablo Fuente (pablofuenteperez@gmail.com)
|
* @author Pablo Fuente (pablofuenteperez@gmail.com)
|
||||||
*/
|
*/
|
||||||
public class KurentoSession implements Session {
|
public class KurentoSession extends Session {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(Session.class);
|
private final static Logger log = LoggerFactory.getLogger(Session.class);
|
||||||
public static final int ASYNC_LATCH_TIMEOUT = 30;
|
public static final int ASYNC_LATCH_TIMEOUT = 30;
|
||||||
|
|
||||||
private OpenviduConfig openviduConfig;
|
|
||||||
private RecordingManager recordingManager;
|
|
||||||
|
|
||||||
private final ConcurrentMap<String, KurentoParticipant> participants = new ConcurrentHashMap<>();
|
|
||||||
private String sessionId;
|
|
||||||
private SessionProperties sessionProperties;
|
|
||||||
private Long startTime;
|
|
||||||
|
|
||||||
private MediaPipeline pipeline;
|
private MediaPipeline pipeline;
|
||||||
private CountDownLatch pipelineLatch = new CountDownLatch(1);
|
private CountDownLatch pipelineLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
private KurentoClient kurentoClient;
|
private KurentoClient kurentoClient;
|
||||||
private KurentoSessionEventsHandler kurentoSessionHandler;
|
private KurentoSessionEventsHandler kurentoSessionHandler;
|
||||||
|
|
||||||
private volatile boolean closed = false;
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, String> filterStates = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, String> filterStates = new ConcurrentHashMap<>();
|
||||||
private AtomicInteger activePublishers = new AtomicInteger(0);
|
|
||||||
|
|
||||||
private Object pipelineCreateLock = new Object();
|
private Object pipelineCreateLock = new Object();
|
||||||
private Object pipelineReleaseLock = new Object();
|
private Object pipelineReleaseLock = new Object();
|
||||||
private volatile boolean pipelineReleased = false;
|
private volatile boolean pipelineReleased = false;
|
||||||
private boolean destroyKurentoClient;
|
private boolean destroyKurentoClient;
|
||||||
|
|
||||||
private CallDetailRecord CDR;
|
|
||||||
|
|
||||||
public final ConcurrentHashMap<String, String> publishedStreamIds = new ConcurrentHashMap<>();
|
public final ConcurrentHashMap<String, String> publishedStreamIds = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public KurentoSession(String sessionId, Long startTime, SessionProperties sessionProperties,
|
public KurentoSession(Session sessionNotActive, KurentoClient kurentoClient,
|
||||||
KurentoClient kurentoClient, KurentoSessionEventsHandler kurentoSessionHandler,
|
KurentoSessionEventsHandler kurentoSessionHandler, boolean destroyKurentoClient) {
|
||||||
boolean destroyKurentoClient, CallDetailRecord CDR, OpenviduConfig openviduConfig,
|
super(sessionNotActive);
|
||||||
RecordingManager recordingManager) {
|
|
||||||
this.sessionId = sessionId;
|
|
||||||
this.sessionProperties = sessionProperties;
|
|
||||||
this.kurentoClient = kurentoClient;
|
this.kurentoClient = kurentoClient;
|
||||||
this.destroyKurentoClient = destroyKurentoClient;
|
this.destroyKurentoClient = destroyKurentoClient;
|
||||||
this.kurentoSessionHandler = kurentoSessionHandler;
|
this.kurentoSessionHandler = kurentoSessionHandler;
|
||||||
this.CDR = CDR;
|
|
||||||
this.openviduConfig = openviduConfig;
|
|
||||||
this.recordingManager = recordingManager;
|
|
||||||
this.startTime = startTime;
|
|
||||||
log.debug("New SESSION instance with id '{}'", sessionId);
|
log.debug("New SESSION instance with id '{}'", sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSessionId() {
|
|
||||||
return this.sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SessionProperties getSessionProperties() {
|
|
||||||
return this.sessionProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void join(Participant participant) {
|
public void join(Participant participant) {
|
||||||
checkClosed();
|
checkClosed();
|
||||||
|
@ -137,11 +93,11 @@ public class KurentoSession implements Session {
|
||||||
registerPublisher();
|
registerPublisher();
|
||||||
|
|
||||||
// pre-load endpoints to recv video from the new publisher
|
// pre-load endpoints to recv video from the new publisher
|
||||||
for (KurentoParticipant p : participants.values()) {
|
for (Participant p : participants.values()) {
|
||||||
if (participant.equals(p)) {
|
if (participant.equals(p)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
p.getNewOrExistingSubscriber(participant.getParticipantPublicId());
|
((KurentoParticipant) p).getNewOrExistingSubscriber(participant.getParticipantPublicId());
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("SESSION {}: Virtually subscribed other participants {} to new publisher {}", sessionId,
|
log.debug("SESSION {}: Virtually subscribed other participants {} to new publisher {}", sessionId,
|
||||||
|
@ -152,11 +108,11 @@ public class KurentoSession implements Session {
|
||||||
deregisterPublisher();
|
deregisterPublisher();
|
||||||
|
|
||||||
// cancel recv video from this publisher
|
// cancel recv video from this publisher
|
||||||
for (KurentoParticipant subscriber : participants.values()) {
|
for (Participant subscriber : participants.values()) {
|
||||||
if (participant.equals(subscriber)) {
|
if (participant.equals(subscriber)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
subscriber.cancelReceivingMedia(participant.getParticipantPublicId(), reason);
|
((KurentoParticipant) subscriber).cancelReceivingMedia(participant.getParticipantPublicId(), reason);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +126,7 @@ public class KurentoSession implements Session {
|
||||||
|
|
||||||
checkClosed();
|
checkClosed();
|
||||||
|
|
||||||
KurentoParticipant participant = participants.get(participantPrivateId);
|
KurentoParticipant participant = (KurentoParticipant) participants.get(participantPrivateId);
|
||||||
if (participant == null) {
|
if (participant == null) {
|
||||||
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE, "Participant with private id "
|
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE, "Participant with private id "
|
||||||
+ participantPrivateId + " not found in session '" + sessionId + "'");
|
+ participantPrivateId + " not found in session '" + sessionId + "'");
|
||||||
|
@ -189,36 +145,13 @@ public class KurentoSession implements Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Participant> getParticipants() {
|
|
||||||
checkClosed();
|
|
||||||
return new HashSet<Participant>(this.participants.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Participant getParticipantByPrivateId(String participantPrivateId) {
|
|
||||||
checkClosed();
|
|
||||||
return participants.get(participantPrivateId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Participant getParticipantByPublicId(String participantPublicId) {
|
|
||||||
checkClosed();
|
|
||||||
for (Participant p : participants.values()) {
|
|
||||||
if (p.getParticipantPublicId().equals(participantPublicId)) {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean close(String reason) {
|
public boolean close(String reason) {
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
|
|
||||||
for (KurentoParticipant participant : participants.values()) {
|
for (Participant participant : participants.values()) {
|
||||||
participant.releaseAllFilters();
|
((KurentoParticipant) participant).releaseAllFilters();
|
||||||
participant.close(reason);
|
((KurentoParticipant) participant).close(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
participants.clear();
|
participants.clear();
|
||||||
|
@ -247,17 +180,6 @@ public class KurentoSession implements Session {
|
||||||
this.kurentoSessionHandler.onMediaElementError(sessionId, participantId, description);
|
this.kurentoSessionHandler.onMediaElementError(sessionId, participantId, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isClosed() {
|
|
||||||
return closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkClosed() {
|
|
||||||
if (isClosed()) {
|
|
||||||
throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "The session '" + sessionId + "' is closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeParticipant(Participant participant, String reason) {
|
private void removeParticipant(Participant participant, String reason) {
|
||||||
|
|
||||||
checkClosed();
|
checkClosed();
|
||||||
|
@ -266,24 +188,11 @@ public class KurentoSession implements Session {
|
||||||
|
|
||||||
log.debug("SESSION {}: Cancel receiving media from participant '{}' for other participant", this.sessionId,
|
log.debug("SESSION {}: Cancel receiving media from participant '{}' for other participant", this.sessionId,
|
||||||
participant.getParticipantPublicId());
|
participant.getParticipantPublicId());
|
||||||
for (KurentoParticipant other : participants.values()) {
|
for (Participant other : participants.values()) {
|
||||||
other.cancelReceivingMedia(participant.getParticipantPublicId(), reason);
|
((KurentoParticipant) other).cancelReceivingMedia(participant.getParticipantPublicId(), reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getActivePublishers() {
|
|
||||||
return activePublishers.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerPublisher() {
|
|
||||||
this.activePublishers.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deregisterPublisher() {
|
|
||||||
this.activePublishers.decrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MediaPipeline getPipeline() {
|
public MediaPipeline getPipeline() {
|
||||||
try {
|
try {
|
||||||
pipelineLatch.await(KurentoSession.ASYNC_LATCH_TIMEOUT, TimeUnit.SECONDS);
|
pipelineLatch.await(KurentoSession.ASYNC_LATCH_TIMEOUT, TimeUnit.SECONDS);
|
||||||
|
@ -361,63 +270,8 @@ public class KurentoSession implements Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void updateFilter(String filterId) {
|
|
||||||
String state = filterStates.get(filterId);
|
|
||||||
String newState = kurentoSessionHandler.getNextFilterState(filterId, state);
|
|
||||||
|
|
||||||
filterStates.put(filterId, newState);
|
|
||||||
|
|
||||||
for (Participant participant : participants.values()) {
|
|
||||||
kurentoSessionHandler.updateFilter(this.sessionId, participant, filterId, newState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonObject toJson() {
|
|
||||||
return this.sharedJson(KurentoParticipant::toJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonObject withStatsToJson() {
|
|
||||||
return this.sharedJson(KurentoParticipant::withStatsToJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
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("defaultOutputMode", this.sessionProperties.defaultOutputMode().name());
|
|
||||||
if (Recording.OutputMode.COMPOSED.equals(this.sessionProperties.defaultOutputMode())) {
|
|
||||||
json.addProperty("defaultRecordingLayout", this.sessionProperties.defaultRecordingLayout().name());
|
|
||||||
if (RecordingLayout.CUSTOM.equals(this.sessionProperties.defaultRecordingLayout())) {
|
|
||||||
json.addProperty("defaultCustomLayout", this.sessionProperties.defaultCustomLayout());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.sessionProperties.customSessionId() != null) {
|
|
||||||
json.addProperty("customSessionId", this.sessionProperties.customSessionId());
|
|
||||||
}
|
|
||||||
JsonObject connections = new JsonObject();
|
|
||||||
JsonArray participants = new JsonArray();
|
|
||||||
this.participants.values().forEach(p -> {
|
|
||||||
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(p.getParticipantPublicId())) {
|
|
||||||
participants.add(toJsonFunction.apply(p));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
connections.addProperty("numberOfElements", participants.size());
|
|
||||||
connections.add("content", participants);
|
|
||||||
json.add("connections", connections);
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getParticipantPrivateIdFromStreamId(String streamId) {
|
public String getParticipantPrivateIdFromStreamId(String streamId) {
|
||||||
return this.publishedStreamIds.get(streamId);
|
return this.publishedStreamIds.get(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getStartTime() {
|
|
||||||
return this.startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,13 +80,19 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
KurentoSession session = (KurentoSession) sessions.get(sessionId);
|
KurentoSession session = (KurentoSession) sessions.get(sessionId);
|
||||||
|
|
||||||
if (session == null && kcSessionInfo != null) {
|
if (session == null && kcSessionInfo != null) {
|
||||||
SessionProperties properties = sessionProperties.get(sessionId);
|
// First user connecting to the session
|
||||||
if (properties == null && this.isInsecureParticipant(participant.getParticipantPrivateId())) {
|
Session sessionNotActive = sessionsNotActive.remove(sessionId);
|
||||||
properties = new SessionProperties.Builder().mediaMode(MediaMode.ROUTED)
|
|
||||||
.recordingMode(RecordingMode.ALWAYS).defaultRecordingLayout(RecordingLayout.BEST_FIT)
|
if (sessionNotActive == null && this.isInsecureParticipant(participant.getParticipantPrivateId())) {
|
||||||
.build();
|
// Insecure user directly call joinRoom RPC method, without REST API use
|
||||||
|
sessionNotActive = new Session(sessionId,
|
||||||
|
new SessionProperties.Builder().mediaMode(MediaMode.ROUTED)
|
||||||
|
.recordingMode(RecordingMode.ALWAYS)
|
||||||
|
.defaultRecordingLayout(RecordingLayout.BEST_FIT).build(),
|
||||||
|
CDR, openviduConfig, recordingManager);
|
||||||
}
|
}
|
||||||
createSession(kcSessionInfo, properties);
|
|
||||||
|
createSession(sessionNotActive, kcSessionInfo);
|
||||||
}
|
}
|
||||||
session = (KurentoSession) sessions.get(sessionId);
|
session = (KurentoSession) sessions.get(sessionId);
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
|
@ -489,7 +495,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
* {@link KurentoClient} that will be used by the room
|
* {@link KurentoClient} that will be used by the room
|
||||||
* @throws OpenViduException in case of error while creating the session
|
* @throws OpenViduException in case of error while creating the session
|
||||||
*/
|
*/
|
||||||
public void createSession(KurentoClientSessionInfo kcSessionInfo, SessionProperties sessionProperties)
|
public void createSession(Session sessionNotActive, KurentoClientSessionInfo kcSessionInfo)
|
||||||
throws OpenViduException {
|
throws OpenViduException {
|
||||||
String sessionId = kcSessionInfo.getRoomName();
|
String sessionId = kcSessionInfo.getRoomName();
|
||||||
KurentoSession session = (KurentoSession) sessions.get(sessionId);
|
KurentoSession session = (KurentoSession) sessions.get(sessionId);
|
||||||
|
@ -498,9 +504,8 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
"Session '" + sessionId + "' already exists");
|
"Session '" + sessionId + "' already exists");
|
||||||
}
|
}
|
||||||
this.kurentoClient = kcProvider.getKurentoClient(kcSessionInfo);
|
this.kurentoClient = kcProvider.getKurentoClient(kcSessionInfo);
|
||||||
session = new KurentoSession(sessionId, this.sessionCreationTime.get(sessionId), sessionProperties,
|
session = new KurentoSession(sessionNotActive, kurentoClient, kurentoSessionEventsHandler,
|
||||||
kurentoClient, kurentoSessionEventsHandler, kcProvider.destroyWhenUnused(), this.CDR,
|
kcProvider.destroyWhenUnused());
|
||||||
this.openviduConfig, this.recordingManager);
|
|
||||||
|
|
||||||
KurentoSession oldSession = (KurentoSession) sessions.putIfAbsent(sessionId, session);
|
KurentoSession oldSession = (KurentoSession) sessions.putIfAbsent(sessionId, session);
|
||||||
if (oldSession != null) {
|
if (oldSession != null) {
|
||||||
|
|
|
@ -158,11 +158,10 @@ public class SessionRestController {
|
||||||
sessionManager.sessionidTokenTokenobj.putIfAbsent(sessionId, new ConcurrentHashMap<>());
|
sessionManager.sessionidTokenTokenobj.putIfAbsent(sessionId, new ConcurrentHashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
Long creationTime = System.currentTimeMillis();
|
Session sessionNotActive = sessionManager.storeSessionNotActive(sessionId, sessionProperties);
|
||||||
sessionManager.storeSessionId(sessionId, creationTime, sessionProperties);
|
|
||||||
JsonObject responseJson = new JsonObject();
|
JsonObject responseJson = new JsonObject();
|
||||||
responseJson.addProperty("id", sessionId);
|
responseJson.addProperty("id", sessionNotActive.getSessionId());
|
||||||
responseJson.addProperty("createdAt", creationTime);
|
responseJson.addProperty("createdAt", sessionNotActive.getStartTime());
|
||||||
|
|
||||||
return new ResponseEntity<>(responseJson.toString(), getResponseHeaders(), HttpStatus.OK);
|
return new ResponseEntity<>(responseJson.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
@ -179,7 +178,14 @@ public class SessionRestController {
|
||||||
response.addProperty("recording", this.recordingManager.sessionIsBeingRecorded(sessionId));
|
response.addProperty("recording", this.recordingManager.sessionIsBeingRecorded(sessionId));
|
||||||
return new ResponseEntity<>(response.toString(), getResponseHeaders(), HttpStatus.OK);
|
return new ResponseEntity<>(response.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
} else {
|
} else {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
Session sessionNotActive = this.sessionManager.getSessionNotActive(sessionId);
|
||||||
|
if (sessionNotActive != null) {
|
||||||
|
JsonObject response = (webRtcStats == true) ? sessionNotActive.withStatsToJson()
|
||||||
|
: sessionNotActive.toJson();
|
||||||
|
return new ResponseEntity<>(response.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
|
} else {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +195,7 @@ public class SessionRestController {
|
||||||
|
|
||||||
log.info("REST API: GET /api/sessions");
|
log.info("REST API: GET /api/sessions");
|
||||||
|
|
||||||
Collection<Session> sessions = this.sessionManager.getSessionObjects();
|
Collection<Session> sessions = this.sessionManager.getSessionsWithNotActive();
|
||||||
JsonObject json = new JsonObject();
|
JsonObject json = new JsonObject();
|
||||||
JsonArray jsonArray = new JsonArray();
|
JsonArray jsonArray = new JsonArray();
|
||||||
sessions.forEach(s -> {
|
sessions.forEach(s -> {
|
||||||
|
@ -212,7 +218,13 @@ public class SessionRestController {
|
||||||
this.sessionManager.closeSession(sessionId, "sessionClosedByServer");
|
this.sessionManager.closeSession(sessionId, "sessionClosedByServer");
|
||||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
} else {
|
} else {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
Session sessionNotActive = this.sessionManager.getSessionNotActive(sessionId);
|
||||||
|
if (sessionNotActive != null) {
|
||||||
|
this.sessionManager.closeSessionAndEmptyCollections(sessionNotActive, "sessionClosedByServer");
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
} else {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +244,9 @@ public class SessionRestController {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (this.sessionManager.getSessionNotActive(sessionId) != null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,6 +265,9 @@ public class SessionRestController {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (this.sessionManager.getSessionNotActive(sessionId) != null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,6 +408,10 @@ public class SessionRestController {
|
||||||
Session session = sessionManager.getSession(sessionId);
|
Session session = sessionManager.getSession(sessionId);
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
|
if (sessionManager.getSessionNotActive(sessionId) != null) {
|
||||||
|
// Session is not active
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
// Session does not exist
|
// Session does not exist
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue