Интеграция Livekit для видеоконференций на сайте
LiveKit — open-source WebRTC-сервер для построения видеоконференций, стримов и голосовых звонков. Self-hosted вариант без ограничений участников и без выплат процентов от дохода.
Архитектура
Клиент (браузер)
│
└── WebRTC ──► LiveKit Server (SFU)
│
LiveKit API ◄── Ваш бэкенд
(room management, access tokens)
Установка LiveKit Server
# docker-compose.yml
services:
livekit:
image: livekit/livekit-server:latest
command: --dev # для разработки
ports:
- "7880:7880" # HTTP
- "7881:7881" # TCP для WebRTC
- "7882:7882/udp" # UDP для WebRTC
environment:
LIVEKIT_KEYS: "APIkey: APIsecret"
# livekit.yaml (продакшн)
port: 7880
rtc:
tcp_port: 7881
udp_port: 7882
use_external_ip: true
keys:
APIkey: APIsecret
Бэкенд: генерация токенов
import { AccessToken, RoomServiceClient } from 'livekit-server-sdk';
const roomService = new RoomServiceClient(
process.env.LIVEKIT_URL,
process.env.LIVEKIT_API_KEY,
process.env.LIVEKIT_API_SECRET
);
// Создать комнату
await roomService.createRoom({
name: `room-${meetingId}`,
maxParticipants: 50,
emptyTimeout: 10 * 60 // закрыть через 10 мин если пусто
});
// Токен доступа для участника
function generateToken(roomName: string, participant: Participant): string {
const at = new AccessToken(
process.env.LIVEKIT_API_KEY,
process.env.LIVEKIT_API_SECRET,
{
identity: participant.id,
name: participant.name,
ttl: '2h'
}
);
at.addGrant({
roomJoin: true,
room: roomName,
canPublish: true,
canSubscribe: true,
canPublishData: true
});
return at.toJwt();
}
// Эндпоинт для получения токена
app.post('/api/meetings/:id/join', authenticate, async (req, res) => {
const meeting = await meetingRepo.findById(req.params.id);
if (!meeting) return res.status(404).json({ error: 'Meeting not found' });
const token = generateToken(
`room-${meeting.id}`,
{ id: req.user.id, name: req.user.displayName }
);
res.json({
token,
serverUrl: process.env.LIVEKIT_URL
});
});
Клиент (React)
import {
LiveKitRoom,
VideoConference,
GridLayout,
ParticipantTile,
RoomAudioRenderer,
ControlBar,
useTracks
} from '@livekit/components-react';
import { Track } from 'livekit-client';
import '@livekit/components-styles';
function VideoRoom({ roomId }) {
const [token, setToken] = useState<string | null>(null);
const [serverUrl, setServerUrl] = useState('');
useEffect(() => {
fetch(`/api/meetings/${roomId}/join`, { method: 'POST' })
.then(r => r.json())
.then(({ token, serverUrl }) => {
setToken(token);
setServerUrl(serverUrl);
});
}, [roomId]);
if (!token) return <div>Подключение...</div>;
return (
<LiveKitRoom
token={token}
serverUrl={serverUrl}
connect={true}
onDisconnected={() => router.push('/meetings')}
video={true}
audio={true}
>
<VideoConference />
<RoomAudioRenderer />
</LiveKitRoom>
);
}
// Кастомный интерфейс
function CustomVideoRoom({ roomId }) {
return (
<LiveKitRoom token={token} serverUrl={serverUrl} connect>
<MyVideoGrid />
<ControlBar />
<RoomAudioRenderer />
</LiveKitRoom>
);
}
function MyVideoGrid() {
const tracks = useTracks([
{ source: Track.Source.Camera, withPlaceholder: true },
{ source: Track.Source.ScreenShare }
]);
return (
<GridLayout tracks={tracks}>
<ParticipantTile />
</GridLayout>
);
}
Запись
// Запись комнаты через Egress API
import { EgressClient, EncodedFileType } from 'livekit-server-sdk';
const egressClient = new EgressClient(
process.env.LIVEKIT_URL,
process.env.LIVEKIT_API_KEY,
process.env.LIVEKIT_API_SECRET
);
const egress = await egressClient.startRoomCompositeEgress(
`room-${meetingId}`,
{
file: {
fileType: EncodedFileType.MP4,
s3: {
accessKey: process.env.AWS_ACCESS_KEY,
secret: process.env.AWS_SECRET,
bucket: 'recordings',
key: `meetings/${meetingId}/${Date.now()}.mp4`
}
}
}
);
Сроки
LiveKit сервер + токен-генерация + React UI с @livekit/components-react — 1 неделя. Кастомный UI + запись + управление комнатами — 2–3 недели.







