Видеокомнаты
Planner включает видеоконференции на базе LiveKit SFU (Selective Forwarding Unit).
Архитектура
- LiveKit Server — Docker-сервис (порты 7880 HTTP, 7881 WS, 3478 TURN, 50000-60000 UDP медиа)
- Бэкенд —
livekit-server-sdkдля управления комнатами и генерации токенов - Фронтенд —
livekit-client(WebRTC) для подключения к LiveKit SFU - WebSocket — пространство имён
/videoдля signaling relay
Типы комнат
| Тип | Описание |
|---|---|
instant | Немедленный звонок + уведомления участникам |
scheduled | Запланированная конференция + событие календаря + напоминания |
API Endpoints
| Метод | Путь | Описание |
|---|---|---|
GET | /api/video-rooms | Список комнат (фильтр: active/scheduled/ended) |
POST | /api/video-rooms | Создать комнату |
GET | /api/video-rooms/:id | Детали комнаты |
PATCH | /api/video-rooms/:id | Обновить комнату |
DELETE | /api/video-rooms/:id | Завершить/удалить комнату |
POST | /api/video-rooms/:id/join | Присоединиться (возвращает LiveKit токен) |
POST | /api/video-rooms/:id/leave | Покинуть комнату |
GET | /api/video-rooms/:id/participants | Список участников |
POST | /api/video-rooms/:id/token | Получить LiveKit токен |
POST | /api/video-rooms/:id/recording/start | Начать запись |
POST | /api/video-rooms/:id/recording/stop | Остановить запись |
GET | /api/video-rooms/:id/recording/status | Статус записи |
WebSocket события (/video)
Клиент → Сервер
| Событие | Описание |
|---|---|
join | Присоединиться к комнате (room:<id>) |
leave | Покинуть комнату |
signal | WebRTC signaling relay |
Сервер → Клиент
| Событие | Описание |
|---|---|
video:participant_joined | Участник подключился |
video:participant_left | Участник отключился |
video:room_updated | Комната обновлена |
video:call_started | Начат instant-звонок |
video:recording_started | Запись начата |
video:recording_stopped | Запись остановлена |
Фронтенд
Store видеокомнат
typescript
const store = useVideoChatStore()
const { rooms, currentRoom, participants } = storeToRefs(store)
await store.fetchRooms()
await store.createRoom({ type, name, scheduledAt? })
await store.joinRoom(roomId) // получает LiveKit токен
await store.leaveRoom(roomId)
await store.endRoom(roomId)Composables
typescript
const {
isConnected, remoteParticipants,
isMuted, isScreenSharing, isRecording, isPiP
} = useLiveKit()
await liveKit.connect(tokenData) // подключиться к LiveKit
liveKit.toggleMute('audio') // вкл/выкл микрофон
liveKit.toggleMute('video') // вкл/выкл камеру
liveKit.toggleScreenShare() // демонстрация экрана
liveKit.startRecording(roomId) // начать запись
liveKit.enterPiP() // Picture-in-PictureКомпоненты
VideoRoomsView.vue(/video-rooms) — хаб с вкладками: Активные, Запланированные, ПрошедшиеVideoRoomView.vue(/video-rooms/:id) — активная комната: VideoGrid + VideoControls + сайдбар участников + копирование ссылкиVideoGrid— сетка видео участниковParticipantTile— плитка одного участникаVideoControls— панель управления (mute, камера, демонстрация, запись, выход)ScheduleVideoDialog— диалог создания запланированной комнатыVideoRoomCard— карточка комнаты в списке
Ключевые детали реализации
- Запланированные комнаты создают
CalendarEventс типомvideo - Напоминания отправляются за 15 минут до начала (cron каждые 5 минут)
- При скрытии вкладки автоматически включается Picture-in-Picture
- Неактивные LiveKit-комнаты очищаются при инициализации модуля
Диалог входящего звонка
При 시작е мгновенного видеозвонка участники получают всплывающее окно IncomingCallDialog.vue:
- Отображает имя звонящего и название комнаты
- Принять → присоединиться к комнате и подключиться к LiveKit
- Отклонить → отправить уведомление об отказе
- Автоматически закрывается через 30 секунд