mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server Recording.name
parent
a34e6db902
commit
766f8e961e
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue