openvidu-server Recording.name

pull/73/head
pabloFuente 2018-04-18 14:21:43 +02:00
parent a34e6db902
commit 766f8e961e
8 changed files with 81 additions and 57 deletions

View File

@ -13,6 +13,7 @@ RESOLUTION="${RESOLUTION:-1920x1080}"
FRAMERATE="${FRAMERATE:-24}" FRAMERATE="${FRAMERATE:-24}"
VIDEO_SIZE="$RESOLUTION" VIDEO_SIZE="$RESOLUTION"
ARRAY=(${VIDEO_SIZE//x/ }) ARRAY=(${VIDEO_SIZE//x/ })
VIDEO_ID="${VIDEO_ID:-video}"
VIDEO_NAME="${VIDEO_NAME:-video}" VIDEO_NAME="${VIDEO_NAME:-video}"
VIDEO_FORMAT="${VIDEO_FORMAT:-mp4}" VIDEO_FORMAT="${VIDEO_FORMAT:-mp4}"
RECORDING_JSON="'${RECORDING_JSON}'" RECORDING_JSON="'${RECORDING_JSON}'"
@ -21,9 +22,9 @@ RECORDING_JSON="'${RECORDING_JSON}'"
### Store Recording json data ### ### Store Recording json data ###
if [[ $CURRENT_UID != $USER_ID ]]; then 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 else
echo ${RECORDING_JSON} > /recordings/.recording.${VIDEO_NAME} echo ${RECORDING_JSON} > /recordings/.recording.${VIDEO_ID}
fi fi
@ -87,9 +88,9 @@ fi
### Generate video report file ### ### Generate video report file ###
if [[ $CURRENT_UID != $USER_ID ]]; then 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 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 fi
@ -97,8 +98,8 @@ fi
if [[ $CURRENT_UID != $USER_ID ]]; then if [[ $CURRENT_UID != $USER_ID ]]; then
TMP=$(su myuser -c "mktemp /recordings/.${VIDEO_NAME}.XXXXXXXXXXXXXXXXXXXXXXX.if.json") TMP=$(su myuser -c "mktemp /recordings/.${VIDEO_ID}.XXXXXXXXXXXXXXXXXXXXXXX.if.json")
INFO=$(su myuser -c "cat /recordings/${VIDEO_NAME}.info | jq '.'") INFO=$(su myuser -c "cat /recordings/${VIDEO_ID}.info | jq '.'")
HAS_AUDIO_AUX=$(su myuser -c "echo '$INFO' | jq '.streams[] | select(.codec_type == \"audio\")'") 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 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\")'") 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'") DURATION=$(su myuser -c "echo '$INFO' | jq '.format.duration | tonumber'")
STATUS="stopped" 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 else
TMP=$(mktemp /recordings/.${VIDEO_NAME}.XXXXXXXXXXXXXXXXXXXXXXX.else.json) TMP=$(mktemp /recordings/.${VIDEO_ID}.XXXXXXXXXXXXXXXXXXXXXXX.else.json)
INFO=$(cat /recordings/${VIDEO_NAME}.info | jq '.') INFO=$(cat /recordings/${VIDEO_ID}.info | jq '.')
HAS_AUDIO_AUX=$(echo "$INFO" | jq '.streams[] | select(.codec_type == "audio")') 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 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")') HAS_VIDEO_AUX=$(echo "$INFO" | jq '.streams[] | select(.codec_type == "video")')
@ -121,7 +122,7 @@ else
DURATION=$(echo "$INFO" | jq '.format.duration | tonumber') DURATION=$(echo "$INFO" | jq '.format.duration | tonumber')
STATUS="stopped" 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 fi

View File

@ -30,6 +30,7 @@ public class CDREvent implements Comparable<CDREvent> {
// Recording events // Recording events
private Long size; private Long size;
private String id; private String id;
private String name;
private Boolean hasAudio; private Boolean hasAudio;
private Boolean hasVideo; private Boolean hasVideo;
@ -63,6 +64,7 @@ public class CDREvent implements Comparable<CDREvent> {
} }
this.timeStamp = System.currentTimeMillis(); this.timeStamp = System.currentTimeMillis();
this.id = recording.getId(); this.id = recording.getId();
this.name = recording.getName();
this.duration = (int) recording.getDuration(); this.duration = (int) recording.getDuration();
this.size = recording.getSize(); this.size = recording.getSize();
this.hasAudio = recording.hasAudio(); this.hasAudio = recording.hasAudio();
@ -132,6 +134,9 @@ public class CDREvent implements Comparable<CDREvent> {
if (this.id != null) { if (this.id != null) {
json.put("id", this.id); json.put("id", this.id);
} }
if (this.name != null) {
json.put("name", this.name);
}
if (this.size != null) { if (this.size != null) {
json.put("size", this.size); json.put("size", this.size);
} }

View File

@ -23,8 +23,8 @@ import io.openvidu.server.recording.Recording;
* - 'participantLeft': {sessionId, timestamp, participantId, startTime, endTime, duration, reason} * - 'participantLeft': {sessionId, timestamp, participantId, startTime, endTime, duration, reason}
* - 'webrtcConnectionCreated' {sessionId, timestamp, participantId, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate]} * - 'webrtcConnectionCreated' {sessionId, timestamp, participantId, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate]}
* - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, endTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason} * - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, endTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason}
* - 'recordingStarted' {sessionId, timestamp, id, hasAudio, hasVideo, size} * - 'recordingStarted' {sessionId, timestamp, id, name, hasAudio, hasVideo, size}
* - 'recordingStopped' {sessionId, timestamp, id, hasAudio, hasVideo, size} * - 'recordingStopped' {sessionId, timestamp, id, name, hasAudio, hasVideo, size}
* *
* PROPERTIES VALUES: * PROPERTIES VALUES:
* *
@ -41,6 +41,7 @@ import io.openvidu.server.recording.Recording;
* - videoSource: "CAMERA", "SCREEN" * - videoSource: "CAMERA", "SCREEN"
* - videoFramerate: number * - videoFramerate: number
* - id: string * - id: string
* - name: string
* - hasAudio: boolean * - hasAudio: boolean
* - hasVideo: boolean * - hasVideo: boolean
* - size: number * - size: number

View File

@ -335,6 +335,7 @@ public class SessionEventsHandler {
JsonObject params = new JsonObject(); JsonObject params = new JsonObject();
params.addProperty(ProtocolElements.RECORDINGSTARTED_ID_PARAM, recording.getId()); params.addProperty(ProtocolElements.RECORDINGSTARTED_ID_PARAM, recording.getId());
params.addProperty(ProtocolElements.RECORDINGSTARTED_NAME_PARAM, recording.getName());
for (Participant p : filteredParticipants) { for (Participant p : filteredParticipants) {
rpcNotificationService.sendNotification(p.getParticipantPrivateId(), rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
@ -366,6 +367,7 @@ public class SessionEventsHandler {
JsonObject params = new JsonObject(); JsonObject params = new JsonObject();
params.addProperty(ProtocolElements.RECORDINGSTOPPED_ID_PARAM, recording.getId()); params.addProperty(ProtocolElements.RECORDINGSTOPPED_ID_PARAM, recording.getId());
params.addProperty(ProtocolElements.RECORDINGSTARTED_NAME_PARAM, recording.getName());
for (Participant p : filteredParticipants) { for (Participant p : filteredParticipants) {
rpcNotificationService.sendNotification(p.getParticipantPrivateId(), rpcNotificationService.sendNotification(p.getParticipantPrivateId(),

View File

@ -233,7 +233,7 @@ public class KurentoSessionManager extends SessionManager {
&& RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode()) && RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
&& !recordingService.sessionIsBeingRecorded(session.getSessionId()) && !recordingService.sessionIsBeingRecorded(session.getSessionId())
&& session.getActivePublishers() == 0) { && session.getActivePublishers() == 0) {
recordingService.startRecording(session); recordingService.startRecording(session, null);
} }
session.newPublisher(participant); session.newPublisher(participant);

View File

@ -81,14 +81,19 @@ public class ComposedRecordingService {
this.dockerClient = DockerClientBuilder.getInstance(config).build(); this.dockerClient = DockerClientBuilder.getInstance(config).build();
} }
public Recording startRecording(Session session) { public Recording startRecording(Session session, String name) {
List<String> envs = new ArrayList<>(); List<String> envs = new ArrayList<>();
String shortSessionId = session.getSessionId().substring(session.getSessionId().lastIndexOf('/') + 1, String shortSessionId = session.getSessionId().substring(session.getSessionId().lastIndexOf('/') + 1,
session.getSessionId().length()); session.getSessionId().length());
String recordingId = this.getFreeRecordingId(session.getSessionId(), shortSessionId); String recordingId = this.getFreeRecordingId(session.getSessionId(), shortSessionId);
String secret = openviduConfig.getOpenViduSecret(); 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.sessionsRecordings.put(session.getSessionId(), recording);
this.sessionHandler.setRecordingStarted(session.getSessionId(), recording); this.sessionHandler.setRecordingStarted(session.getSessionId(), recording);
@ -111,7 +116,8 @@ public class ComposedRecordingService {
+ "/" + secret); + "/" + secret);
envs.add("RESOLUTION=1920x1080"); envs.add("RESOLUTION=1920x1080");
envs.add("FRAMERATE=30"); 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("VIDEO_FORMAT=mp4");
envs.add("USER_ID=" + uid); envs.add("USER_ID=" + uid);
envs.add("RECORDING_JSON=" + recording.toJson().toJSONString()); envs.add("RECORDING_JSON=" + recording.toJson().toJSONString());
@ -122,7 +128,7 @@ public class ComposedRecordingService {
String containerId = this.runRecordingContainer(envs, "recording_" + recordingId); String containerId = this.runRecordingContainer(envs, "recording_" + recordingId);
this.waitForVideoFileNotEmpty(recordingId); this.waitForVideoFileNotEmpty(name);
this.sessionsContainers.put(session.getSessionId(), containerId); this.sessionsContainers.put(session.getSessionId(), containerId);
@ -174,7 +180,7 @@ public class ComposedRecordingService {
// Update recording attributes reading from video report file // Update recording attributes reading from video report file
try { try {
RecordingInfoUtils infoUtils = new RecordingInfoUtils( RecordingInfoUtils infoUtils = new RecordingInfoUtils(
this.openviduConfig.getOpenViduRecordingPath() + recording.getName() + ".info"); this.openviduConfig.getOpenViduRecordingPath() + recording.getId() + ".info");
if (openviduConfig.getOpenViduRecordingPublicAccess()) { if (openviduConfig.getOpenViduRecordingPublicAccess()) {
recording.setStatus(Recording.Status.available); recording.setStatus(Recording.Status.available);
@ -282,7 +288,7 @@ public class ComposedRecordingService {
} }
public Collection<Recording> getAllRecordings() { public Collection<Recording> getAllRecordings() {
return this.getRecordingEntitiesFromHost(); return this.getAllRecordingsFromHost();
} }
public Collection<Recording> getStartingRecordings() { public Collection<Recording> getStartingRecordings() {
@ -294,7 +300,7 @@ public class ComposedRecordingService {
} }
public Collection<Recording> getFinishedRecordings() { public Collection<Recording> getFinishedRecordings() {
return this.getRecordingEntitiesFromHost().stream() return this.getAllRecordingsFromHost().stream()
.filter(recording -> (recording.getStatus().equals(Recording.Status.stopped) .filter(recording -> (recording.getStatus().equals(Recording.Status.stopped)
|| recording.getStatus().equals(Recording.Status.available))) || recording.getStatus().equals(Recording.Status.available)))
.collect(Collectors.toSet()); .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<Recording> getAllRecordingsFromHost() {
File folder = new File(this.openviduConfig.getOpenViduRecordingPath());
File[] files = folder.listFiles();
if (files == null) {
files = initRecordingPath().listFiles();
}
Set<Recording> 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<String> getRecordingIdsFromHost() { private Set<String> getRecordingIdsFromHost() {
File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); File folder = new File(this.openviduConfig.getOpenViduRecordingPath());
File[] files = folder.listFiles(); File[] files = folder.listFiles();
@ -336,31 +372,6 @@ public class ComposedRecordingService {
return fileNamesNoExtension; return fileNamesNoExtension;
} }
private Set<Recording> getRecordingEntitiesFromHost() {
File folder = new File(this.openviduConfig.getOpenViduRecordingPath());
File[] files = folder.listFiles();
if (files == null) {
files = initRecordingPath().listFiles();
}
Set<Recording> 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) { public HttpStatus deleteRecordingFromHost(String recordingId) {
if (this.startedRecordings.containsKey(recordingId) || this.startingRecordings.containsKey(recordingId)) { if (this.startedRecordings.containsKey(recordingId) || this.startingRecordings.containsKey(recordingId)) {
@ -368,11 +379,13 @@ public class ComposedRecordingService {
return HttpStatus.CONFLICT; return HttpStatus.CONFLICT;
} }
String name = getRecordingFromHost(recordingId).getName();
File folder = new File(this.openviduConfig.getOpenViduRecordingPath()); File folder = new File(this.openviduConfig.getOpenViduRecordingPath());
File[] files = folder.listFiles(); File[] files = folder.listFiles();
int numFilesDeleted = 0; int numFilesDeleted = 0;
for (int i = 0; i < files.length; i++) { 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(); files[i].delete();
numFilesDeleted++; numFilesDeleted++;
} }
@ -387,7 +400,7 @@ public class ComposedRecordingService {
return status; return status;
} }
private Recording getRecordingFromFile(File file) { private Recording getRecordingFromEntityFile(File file) {
if (file.isFile() && file.getName().startsWith(RECORDING_ENTITY_FILE)) { if (file.isFile() && file.getName().startsWith(RECORDING_ENTITY_FILE)) {
JSONParser parser = new JSONParser(); JSONParser parser = new JSONParser();
JSONObject json = null; JSONObject json = null;
@ -401,9 +414,10 @@ public class ComposedRecordingService {
return null; return null;
} }
private boolean isFileFromRecording(File file, String recordingId) { private boolean isFileFromRecording(File file, String recordingId, String recordingName) {
return (((recordingId + ".info").equals(file.getName())) || ((recordingId + ".mp4").equals(file.getName())) return (((recordingId + ".info").equals(file.getName()))
|| ((".recording." + recordingId).equals(file.getName()))); || ((RECORDING_ENTITY_FILE + recordingId).equals(file.getName()))
|| (file.getName().equals(recordingName + ".mp4")));
} }
private String getFreeRecordingId(String sessionId, String shortSessionId) { private String getFreeRecordingId(String sessionId, String shortSessionId) {
@ -421,12 +435,12 @@ public class ComposedRecordingService {
return recordingId; return recordingId;
} }
private void waitForVideoFileNotEmpty(String recordingId) { private void waitForVideoFileNotEmpty(String videoName) {
boolean isPresent = false; boolean isPresent = false;
while (!isPresent) { while (!isPresent) {
try { try {
Thread.sleep(150); 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)); isPresent = ((f.isFile()) && (f.length() > 0));
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -29,7 +29,7 @@ public class Recording {
this.sessionId = sessionId; this.sessionId = sessionId;
this.createdAt = System.currentTimeMillis(); this.createdAt = System.currentTimeMillis();
this.id = id; 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; this.status = Status.started;
} }

View File

@ -135,6 +135,7 @@ public class SessionRestController {
public ResponseEntity<JSONObject> startRecordingSession(@RequestBody Map<?, ?> params) { public ResponseEntity<JSONObject> startRecordingSession(@RequestBody Map<?, ?> params) {
String sessionId = (String) params.get("session"); String sessionId = (String) params.get("session");
String name = (String) params.get("name");
if (sessionId == null) { if (sessionId == null) {
// "session" parameter not found // "session" parameter not found
@ -157,7 +158,7 @@ public class SessionRestController {
return new ResponseEntity<JSONObject>(HttpStatus.CONFLICT); return new ResponseEntity<JSONObject>(HttpStatus.CONFLICT);
} }
Recording startedRecording = this.recordingService.startRecording(session); Recording startedRecording = this.recordingService.startRecording(session, name);
return new ResponseEntity<>(startedRecording.toJson(), HttpStatus.OK); return new ResponseEntity<>(startedRecording.toJson(), HttpStatus.OK);
} }