mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: refactor Media Node selection
parent
e32b1f01b4
commit
d358562033
|
@ -46,7 +46,6 @@ 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.ConnectionProperties;
|
import io.openvidu.java.client.ConnectionProperties;
|
||||||
import io.openvidu.java.client.ConnectionType;
|
|
||||||
import io.openvidu.java.client.KurentoOptions;
|
import io.openvidu.java.client.KurentoOptions;
|
||||||
import io.openvidu.java.client.OpenViduRole;
|
import io.openvidu.java.client.OpenViduRole;
|
||||||
import io.openvidu.java.client.Recording;
|
import io.openvidu.java.client.Recording;
|
||||||
|
@ -307,8 +306,8 @@ public abstract class SessionManager {
|
||||||
log.error("Data invalid format");
|
log.error("Data invalid format");
|
||||||
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
|
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
|
||||||
}
|
}
|
||||||
Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), serverMetadata,
|
Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), serverMetadata, record, role,
|
||||||
record, role, kurentoOptions);
|
kurentoOptions);
|
||||||
session.storeToken(tokenObj);
|
session.storeToken(tokenObj);
|
||||||
session.showTokens("Token created");
|
session.showTokens("Token created");
|
||||||
return tokenObj;
|
return tokenObj;
|
||||||
|
|
|
@ -78,13 +78,13 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
private static final Logger log = LoggerFactory.getLogger(KurentoSessionManager.class);
|
private static final Logger log = LoggerFactory.getLogger(KurentoSessionManager.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private KmsManager kmsManager;
|
protected KmsManager kmsManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private KurentoSessionEventsHandler kurentoSessionEventsHandler;
|
protected KurentoSessionEventsHandler kurentoSessionEventsHandler;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private KurentoParticipantEndpointConfig kurentoEndpointConfig;
|
protected KurentoParticipantEndpointConfig kurentoEndpointConfig;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/* Protected by Session.closingLock.readLock */
|
/* Protected by Session.closingLock.readLock */
|
||||||
|
@ -110,23 +110,10 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
if (KmsManager.selectAndRemoveKmsLock.tryLock(KmsManager.MAX_SECONDS_LOCK_WAIT, TimeUnit.SECONDS)) {
|
if (KmsManager.selectAndRemoveKmsLock.tryLock(KmsManager.MAX_SECONDS_LOCK_WAIT, TimeUnit.SECONDS)) {
|
||||||
try {
|
try {
|
||||||
kSession = (KurentoSession) sessions.get(sessionId);
|
kSession = (KurentoSession) sessions.get(sessionId);
|
||||||
|
|
||||||
if (kSession == null) {
|
if (kSession == null) {
|
||||||
// Session still null. It was not created by other thread while waiting for lock
|
// Session still null. It was not created by other thread while waiting for lock
|
||||||
Kms lessLoadedKms = null;
|
Kms selectedMediaNode = this.selectMediaNode(sessionNotActive);
|
||||||
try {
|
kSession = createSession(sessionNotActive, selectedMediaNode);
|
||||||
lessLoadedKms = this.kmsManager.getLessLoadedConnectedAndRunningKms();
|
|
||||||
} catch (NoSuchElementException e) {
|
|
||||||
// Restore session not active
|
|
||||||
this.cleanCollections(sessionId);
|
|
||||||
this.storeSessionNotActive(sessionNotActive);
|
|
||||||
throw new OpenViduException(Code.ROOM_CANNOT_BE_CREATED_ERROR_CODE,
|
|
||||||
"There is no available Media Node where to initialize session '" + sessionId
|
|
||||||
+ "'");
|
|
||||||
}
|
|
||||||
log.info("KMS less loaded is {} with a load of {}", lessLoadedKms.getUri(),
|
|
||||||
lessLoadedKms.getLoad());
|
|
||||||
kSession = createSession(sessionNotActive, lessLoadedKms);
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
KmsManager.selectAndRemoveKmsLock.unlock();
|
KmsManager.selectAndRemoveKmsLock.unlock();
|
||||||
|
@ -992,8 +979,8 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/* Protected by Session.closingLock.readLock */
|
/* Protected by Session.closingLock.readLock */
|
||||||
public Participant publishIpcam(Session session, MediaOptions mediaOptions, ConnectionProperties connectionProperties)
|
public Participant publishIpcam(Session session, MediaOptions mediaOptions,
|
||||||
throws Exception {
|
ConnectionProperties connectionProperties) throws Exception {
|
||||||
final String sessionId = session.getSessionId();
|
final String sessionId = session.getSessionId();
|
||||||
final KurentoMediaOptions kMediaOptions = (KurentoMediaOptions) mediaOptions;
|
final KurentoMediaOptions kMediaOptions = (KurentoMediaOptions) mediaOptions;
|
||||||
|
|
||||||
|
@ -1119,7 +1106,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
sessionEventsHandler.onVideoData(participant, transactionId, height, width, videoActive, audioActive);
|
sessionEventsHandler.onVideoData(participant, transactionId, height, width, videoActive, audioActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyFilterInPublisher(KurentoParticipant kParticipant, KurentoFilter filter)
|
protected void applyFilterInPublisher(KurentoParticipant kParticipant, KurentoFilter filter)
|
||||||
throws OpenViduException {
|
throws OpenViduException {
|
||||||
GenericMediaElement.Builder builder = new GenericMediaElement.Builder(kParticipant.getPipeline(),
|
GenericMediaElement.Builder builder = new GenericMediaElement.Builder(kParticipant.getPipeline(),
|
||||||
filter.getType());
|
filter.getType());
|
||||||
|
@ -1131,13 +1118,13 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
kParticipant.getPublisher().getMediaOptions().setFilter(filter);
|
kParticipant.getPublisher().getMediaOptions().setFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFilterInPublisher(KurentoParticipant kParticipant) {
|
protected void removeFilterInPublisher(KurentoParticipant kParticipant) {
|
||||||
kParticipant.getPublisher().cleanAllFilterListeners();
|
kParticipant.getPublisher().cleanAllFilterListeners();
|
||||||
kParticipant.getPublisher().revert(kParticipant.getPublisher().getFilter());
|
kParticipant.getPublisher().revert(kParticipant.getPublisher().getFilter());
|
||||||
kParticipant.getPublisher().getMediaOptions().setFilter(null);
|
kParticipant.getPublisher().getMediaOptions().setFilter(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KurentoFilter execFilterMethodInPublisher(KurentoParticipant kParticipant, String method,
|
protected KurentoFilter execFilterMethodInPublisher(KurentoParticipant kParticipant, String method,
|
||||||
JsonObject params) {
|
JsonObject params) {
|
||||||
kParticipant.getPublisher().execMethod(method, params);
|
kParticipant.getPublisher().execMethod(method, params);
|
||||||
KurentoFilter filter = kParticipant.getPublisher().getMediaOptions().getFilter();
|
KurentoFilter filter = kParticipant.getPublisher().getMediaOptions().getFilter();
|
||||||
|
@ -1146,7 +1133,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
return updatedFilter;
|
return updatedFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFilterEventListenerInPublisher(KurentoParticipant kParticipant, String eventType)
|
protected void addFilterEventListenerInPublisher(KurentoParticipant kParticipant, String eventType)
|
||||||
throws OpenViduException {
|
throws OpenViduException {
|
||||||
PublisherEndpoint pub = kParticipant.getPublisher();
|
PublisherEndpoint pub = kParticipant.getPublisher();
|
||||||
if (!pub.isListenerAddedToFilterEvent(eventType)) {
|
if (!pub.isListenerAddedToFilterEvent(eventType)) {
|
||||||
|
@ -1170,7 +1157,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFilterEventListenerInPublisher(KurentoParticipant kParticipant, String eventType) {
|
protected void removeFilterEventListenerInPublisher(KurentoParticipant kParticipant, String eventType) {
|
||||||
PublisherEndpoint pub = kParticipant.getPublisher();
|
PublisherEndpoint pub = kParticipant.getPublisher();
|
||||||
if (pub.isListenerAddedToFilterEvent(eventType)) {
|
if (pub.isListenerAddedToFilterEvent(eventType)) {
|
||||||
GenericMediaElement filter = kParticipant.getPublisher().getFilter();
|
GenericMediaElement filter = kParticipant.getPublisher().getFilter();
|
||||||
|
@ -1178,4 +1165,19 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Kms selectMediaNode(Session session) throws OpenViduException {
|
||||||
|
Kms lessLoadedKms = null;
|
||||||
|
try {
|
||||||
|
lessLoadedKms = this.kmsManager.getLessLoadedConnectedAndRunningKms();
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// Restore session not active
|
||||||
|
this.cleanCollections(session.getSessionId());
|
||||||
|
this.storeSessionNotActive(session);
|
||||||
|
throw new OpenViduException(Code.ROOM_CANNOT_BE_CREATED_ERROR_CODE,
|
||||||
|
"There is no available Media Node where to initialize session '" + session + "'");
|
||||||
|
}
|
||||||
|
log.info("KMS less loaded is {} with a load of {}", lessLoadedKms.getUri(), lessLoadedKms.getLoad());
|
||||||
|
return lessLoadedKms;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,80 +99,19 @@ public class SessionRestController {
|
||||||
|
|
||||||
log.info("REST API: POST {}/sessions {}", RequestMappings.API, params != null ? params.toString() : "{}");
|
log.info("REST API: POST {}/sessions {}", RequestMappings.API, params != null ? params.toString() : "{}");
|
||||||
|
|
||||||
SessionProperties.Builder builder = new SessionProperties.Builder();
|
SessionProperties sessionProperties;
|
||||||
String customSessionId = null;
|
try {
|
||||||
|
sessionProperties = getSessionPropertiesFromParams(params).build();
|
||||||
if (params != null) {
|
} catch (Exception e) {
|
||||||
|
return this.generateErrorResponse(e.getMessage(), "/sessions", HttpStatus.BAD_REQUEST);
|
||||||
String mediaModeString;
|
|
||||||
String recordingModeString;
|
|
||||||
String defaultOutputModeString;
|
|
||||||
String defaultRecordingLayoutString;
|
|
||||||
String defaultCustomLayout;
|
|
||||||
try {
|
|
||||||
mediaModeString = (String) params.get("mediaMode");
|
|
||||||
recordingModeString = (String) params.get("recordingMode");
|
|
||||||
defaultOutputModeString = (String) params.get("defaultOutputMode");
|
|
||||||
defaultRecordingLayoutString = (String) params.get("defaultRecordingLayout");
|
|
||||||
defaultCustomLayout = (String) params.get("defaultCustomLayout");
|
|
||||||
customSessionId = (String) params.get("customSessionId");
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return this.generateErrorResponse("Type error in some parameter", "/sessions", HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Safe parameter retrieval. Default values if not defined
|
|
||||||
if (recordingModeString != null) {
|
|
||||||
RecordingMode recordingMode = RecordingMode.valueOf(recordingModeString);
|
|
||||||
builder = builder.recordingMode(recordingMode);
|
|
||||||
} else {
|
|
||||||
builder = builder.recordingMode(RecordingMode.MANUAL);
|
|
||||||
}
|
|
||||||
if (defaultOutputModeString != null) {
|
|
||||||
OutputMode defaultOutputMode = OutputMode.valueOf(defaultOutputModeString);
|
|
||||||
builder = builder.defaultOutputMode(defaultOutputMode);
|
|
||||||
} else {
|
|
||||||
builder.defaultOutputMode(OutputMode.COMPOSED);
|
|
||||||
}
|
|
||||||
if (defaultRecordingLayoutString != null) {
|
|
||||||
RecordingLayout defaultRecordingLayout = RecordingLayout.valueOf(defaultRecordingLayoutString);
|
|
||||||
builder = builder.defaultRecordingLayout(defaultRecordingLayout);
|
|
||||||
} else {
|
|
||||||
builder.defaultRecordingLayout(RecordingLayout.BEST_FIT);
|
|
||||||
}
|
|
||||||
if (mediaModeString != null) {
|
|
||||||
MediaMode mediaMode = MediaMode.valueOf(mediaModeString);
|
|
||||||
builder = builder.mediaMode(mediaMode);
|
|
||||||
} else {
|
|
||||||
builder = builder.mediaMode(MediaMode.ROUTED);
|
|
||||||
}
|
|
||||||
if (customSessionId != null && !customSessionId.isEmpty()) {
|
|
||||||
if (!sessionManager.formatChecker.isValidCustomSessionId(customSessionId)) {
|
|
||||||
return this.generateErrorResponse(
|
|
||||||
"Parameter 'customSessionId' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-]",
|
|
||||||
"/sessions", HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
builder = builder.customSessionId(customSessionId);
|
|
||||||
}
|
|
||||||
builder = builder.defaultCustomLayout((defaultCustomLayout != null) ? defaultCustomLayout : "");
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return this.generateErrorResponse("RecordingMode " + params.get("recordingMode") + " | "
|
|
||||||
+ "Default OutputMode " + params.get("defaultOutputMode") + " | " + "Default RecordingLayout "
|
|
||||||
+ params.get("defaultRecordingLayout") + " | " + "MediaMode " + params.get("mediaMode")
|
|
||||||
+ ". Some parameter is not defined", "/sessions", HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionProperties sessionProperties = builder.build();
|
|
||||||
|
|
||||||
String sessionId;
|
String sessionId;
|
||||||
if (customSessionId != null && !customSessionId.isEmpty()) {
|
if (sessionProperties.customSessionId() != null && !sessionProperties.customSessionId().isEmpty()) {
|
||||||
if (sessionManager.getSessionWithNotActive(customSessionId) != null) {
|
if (sessionManager.getSessionWithNotActive(sessionProperties.customSessionId()) != null) {
|
||||||
return new ResponseEntity<>(HttpStatus.CONFLICT);
|
return new ResponseEntity<>(HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
sessionId = customSessionId;
|
sessionId = sessionProperties.customSessionId();
|
||||||
} else {
|
} else {
|
||||||
sessionId = IdentifierPrefixes.SESSION_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
|
sessionId = IdentifierPrefixes.SESSION_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
|
||||||
+ RandomStringUtils.randomAlphanumeric(9);
|
+ RandomStringUtils.randomAlphanumeric(9);
|
||||||
|
@ -846,17 +785,76 @@ public class SessionRestController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Token getTokenFromConnectionId(String connectionId, Iterator<Entry<String, Token>> iterator) {
|
protected SessionProperties.Builder getSessionPropertiesFromParams(Map<?, ?> params) throws Exception {
|
||||||
boolean found = false;
|
|
||||||
Token token = null;
|
SessionProperties.Builder builder = new SessionProperties.Builder();
|
||||||
while (iterator.hasNext() && !found) {
|
String customSessionId = null;
|
||||||
Token tAux = iterator.next().getValue();
|
|
||||||
found = tAux.getConnectionId().equals(connectionId);
|
if (params != null) {
|
||||||
if (found) {
|
|
||||||
token = tAux;
|
String mediaModeString;
|
||||||
|
String recordingModeString;
|
||||||
|
String defaultOutputModeString;
|
||||||
|
String defaultRecordingLayoutString;
|
||||||
|
String defaultCustomLayout;
|
||||||
|
try {
|
||||||
|
mediaModeString = (String) params.get("mediaMode");
|
||||||
|
recordingModeString = (String) params.get("recordingMode");
|
||||||
|
defaultOutputModeString = (String) params.get("defaultOutputMode");
|
||||||
|
defaultRecordingLayoutString = (String) params.get("defaultRecordingLayout");
|
||||||
|
defaultCustomLayout = (String) params.get("defaultCustomLayout");
|
||||||
|
customSessionId = (String) params.get("customSessionId");
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new Exception("Type error in some parameter: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Safe parameter retrieval. Default values if not defined
|
||||||
|
if (recordingModeString != null) {
|
||||||
|
RecordingMode recordingMode = RecordingMode.valueOf(recordingModeString);
|
||||||
|
builder = builder.recordingMode(recordingMode);
|
||||||
|
} else {
|
||||||
|
builder = builder.recordingMode(RecordingMode.MANUAL);
|
||||||
|
}
|
||||||
|
if (defaultOutputModeString != null) {
|
||||||
|
OutputMode defaultOutputMode = OutputMode.valueOf(defaultOutputModeString);
|
||||||
|
builder = builder.defaultOutputMode(defaultOutputMode);
|
||||||
|
} else {
|
||||||
|
builder.defaultOutputMode(OutputMode.COMPOSED);
|
||||||
|
}
|
||||||
|
if (defaultRecordingLayoutString != null) {
|
||||||
|
RecordingLayout defaultRecordingLayout = RecordingLayout.valueOf(defaultRecordingLayoutString);
|
||||||
|
builder = builder.defaultRecordingLayout(defaultRecordingLayout);
|
||||||
|
} else {
|
||||||
|
builder.defaultRecordingLayout(RecordingLayout.BEST_FIT);
|
||||||
|
}
|
||||||
|
if (defaultCustomLayout != null) {
|
||||||
|
builder.defaultCustomLayout(defaultCustomLayout);
|
||||||
|
} else {
|
||||||
|
builder.defaultCustomLayout("");
|
||||||
|
}
|
||||||
|
if (mediaModeString != null) {
|
||||||
|
MediaMode mediaMode = MediaMode.valueOf(mediaModeString);
|
||||||
|
builder = builder.mediaMode(mediaMode);
|
||||||
|
} else {
|
||||||
|
builder = builder.mediaMode(MediaMode.ROUTED);
|
||||||
|
}
|
||||||
|
if (customSessionId != null && !customSessionId.isEmpty()) {
|
||||||
|
if (!sessionManager.formatChecker.isValidCustomSessionId(customSessionId)) {
|
||||||
|
throw new Exception(
|
||||||
|
"Parameter 'customSessionId' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-]");
|
||||||
|
}
|
||||||
|
builder = builder.customSessionId(customSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new Exception("RecordingMode " + params.get("recordingMode") + " | " + "Default OutputMode "
|
||||||
|
+ params.get("defaultOutputMode") + " | " + "Default RecordingLayout "
|
||||||
|
+ params.get("defaultRecordingLayout") + " | " + "MediaMode " + params.get("mediaMode")
|
||||||
|
+ ". Some parameter is not defined");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return token;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ConnectionProperties.Builder getConnectionPropertiesFromParams(Map<?, ?> params) throws Exception {
|
protected ConnectionProperties.Builder getConnectionPropertiesFromParams(Map<?, ?> params) throws Exception {
|
||||||
|
@ -975,6 +973,19 @@ public class SessionRestController {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Token getTokenFromConnectionId(String connectionId, Iterator<Entry<String, Token>> iterator) {
|
||||||
|
boolean found = false;
|
||||||
|
Token token = null;
|
||||||
|
while (iterator.hasNext() && !found) {
|
||||||
|
Token tAux = iterator.next().getValue();
|
||||||
|
found = tAux.getConnectionId().equals(connectionId);
|
||||||
|
if (found) {
|
||||||
|
token = tAux;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
protected ResponseEntity<String> generateErrorResponse(String errorMessage, String path, HttpStatus status) {
|
protected ResponseEntity<String> generateErrorResponse(String errorMessage, String path, HttpStatus status) {
|
||||||
JsonObject responseJson = new JsonObject();
|
JsonObject responseJson = new JsonObject();
|
||||||
responseJson.addProperty("timestamp", System.currentTimeMillis());
|
responseJson.addProperty("timestamp", System.currentTimeMillis());
|
||||||
|
|
Loading…
Reference in New Issue