From a228b1242e29641bbf8fdda8fe7bc5dabbc92f3c Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Fri, 20 Apr 2018 12:10:06 +0200 Subject: [PATCH] openvidu-server: added RecordingProperties feature --- .../java/io/openvidu/server/cdr/CDREvent.java | 6 ++ .../kurento/core/KurentoSessionManager.java | 7 ++- .../recording/ComposedRecordingService.java | 18 +++--- .../openvidu/server/recording/Recording.java | 39 ++++++++----- .../server/rest/SessionRestController.java | 56 +++++++++++++------ 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java index 2fbd2212..db9e205d 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDREvent.java @@ -2,6 +2,7 @@ package io.openvidu.server.cdr; import org.json.simple.JSONObject; +import io.openvidu.java.client.RecordingLayout; import io.openvidu.server.core.MediaOptions; import io.openvidu.server.core.Participant; import io.openvidu.server.recording.Recording; @@ -33,6 +34,7 @@ public class CDREvent implements Comparable { private String name; private Boolean hasAudio; private Boolean hasVideo; + private RecordingLayout layout; public CDREvent(String eventName, CDREvent event) { this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime, event.reason); @@ -69,6 +71,7 @@ public class CDREvent implements Comparable { this.size = recording.getSize(); this.hasAudio = recording.hasAudio(); this.hasVideo = recording.hasVideo(); + this.layout = recording.getLayout(); } public CDREvent(String eventName, Participant participant, String sessionId) { @@ -146,6 +149,9 @@ public class CDREvent implements Comparable { if (this.hasVideo != null) { json.put("hasVideo", this.hasVideo); } + if (this.layout != null) { + json.put("layout", this.layout.name()); + } JSONObject root = new JSONObject(); root.put(this.eventName, json); diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java index 493555fd..fffd7d88 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java @@ -20,6 +20,7 @@ import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.internal.ProtocolElements; import io.openvidu.java.client.RecordingLayout; import io.openvidu.java.client.RecordingMode; +import io.openvidu.java.client.RecordingProperties; import io.openvidu.java.client.MediaMode; import io.openvidu.java.client.SessionProperties; import io.openvidu.server.core.SessionManager; @@ -55,7 +56,8 @@ public class KurentoSessionManager extends SessionManager { SessionProperties properties = sessionProperties.get(sessionId); if (properties == null && this.isInsecureParticipant(participant.getParticipantPrivateId())) { properties = new SessionProperties.Builder().mediaMode(MediaMode.ROUTED) - .recordingMode(RecordingMode.ALWAYS).recordingLayout(RecordingLayout.BEST_FIT).build(); + .recordingMode(RecordingMode.ALWAYS).defaultRecordingLayout(RecordingLayout.BEST_FIT) + .build(); } createSession(kcSessionInfo, properties); } @@ -235,7 +237,8 @@ public class KurentoSessionManager extends SessionManager { && session.getActivePublishers() == 0) { // Insecure session recording new Thread(() -> { - recordingService.startRecording(session, null); + recordingService.startRecording(session, new RecordingProperties.Builder().name("") + .recordingLayout(session.getSessionProperties().defaultRecordingLayout()).build()); }).start(); } diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/ComposedRecordingService.java b/openvidu-server/src/main/java/io/openvidu/server/recording/ComposedRecordingService.java index bb196ff6..ceb38c84 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/recording/ComposedRecordingService.java +++ b/openvidu-server/src/main/java/io/openvidu/server/recording/ComposedRecordingService.java @@ -47,6 +47,7 @@ import com.github.dockerjava.core.command.PullImageResultCallback; import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException.Code; +import io.openvidu.java.client.RecordingProperties; import io.openvidu.server.CommandExecutor; import io.openvidu.server.OpenViduServer; import io.openvidu.server.config.OpenviduConfig; @@ -81,19 +82,20 @@ public class ComposedRecordingService { this.dockerClient = DockerClientBuilder.getInstance(config).build(); } - public Recording startRecording(Session session, String name) { + public Recording startRecording(Session session, RecordingProperties properties) { List envs = new ArrayList<>(); String shortSessionId = session.getSessionId().substring(session.getSessionId().lastIndexOf('/') + 1, session.getSessionId().length()); String recordingId = this.getFreeRecordingId(session.getSessionId(), shortSessionId); String secret = openviduConfig.getOpenViduSecret(); - if (name == null || name.isEmpty()) { + if (properties.name() == null || properties.name().isEmpty()) { // No name provided for the recording file - name = recordingId; + properties = new RecordingProperties.Builder().name(recordingId) + .recordingLayout(properties.recordingLayout()).build(); } - Recording recording = new Recording(session.getSessionId(), recordingId, name); + Recording recording = new Recording(session.getSessionId(), recordingId, properties); this.sessionsRecordings.put(session.getSessionId(), recording); this.sessionHandler.setRecordingStarted(session.getSessionId(), recording); @@ -110,14 +112,14 @@ public class ComposedRecordingService { } String location = OpenViduServer.publicUrl.replaceFirst("wss://", ""); - String layoutUrl = session.getSessionProperties().recordingLayout().name().toLowerCase().replaceAll("_", "-"); + String layoutUrl = properties.recordingLayout().name().toLowerCase().replaceAll("_", "-"); envs.add("URL=https://OPENVIDUAPP:" + secret + "@" + location + "/#/layout-" + layoutUrl + "/" + shortSessionId + "/" + secret); envs.add("RESOLUTION=1920x1080"); envs.add("FRAMERATE=30"); envs.add("VIDEO_ID=" + recordingId); - envs.add("VIDEO_NAME=" + name); + envs.add("VIDEO_NAME=" + properties.name()); envs.add("VIDEO_FORMAT=mp4"); envs.add("USER_ID=" + uid); envs.add("RECORDING_JSON=" + recording.toJson().toJSONString()); @@ -128,7 +130,7 @@ public class ComposedRecordingService { String containerId = this.runRecordingContainer(envs, "recording_" + recordingId); - this.waitForVideoFileNotEmpty(name); + this.waitForVideoFileNotEmpty(properties.name()); this.sessionsContainers.put(session.getSessionId(), containerId); @@ -378,7 +380,7 @@ public class ComposedRecordingService { // Cannot delete an active recording return HttpStatus.CONFLICT; } - + String name = getRecordingFromHost(recordingId).getName(); File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/Recording.java b/openvidu-server/src/main/java/io/openvidu/server/recording/Recording.java index 47038181..e49770a1 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/recording/Recording.java +++ b/openvidu-server/src/main/java/io/openvidu/server/recording/Recording.java @@ -2,6 +2,9 @@ package io.openvidu.server.recording; import org.json.simple.JSONObject; +import io.openvidu.java.client.RecordingLayout; +import io.openvidu.java.client.RecordingProperties; + public class Recording { public enum Status { @@ -9,14 +12,13 @@ public class Recording { started, // The recording has started and is going on stopped, // The recording has finished OK available, // The recording is available for downloading. This status is reached for all - // stopped recordings if property 'openvidu.recording.free-access' is true + // stopped recordings if property 'openvidu.recording.free-access' is true failed; // The recording has failed } - private Status status; + private Recording.Status status; private String id; - private String name; private String sessionId; private long createdAt; // milliseconds (UNIX Epoch time) private long size = 0; // bytes @@ -24,18 +26,18 @@ public class Recording { private String url; private boolean hasAudio = true; private boolean hasVideo = true; + private RecordingProperties recordingProperties; - public Recording(String sessionId, String id, String name) { + public Recording(String sessionId, String id, RecordingProperties recordingProperties) { this.sessionId = sessionId; this.createdAt = System.currentTimeMillis(); this.id = id; - this.name = name; this.status = Status.started; + this.recordingProperties = recordingProperties; } public Recording(JSONObject json) { this.id = (String) json.get("id"); - this.name = (String) json.get("name"); this.sessionId = (String) json.get("sessionId"); this.createdAt = (long) json.get("createdAt"); this.size = (long) json.get("size"); @@ -44,6 +46,8 @@ public class Recording { this.hasAudio = (boolean) json.get("hasAudio"); this.hasVideo = (boolean) json.get("hasVideo"); this.status = Status.valueOf((String) json.get("status")); + this.recordingProperties = new RecordingProperties.Builder().name((String) json.get("name")) + .recordingLayout(RecordingLayout.valueOf((String) json.get("layout"))).build(); } public Status getStatus() { @@ -62,13 +66,21 @@ public class Recording { this.id = id; } - public String getName() { - return name; - } + public String getName() { + return this.recordingProperties.name(); + } + + public String setName() { + return this.recordingProperties.name(); + } - public void setName(String name) { - this.name = name; - } + public RecordingLayout getLayout() { + return this.recordingProperties.recordingLayout(); + } + + public RecordingLayout setLayout() { + return this.recordingProperties.recordingLayout(); + } public String getSessionId() { return sessionId; @@ -130,7 +142,8 @@ public class Recording { public JSONObject toJson() { JSONObject json = new JSONObject(); json.put("id", this.id); - json.put("name", this.name); + json.put("name", this.recordingProperties.name()); + json.put("layout", this.recordingProperties.recordingLayout().name()); json.put("sessionId", this.sessionId); json.put("createdAt", this.createdAt); json.put("size", this.size); diff --git a/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java b/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java index f5a64834..8903f299 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java +++ b/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java @@ -37,6 +37,7 @@ import io.openvidu.client.OpenViduException; import io.openvidu.client.internal.ProtocolElements; import io.openvidu.java.client.RecordingLayout; import io.openvidu.java.client.RecordingMode; +import io.openvidu.java.client.RecordingProperties; import io.openvidu.java.client.MediaMode; import io.openvidu.java.client.SessionProperties; import io.openvidu.server.core.ParticipantRole; @@ -72,7 +73,7 @@ public class SessionRestController { SessionProperties.Builder builder = new SessionProperties.Builder(); if (params != null) { String recordingModeString = (String) params.get("recordingMode"); - String recordingLayoutString = (String) params.get("recordingLayout"); + String defaultRecordingLayoutString = (String) params.get("defaultRecordingLayout"); String mediaModeString = (String) params.get("mediaMode"); try { @@ -80,18 +81,18 @@ public class SessionRestController { RecordingMode recordingMode = RecordingMode.valueOf(recordingModeString); builder = builder.recordingMode(recordingMode); } - if (recordingLayoutString != null) { - RecordingLayout recordingLayout = RecordingLayout.valueOf(recordingLayoutString); - builder = builder.recordingLayout(recordingLayout); + if (defaultRecordingLayoutString != null) { + RecordingLayout defaultRecordingLayout = RecordingLayout.valueOf(defaultRecordingLayoutString); + builder = builder.defaultRecordingLayout(defaultRecordingLayout); } if (mediaModeString != null) { MediaMode mediaMode = MediaMode.valueOf(mediaModeString); builder = builder.mediaMode(mediaMode); } } catch (IllegalArgumentException e) { - return this.generateErrorResponse("RecordingMode " + params.get("recordingMode") + " | " + "RecordingLayout " - + params.get("recordingLayout") + " | " + "MediaMode " + params.get("mediaMode") - + " are not defined", "/api/tokens", HttpStatus.BAD_REQUEST); + return this.generateErrorResponse("RecordingMode " + params.get("recordingMode") + " | " + + "Default RecordingLayout " + params.get("defaultRecordingLayout") + " | " + "MediaMode " + + params.get("mediaMode") + " are not defined", "/api/tokens", HttpStatus.BAD_REQUEST); } } @@ -109,9 +110,20 @@ public class SessionRestController { try { String sessionId = (String) params.get("session"); - ParticipantRole role = ParticipantRole.valueOf((String) params.get("role")); + String roleString = (String) params.get("role"); String metadata = (String) params.get("data"); + ParticipantRole role; + if (roleString != null) { + role = ParticipantRole.valueOf(roleString); + } else { + role = ParticipantRole.PUBLISHER; + } + + if (metadata == null) { + metadata = ""; + } + String token = sessionManager.newToken(sessionId, role, metadata); JSONObject responseJson = new JSONObject(); responseJson.put("id", token); @@ -136,6 +148,7 @@ public class SessionRestController { String sessionId = (String) params.get("session"); String name = (String) params.get("name"); + String recordingLayoutString = (String) params.get("recordingLayout"); if (sessionId == null) { // "session" parameter not found @@ -158,7 +171,18 @@ public class SessionRestController { return new ResponseEntity(HttpStatus.CONFLICT); } - Recording startedRecording = this.recordingService.startRecording(session, name); + RecordingLayout recordingLayout; + if (recordingLayoutString == null || recordingLayoutString.isEmpty()) { + // "recordingLayout" parameter not defined. Use global layout from + // SessionProperties + // (it is always configured as it has RecordingLayout.BEST_FIT as default value) + recordingLayout = session.getSessionProperties().defaultRecordingLayout(); + } else { + recordingLayout = RecordingLayout.valueOf(recordingLayoutString); + } + + Recording startedRecording = this.recordingService.startRecording(session, + new RecordingProperties.Builder().name(name).recordingLayout(recordingLayout).build()); return new ResponseEntity<>(startedRecording.toJson(), HttpStatus.OK); } @@ -184,14 +208,14 @@ public class SessionRestController { // Session is not being recorded return new ResponseEntity(HttpStatus.CONFLICT); } - + Session session = sessionManager.getSession(recording.getSessionId()); - - Recording stoppedRecording = this.recordingService - .stopRecording(session); - - sessionManager.evictParticipant(session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID).getParticipantPrivateId(), "EVICT_RECORDER"); - + + Recording stoppedRecording = this.recordingService.stopRecording(session); + + sessionManager.evictParticipant(session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID) + .getParticipantPrivateId(), "EVICT_RECORDER"); + return new ResponseEntity<>(stoppedRecording.toJson(), HttpStatus.OK); }