openvidu-recording-basic: Improve video seeking
This commit is contained in:
parent
081e45bc9e
commit
4f75e00f9d
@ -14,6 +14,7 @@ const LIVEKIT_API_KEY = process.env.LIVEKIT_API_KEY || "devkey";
|
||||
const LIVEKIT_API_SECRET = process.env.LIVEKIT_API_SECRET || "secret";
|
||||
|
||||
const RECORDINGS_PATH = process.env.RECORDINGS_PATH ?? "recordings/";
|
||||
const RECORDING_FILE_PORTION_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
const app = express();
|
||||
|
||||
@ -175,6 +176,7 @@ const getRecordingInfo = async (payloadKey) => {
|
||||
|
||||
app.get("/recordings/:recordingName", async (req, res) => {
|
||||
const { recordingName } = req.params;
|
||||
const { range } = req.headers;
|
||||
const key = RECORDINGS_PATH + recordingName;
|
||||
const exists = await s3Service.exists(key);
|
||||
|
||||
@ -185,21 +187,38 @@ app.get("/recordings/:recordingName", async (req, res) => {
|
||||
|
||||
try {
|
||||
// Get the recording file from S3
|
||||
const { body, size } = await s3Service.getObject(key);
|
||||
const { stream, size, start, end } = await getRecordingStream(recordingName, range);
|
||||
|
||||
// Set the response headers
|
||||
// Set response headers
|
||||
res.status(206);
|
||||
res.setHeader("Cache-Control", "no-cache");
|
||||
res.setHeader("Content-Type", "video/mp4");
|
||||
res.setHeader("Content-Length", size);
|
||||
res.setHeader("Accept-Ranges", "bytes");
|
||||
res.setHeader("Content-Range", `bytes ${start}-${end}/${size}`);
|
||||
res.setHeader("Content-Length", end - start + 1);
|
||||
|
||||
// Pipe the recording file to the response
|
||||
body.pipe(res).on("finish", () => res.end());
|
||||
stream.pipe(res).on("finish", () => res.end());
|
||||
} catch (error) {
|
||||
console.error("Error getting recording.", error);
|
||||
res.status(500).json({ errorMessage: "Error getting recording" });
|
||||
}
|
||||
});
|
||||
|
||||
const getRecordingStream = async (recordingName, range) => {
|
||||
const key = RECORDINGS_PATH + recordingName;
|
||||
const size = await s3Service.getObjectSize(key);
|
||||
|
||||
// Get the requested range
|
||||
const parts = range?.replace(/bytes=/, "").split("-");
|
||||
const start = range ? parseInt(parts[0], 10) : 0;
|
||||
const endRange = parts[1] ? parseInt(parts[1], 10) : start + RECORDING_FILE_PORTION_SIZE;
|
||||
const end = Math.min(endRange, size - 1);
|
||||
|
||||
const stream = await s3Service.getObject(key, { start, end });
|
||||
return { stream, size, start, end };
|
||||
};
|
||||
|
||||
app.delete("/recordings/:recordingName", async (req, res) => {
|
||||
const { recordingName } = req.params;
|
||||
const key = RECORDINGS_PATH + recordingName;
|
||||
|
||||
@ -54,22 +54,23 @@ export class S3Service {
|
||||
}
|
||||
|
||||
async getObjectSize(key) {
|
||||
const { ContentLength } = await this.headObject(key);
|
||||
return ContentLength;
|
||||
const { ContentLength: size } = await this.headObject(key);
|
||||
return size;
|
||||
}
|
||||
|
||||
async getObject(key) {
|
||||
async getObject(key, range) {
|
||||
const params = {
|
||||
Bucket: S3_BUCKET,
|
||||
Key: key
|
||||
Key: key,
|
||||
Range: range ? `bytes=${range.start}-${range.end}` : undefined
|
||||
};
|
||||
const command = new GetObjectCommand(params);
|
||||
const { Body: body, ContentLength: size } = await this.run(command);
|
||||
return { body, size };
|
||||
const { Body: body } = await this.run(command);
|
||||
return body;
|
||||
}
|
||||
|
||||
async getObjectAsJson(key) {
|
||||
const { body } = await this.getObject(key);
|
||||
const body = await this.getObject(key);
|
||||
const stringifiedData = await body.transformToString();
|
||||
return JSON.parse(stringifiedData);
|
||||
}
|
||||
@ -83,11 +84,7 @@ export class S3Service {
|
||||
const { Contents: objects } = await this.run(command);
|
||||
|
||||
// Filter objects by regex and return the keys
|
||||
return (
|
||||
objects
|
||||
?.filter((object) => regex.test(object.Key))
|
||||
.map((payload) => payload.Key) ?? []
|
||||
);
|
||||
return objects?.filter((object) => regex.test(object.Key)).map((payload) => payload.Key) ?? [];
|
||||
}
|
||||
|
||||
async deleteObject(key) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user