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}"
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

View File

@ -30,6 +30,7 @@ public class CDREvent implements Comparable<CDREvent> {
// 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<CDREvent> {
}
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<CDREvent> {
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);
}

View File

@ -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

View File

@ -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(),

View File

@ -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);

View File

@ -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<String> 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<Recording> getAllRecordings() {
return this.getRecordingEntitiesFromHost();
return this.getAllRecordingsFromHost();
}
public Collection<Recording> getStartingRecordings() {
@ -294,7 +300,7 @@ public class ComposedRecordingService {
}
public Collection<Recording> 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<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() {
File folder = new File(this.openviduConfig.getOpenViduRecordingPath());
File[] files = folder.listFiles();
@ -336,43 +372,20 @@ public class ComposedRecordingService {
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) {
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();

View File

@ -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;
}

View File

@ -135,6 +135,7 @@ public class SessionRestController {
public ResponseEntity<JSONObject> 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<JSONObject>(HttpStatus.CONFLICT);
}
Recording startedRecording = this.recordingService.startRecording(session);
Recording startedRecording = this.recordingService.startRecording(session, name);
return new ResponseEntity<>(startedRecording.toJson(), HttpStatus.OK);
}