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

VonageビデオAPIを使ってJavaScriptでブレイクアウト・ルーム・アプリケーションを構築する

最終更新日 May 24, 2022

所要時間:1 分

この記事は以下の協力により執筆された。 葛銀平

ブレイクアウト・ルームは、多くのお客様、特に教育関係のお客様に必要とされる一般的な機能です。メインの会議室を分割して使用する」、「参加者を分割して使用する」、「参加者がどの部屋にいてもホストにメッセージを送信する」などが可能です。

Vonageと Video APIを使えば、あなたのアプリケーションにこのようなブレイクアウト・ルーム機能を実装する方法は一つではありません。

ひとつの方法は、大きな Videoセッションを作成することです。もう1つは、"ブレイクアウトルームを個別のセッションとして実装し"、"参加者をブレイクアウトルームごとに作成された異なるセッションに接続する "方法です。

このチュートリアルでは 個別セッションを使用して、デモ・アプリケーションにブレイクアウト・ルーム機能を構築する方法を説明します。このデモ・アプリケーションでは、ブレイクアウト・ルームの管理を実装するためにシグナリングAPIを使用します。

以下のグラフで、まず大まかなイメージをつかんでほしい。最初は、すべての参加者がメインルームのセッションに接続する:

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

ホストが分科室を作成するボタンをクリックした後、アプリケーションサーバーはVonage Video APIを呼び出して各分科室のセッションを作成し、これらのセッションIDを各参加者に返します。

Graph showing application connects participants to breakout rooms

その後、アプリケーションは、参加者に参加する部屋を選択させるか、またはホストがブレイクアウトルームを作成する際に選択したオプションに応じて、参加者を自動的に異なる部屋に分割することにより、これらのブレイクアウトルームのセッションに参加者を接続します(ホストは、「自動的に割り当てる」と「参加者に部屋を選択させる」のいずれかを選択できます)。

前提条件

Video API アカウント。クリック サインアップをクリックして作成してください。ReactJSのバージョン >= 16.8 Node.jsのバージョン >= 16.13 データベースとしてPostgreSQL 14、あなたが好む任意のストレージを選択することができます。

すべての依存関係を GitHub リポジトリですべての依存関係を見ることができるはずです。Vonage SDKは常に最新版を使うことをお勧めします。ここに記載されているバージョンは、私たちがこのデモアプリに取り組んでいたときに使用していたものです。

アプリケーションのサーバーとデータベースの設計

アプリケーションサーバーは、ルームを作成し、セッションを作成し、トークンを生成し、ルームと参加者を管理し、ルームにシグナリングメッセージを送信する。

アプリケーション・サーバーは、「リレー」として機能する。 シグナリング-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には、その部屋に関連付けられているセッションの ID が格納されます。セッションID max_participantsはルームが許可する最大参加者数を定義します。メインルームと main_room_idは、この部屋がメインルームに属するブレイクアウトルームなのか、ブレイクアウトルームを持つことができるメインルームなのかを区別します。 NULLに設定されている場合、それはメインルームです。そうでない場合、それはブレイクアウトルームであり、その値はメインルームのルームIDに設定されるべきです。

最初に、ログインページで、すべてのユーザーは、1つのルーム、別名メインルームに参加することを選択します。フロントエンドのリクエストを受け取ると、アプリケーションサーバーは Video API を呼び出してこのメインルームのセッションを作成し、ルームテーブルにレコードを追加します。 session_idレコードをルームテーブルに追加します。 main_room_idに設定します。 NULL.そして session_idをすべてのログインユーザに返します。

会議が進行中で、ホストユーザーが分科室を作成することを決定した場合、「分科室コントロール」に記載されているオプション、例えば「いくつの分科室を作成するか」、「参加者に部屋を選ばせる」、「自動的に割り当てる」などを送信します。フロントエンドは createSessionリクエストを送信します。 breakoutRoomsアプリケーションサーバーはそれに応じて各分割室のセッションを作成し、セッションIDとその他の情報を会議室テーブルに保存します。 main_room_idセッションIDとその他の情報をルームテーブルに保存します。

ブレイクアウト・ルーム管理の実装にシグナリングAPIを使用する

Roomオブジェクトは、セッション、メッセージ(breakoutRoomSignal)、参加者への参照を保持し、ブレークアウトルームの作成と参加者の管理のためのエントリを提供します。

アプリケーションは シグナリング-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);
}

部屋を行き来する際にパブリッシャーオブジェクトを再利用する

参加者がメイン・ルームを出て、ブレイクアウト・ルームに参加する場合(またはそれ以外の場合)、 リソースを節約するために、パブリッシャー・オブジェクトオブジェクトを再利用することをお勧めします。

type": "signal:breakout-roomクライアントを退室させ、別の部屋に参加させることができる各メッセージ、例えば roomCreated (automatic)アプリケーションが行うのは、セッションを切断し、別のセッションに接続することである。このプロセスの中で、前のセッションに発行されたストリームは破棄され、イベント streamDestroyedイベントがパブリッシャークライアントにディスパッチされます。再利用のためにPublisherオブジェクトを保持するためには、streamDestroyedイベントのpreventDefaultメソッドを呼び出す必要があります。

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

結論

ブレイクアウトルーム機能で個別のセッションを作成する方法を使えば、参加者を適切なセッションに接続することだけを心配すればよいのです。次のコードを見てください。 コードをご覧ください。あなたの分科会ルームアプリケーションに役立つと思います。

シェア:

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.