openvidu-server: automatically stip MANUAL recording after timeout

pull/173/head
pabloFuente 2018-11-23 15:36:49 +01:00
parent a05b23347f
commit 4452e048a2
2 changed files with 66 additions and 31 deletions

View File

@ -175,14 +175,21 @@ public class KurentoSessionManager extends SessionManager {
showTokens(); showTokens();
} else if (remainingParticipants.size() == 1 && openviduConfig.isRecordingModuleEnabled() } else if (remainingParticipants.size() == 1 && openviduConfig.isRecordingModuleEnabled()
&& MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode()) && MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode())
&& RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
&& ProtocolElements.RECORDER_PARTICIPANT_PUBLICID && ProtocolElements.RECORDER_PARTICIPANT_PUBLICID
.equals(remainingParticipants.iterator().next().getParticipantPublicId())) { .equals(remainingParticipants.iterator().next().getParticipantPublicId())) {
if (RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())) {
// Immediately stop recording when last real participant left if
// RecordingMode.ALWAYS
log.info("Last participant left. Stopping recording for session {}", sessionId); log.info("Last participant left. Stopping recording for session {}", sessionId);
recordingService.stopRecording(session, null, reason); recordingService.stopRecording(session, null, reason);
evictParticipant(session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID), null, evictParticipant(session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID), null,
null, "EVICT_RECORDER"); null, "EVICT_RECORDER");
} else if (RecordingMode.MANUAL.equals(session.getSessionProperties().recordingMode())) {
// Start countdown to stop recording if RecordingMode.MANUAL (will be aborted if
// a Publisher starts before timeout)
log.info("Last participant left. Starting countdown for stopping recording of session {}", sessionId);
recordingService.initAutomaticRecordingStopThread(session.getSessionId());
}
} }
// Finally close websocket session if required // Finally close websocket session if required
@ -206,14 +213,10 @@ public class KurentoSessionManager extends SessionManager {
* the peer's request by sending it the SDP response (answer or updated offer) * the peer's request by sending it the SDP response (answer or updated offer)
* generated by the WebRTC endpoint on the server. * generated by the WebRTC endpoint on the server.
* *
* @param participant * @param participant Participant publishing video
* Participant publishing video * @param MediaOptions configuration of the stream to publish
* @param MediaOptions * @param transactionId identifier of the Transaction
* configuration of the stream to publish * @throws OpenViduException on error
* @param transactionId
* identifier of the Transaction
* @throws OpenViduException
* on error
*/ */
@Override @Override
public void publishVideo(Participant participant, MediaOptions mediaOptions, Integer transactionId) public void publishVideo(Participant participant, MediaOptions mediaOptions, Integer transactionId)
@ -272,9 +275,9 @@ public class KurentoSessionManager extends SessionManager {
if (this.openviduConfig.isRecordingModuleEnabled() if (this.openviduConfig.isRecordingModuleEnabled()
&& MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode()) && MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode())
&& RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
&& !recordingService.sessionIsBeingRecorded(session.getSessionId())
&& session.getActivePublishers() == 0) { && session.getActivePublishers() == 0) {
if (RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
&& !recordingService.sessionIsBeingRecorded(session.getSessionId())) {
// Insecure session recording // Insecure session recording
new Thread(() -> { new Thread(() -> {
recordingService.startRecording(session, recordingService.startRecording(session,
@ -282,6 +285,19 @@ public class KurentoSessionManager extends SessionManager {
.recordingLayout(session.getSessionProperties().defaultRecordingLayout()) .recordingLayout(session.getSessionProperties().defaultRecordingLayout())
.customLayout(session.getSessionProperties().defaultCustomLayout()).build()); .customLayout(session.getSessionProperties().defaultCustomLayout()).build());
}).start(); }).start();
} else if (RecordingMode.MANUAL.equals(session.getSessionProperties().recordingMode())
&& recordingService.sessionIsBeingRecorded(session.getSessionId())) {
// Abort automatic recording stop (user published before timeout)
log.info("Participant {} published before timeout finished. Aborting automatic recording stop",
participant.getParticipantPublicId());
boolean stopAborted = recordingService.abortAutomaticRecordingStopThread(session.getSessionId());
if (stopAborted) {
log.info("Automatic recording stopped succesfully aborted");
} else {
log.info("Automatic recording stopped couldn't be aborted. Recording of session {} has stopped",
session.getSessionId());
}
}
} }
session.newPublisher(participant); session.newPublisher(participant);
@ -458,12 +474,10 @@ public class KurentoSessionManager extends SessionManager {
* Creates a session if it doesn't already exist. The session's id will be * Creates a session if it doesn't already exist. The session's id will be
* indicated by the session info bean. * indicated by the session info bean.
* *
* @param kcSessionInfo * @param kcSessionInfo bean that will be passed to the
* bean that will be passed to the {@link KurentoClientProvider} in * {@link KurentoClientProvider} in order to obtain the
* order to obtain the {@link KurentoClient} that will be used by the * {@link KurentoClient} that will be used by the room
* room * @throws OpenViduException in case of error while creating the session
* @throws OpenViduException
* in case of error while creating the session
*/ */
public void createSession(KurentoClientSessionInfo kcSessionInfo, SessionProperties sessionProperties) public void createSession(KurentoClientSessionInfo kcSessionInfo, SessionProperties sessionProperties)
throws OpenViduException { throws OpenViduException {

View File

@ -31,6 +31,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -87,6 +89,10 @@ public class ComposedRecordingService {
private Map<String, Recording> startingRecordings = new ConcurrentHashMap<>(); private Map<String, Recording> startingRecordings = new ConcurrentHashMap<>();
private Map<String, Recording> startedRecordings = new ConcurrentHashMap<>(); private Map<String, Recording> startedRecordings = new ConcurrentHashMap<>();
private Map<String, Recording> sessionsRecordings = new ConcurrentHashMap<>(); private Map<String, Recording> sessionsRecordings = new ConcurrentHashMap<>();
private final Map<String, ScheduledFuture<?>> automaticRecordingStopThreads = new ConcurrentHashMap<>();
private ScheduledThreadPoolExecutor automaticRecordingStopExecutor = new ScheduledThreadPoolExecutor(
Runtime.getRuntime().availableProcessors());
private final String IMAGE_NAME = "openvidu/openvidu-recording"; private final String IMAGE_NAME = "openvidu/openvidu-recording";
private String IMAGE_TAG; private String IMAGE_TAG;
@ -162,8 +168,8 @@ public class ComposedRecordingService {
if (session == null) { if (session == null) {
log.warn( log.warn(
"Existing recording {} does not have an active session associated. This usually means the recording" "Existing recording {} does not have an active session associated. This usually means the recording"
+ " layout did not join a recorded participant and therefore the session closed before" + " layout did not join a recorded participant or the recording has been automatically"
+ " stopping the recording container", + " stopped after last user left and timeout passed",
recordingId); recordingId);
recording = this.startedRecordings.remove(recordingId); recording = this.startedRecordings.remove(recordingId);
containerId = this.sessionsContainers.remove(recording.getSessionId()); containerId = this.sessionsContainers.remove(recording.getSessionId());
@ -543,4 +549,19 @@ public class ComposedRecordingService {
this.IMAGE_TAG = version; this.IMAGE_TAG = version;
} }
public void initAutomaticRecordingStopThread(String sessionId) {
final String recordingId = this.sessionsRecordings.get(sessionId).getId();
ScheduledFuture<?> future = this.automaticRecordingStopExecutor.schedule(() -> {
log.info("Stopping recording {} after 2 minutes wait (no publisher published before timeout)", recordingId);
this.stopRecording(null, recordingId, "lastParticipantLeft");
this.automaticRecordingStopThreads.remove(sessionId);
}, 2, TimeUnit.MINUTES);
this.automaticRecordingStopThreads.putIfAbsent(sessionId, future);
}
public boolean abortAutomaticRecordingStopThread(String sessionId) {
ScheduledFuture<?> future = this.automaticRecordingStopThreads.remove(sessionId);
return future.cancel(false);
}
} }