backend: refactor recording start process and add room validation checks
This commit is contained in:
parent
b87e548cdf
commit
7a8f3fbe69
@ -57,50 +57,43 @@ export class RecordingService {
|
|||||||
|
|
||||||
async startRecording(roomId: string): Promise<MeetRecordingInfo> {
|
async startRecording(roomId: string): Promise<MeetRecordingInfo> {
|
||||||
let acquiredLock: RedisLock | null = null;
|
let acquiredLock: RedisLock | null = null;
|
||||||
|
let eventListener!: (info: Record<string, unknown>) => void;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const room = await this.roomService.getMeetRoom(roomId);
|
await this.validateRoomsPreconditions(roomId);
|
||||||
|
|
||||||
if (!room) throw errorRoomNotFound(roomId);
|
|
||||||
|
|
||||||
//TODO: Check if the room has participants before starting the recording
|
|
||||||
//room.numParticipants === 0 ? throw errorNoParticipants(roomId);
|
|
||||||
const lkRoom = await this.livekitService.getRoom(roomId);
|
|
||||||
|
|
||||||
if (!lkRoom) throw errorRoomNotFound(roomId);
|
|
||||||
|
|
||||||
const hasParticipants = await this.livekitService.roomHasParticipants(roomId);
|
|
||||||
|
|
||||||
if (!hasParticipants) throw errorRoomHasNoParticipants(roomId);
|
|
||||||
|
|
||||||
// Attempt to acquire lock. If the lock is not acquired, the recording is already active.
|
// Attempt to acquire lock. If the lock is not acquired, the recording is already active.
|
||||||
acquiredLock = await this.acquireRoomRecordingActiveLock(roomId);
|
acquiredLock = await this.acquireRoomRecordingActiveLock(roomId);
|
||||||
|
|
||||||
if (!acquiredLock) throw errorRecordingAlreadyStarted(roomId);
|
if (!acquiredLock) throw errorRecordingAlreadyStarted(roomId);
|
||||||
|
|
||||||
|
let resolveRecording!: (r: MeetRecordingInfo) => void;
|
||||||
|
let rejectRecording!: (e: unknown) => void;
|
||||||
|
const recordingPromise = new Promise<MeetRecordingInfo>((res, rej) => {
|
||||||
|
resolveRecording = res;
|
||||||
|
rejectRecording = rej;
|
||||||
|
});
|
||||||
|
let recordingId = '';
|
||||||
|
|
||||||
|
eventListener = (info: Record<string, unknown>) => {
|
||||||
|
// This listener is triggered only for the instance that started the recording.
|
||||||
|
// Check if the recording ID matches the one that was started
|
||||||
|
const isEventForCurrentRecording = info?.recordingId === recordingId && info?.roomId === roomId;
|
||||||
|
|
||||||
|
if (isEventForCurrentRecording) {
|
||||||
|
this.taskSchedulerService.cancelTask(`${roomId}_recording_timeout`);
|
||||||
|
this.systemEventService.off(SystemEventType.RECORDING_ACTIVE, eventListener);
|
||||||
|
resolveRecording(info as unknown as MeetRecordingInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.systemEventService.on(SystemEventType.RECORDING_ACTIVE, eventListener);
|
||||||
|
this.registerRecordingTimeout(roomId, recordingId, eventListener, rejectRecording);
|
||||||
|
|
||||||
const options = this.generateCompositeOptionsFromRequest();
|
const options = this.generateCompositeOptionsFromRequest();
|
||||||
const output = this.generateFileOutputFromRequest(roomId);
|
const output = this.generateFileOutputFromRequest(roomId);
|
||||||
const egressInfo = await this.livekitService.startRoomComposite(roomId, output, options);
|
const egressInfo = await this.livekitService.startRoomComposite(roomId, output, options);
|
||||||
const recordingInfo = RecordingHelper.toRecordingInfo(egressInfo);
|
const recordingInfo = RecordingHelper.toRecordingInfo(egressInfo);
|
||||||
const { recordingId } = recordingInfo;
|
recordingId = recordingInfo.recordingId;
|
||||||
|
|
||||||
const recordingPromise = new Promise<MeetRecordingInfo>((resolve, reject) => {
|
|
||||||
const eventListener = (info: Record<string, unknown>) => {
|
|
||||||
// This listener is triggered only for the instance that started the recording.
|
|
||||||
// Check if the recording ID matches the one that was started
|
|
||||||
const isEventForCurrentRecording = info?.recordingId === recordingId && info?.roomId === roomId;
|
|
||||||
|
|
||||||
if (isEventForCurrentRecording) {
|
|
||||||
this.taskSchedulerService.cancelTask(`${roomId}_recording_timeout`);
|
|
||||||
this.systemEventService.off(SystemEventType.RECORDING_ACTIVE, eventListener);
|
|
||||||
resolve(info as unknown as MeetRecordingInfo);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.registerRecordingTimeout(roomId, recordingId, eventListener, reject);
|
|
||||||
|
|
||||||
this.systemEventService.on(SystemEventType.RECORDING_ACTIVE, eventListener);
|
|
||||||
});
|
|
||||||
|
|
||||||
return await recordingPromise;
|
return await recordingPromise;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -108,6 +101,10 @@ export class RecordingService {
|
|||||||
|
|
||||||
if (acquiredLock) await this.releaseRoomRecordingActiveLock(roomId);
|
if (acquiredLock) await this.releaseRoomRecordingActiveLock(roomId);
|
||||||
|
|
||||||
|
if (eventListener) this.systemEventService.off(SystemEventType.RECORDING_ACTIVE, eventListener);
|
||||||
|
|
||||||
|
this.taskSchedulerService.cancelTask(`${roomId}_recording_timeout`);
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,6 +366,22 @@ export class RecordingService {
|
|||||||
return this.roomService.sendSignal(roomId, payload, options);
|
return this.roomService.sendSignal(roomId, payload, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async validateRoomsPreconditions(roomId: string): Promise<void> {
|
||||||
|
const room = await this.roomService.getMeetRoom(roomId);
|
||||||
|
|
||||||
|
if (!room) throw errorRoomNotFound(roomId);
|
||||||
|
|
||||||
|
//TODO: Check if the room has participants before starting the recording
|
||||||
|
//room.numParticipants === 0 ? throw errorNoParticipants(roomId);
|
||||||
|
const lkRoom = await this.livekitService.getRoom(roomId);
|
||||||
|
|
||||||
|
if (!lkRoom) throw errorRoomNotFound(roomId);
|
||||||
|
|
||||||
|
const hasParticipants = await this.livekitService.roomHasParticipants(roomId);
|
||||||
|
|
||||||
|
if (!hasParticipants) throw errorRoomHasNoParticipants(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the data required to delete a recording, including the file paths
|
* Retrieves the data required to delete a recording, including the file paths
|
||||||
* to be deleted and the recording's metadata information.
|
* to be deleted and the recording's metadata information.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user