...
This commit is contained in:
70
app/api/record/start/route.ts
Normal file
70
app/api/record/start/route.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { EgressClient, EncodedFileOutput, S3Upload } from 'livekit-server-sdk';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const roomName = req.nextUrl.searchParams.get('roomName');
|
||||
|
||||
/**
|
||||
* CAUTION:
|
||||
* for simplicity this implementation does not authenticate users and therefore allows anyone with knowledge of a roomName
|
||||
* to start/stop recordings for that room.
|
||||
* DO NOT USE THIS FOR PRODUCTION PURPOSES AS IS
|
||||
*/
|
||||
|
||||
if (roomName === null) {
|
||||
return new NextResponse('Missing roomName parameter', { status: 403 });
|
||||
}
|
||||
|
||||
const {
|
||||
LIVEKIT_API_KEY,
|
||||
LIVEKIT_API_SECRET,
|
||||
LIVEKIT_URL,
|
||||
S3_KEY_ID,
|
||||
S3_KEY_SECRET,
|
||||
S3_BUCKET,
|
||||
S3_ENDPOINT,
|
||||
S3_REGION,
|
||||
} = process.env;
|
||||
|
||||
const hostURL = new URL(LIVEKIT_URL!);
|
||||
hostURL.protocol = 'https:';
|
||||
|
||||
const egressClient = new EgressClient(hostURL.origin, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
|
||||
|
||||
const existingEgresses = await egressClient.listEgress({ roomName });
|
||||
if (existingEgresses.length > 0 && existingEgresses.some((e) => e.status < 2)) {
|
||||
return new NextResponse('Meeting is already being recorded', { status: 409 });
|
||||
}
|
||||
|
||||
const fileOutput = new EncodedFileOutput({
|
||||
filepath: `${new Date(Date.now()).toISOString()}-${roomName}.mp4`,
|
||||
output: {
|
||||
case: 's3',
|
||||
value: new S3Upload({
|
||||
endpoint: S3_ENDPOINT,
|
||||
accessKey: S3_KEY_ID,
|
||||
secret: S3_KEY_SECRET,
|
||||
region: S3_REGION,
|
||||
bucket: S3_BUCKET,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
await egressClient.startRoomCompositeEgress(
|
||||
roomName,
|
||||
{
|
||||
file: fileOutput,
|
||||
},
|
||||
{
|
||||
layout: 'speaker',
|
||||
},
|
||||
);
|
||||
|
||||
return new NextResponse(null, { status: 200 });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return new NextResponse(error.message, { status: 500 });
|
||||
}
|
||||
}
|
||||
}
|
39
app/api/record/stop/route.ts
Normal file
39
app/api/record/stop/route.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { EgressClient } from 'livekit-server-sdk';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const roomName = req.nextUrl.searchParams.get('roomName');
|
||||
|
||||
/**
|
||||
* CAUTION:
|
||||
* for simplicity this implementation does not authenticate users and therefore allows anyone with knowledge of a roomName
|
||||
* to start/stop recordings for that room.
|
||||
* DO NOT USE THIS FOR PRODUCTION PURPOSES AS IS
|
||||
*/
|
||||
|
||||
if (roomName === null) {
|
||||
return new NextResponse('Missing roomName parameter', { status: 403 });
|
||||
}
|
||||
|
||||
const { LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL } = process.env;
|
||||
|
||||
const hostURL = new URL(LIVEKIT_URL!);
|
||||
hostURL.protocol = 'https:';
|
||||
|
||||
const egressClient = new EgressClient(hostURL.origin, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
|
||||
const activeEgresses = (await egressClient.listEgress({ roomName })).filter(
|
||||
(info) => info.status < 2,
|
||||
);
|
||||
if (activeEgresses.length === 0) {
|
||||
return new NextResponse('No active recording found', { status: 404 });
|
||||
}
|
||||
await Promise.all(activeEgresses.map((info) => egressClient.stopEgress(info.egressId)));
|
||||
|
||||
return new NextResponse(null, { status: 200 });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return new NextResponse(error.message, { status: 500 });
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user