openvidu-recording-improved: Notify participants when recording is deleted and remove corresponding container

This commit is contained in:
juancarmore 2024-09-10 18:10:22 +02:00
parent 2cc5d505da
commit 8664ba3312
4 changed files with 74 additions and 9 deletions

View File

@ -47,6 +47,15 @@ async function joinRoom() {
await updateRecordingInfo(recordingStatus);
});
// When a message is received...
room.on(LivekitClient.RoomEvent.DataReceived, async (payload, _participant, _kind, topic) => {
// If the message is a recording deletion notification, remove the recording from the list
if (topic === "RECORDING_DELETED") {
const { recordingName } = JSON.parse(new TextDecoder().decode(payload));
deleteRecordingContainer(recordingName);
}
});
try {
// Get the room name and participant name from the form
const roomName = document.getElementById("room-name").value;
@ -267,8 +276,21 @@ async function deleteRecording(recordingName) {
const [error, _] = await httpRequest("DELETE", `/recordings/${recordingName}`);
if (!error || error.status === 404) {
const roomId = await room?.getSid();
await listRecordings(room?.name, roomId);
deleteRecordingContainer(recordingName);
}
}
function deleteRecordingContainer(recordingName) {
const recordingContainer = document.getElementById(recordingName);
if (recordingContainer) {
recordingContainer.remove();
const recordingsList = document.getElementById("recording-list");
if (recordingsList.children.length === 0) {
recordingsList.innerHTML = "<span>There are no recordings available</span>";
}
}
}

View File

@ -1,7 +1,9 @@
import { Router } from "express";
import { RecordingService } from "../services/recording.service.js";
import { RoomService } from "../services/room.service.js";
const recordingService = new RecordingService();
const roomService = new RoomService();
export const recordingController = Router();
@ -104,7 +106,11 @@ recordingController.delete("/:recordingName", async (req, res) => {
}
try {
const { roomName } = await recordingService.getRecordingMetadata(recordingName);
await recordingService.deleteRecording(recordingName);
// Notify to all participants that the recording was deleted
await roomService.sendDataToRoom(roomName, { recordingName });
res.json({ message: "Recording deleted" });
} catch (error) {
console.error("Error deleting recording.", error);

View File

@ -1,5 +1,11 @@
import { EgressClient, EgressStatus, EncodedFileOutput, EncodedFileType } from "livekit-server-sdk";
import { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, RECORDINGS_PATH, RECORDINGS_METADATA_PATH } from "../config.js";
import {
LIVEKIT_URL,
LIVEKIT_API_KEY,
LIVEKIT_API_SECRET,
RECORDINGS_PATH,
RECORDINGS_METADATA_PATH
} from "../config.js";
import { S3Service } from "./s3.service.js";
const s3Service = new S3Service();
@ -58,34 +64,41 @@ export class RecordingService {
}
}
async getRecordingMetadata(recordingName) {
const key = this.getMetadataKey(recordingName);
return s3Service.getObjectAsJson(key);
}
async getRecordingStream(recordingName) {
const key = RECORDINGS_PATH + recordingName;
const key = this.getRecordingKey(recordingName);
return s3Service.getObject(key);
}
async existsRecording(recordingName) {
const key = RECORDINGS_PATH + recordingName;
const key = this.getRecordingKey(recordingName);
return s3Service.exists(key);
}
async deleteRecording(recordingName) {
const recordingKey = RECORDINGS_PATH + recordingName;
const metadataKey = RECORDINGS_PATH + RECORDINGS_METADATA_PATH + recordingName.replace(".mp4", ".json");
const metadataKey = this.getMetadataKey(recordingName);
// Delete the recording file and metadata file from S3
await Promise.all([s3Service.deleteObject(recordingKey), s3Service.deleteObject(metadataKey)]);
}
async saveRecordingMetadata(egressInfo) {
const recordingInfo = this.convertToRecordingInfo(egressInfo);
const metadataName = recordingInfo.name.replace(".mp4", ".json");
const key = RECORDINGS_PATH + RECORDINGS_METADATA_PATH + metadataName;
const key = this.getMetadataKey(recordingInfo.name);
await s3Service.uploadObject(key, recordingInfo);
}
convertToRecordingInfo(egressInfo) {
const file = egressInfo.fileResults[0];
return {
id: egressInfo.egressId,
name: file.filename.split("/").pop(),
roomName: egressInfo.roomName,
roomId: egressInfo.roomId,
startedAt: Number(egressInfo.startedAt) / 1_000_000,
duration: Number(file.duration) / 1_000_000_000,
size: Number(file.size)
@ -106,4 +119,12 @@ export class RecordingService {
return "FAILED";
}
}
getRecordingKey(recordingName) {
return RECORDINGS_PATH + recordingName;
}
getMetadataKey(recordingName) {
return RECORDINGS_PATH + RECORDINGS_METADATA_PATH + recordingName.replace(".mp4", ".json");
}
}

View File

@ -1,6 +1,8 @@
import { RoomServiceClient } from "livekit-server-sdk";
import { DataPacket_Kind, RoomServiceClient } from "livekit-server-sdk";
import { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, APP_NAME } from "../config.js";
const encoder = new TextEncoder();
export class RoomService {
static instance;
@ -37,4 +39,18 @@ export class RoomService {
};
return this.roomClient.updateRoomMetadata(roomName, JSON.stringify(metadata));
}
async sendDataToRoom(roomName, rawData) {
const data = encoder.encode(JSON.stringify(rawData));
const options = {
topic: "RECORDING_DELETED",
destinationSids: []
};
try {
await this.roomClient.sendData(roomName, data, DataPacket_Kind.RELIABLE, options);
} catch (error) {
console.error("Error sending data to room", error);
}
}
}