Комната отдыха — это обычная функция, необходимая многим клиентам, особенно в сфере образования. Это часто позволяет разделить основную переговорную комнату на отдельные, разделить участников на эти комнаты обсуждения, а также отправить участникам сообщения организатору, независимо от того, в какой комнате они находятся, и т. д.

С Vonage Video API есть несколько способов реализовать такую ​​функцию комнаты отдыха для вашего приложения.

Один из способов — создать большую Видеосессию с логикой, контролирующей, на какие потоки подписаться для каждого пользователя. Другой вариант — внедрить комнаты обсуждения в виде отдельных сеансов, а затем подключить участников к этим различным сеансам, созданным для каждой комнаты обсуждения.

В этом руководстве объясняется, как использовать отдельные сеансы для встраивания функции «Комната обсуждения» в наше демонстрационное приложение, которое использует сигнальный API для реализации управления комнатой обсуждения, повторно использует объект «Издатель» при переключении между комнатами.

Надеюсь, что следующие графики могут дать вам общее представление в первую очередь. Изначально все участники подключаются к сеансу основной комнаты:

После того, как организатор нажимает кнопку для создания комнат обсуждения, сервер приложений вызывает Vonage Video API для создания сеанса для каждой комнаты обсуждения и возвращает эти идентификаторы сеанса каждому участнику.

Затем приложение подключает участников к сеансам этих комнат обсуждения, позволяя участникам выбрать комнату для присоединения или автоматически распределяя участников по разным комнатам, в зависимости от того, какой вариант выбрал организатор при создании комнат обсуждения. (Хозяин может выбрать между «Назначить автоматически» и «Разрешить участникам выбирать комнату»).

Предпосылки

Аккаунт Vonage Video API. Нажмите Зарегистрироваться, чтобы создать его, если у вас его еще нет. Версия ReactJS ›= 16.8 Версия Node.js ›= 16.13 PostgreSQL 14 в качестве базы данных, вы можете выбрать любое хранилище, которое вы предпочитаете

Вы должны увидеть все зависимости в репозитории GitHub, и мы рекомендуем вам всегда использовать последнюю версию Vonage SDK. Перечисленные здесь версии использовались, когда мы работали над этим демо-приложением.

Сервер приложения и дизайн базы данных

Сервер приложений создает комнаты, создает сеансы, генерирует токены, поддерживает комнаты и участников и отправляет сигнальные сообщения в комнаты.

Сервер приложений действует как ретранслятор, используя Signaling-REST API для передачи сообщений между разными комнатами/сеансами для сценариев, когда одному участнику нужно поднять руку на хост, который находится в другой комнате (т.е. подключен к другому сеансу). ), и для основной функции: управление переговорными комнатами. Позже мы подробно объясним, как мы используем сигнальные сообщения в управлении комнатами обсуждения.

При запуске сервера приложений будет создана таблица помещений, если она не существует. Я понимаю, что таблица комнаты может быть немного сложнее в реальной жизни. Здесь мы просто перечислим основные данные, которые нам нужны. Сценарий для создания таблицы комнаты выглядит следующим образом:

CREATE TABLE IF NOT EXISTS rooms(
    id VARCHAR(255) PRIMARY KEY,
    name VARCHAR(255) DEFAULT NULL,
    session_id VARCHAR(255) DEFAULT NULL,
    main_room_id VARCHAR(255) DEFAULT NULL,
    max_participants SMALLINT DEFAULT 0
)

session_id хранит идентификатор сеанса, связанного с комнатой. max_participants определяет максимальное количество участников, которое позволяет комната. main_room_id определяет, является ли это комнатой обсуждения, принадлежащей основной комнате, или просто главной комнатой, в которой могут быть комнаты обсуждения: когда для него установлено значение NULL, это основная комната; в противном случае это комната обсуждения, и ее значение должно быть равно идентификатору основной комнаты.

Изначально на странице входа все пользователи выбирают присоединиться к одной комнате, также известной как основная комната. После получения внешнего запроса сервер приложений вызывает Video API для создания сеанса для этой основной комнаты и добавляет запись в таблицу комнат с session_id, установленным на идентификатор созданного сеанса, и main_room_id, установленным на NULL. Затем он возвращает session_id всем зарегистрированным пользователям, чтобы они могли подключиться к сеансу.

Когда собрание продолжается и пользователь-организатор решает создать комнаты обсуждения, после того как он отправит параметры, перечисленные в разделе «Управление комнатой обсуждения», например, сколько комнат обсуждения нужно создать», «Разрешить участникам выбирать комнату» или «Назначить автоматически» и т. д. Front-end отправляет запрос createSession с параметром breakoutRooms, содержащим вышеуказанные выборы, на сервер приложений, который затем создаст сеанс для каждой комнаты обсуждения соответственно и сохранит идентификатор сеанса и другую информацию в таблице комнаты, одна запись для каждой комнаты обсуждения с main_room_id, установленным в качестве идентификатора основной комнаты.

Используйте Signaling API для реализации управления комнатой отдыха

Объект Room содержит ссылки на сеанс, сообщение (breakoutRoomSignal) и участников, а также предоставляет записи для создания комнат обсуждения и управления участниками.

Приложение использует Signaling-REST API для отправки сообщений клиентам, подключенным ко всем сессиям, относящимся к основной комнате/комнате отдыха, информированию об изменениях комнаты, запросам таймера и поднятия руки и т. д.

Например, сигнальное сообщение с указанным ниже типом и данными предназначено для информирования пользователей приложения о создании новых комнат обсуждения, и они могут выбрать одну из них для присоединения:

{
   "type": "signal:breakout-room",
   "data": {
       "message": "roomCreated (chooseroom)",
       "breakoutRooms": \[], //array of available rooms
   }
}
  • сигнальное сообщение об удалении всех комнат:
{
     "type": "signal:breakout-room",
     "data": {
         "message": "allRoomRemoved",
         "breakoutRooms": \[...],
     }
 }
  • сообщить участнику, который перемещается из одной (сессионной) комнаты в другую:
{
   "type": "signal:breakout-room",
   "data": {
       "message": "'participantMoved'",
       "breakoutRooms": \[...],
   }
}
  • в то время как сигнальное сообщение с типом, установленным на signal:count-down-timer, должно информировать о таймере:
{
   "type": "signal:count-down-timer",
   "data": {
       "period": 1,
   }
}

Для этих breakoutRoomSignal сообщений приложение выполняет соответствующие действия, например, для participantMoved оно перемещает участника в назначенную комнату.

if (mMessage.breakoutRoomSignal.message === 'participantMoved' && roomAssigned && (!currentRoomAssigned || currentRoomAssigned.id !== roomAssigned.id)) {
    setCurrentRoomAssigned(roomAssigned);
    mNotification.openNotification("Room assigned by Host/Co-host", `You will be redirected to Room: ${roomAssigned.name} in 5 seconds.`, () => handleChangeRoom(roomAssigned.name))
}

В течение handleChangeRoom приложение покинет текущую комнату (путем отключения от связанного сеанса) и присоединится к назначенной комнате (путем подключения к связанному сеансу).

async function handleChangeRoom(publisher, roomName) {
    const newRooms = \ [...mMessage.breakoutRooms];
    let targetRoom = newRooms.find((room) => room.name === roomName);

    await mSession.session.unpublish(publisher);
    await mSession.session.disconnect();

    const connectionSuccess = await connect(mSession.user, targetRoom ? targetRoom.id : '');

    if (!connectionSuccess) {
        // Force connect to main room;
        targetRoom = null;
        roomName = '';
        await connect(mSession.user);
    }

    let data = {
        fromRoom: currentRoom.name,
        toRoom: roomName ? roomName : mainRoom.name,
        participant: mSession.user.name
    }

    setInBreakoutRoom(targetRoom && targetRoom.name !== mainRoom.name ? targetRoom : null);
}

Повторно используйте объект Publisher при переключении между комнатами

Когда участник покидает основную комнату и присоединяется к комнате обсуждения (или иным образом), рекомендуется повторно использовать объект Publisher для экономии ресурсов.

Для каждого type": "signal:breakout-room сообщения, которое может заставить клиента выйти из комнаты и присоединиться к другой комнате, например. roomCreated (automatic) приложение отключается от сеанса, а затем подключается к другому сеансу. При этом поток, опубликованный в предыдущей сессии, будет уничтожен, а клиенту публикатора будет отправлено событие streamDestroyed. Чтобы сохранить объект Publisher для повторного использования, следует вызвать метод preventDefault события streamDestroyed.

function handleStreamDestroyed(e) {
    if (e.stream.name !== "sharescreen") e.preventDefault();
    if (e.reason === 'forceUnpublished') {
        console.log('You are forceUnpublished');
        setStream({
            ...e.stream
        })
        setPublisher({
            ...e.stream.publisher
        })
    }
}

Демонстрационное приложение повторно использует этот объект Publisher для публикации в сеансе, связанном с комнатой обсуждения.

async function publish(
    user,
    extraData
) {
    try {
        if (!mSession.session) throw new Error("You are not connected to session");
        if (!publisher || publisherOptions.publishVideo !== hasVideo || publisherOptions.publishAudio !== hasAudio) {


            if (publisher) resetPublisher();
            const isScreenShare = extraData && extraData.videoSource === 'screen' ? true : false;
            const options = {
                insertMode: "append",
                name: user.name,
                publishAudio: isScreenShare ? true : hasVideo,
                publishVideo: isScreenShare ? true : hasAudio,
                style: {
                    buttonDisplayMode: "off",
                    nameDisplayMode: displayName ? "on" : "off"
                }
            };
            const finalOptions = Object.assign({}, options, extraData);
            setPublisherOptions(finalOptions);
            const newPublisher = OT.initPublisher(containerId, finalOptions);
            publishAttempt(newPublisher, 1, isScreenShare);
        } else {
            publishAttempt(publisher);
        }
    } catch (err) {
        console.log(err.stack);
    }
}

Заключение

Используя способ создания отдельных сеансов для функции комнаты обсуждения, вам нужно беспокоиться только о подключении участников к нужному сеансу. Взгляните на код для получения более подробной информации, и, надеюсь, вы найдете это полезным для вашего приложения для комнаты отдыха.