mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: automatically stip MANUAL recording after timeout
parent
a05b23347f
commit
4452e048a2
|
@ -175,14 +175,21 @@ public class KurentoSessionManager extends SessionManager {
|
|||
showTokens();
|
||||
} else if (remainingParticipants.size() == 1 && openviduConfig.isRecordingModuleEnabled()
|
||||
&& MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode())
|
||||
&& RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
|
||||
&& ProtocolElements.RECORDER_PARTICIPANT_PUBLICID
|
||||
.equals(remainingParticipants.iterator().next().getParticipantPublicId())) {
|
||||
|
||||
log.info("Last participant left. Stopping recording for session {}", sessionId);
|
||||
recordingService.stopRecording(session, null, reason);
|
||||
evictParticipant(session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID), null,
|
||||
null, "EVICT_RECORDER");
|
||||
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);
|
||||
recordingService.stopRecording(session, null, reason);
|
||||
evictParticipant(session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID), null,
|
||||
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
|
||||
|
@ -206,14 +213,10 @@ public class KurentoSessionManager extends SessionManager {
|
|||
* the peer's request by sending it the SDP response (answer or updated offer)
|
||||
* generated by the WebRTC endpoint on the server.
|
||||
*
|
||||
* @param participant
|
||||
* Participant publishing video
|
||||
* @param MediaOptions
|
||||
* configuration of the stream to publish
|
||||
* @param transactionId
|
||||
* identifier of the Transaction
|
||||
* @throws OpenViduException
|
||||
* on error
|
||||
* @param participant Participant publishing video
|
||||
* @param MediaOptions configuration of the stream to publish
|
||||
* @param transactionId identifier of the Transaction
|
||||
* @throws OpenViduException on error
|
||||
*/
|
||||
@Override
|
||||
public void publishVideo(Participant participant, MediaOptions mediaOptions, Integer transactionId)
|
||||
|
@ -272,16 +275,29 @@ public class KurentoSessionManager extends SessionManager {
|
|||
|
||||
if (this.openviduConfig.isRecordingModuleEnabled()
|
||||
&& MediaMode.ROUTED.equals(session.getSessionProperties().mediaMode())
|
||||
&& RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
|
||||
&& !recordingService.sessionIsBeingRecorded(session.getSessionId())
|
||||
&& session.getActivePublishers() == 0) {
|
||||
// Insecure session recording
|
||||
new Thread(() -> {
|
||||
recordingService.startRecording(session,
|
||||
new RecordingProperties.Builder().name("")
|
||||
.recordingLayout(session.getSessionProperties().defaultRecordingLayout())
|
||||
.customLayout(session.getSessionProperties().defaultCustomLayout()).build());
|
||||
}).start();
|
||||
if (RecordingMode.ALWAYS.equals(session.getSessionProperties().recordingMode())
|
||||
&& !recordingService.sessionIsBeingRecorded(session.getSessionId())) {
|
||||
// Insecure session recording
|
||||
new Thread(() -> {
|
||||
recordingService.startRecording(session,
|
||||
new RecordingProperties.Builder().name("")
|
||||
.recordingLayout(session.getSessionProperties().defaultRecordingLayout())
|
||||
.customLayout(session.getSessionProperties().defaultCustomLayout()).build());
|
||||
}).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);
|
||||
|
@ -458,12 +474,10 @@ public class KurentoSessionManager extends SessionManager {
|
|||
* Creates a session if it doesn't already exist. The session's id will be
|
||||
* indicated by the session info bean.
|
||||
*
|
||||
* @param kcSessionInfo
|
||||
* bean that will be passed to the {@link KurentoClientProvider} in
|
||||
* order to obtain the {@link KurentoClient} that will be used by the
|
||||
* room
|
||||
* @throws OpenViduException
|
||||
* in case of error while creating the session
|
||||
* @param kcSessionInfo bean that will be passed to the
|
||||
* {@link KurentoClientProvider} in order to obtain the
|
||||
* {@link KurentoClient} that will be used by the room
|
||||
* @throws OpenViduException in case of error while creating the session
|
||||
*/
|
||||
public void createSession(KurentoClientSessionInfo kcSessionInfo, SessionProperties sessionProperties)
|
||||
throws OpenViduException {
|
||||
|
|
|
@ -31,6 +31,8 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -87,6 +89,10 @@ public class ComposedRecordingService {
|
|||
private Map<String, Recording> startingRecordings = new ConcurrentHashMap<>();
|
||||
private Map<String, Recording> startedRecordings = 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 String IMAGE_TAG;
|
||||
|
@ -162,8 +168,8 @@ public class ComposedRecordingService {
|
|||
if (session == null) {
|
||||
log.warn(
|
||||
"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"
|
||||
+ " stopping the recording container",
|
||||
+ " layout did not join a recorded participant or the recording has been automatically"
|
||||
+ " stopped after last user left and timeout passed",
|
||||
recordingId);
|
||||
recording = this.startedRecordings.remove(recordingId);
|
||||
containerId = this.sessionsContainers.remove(recording.getSessionId());
|
||||
|
@ -543,4 +549,19 @@ public class ComposedRecordingService {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue