openvidu-recording: Add comments

This commit is contained in:
juancarmore 2024-08-31 14:23:26 +02:00
parent f5da0c397d
commit 99bb02ce6a
3 changed files with 21 additions and 0 deletions

View File

@ -41,6 +41,7 @@ async function joinRoom() {
} }
}); });
// When recording status changes...
room.on(LivekitClient.RoomEvent.RecordingStatusChanged, async (isRecording) => { room.on(LivekitClient.RoomEvent.RecordingStatusChanged, async (isRecording) => {
await updateRecordingInfo(isRecording); await updateRecordingInfo(isRecording);
}); });
@ -66,6 +67,7 @@ async function joinRoom() {
const localVideoTrack = this.room.localParticipant.videoTrackPublications.values().next().value.track; const localVideoTrack = this.room.localParticipant.videoTrackPublications.values().next().value.track;
addTrack(localVideoTrack, userName, true); addTrack(localVideoTrack, userName, true);
// Update recording info
await updateRecordingInfo(room.isRecording); await updateRecordingInfo(room.isRecording);
} catch (error) { } catch (error) {
console.log("There was an error connecting to the room:", error.message); console.log("There was an error connecting to the room:", error.message);
@ -126,6 +128,7 @@ document.addEventListener("DOMContentLoaded", async function () {
generateFormValues(); generateFormValues();
} }
// Remove recording video when the dialog is closed
document.getElementById("recording-video-dialog").addEventListener("close", () => { document.getElementById("recording-video-dialog").addEventListener("close", () => {
const recordingVideo = document.getElementById("recording-video"); const recordingVideo = document.getElementById("recording-video");
recordingVideo.src = ""; recordingVideo.src = "";

View File

@ -68,17 +68,20 @@ app.post("/recordings/start", async (req, res) => {
const activeEgresses = await getActiveEgressesByRoom(roomName); const activeEgresses = await getActiveEgressesByRoom(roomName);
// Check if there is already an active egress for this room
if (activeEgresses.length > 0) { if (activeEgresses.length > 0) {
res.status(409).json({ errorMessage: "Recording already started for this room" }); res.status(409).json({ errorMessage: "Recording already started for this room" });
return; return;
} }
// Use the EncodedFileOutput to save the recording to an MP4 file
const fileOutput = new EncodedFileOutput({ const fileOutput = new EncodedFileOutput({
fileType: EncodedFileType.MP4, fileType: EncodedFileType.MP4,
filepath: `${RECORDINGS_PATH}{room_name}-{room_id}-{time}` filepath: `${RECORDINGS_PATH}{room_name}-{room_id}-{time}`
}); });
try { try {
// Start a RoomCompositeEgress to record all participants in the room
const egressInfo = await egressClient.startRoomCompositeEgress(roomName, { file: fileOutput }); const egressInfo = await egressClient.startRoomCompositeEgress(roomName, { file: fileOutput });
const recording = { const recording = {
name: egressInfo.fileResults[0].filename.split("/").pop(), name: egressInfo.fileResults[0].filename.split("/").pop(),
@ -101,6 +104,7 @@ app.post("/recordings/stop", async (req, res) => {
const activeEgresses = await getActiveEgressesByRoom(roomName); const activeEgresses = await getActiveEgressesByRoom(roomName);
// Check if there is an active egress for this room
if (activeEgresses.length === 0) { if (activeEgresses.length === 0) {
res.status(409).json({ errorMessage: "Recording not started for this room" }); res.status(409).json({ errorMessage: "Recording not started for this room" });
return; return;
@ -109,6 +113,7 @@ app.post("/recordings/stop", async (req, res) => {
const egressId = activeEgresses[0].egressId; const egressId = activeEgresses[0].egressId;
try { try {
// Stop the Egress to finish the recording
const egressInfo = await egressClient.stopEgress(egressId); const egressInfo = await egressClient.stopEgress(egressId);
const file = egressInfo.fileResults[0]; const file = egressInfo.fileResults[0];
const recording = { const recording = {
@ -125,6 +130,7 @@ app.post("/recordings/stop", async (req, res) => {
const getActiveEgressesByRoom = async (roomName) => { const getActiveEgressesByRoom = async (roomName) => {
try { try {
// List all active egresses for the room
return await egressClient.listEgress({ roomName, active: true }); return await egressClient.listEgress({ roomName, active: true });
} catch (error) { } catch (error) {
console.error("Error listing egresses.", error); console.error("Error listing egresses.", error);
@ -140,6 +146,8 @@ app.get("/recordings", async (req, res) => {
const keyStart = RECORDINGS_PATH + (roomName ? `${roomName}` + (roomId ? `-${roomId}` : "") : ""); const keyStart = RECORDINGS_PATH + (roomName ? `${roomName}` + (roomId ? `-${roomId}` : "") : "");
const keyEnd = ".mp4.json"; const keyEnd = ".mp4.json";
const regex = new RegExp(`^${keyStart}.*${keyEnd}$`); const regex = new RegExp(`^${keyStart}.*${keyEnd}$`);
// List all Egress metadata files in the recordings path that match the regex
const payloadKeys = await s3Service.listObjects(RECORDINGS_PATH, regex); const payloadKeys = await s3Service.listObjects(RECORDINGS_PATH, regex);
const recordings = await Promise.all(payloadKeys.map((payloadKey) => getRecordingInfo(payloadKey))); const recordings = await Promise.all(payloadKeys.map((payloadKey) => getRecordingInfo(payloadKey)));
res.json({ recordings }); res.json({ recordings });
@ -150,8 +158,10 @@ app.get("/recordings", async (req, res) => {
}); });
const getRecordingInfo = async (payloadKey) => { const getRecordingInfo = async (payloadKey) => {
// Get the Egress metadata file as JSON
const data = await s3Service.getObjectAsJson(payloadKey); const data = await s3Service.getObjectAsJson(payloadKey);
// Get the recording file size
const recordingKey = payloadKey.replace(".json", ""); const recordingKey = payloadKey.replace(".json", "");
const size = await s3Service.getObjectSize(recordingKey); const size = await s3Service.getObjectSize(recordingKey);
@ -175,10 +185,15 @@ app.get("/recordings/:recordingName", async (req, res) => {
} }
try { try {
// Get the recording file from S3
const { body, size } = await s3Service.getObject(key); const { body, size } = await s3Service.getObject(key);
// Set the response headers
res.setHeader("Content-Type", "video/mp4"); res.setHeader("Content-Type", "video/mp4");
res.setHeader("Content-Length", size); res.setHeader("Content-Length", size);
res.setHeader("Accept-Ranges", "bytes"); res.setHeader("Accept-Ranges", "bytes");
// Pipe the recording file to the response
body.pipe(res).on("finish", () => res.end()); body.pipe(res).on("finish", () => res.end());
} catch (error) { } catch (error) {
console.error("Error getting recording.", error); console.error("Error getting recording.", error);
@ -197,6 +212,7 @@ app.delete("/recordings/:recordingName", async (req, res) => {
} }
try { try {
// Delete the recording file and metadata file from S3
await Promise.all([s3Service.deleteObject(key), s3Service.deleteObject(`${key}.json`)]); await Promise.all([s3Service.deleteObject(key), s3Service.deleteObject(`${key}.json`)]);
res.json({ message: "Recording deleted" }); res.json({ message: "Recording deleted" });
} catch (error) { } catch (error) {

View File

@ -81,6 +81,8 @@ export class S3Service {
}; };
const command = new ListObjectsV2Command(params); const command = new ListObjectsV2Command(params);
const { Contents: objects } = await this.run(command); const { Contents: objects } = await this.run(command);
// Filter objects by regex and return the keys
return ( return (
objects objects
?.filter((object) => regex.test(object.Key)) ?.filter((object) => regex.test(object.Key))