https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-a-breakout-room-application-in-javascript-with-vonage-video-api/breakoutroom.jpg

Crea una aplicación de sala de reuniones en JavaScript con la Video API de Vonage

Publicado el May 24, 2022

Tiempo de lectura: 5 minutos

Este artículo ha sido escrito en colaboración con Yinping Ge

La sala de reuniones es una función muy solicitada por muchos clientes, especialmente en el sector educativo. A menudo permite "dividir la sala de reuniones principal en otras distintas", "dividir a los participantes en estas salas de descanso", y "que los participantes envíen mensajes al anfitrión independientemente de la sala en la que se encuentren", etc.

Con Vonage Video API de Vonagehay más de una manera de implementar esta función de sala de reuniones para tu aplicación.

Una forma es crear una gran Sesión de Video con una lógica que controle a qué flujos debe suscribirse cada usuario. Otra es "implementar salas de breakout como sesiones separadas", luego "conectar a los participantes a estas diferentes sesiones creadas para cada sala de breakout".

Este tutorial explica cómo utilizar las sesiones separadas para incorporar la función de sala de descanso en nuestra aplicación de demostración, que utiliza la API de señalización para implementar la gestión de salas de descanso y reutiliza el objeto Editor al cambiar de una sala a otra.

Espero que los siguientes gráficos puedan darle una idea general. Al principio, todos los participantes se conectan a la sesión de la sala principal:

Graph showing all participants connect to the main-room’s session

Después de que el anfitrión hace clic en el botón para crear salas de breakout, el servidor de aplicaciones llama a la Video API de Vonage para crear una sesión para cada sala de breakout y devuelve estos ID de sesión a cada participante.

Graph showing application connects participants to breakout rooms

A continuación, la aplicación conecta a los participantes a las sesiones de estas salas de breakout dejando que los participantes elijan una sala a la que unirse o dividiendo a los participantes en diferentes salas automáticamente, dependiendo de la opción que el anfitrión haya seleccionado al crear las salas de breakout (el anfitrión puede elegir entre "Asignar automáticamente" y "Dejar que los participantes elijan una sala").

Requisitos previos

Una cuenta de Video API de Vonage. Haz clic en Regístrate para crear una si aún no la tienes. Versión de ReactJS >= 16.8 Versión de Node.js >= 16.13 PostgreSQL 14 como base de datos, puedes elegir cualquier almacenamiento que prefieras.

Usted debe ser capaz de ver todas las dependencias en el repositorio de GitHub y te sugerimos que utilices siempre la última versión del SDK de Vonage. Las versiones enumeradas aquí fueron las que usamos cuando trabajamos en esta aplicación de demostración.

Diseño del servidor y la base de datos de Applications

El servidor de aplicaciones crea salas, crea sesiones, genera tokens, mantiene las salas y los participantes, y envía mensajes de señalización a las salas.

El servidor de aplicaciones actúa como "relé" utilizando la API de señalización-REST para pasar mensajes entre diferentes salas/sesiones en situaciones en las que un participante necesita levantar la mano al anfitrión que está en otra sala (es decir, conectado a otra sesión), y para la función principal: la gestión de salas de descanso. Más adelante explicaremos en detalle cómo utilizamos los mensajes de señalización para gestionar las salas de descanso.

Al ejecutar el servidor de aplicaciones, la tabla de salas se creará si no existe. Entiendo que la tabla de habitaciones puede ser un poco más compleja en la vida real. Aquí solo listamos los datos básicos que necesitamos. El script para crear la tabla de habitaciones es el siguiente:

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
)

En session_id almacena el id de una sesión asociada a la sala. El max_participants define el número máximo de participantes que permite la sala. El main_room_id diferencia si se trata de una sala de breakout que pertenece a la sala principal o sólo de una sala principal que puede tener salas de breakout: cuando se establece en NULLse trata de una sala principal; en caso contrario, se trata de una sala de breakout y su valor debe establecerse en el id de sala de su sala principal.

Inicialmente, en la página de inicio de sesión, todos los usuarios eligen unirse a una sala, la sala principal. Al recibir la solicitud, el servidor de aplicaciones llama a la Video API para crear una sesión para esta sala principal y añade un registro a la tabla de salas con el valor session_id con el id de la sesión creada y main_room_id con el valor NULL. A continuación, devuelve el session_id a todos los usuarios conectados para que se conecten a la sesión.

Cuando la reunión está en curso y un usuario anfitrión decide crear salas de descanso, después de enviar las opciones que aparecen en "Control de salas de descanso", como cuántas salas de descanso se van a crear", "Dejar que los participantes elijan la sala", o "Asignar automáticamente", etc. El front-end envía una createSession solicitud con el parámetro breakoutRooms con las selecciones anteriores al servidor de aplicaciones, que creará una sesión para cada sala de reuniones y almacenará el identificador de sesión y otra información en la tabla de salas, un registro para cada sala de reuniones con el valor main_room_id con el identificador de la sala principal.

Utilice la API de señalización para gestionar las salas de descanso

El objeto Room contiene las referencias a la sesión, el mensaje (breakoutRoomSignal) y los participantes, y proporciona las entradas para crear salas de reunión y gestionar a los participantes.

La aplicación utiliza API de señalización REST para enviar mensajes a los clientes conectados a todas las sesiones relacionadas con una sala principal/sala de descanso, informando de cambios de sala, solicitudes de temporizador y aumento de mano, etc.

Por ejemplo, el mensaje de señalización con el tipo y los datos que se indican a continuación sirve para informar a los usuarios de la aplicación de que se están creando nuevas salas de descanso y de que pueden elegir una a la que unirse:

{
   "type": "signal:breakout-room",
   "data": {
       "message": "roomCreated (chooseroom)",
       "breakoutRooms": \[], //array of available rooms
   }
}
  • Mensaje de señalización para informar de que "se han eliminado todas las habitaciones":

{
     "type": "signal:breakout-room",
     "data": {
         "message": "allRoomRemoved",
         "breakoutRooms": \[...],
     }
 }
  • informar a un participante que se traslada de una sala (de descanso) a otra:

{
   "type": "signal:breakout-room",
   "data": {
       "message": "'participantMoved'",
       "breakoutRooms": \[...],
   }
}
  • mientras que, un mensaje de señalización con el tipo establecido en signal:count-down-timer es para informar de un temporizador:

{
   "type": "signal:count-down-timer",
   "data": {
       "period": 1,
   }
}

Para estos breakoutRoomSignal mensajes, la aplicación actúa en consecuencia, por ejemplo para participantMovedtraslada al participante a la sala asignada.

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))
}

En handleChangeRoomla aplicación abandonará la sala actual (desconectándose de su sesión asociada) y se unirá a la sala asignada (conectándose a su sesión asociada).

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);
}

Volver a utilizar el objeto editor al cambiar de una sala a otra

Cuando un participante abandona la sala principal y se incorpora a una sala de breakout (o de otro tipo), se recomienda reutilizar el objeto Editor para ahorrar recursos.

Para cada type": "signal:breakout-room mensaje que puede hacer que un cliente abandone una sesión y se conecte a otra, por ejemplo roomCreated (automatic), lo que hace la aplicación es desconectarse de una sesión y luego conectarse a otra. Dentro del proceso, el stream publicado a la sesión anterior será destruido y el evento streamDestroyed será enviado al cliente publicador. Para retener el objeto Publisher para su reutilización, se debe llamar al método preventDefault del evento 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
        })
    }
}

La aplicación de demostración reutiliza este objeto Publisher para publicar en la sesión asociada a la sala de descanso.

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);
    }
}

Conclusión

Gracias a la creación de sesiones independientes para la función de sala de reuniones, sólo tendrá que preocuparse de conectar a los participantes a la sesión adecuada. Eche un vistazo al el código para más detalles y esperamos que te resulte útil para tu aplicación de sala de reuniones.

Compartir:

https://a.storyblok.com/f/270183/400x351/0c294bb1fc/iu-jie-lim.png
Iu Jie Lim

Iu Jie is a Software Engineer who is constantly seeking innovative ways to solve a problem. She is passionate about new technology, especially relating to cloud and AI. Out of work, she likes to spend her time hunting for tasty food with family.