diff --git a/openvidu-server/docker/openvidu-recording/entrypoint.sh b/openvidu-server/docker/openvidu-recording/entrypoint.sh index 8fcc45ab..df3cc40c 100755 --- a/openvidu-server/docker/openvidu-recording/entrypoint.sh +++ b/openvidu-server/docker/openvidu-recording/entrypoint.sh @@ -13,6 +13,7 @@ RESOLUTION="${RESOLUTION:-1920x1080}" FRAMERATE="${FRAMERATE:-24}" VIDEO_SIZE="$RESOLUTION" ARRAY=(${VIDEO_SIZE//x/ }) +VIDEO_ID="${VIDEO_ID:-video}" VIDEO_NAME="${VIDEO_NAME:-video}" VIDEO_FORMAT="${VIDEO_FORMAT:-mp4}" RECORDING_JSON="'${RECORDING_JSON}'" @@ -21,9 +22,9 @@ RECORDING_JSON="'${RECORDING_JSON}'" ### Store Recording json data ### if [[ $CURRENT_UID != $USER_ID ]]; then - su myuser -c "echo ${RECORDING_JSON} > /recordings/.recording.${VIDEO_NAME}" + su myuser -c "echo ${RECORDING_JSON} > /recordings/.recording.${VIDEO_ID}" else - echo ${RECORDING_JSON} > /recordings/.recording.${VIDEO_NAME} + echo ${RECORDING_JSON} > /recordings/.recording.${VIDEO_ID} fi @@ -87,9 +88,9 @@ fi ### Generate video report file ### if [[ $CURRENT_UID != $USER_ID ]]; then - su myuser -c "ffprobe -v quiet -print_format json -show_format -show_streams /recordings/${VIDEO_NAME}.${VIDEO_FORMAT} > /recordings/${VIDEO_NAME}.info" + su myuser -c "ffprobe -v quiet -print_format json -show_format -show_streams /recordings/${VIDEO_NAME}.${VIDEO_FORMAT} > /recordings/${VIDEO_ID}.info" else - ffprobe -v quiet -print_format json -show_format -show_streams /recordings/${VIDEO_NAME}.${VIDEO_FORMAT} > /recordings/${VIDEO_NAME}.info + ffprobe -v quiet -print_format json -show_format -show_streams /recordings/${VIDEO_NAME}.${VIDEO_FORMAT} > /recordings/${VIDEO_ID}.info fi @@ -97,8 +98,8 @@ fi if [[ $CURRENT_UID != $USER_ID ]]; then - TMP=$(su myuser -c "mktemp /recordings/.${VIDEO_NAME}.XXXXXXXXXXXXXXXXXXXXXXX.if.json") - INFO=$(su myuser -c "cat /recordings/${VIDEO_NAME}.info | jq '.'") + TMP=$(su myuser -c "mktemp /recordings/.${VIDEO_ID}.XXXXXXXXXXXXXXXXXXXXXXX.if.json") + INFO=$(su myuser -c "cat /recordings/${VIDEO_ID}.info | jq '.'") HAS_AUDIO_AUX=$(su myuser -c "echo '$INFO' | jq '.streams[] | select(.codec_type == \"audio\")'") if [ -z "$HAS_AUDIO_AUX" ]; then HAS_AUDIO=false; else HAS_AUDIO=true; fi HAS_VIDEO_AUX=$(su myuser -c "echo '$INFO' | jq '.streams[] | select(.codec_type == \"video\")'") @@ -107,12 +108,12 @@ if [[ $CURRENT_UID != $USER_ID ]]; then DURATION=$(su myuser -c "echo '$INFO' | jq '.format.duration | tonumber'") STATUS="stopped" - su myuser -c "jq -c -r \".hasAudio=${HAS_AUDIO} | .hasVideo=${HAS_VIDEO} | .duration=${DURATION} | .size=${SIZE} | .status=\\\"${STATUS}\\\"\" \"/recordings/.recording.${VIDEO_NAME}\" > ${TMP} && mv ${TMP} \"/recordings/.recording.${VIDEO_NAME}\"" + su myuser -c "jq -c -r \".hasAudio=${HAS_AUDIO} | .hasVideo=${HAS_VIDEO} | .duration=${DURATION} | .size=${SIZE} | .status=\\\"${STATUS}\\\"\" \"/recordings/.recording.${VIDEO_ID}\" > ${TMP} && mv ${TMP} \"/recordings/.recording.${VIDEO_ID}\"" else - TMP=$(mktemp /recordings/.${VIDEO_NAME}.XXXXXXXXXXXXXXXXXXXXXXX.else.json) - INFO=$(cat /recordings/${VIDEO_NAME}.info | jq '.') + TMP=$(mktemp /recordings/.${VIDEO_ID}.XXXXXXXXXXXXXXXXXXXXXXX.else.json) + INFO=$(cat /recordings/${VIDEO_ID}.info | jq '.') HAS_AUDIO_AUX=$(echo "$INFO" | jq '.streams[] | select(.codec_type == "audio")') if [ -z "$HAS_AUDIO_AUX" ]; then HAS_AUDIO=false; else HAS_AUDIO=true; fi HAS_VIDEO_AUX=$(echo "$INFO" | jq '.streams[] | select(.codec_type == "video")') @@ -121,7 +122,7 @@ else DURATION=$(echo "$INFO" | jq '.format.duration | tonumber') STATUS="stopped" - jq -c -r ".hasAudio=${HAS_AUDIO} | .hasVideo=${HAS_VIDEO} | .duration=${DURATION} | .size=${SIZE} | .status=\"${STATUS}\"" "/recordings/.recording.${VIDEO_NAME}" > ${TMP} && mv ${TMP} "/recordings/.recording.${VIDEO_NAME}" + jq -c -r ".hasAudio=${HAS_AUDIO} | .hasVideo=${HAS_VIDEO} | .duration=${DURATION} | .size=${SIZE} | .status=\"${STATUS}\"" "/recordings/.recording.${VIDEO_ID}" > ${TMP} && mv ${TMP} "/recordings/.recording.${VIDEO_ID}" fi 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 e33e1e42..2fbd2212 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 @@ -30,6 +30,7 @@ public class CDREvent implements Comparable { // Recording events private Long size; private String id; + private String name; private Boolean hasAudio; private Boolean hasVideo; @@ -63,6 +64,7 @@ public class CDREvent implements Comparable { } this.timeStamp = System.currentTimeMillis(); this.id = recording.getId(); + this.name = recording.getName(); this.duration = (int) recording.getDuration(); this.size = recording.getSize(); this.hasAudio = recording.hasAudio(); @@ -132,6 +134,9 @@ public class CDREvent implements Comparable { if (this.id != null) { json.put("id", this.id); } + if (this.name != null) { + json.put("name", this.name); + } if (this.size != null) { json.put("size", this.size); } diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java index 4d6576ac..2a9a62a9 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java @@ -23,8 +23,8 @@ import io.openvidu.server.recording.Recording; * - 'participantLeft': {sessionId, timestamp, participantId, startTime, endTime, duration, reason} * - 'webrtcConnectionCreated' {sessionId, timestamp, participantId, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate]} * - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, endTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason} - * - 'recordingStarted' {sessionId, timestamp, id, hasAudio, hasVideo, size} - * - 'recordingStopped' {sessionId, timestamp, id, hasAudio, hasVideo, size} + * - 'recordingStarted' {sessionId, timestamp, id, name, hasAudio, hasVideo, size} + * - 'recordingStopped' {sessionId, timestamp, id, name, hasAudio, hasVideo, size} * * PROPERTIES VALUES: * @@ -41,6 +41,7 @@ import io.openvidu.server.recording.Recording; * - videoSource: "CAMERA", "SCREEN" * - videoFramerate: number * - id: string + * - name: string * - hasAudio: boolean * - hasVideo: boolean * - size: number diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java index 1306bf5d..55fb79b6 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java @@ -335,6 +335,7 @@ public class SessionEventsHandler { JsonObject params = new JsonObject(); params.addProperty(ProtocolElements.RECORDINGSTARTED_ID_PARAM, recording.getId()); + params.addProperty(ProtocolElements.RECORDINGSTARTED_NAME_PARAM, recording.getName()); for (Participant p : filteredParticipants) { rpcNotificationService.sendNotification(p.getParticipantPrivateId(), @@ -366,6 +367,7 @@ public class SessionEventsHandler { JsonObject params = new JsonObject(); params.addProperty(ProtocolElements.RECORDINGSTOPPED_ID_PARAM, recording.getId()); + params.addProperty(ProtocolElements.RECORDINGSTARTED_NAME_PARAM, recording.getName()); for (Participant p : filteredParticipants) { rpcNotificationService.sendNotification(p.getParticipantPrivateId(), 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 dab9c44c..483df48a 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 @@ -233,7 +233,7 @@ public class KurentoSessionManager extends SessionManager { && RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode()) && !recordingService.sessionIsBeingRecorded(session.getSessionId()) && session.getActivePublishers() == 0) { - recordingService.startRecording(session); + recordingService.startRecording(session, null); } session.newPublisher(participant); 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 e9d4556a..bb196ff6 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 @@ -60,7 +60,7 @@ public class ComposedRecordingService { @Autowired OpenviduConfig openviduConfig; - + @Autowired private SessionEventsHandler sessionHandler; @@ -81,14 +81,19 @@ public class ComposedRecordingService { this.dockerClient = DockerClientBuilder.getInstance(config).build(); } - public Recording startRecording(Session session) { + public Recording startRecording(Session session, String name) { 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(); - Recording recording = new Recording(session.getSessionId(), recordingId, recordingId); + if (name == null || name.isEmpty()) { + // No name provided for the recording file + name = recordingId; + } + + Recording recording = new Recording(session.getSessionId(), recordingId, name); this.sessionsRecordings.put(session.getSessionId(), recording); this.sessionHandler.setRecordingStarted(session.getSessionId(), recording); @@ -111,7 +116,8 @@ public class ComposedRecordingService { + "/" + secret); envs.add("RESOLUTION=1920x1080"); envs.add("FRAMERATE=30"); - envs.add("VIDEO_NAME=" + recordingId); + envs.add("VIDEO_ID=" + recordingId); + envs.add("VIDEO_NAME=" + name); envs.add("VIDEO_FORMAT=mp4"); envs.add("USER_ID=" + uid); envs.add("RECORDING_JSON=" + recording.toJson().toJSONString()); @@ -122,7 +128,7 @@ public class ComposedRecordingService { String containerId = this.runRecordingContainer(envs, "recording_" + recordingId); - this.waitForVideoFileNotEmpty(recordingId); + this.waitForVideoFileNotEmpty(name); this.sessionsContainers.put(session.getSessionId(), containerId); @@ -174,7 +180,7 @@ public class ComposedRecordingService { // Update recording attributes reading from video report file try { RecordingInfoUtils infoUtils = new RecordingInfoUtils( - this.openviduConfig.getOpenViduRecordingPath() + recording.getName() + ".info"); + this.openviduConfig.getOpenViduRecordingPath() + recording.getId() + ".info"); if (openviduConfig.getOpenViduRecordingPublicAccess()) { recording.setStatus(Recording.Status.available); @@ -194,9 +200,9 @@ public class ComposedRecordingService { throw new OpenViduException(Code.RECORDING_REPORT_ERROR_CODE, "There was an error generating the metadata report file for the recording"); } - + this.sessionHandler.sendRecordingStoppedNotification(session, recording); - + return recording; } @@ -282,7 +288,7 @@ public class ComposedRecordingService { } public Collection getAllRecordings() { - return this.getRecordingEntitiesFromHost(); + return this.getAllRecordingsFromHost(); } public Collection getStartingRecordings() { @@ -294,7 +300,7 @@ public class ComposedRecordingService { } public Collection getFinishedRecordings() { - return this.getRecordingEntitiesFromHost().stream() + return this.getAllRecordingsFromHost().stream() .filter(recording -> (recording.getStatus().equals(Recording.Status.stopped) || recording.getStatus().equals(Recording.Status.available))) .collect(Collectors.toSet()); @@ -319,6 +325,36 @@ public class ComposedRecordingService { } } + private Recording getRecordingFromHost(String recordingId) { + File file = new File(this.openviduConfig.getOpenViduRecordingPath() + RECORDING_ENTITY_FILE + recordingId); + return this.getRecordingFromEntityFile(file); + } + + private Set getAllRecordingsFromHost() { + File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); + File[] files = folder.listFiles(); + + if (files == null) { + files = initRecordingPath().listFiles(); + } + + Set recordingEntities = new HashSet<>(); + for (int i = 0; i < files.length; i++) { + Recording recording = this.getRecordingFromEntityFile(files[i]); + if (recording != null) { + if (openviduConfig.getOpenViduRecordingPublicAccess()) { + if (Recording.Status.stopped.equals(recording.getStatus())) { + recording.setStatus(Recording.Status.available); + recording.setUrl( + this.openviduConfig.getFinalUrl() + "recordings/" + recording.getName() + ".mp4"); + } + } + recordingEntities.add(recording); + } + } + return recordingEntities; + } + private Set getRecordingIdsFromHost() { File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); File[] files = folder.listFiles(); @@ -336,43 +372,20 @@ public class ComposedRecordingService { return fileNamesNoExtension; } - private Set getRecordingEntitiesFromHost() { - File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); - File[] files = folder.listFiles(); - - if (files == null) { - files = initRecordingPath().listFiles(); - } - - Set recordingEntities = new HashSet<>(); - for (int i = 0; i < files.length; i++) { - Recording recording = this.getRecordingFromFile(files[i]); - if (recording != null) { - if (openviduConfig.getOpenViduRecordingPublicAccess()) { - if (Recording.Status.stopped.equals(recording.getStatus())) { - recording.setStatus(Recording.Status.available); - recording.setUrl( - this.openviduConfig.getFinalUrl() + "recordings/" + recording.getName() + ".mp4"); - } - } - recordingEntities.add(recording); - } - } - return recordingEntities; - } - public HttpStatus deleteRecordingFromHost(String recordingId) { if (this.startedRecordings.containsKey(recordingId) || this.startingRecordings.containsKey(recordingId)) { // Cannot delete an active recording return HttpStatus.CONFLICT; } + + String name = getRecordingFromHost(recordingId).getName(); File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); File[] files = folder.listFiles(); int numFilesDeleted = 0; for (int i = 0; i < files.length; i++) { - if (files[i].isFile() && isFileFromRecording(files[i], recordingId)) { + if (files[i].isFile() && isFileFromRecording(files[i], recordingId, name)) { files[i].delete(); numFilesDeleted++; } @@ -387,7 +400,7 @@ public class ComposedRecordingService { return status; } - private Recording getRecordingFromFile(File file) { + private Recording getRecordingFromEntityFile(File file) { if (file.isFile() && file.getName().startsWith(RECORDING_ENTITY_FILE)) { JSONParser parser = new JSONParser(); JSONObject json = null; @@ -401,9 +414,10 @@ public class ComposedRecordingService { return null; } - private boolean isFileFromRecording(File file, String recordingId) { - return (((recordingId + ".info").equals(file.getName())) || ((recordingId + ".mp4").equals(file.getName())) - || ((".recording." + recordingId).equals(file.getName()))); + private boolean isFileFromRecording(File file, String recordingId, String recordingName) { + return (((recordingId + ".info").equals(file.getName())) + || ((RECORDING_ENTITY_FILE + recordingId).equals(file.getName())) + || (file.getName().equals(recordingName + ".mp4"))); } private String getFreeRecordingId(String sessionId, String shortSessionId) { @@ -421,12 +435,12 @@ public class ComposedRecordingService { return recordingId; } - private void waitForVideoFileNotEmpty(String recordingId) { + private void waitForVideoFileNotEmpty(String videoName) { boolean isPresent = false; while (!isPresent) { try { Thread.sleep(150); - File f = new File(this.openviduConfig.getOpenViduRecordingPath() + recordingId + ".mp4"); + File f = new File(this.openviduConfig.getOpenViduRecordingPath() + videoName + ".mp4"); isPresent = ((f.isFile()) && (f.length() > 0)); } catch (InterruptedException e) { e.printStackTrace(); 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 9fa07cbd..47038181 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 @@ -29,7 +29,7 @@ public class Recording { this.sessionId = sessionId; this.createdAt = System.currentTimeMillis(); this.id = id; - this.name = id; // For now the name of the recording file is the same as its id + this.name = name; this.status = Status.started; } 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 3637be28..f5a64834 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 @@ -135,6 +135,7 @@ public class SessionRestController { public ResponseEntity startRecordingSession(@RequestBody Map params) { String sessionId = (String) params.get("session"); + String name = (String) params.get("name"); if (sessionId == null) { // "session" parameter not found @@ -157,7 +158,7 @@ public class SessionRestController { return new ResponseEntity(HttpStatus.CONFLICT); } - Recording startedRecording = this.recordingService.startRecording(session); + Recording startedRecording = this.recordingService.startRecording(session, name); return new ResponseEntity<>(startedRecording.toJson(), HttpStatus.OK); }