Розробка системи групових відеоконференцій на веб-сайті
Групові відеоконференції — це 3–50+ учасників, управління мікрофоном/камерою ведучим, піднята рука, брейкаут-комнати, чат, демонстрація екрану, запис. Все це вимагає продуманої архітектури як на стороні WebRTC-інфраструктури, так і на UI.
Вибір інфраструктури за масштабом
| Учасників | Рекомендоване рішення |
|---|---|
| 2–10 | LiveKit (SFU), Daily.co |
| 10–50 | LiveKit з Simulcast, 100ms |
| 50–1000 | LiveKit Broadcast, Agora, Amazon Chime |
| 1000+ | HLS-трансляція, не WebRTC |
LiveKit — рекомендована основа
npm install livekit-server-sdk # сервер
npm install @livekit/components-react livekit-client # клієнт
Створення конференції:
import { RoomServiceClient, AccessToken, RoomOptions } from 'livekit-server-sdk';
const svc = new RoomServiceClient(
process.env.LIVEKIT_URL!,
process.env.LIVEKIT_API_KEY!,
process.env.LIVEKIT_API_SECRET!
);
async function createConference(conferenceId: string, options: {
maxParticipants?: number;
enableRecording?: boolean;
}): Promise<void> {
await svc.createRoom({
name: `conf-${conferenceId}`,
maxParticipants: options.maxParticipants ?? 50,
emptyTimeout: 300, // 5 хв до закриття пустої комнати
metadata: JSON.stringify({ conferenceId, createdAt: new Date().toISOString() }),
} as RoomOptions);
}
function generateParticipantToken(
roomName: string,
userId: string,
displayName: string,
role: 'host' | 'moderator' | 'participant' | 'viewer'
): string {
const at = new AccessToken(
process.env.LIVEKIT_API_KEY!,
process.env.LIVEKIT_API_SECRET!,
{ identity: userId, name: displayName, ttl: 4 * 60 * 60 }
);
at.addGrant({
roomJoin: true,
room: roomName,
canPublish: role !== 'viewer',
canSubscribe: true,
canPublishData: true,
roomAdmin: role === 'host',
hidden: false,
});
return at.toJwt();
}
Управління учасниками з сервера:
// Заглушити конкретного учасника
app.post('/api/conferences/:roomName/mute/:participantId', authenticate, async (req, res) => {
const conference = await db.conferences.findByRoomName(req.params.roomName);
if (conference.hostId !== req.user.id) return res.status(403).end();
await svc.mutePublishedTrack(
req.params.roomName,
req.params.participantId,
'microphone-track',
true
);
res.json({ ok: true });
});
React компонент конференції
import {
LiveKitRoom,
VideoConference,
useLocalParticipant,
useParticipants,
Chat,
} from '@livekit/components-react';
function GroupConference({ token, roomName }: { token: string; roomName: string }) {
return (
<LiveKitRoom
token={token}
serverUrl={process.env.NEXT_PUBLIC_LIVEKIT_URL}
video={true}
audio={true}
>
<VideoConference />
<Chat />
</LiveKitRoom>
);
}
Брейкаут-комнати
async function createBreakoutRooms(mainRoomName: string, groups: string[][]) {
const breakoutRooms = await Promise.all(
groups.map((group, i) =>
createConference(`${mainRoomName}-breakout-${i}`, { maxParticipants: group.length + 2 })
)
);
for (let i = 0; i < groups.length; i++) {
for (const participantId of groups[i]) {
const token = generateParticipantToken(
`conf-${mainRoomName}-breakout-${i}`,
participantId,
'',
'participant'
);
await svc.sendData(
`conf-${mainRoomName}`,
Buffer.from(JSON.stringify({ type: 'breakout_invite', token, roomIndex: i })),
[participantId]
);
}
}
}
Терміни
Базова групова конференція з LiveKit + React компонентами — 1 тиждень. З брейкаут-комнатами, піднятою рукою, записом та управлінням учасниками — 2–3 тижня.







