Сессионные залы (Breakout Rooms)
Сессионные залы позволяют разделить участников звонка на отдельные комнаты для работы в малых группах.
Основные понятия
- Основной зал (Main Room) — комната с
id: 0, в которой находятся все участники по умолчанию - Сессионный зал — дополнительная комната с уникальным
id - Назначенная комната (
assignedRoomId) — комната, в которую участник назначен - Текущая комната (
currentRoomId) — комната, в которой участник находится сейчас
Свойства комнаты
typescript
interface Room {
id: number; // Уникальный ID комнаты (0 = основной зал)
name: string; // Название комнаты
active?: boolean; // Активна ли комната
muteStates?: MuteStates; // Глобальные мьют-состояния комнаты
pinnedParticipantId?: ExternalParticipantId; // Закреплённый участник
countdownSec?: number; // Обратный отсчёт (секунды)
timeoutMs?: number; // Таймаут комнаты (мс)
}Создание и обновление комнат
javascript
// Создать новую комнату
await SDK.updateRooms([{
name: 'Группа 1'
}]);
// Создать комнату с определённым ID
await SDK.updateRooms([{
id: 1,
name: 'Группа 1'
}]);
// Создать несколько комнат
await SDK.updateRooms([
{ name: 'Группа 1' },
{ name: 'Группа 2' },
{ name: 'Группа 3' }
]);
// Обновить существующую комнату
await SDK.updateRooms([{
id: 1,
name: 'Новое название',
countdownSec: 300, // 5 минут
timeoutMs: 600000 // 10 минут
}]);Назначение участников в комнаты
javascript
import { ExternalIdType } from '@vkontakte/calls-sdk';
// Добавить участника в комнату
await SDK.updateRooms([{
id: 1,
addParticipantIds: [
{ id: 'user123', type: ExternalIdType.USER }
]
}]);
// Удалить участника из комнаты
await SDK.updateRooms([{
id: 1,
removeParticipantIds: [
{ id: 'user123', type: ExternalIdType.USER }
]
}]);
// Переместить участника из одной комнаты в другую
await SDK.updateRooms([
{
id: 1, // Из комнаты 1
removeParticipantIds: [{ id: 'user123', type: ExternalIdType.USER }]
},
{
id: 2, // В комнату 2
addParticipantIds: [{ id: 'user123', type: ExternalIdType.USER }]
}
]);Случайное распределение участников
javascript
// Распределить участников случайным образом
await SDK.updateRooms([
{ id: 1, participantCount: 3 }, // 3 участника в комнату 1
{ id: 2, participantCount: 3 }, // 3 участника в комнату 2
{ id: 3, participantCount: 2 } // 2 участника в комнату 3
], true); // assignRandomly = trueАктивация и деактивация комнат
Комнаты нужно активировать, чтобы участники переместились в них:
javascript
// Активировать комнаты
await SDK.activateRooms([1, 2, 3], false); // deactivate = false
// Деактивировать комнаты (участники вернутся в основной зал)
await SDK.activateRooms([1, 2, 3], true); // deactivate = trueПереключение между комнатами
Для себя
javascript
// Перейти в комнату
await SDK.switchRoom(1);
// Вернуться в основной зал
await SDK.switchRoom(null);
// или
await SDK.switchRoom(0);Для другого участника (только админ)
javascript
// Переместить участника в комнату
await SDK.switchRoom(1, { id: 'user123', type: ExternalIdType.USER });
// Вернуть участника в основной зал
await SDK.switchRoom(null, { id: 'user123', type: ExternalIdType.USER });Удаление комнат
javascript
// Удалить комнату (участники вернутся в основной зал)
await SDK.removeRooms([1]);
// Удалить несколько комнат
await SDK.removeRooms([1, 2, 3]);Коллбэки
Для администратора
javascript
await SDK.init({
// ...
// Обновление всех комнат (только для админа)
onRoomsUpdated: (updates) => {
// updates содержит изменения по типам событий:
// - RoomsEventType.UPDATE - обновление комнат
// - RoomsEventType.ACTIVATE - активация/деактивация
// - RoomsEventType.REMOVE - удаление
for (const [eventType, update] of Object.entries(updates)) {
console.log('Событие:', eventType, update);
}
}
});Для всех участников
javascript
import { RoomsEventType } from '@vkontakte/calls-sdk';
await SDK.init({
// ...
// При старте звонка — узнать начальную комнату
onRoomStart: (roomId) => {
console.log('Начальная комната:', roomId);
},
// Обновление комнаты, доступной участнику
onRoomUpdated: (eventTypes, roomId, room, deactivate) => {
if (eventTypes.includes(RoomsEventType.UPDATE) && room) {
console.log('Комната обновлена:', room.name);
}
if (eventTypes.includes(RoomsEventType.ACTIVATE)) {
console.log('Комната', deactivate ? 'деактивирована' : 'активирована');
}
},
// Участник переключился в другую комнату
onRoomSwitched: (roomId) => {
console.log('Вы перешли в комнату:', roomId ?? 'основной зал');
},
// Обновление участников в комнате
onRoomParticipantsUpdated: (update) => {
// update.roomId - ID комнаты
// update.addedParticipantIds - назначенные участники
// update.addedParticipants - активные участники (с данными)
if (update.addedParticipants) {
console.log('В комнату вошли:', update.addedParticipants);
}
}
});Полный пример
javascript
import * as SDK from '@vkontakte/calls-sdk';
import { RoomsEventType, ExternalIdType } from '@vkontakte/calls-sdk';
let currentRoomId = 0;
let assignedRoomId = 0;
let rooms = [{ id: 0, name: 'Основной зал' }];
await SDK.init({
// ...
onRoomStart: (roomId) => {
currentRoomId = roomId ?? 0;
},
onRoomsUpdated: (updates) => {
// Обработка для админа
const updateEvent = updates[RoomsEventType.UPDATE];
if (updateEvent?.rooms) {
updateEvent.rooms.forEach(room => {
const existing = rooms.find(r => r.id === room.id);
if (existing) {
Object.assign(existing, room);
} else {
rooms.push(room);
}
});
}
const activateEvent = updates[RoomsEventType.ACTIVATE];
if (activateEvent?.roomIds) {
activateEvent.roomIds.forEach(id => {
const room = rooms.find(r => r.id === id);
if (room) room.active = !activateEvent.deactivated;
});
}
const removeEvent = updates[RoomsEventType.REMOVE];
if (removeEvent?.roomIds) {
rooms = rooms.filter(r => !removeEvent.roomIds.includes(r.id));
}
},
onRoomUpdated: (eventTypes, roomId, room, deactivate) => {
// Обработка для обычного участника
if (eventTypes.includes(RoomsEventType.UPDATE) && room) {
assignedRoomId = roomId;
}
if (eventTypes.includes(RoomsEventType.ACTIVATE)) {
const r = rooms.find(r => r.id === roomId);
if (r) r.active = !deactivate;
}
},
onRoomSwitched: (roomId) => {
currentRoomId = roomId ?? 0;
updateUI();
},
onRoomParticipantsUpdated: (update) => {
// Обновить список участников в комнатах
updateParticipantsList(update);
}
});
// Пример: Админ создаёт комнаты и распределяет участников
async function setupBreakoutRooms() {
// 1. Создать комнаты
await SDK.updateRooms([
{ name: 'Группа 1' },
{ name: 'Группа 2' }
]);
// 2. Активировать комнаты
await SDK.activateRooms([1, 2], false);
}
// Пример: Участник переходит в назначенную комнату
async function goToAssignedRoom() {
if (assignedRoomId && assignedRoomId !== currentRoomId) {
await SDK.switchRoom(assignedRoomId);
}
}
// Пример: Вернуться в основной зал
async function goToMainRoom() {
if (currentRoomId !== 0) {
await SDK.switchRoom(null);
}
}Пример сценария работы
Участники: Админ А, Участник У1, Участник У2
Все находятся в основном зале
Админ создаёт комнату и назначает У1:
javascriptawait SDK.updateRooms([{ name: 'Комната N', addParticipantIds: [{ id: 'У1', type: ExternalIdType.USER }] }]);- Админ получает
onRoomsUpdated - У1 получает
onRoomUpdated
- Админ получает
Админ активирует комнату:
javascriptawait SDK.activateRooms([roomId], false);- Админ получает:
onRoomsUpdated(комната активирована)onRoomParticipantsUpdated(У1 добавлен в N)onRoomParticipantsUpdated(У1 удалён из основного зала)
- У1 получает:
onRoomUpdated(комната активирована)onRoomSwitched(теперь в комнате N)onRoomParticipantsUpdated
- У2 получает:
onRoomParticipantsUpdated(У1 удалён из основного зала)
- Админ получает:
Особенности
Права доступа
Создавать, редактировать и удалять комнаты могут только пользователи с ролью ADMIN или CREATOR.
Важно
При удалении или деактивации комнаты все её участники автоматически возвращаются в основной зал.
Видимость участников
Участники видят только тех, кто находится в той же комнате. При переключении комнаты меняется список видимых участников.