feat: enhance collaboration session and LiveKit integration

- Added LiveKitRoomService to manage meeting room creation and recording functionalities.
- Updated CollaborationSessionSchema to create a LiveKit room upon new collaboration session creation.
- Introduced meetingRoomJoinInfo field in MeetingRoomSchema to provide join tokens and server URLs for meeting rooms.
- Improved LiveKitService to include user metadata in token generation and added a method to retrieve the server URL.
- Enhanced error handling and authorization checks across schemas to ensure proper access control for collaboration sessions and meeting rooms.
This commit is contained in:
2024-12-03 17:37:47 +07:00
parent 2b92f3bf5f
commit a6c511a2de
8 changed files with 153 additions and 14 deletions

View File

@@ -0,0 +1,40 @@
// @ts-nocheck
import { Injectable } from '@nestjs/common'
import {
EgressClient,
EncodedFileOutput,
StreamOutput,
EncodedFileType,
EncodingOptionsPreset,
} from 'livekit-server-sdk'
@Injectable()
export class LiveKitEgressService {
private readonly egressClient = new EgressClient(
process.env.LIVEKIT_URL as string,
process.env.LIVEKIT_API_KEY as string,
process.env.LIVEKIT_API_SECRET as string,
)
private readonly output = new EncodedFileOutput({
fileType: EncodedFileType.MP4,
output: {
case: 's3',
value: {
bucket: process.env.RECORDING_BUCKET_NAME as string,
accessKey: process.env.MINIO_ACCESS_KEY as string,
secret: process.env.MINIO_SECRET_KEY as string,
},
},
})
constructor() {}
async startRecording(roomId: string) {
const egress = await this.egressClient.startRoomCompositeEgress(roomId, this.output, {
layout: 'grid',
encodingOptions: EncodingOptionsPreset.H264_1080P_60,
audioOnly: false,
videoOnly: false,
})
return egress
}
}

View File

@@ -1,8 +1,10 @@
import { Module, Global } from '@nestjs/common'
import { LiveKitService } from './livekit.service'
import { LiveKitRoomService } from './livekit.room.service'
import { LiveKitEgressService } from './livekit.egress'
@Global()
@Module({
providers: [LiveKitService],
exports: [LiveKitService],
providers: [LiveKitService, LiveKitRoomService, LiveKitEgressService],
exports: [LiveKitService, LiveKitRoomService, LiveKitEgressService],
})
export class LiveKitModule {}

View File

@@ -1,16 +1,24 @@
import { forwardRef, Injectable } from '@nestjs/common'
import { Injectable } from '@nestjs/common'
// @ts-expect-error
import { Room, RoomServiceClient } from 'livekit-server-sdk'
import { LiveKitEgressService } from './livekit.egress'
@Injectable()
export class LiveKitRoomService {
constructor(private readonly roomServiceClient: RoomServiceClient) {}
private readonly roomServiceClient = new RoomServiceClient(
process.env.LIVEKIT_URL as string,
process.env.LIVEKIT_API_KEY as string,
process.env.LIVEKIT_API_SECRET as string,
)
constructor(private readonly egressService: LiveKitEgressService) {}
async createServiceMeetingRoom(roomId: string) {
const room = await this.roomServiceClient.createRoom({
name: roomId,
maxParticipants: 2,
})
// start recording
await this.egressService.startRecording(roomId)
return room
}
@@ -22,5 +30,3 @@ export class LiveKitRoomService {
return room
}
}
export const roomServiceClient = forwardRef(() => LiveKitRoomService)

View File

@@ -15,7 +15,9 @@ export class LiveKitService {
throw new Error('User must have a name')
}
const token = new AccessToken(process.env.LIVEKIT_API_KEY as string, process.env.LIVEKIT_API_SECRET as string, {
identity: me.name,
identity: me.id,
name: me.name,
metadata: me.avatarUrl ?? '',
})
token.addGrant({
roomJoin: true,
@@ -23,4 +25,8 @@ export class LiveKitService {
})
return await token.toJwt()
}
getServerUrl() {
return process.env.LIVEKIT_URL
}
}