実装する安全なオンライン試験プラットフォームとRTCエンジン:開発者のガイド

10 分読む
Feb 18, 2025

シナリオの概要

オンライン試験とは、ネットワーク上でコンピュータを操作して行われる形式の試験であり、紙媒体から分離されており、オンラインメディアを通じて行われる試験とも説明できます。

  • オンライン試験には、国家コンピュータランク試験、大学英語試験、大学院入試、職業試験、金融試験、工学試験、外国貿易試験、短大から学部への進学試験、公務員試験、および企業の筆記試験など、さまざまなペーパーレス試験システムが含まれます。試験が終了した後、自動採点などの操作が実施され、最終スコアレポートが取得され、保存用にメールで送信されたり、オンラインで印刷されたりします。
  • 従来の試験では、問題設定、作成、試験問題の印刷、試験問題の配布、回答の提出、試験問題の回収と採点、結果の発表、および試験結果の統計分析に至るまで、全過程に手動で参加する必要があります。このプロセスは長く、労力を要し、エラーが発生しやすく、適切な機密保持作業が必要であるため、全体的な学習と試験のコストが高くなります。オンライン試験学習システムは、完全にペーパーレス、ネットワーク化、および自動化されたコンピュータオンライン学習と試験を実現でき、単位の情報化構築に深い実用的意義と価値を持ちます。

「オンライン試験」と「オフラインコンピュータベースの試験」は同じビジネスモデルではないことに注意してください。オフラインコンピュータベースの試験は、オフラインIDC内のオンラインシステムで試験を実施することを指し、伝統的な試験との違いは、試験問題が紙で完成されるか、コンピュータソフトウェアで完成されるかだけです。

実施方案

オンライン試験シーンの全体的な参考ビジネスプロセスは、図に示されています。オンライン試験システムのユーザーには、受験者、監視者、試験管理者、および問題作成者(採点者)が一般的に含まれます。

  • 受験者:受験者は受験者アカウントにログインし、試験室に入室し、カメラと画面共有を有効にし、監視条件下で試験問題を完了し、提出する必要があります。
  • 監視者:監視者は監視者アカウントにログインし、試験に参加しているすべての受験者のカメラフィードを確認し、不正行為がないかどうかを判断します。システム自体にも、試験アプリケーションが切り替えられた回数と期間を監視するなど、一定の自動監視機能があります。一部のシーンでは、受験者が許可された範囲内で質問をすることにも答える必要があります。
  • 試験管理者:試験室を作成し、関連する試験室に試験問題をアップロードし、試験室へのアクセスを制御する必要があります。一般的に、監視者の1人がこの役割も担うことができます。
  • 教師:主な仕事は、試験前に問題を設定し、試験後に試験問題を手動で採点することです(必要に応じて)。

オンライン試験ビジネスフローチャート:

Online Examination Business Flowchart: This flowchart outlines the steps involved in an online examination process, including pre-exam review

ビジネスプロセス

この文書は、シナリオ全体の実施フローをよりよく理解するために、いくつかの一般的なビジネスプロセスをまとめています。

  • ログインとログアウト
流程图描述了聊天系统的操作流程,从启动到登录成功或失败的处理。关键步骤包括从业务后端检索用户信息、初始化聊天、设置事件监听、登录尝试、异常处理、重新登录或登出。该流程图有助于确保聊天系统的稳定性和用户交互的顺畅。

Chat Flow Diagram:
1. Start
  • ルームの作成/破棄
  • 音声と映像のストリーミング
  • 音声と映像のプルストリーミング

適用製品

RTCエンジン & チャット

基本統合ガイドライン

オンライン試験の円滑な進行を確保するために、事前にコンソールを通じてチケットを提出し、受験者数、地域分布、解像度、ビットレートなどの情報を登録することをお勧めします。

サービスを有効化する

ボイスチャットルームシナリオは通常、クラウドプラットフォームからの2つの有料PaaSサービスであるチャットおよびリアルタイムコミュニケーション(TRTC)に依存する必要があります。インタラクティブホワイトボードはオプションであり、選択または自己ホストできます。

1. コンソールにログインしてアプリケーションを作成する必要があります。RTCエンジンとチャットサービスを選択します。この時、SDKAppIDはコンソールで自動的に作成されます。両者のアカウントと認証システムは再利用可能です。その後、必要に応じてRTCまたはチャットアプリケーションバージョンをアップグレードすることができます。例えば、高度なバージョンでは、より多くの付加価値機能やサービスをアンロックできます。

注意:

  • テスト環境と本番環境のために、2つの別々のアプリケーションを作成することをお勧めします。各アカウント(UIN)は、1年間に月あたり10,000分の無料使用が提供されます。
  • TRTCの月額パッケージは、トライアル版、基本版、およびプロフェッショナル版に分かれており、異なる付加価値機能やサービスをアンロックできます。詳細についてはバージョン機能と月額パッケージの説明をご覧ください。

2. アプリケーションが作成された後、アプリケーション管理 - アプリケーション概要セクションでその基本情報を見つけることができます。後で使用するためにSDKAppIDSDKSecretKeyを安全に保管し、漏洩を避けて不正なトラフィック使用を防ぐことが重要です。

SDKのインポート

TRTC SDKおよびチャットSDKのzip圧縮パッケージをWindowsにダウンロードし、ローカルマシンに抽出します。プロジェクトのルートディレクトリにthirdpartyという名前のディレクトリを作成して、すべてのSDKを保存します。TRTC SDKとチャットSDKをthirdpartyディレクトリに移動し、今後の使用のために準備します。

1. QTCreatorとの統合

// *.pro
INCLUDEPATH +=  $$PWD/thirdparty/TRTC_SDK/CPlusPlus/Win64/include \
              $$PWD/thirdparty/TRTC_SDK/CPlusPlus/Win64/include/TRTC \
              $$PWD/thirdparty/IM_SDK/include

LIBS += -L'$$PWD/thirdparty/TRTC_SDK/CPlusPlus/Win64/lib' -lliteav \
        -L'$$PWD/thirdparty/IM_SDK/lib/Win64' -lImSDK

2. Visual Studioとの統合

  • Visual Studioでヘッダーファイルディレクトリを追加するには、構成プロパティ > C/C++ > 一般 > 追加のヘッダーディレクトリに移動します。次に、ヘッダーファイルのパスを追加します。
$(SolutionDir)thirdparty/TRTC_SDK/CPlusPlus/Win64/include
$(SolutionDir)thirdparty/TRTC_SDK/CPlusPlus/Win64/include/TRTC
$(SolutionDir)thirdparty/IM_SDK/include
  • ライブラリファイルディレクトリを追加するには、構成プロパティ > リンク > 一般 > 追加のライブラリディレクトリに移動します。
$(SolutionDir)thirdparty/TRTC_SDK/CPlusPlus/Win64/lib$(SolutionDir)thirdparty/IM_SDK/lib/Win64
  • ライブラリファイルを参照します。
#pragma comment(lib,"liteav.lib")
#pragma comment(lib,"ImSDK.lib")

注意:

  • 特定のビジネスニーズに応じて、x86を統合する必要がある場合は、Win32ディレクトリのヘッダーファイルとライブラリファイルを使用してください。
  • DLLダイナミックライブラリは、実行可能ファイル(exe)が存在するディレクトリにコピーする必要があります。
  • x86およびx64のLIBファイルとDLLファイルは混在させることができず、一貫性が必要です。

シナリオ固有の実装

認証資格情報の生成

UserSigは、攻撃者があなたのクラウドアカウントにアクセスするのを防ぐためにTencent Cloudによって設計されたセキュリティ署名です。リアルタイムコミュニケーション(TRTC)やチャットなどのクラウドサービスは、両方ともこのセキュリティ保護メカニズムを採用しています。TRTCはルームに入る際に認証を行い、チャットはログイン時に認証を行います。

  • デバッグおよびテスト段階:UserSigは、クライアント側UserSig生成およびTRTCコンソールUserSig生成を通じて生成できます。これはデバッグおよびテスト専用です。
  • プロダクション段階:サーバー側のUserSig生成を使用することをお勧めします。これにより、クライアントが逆コンパイルされるリスクを避け、キー漏洩のリスクを軽減します。

具体的な実装プロセスは次のとおりです:

1. アプリケーションがSDKの初期化APIを呼び出す前に、サーバーからUserSigを要求します。

2. サーバーはSDKAppIDとUserIDに基づいてUserSigを生成します。

3. サーバーはUserSigをアプリケーションに返します。

4. アプリケーションは特定のAPIを介してUserSigをSDKに送信します。

5. SDKはSDKAppID、UserID、およびUserSigをクラウドサーバーに提出して検証します。

6. クラウドプラットフォームはUserSigの有効性を検証します。

7. UserSigが有効な場合、チャットSDKおよびTRTC SDKへのサービスが提供されます。

注意:

  • デバッグおよびテスト段階でのUserSigのローカル生成方法は、オンライン環境には推奨されません。これは容易に逆コンパイルされ、キー漏洩の危険があるためです。
  • 複数の言語(Java/GO/PHP/Nodejs/Python/C#/C++)でUserSig生成のソースコードを提供しています。詳細についてはUserSig生成ソースコードをご覧ください。

初期化とリスニング

APIシーケンス図

1. チャットSDKの初期化とイベントリスナーの追加

チャットSDKは関数コールバック方式を使用します。使用を容易にするために、コールバッククラスにカプセル化できます。

// IMWrapperCallback.h
class IMWrapperCallback
{
public:
    virtual void OnLogin(int errCode, const char* errMsg) = 0;
    virtual void OnLogout(int errCode, const char* errMsg) = 0;
    virtual void OnError(int code, const char* errMsg) = 0;
    virtual void OnCreateGroup(int errCode, const char* errMsg) = 0;
    virtual void OnJoinGroup(int errCode, const char* errMsg) = 0;
    virtual void OnRecvNewMsg(const char* msg) = 0;
    //…
};

// IMWrapper.h
class IMWrapper
{
public:
    IMWrapper();
    bool InitIM(const char* path);
    bool UnInitIM();
    void SetCallback(IMWrapperCallback* callback);

    bool LoginIM(const char* id, const char* sig);
    bool LogoutIM();

    bool CreateGroup(const char* group_name, const char* group_type, const char* group_id);
    bool JoinGroup(const char* group_id);

    bool SendGroupTextMsg(const char* group_id, const char* text);

private:
    IMWrapperCallback* m_callback;
    std::string m_userId;
};

// IMWrapper.cpp
bool IMWrapper::InitIM(const char* path)
{
    Json::Value json_value_init;
    json_value_init[kTIMSdkConfigLogFilePath] = path;
    int nRet = TIMInit(SDKAppID_IM, json_value_init.toStyledString().c_str());
    if(nRet != TIM_SUCC){
        return false;
    }

    TIMAddRecvNewMsgCallback([](const char* json_param, const void* user_data) {
        if(user_data != nullptr){
            IMWrapper* wrapper = (IMWrapper*)user_data;
            if(wrapper->m_callback != nullptr){
                wrapper->m_callback->OnRecvNewMsg(json_param);
            }
        }
    }, this);

    return true;
}

注意:アプリケーションのライフサイクルがSDKのライフサイクルと一致する場合は、アプリケーションを終了する前に初期化を解除する必要はありません。ただし、特定のインターフェースに入るときだけSDKを初期化し、そのインターフェースを退出した後は使用しなくなる場合は、SDKを初期化解除できます。

2. TRTC SDKのインスタンス作成とイベントリスナー設定

//OnlineExam.h
#include "ITRTCCloud.h"
class OnlineExam: public ITRTCCloudCallback
{
public:
    OnlineExam();
    ~OnlineExam();
    virtual void onWarning(TXLiteAVWarning warningCode, const char* warningMsg, void* extraInfo) override;
    virtual void onError(TXLiteAVError errCode, const char *errMsg, void* extraInfo) override;
    virtual void onEnterRoom(int result) override;
    virtual void onExitRoom(int reason) override;
    //…
}

OnlineExam::OnlineExam(){
    getTRTCShareInstance()->addCallback(this);// シングルトンパターンを作成し、イベントリスニングを設定。
}

OnlineExam::~OnlineExam(){
    getTRTCShareInstance()->removeCallback(this);// イベントリスニングをキャンセル。
    destroyTRTCShareInstance();// インスタンスを破棄。
}

注意:SDKイベント通知をリッスンすることをお勧めします。一般的なエラーに対してログを印刷および処理してください。詳細についてはエラーコード表をご覧ください。

ログインとログアウト

チャットSDKを初期化した後、SDKログインAPIを呼び出してアカウントの身分を認証し、機能を使用する権限を得る必要があります。他の機能を使用する前に、必ずログインに成功していることを確認してください。そうしないと、機能の故障や利用不可が発生する可能性があります。TRTCの音声および映像サービスのみを使用する場合は、このステップをスキップできます。

APIシーケンス図

// ログイン:userIDはカスタマイズ可能で、userSigはステップ1で取得します。
bool IMWrapper::LoginIM(const char* id, const char* sig){
    m_userId = id;
    int nRet = TIMLogin(id, sig, [](int32_t code, const char* desc, const char* json_param, const void* user_data) {
            if(user_data != nullptr){
                IMWrapper* wrapper = (IMWrapper*)user_data;
                if(wrapper->m_callback != nullptr){
                    wrapper->m_callback->OnLogin(code, desc);
                }
            }
    }, this);

    if(nRet != TIM_SUCC){
        return false;
    }
    return true;
}

// ログアウト
bool IMWrapper::LogoutIM(){
    int nRet = TIMLogout([](int32_t code, const char* desc, const char* json_param, const void* user_data) {
            if(user_data != nullptr){
                IMWrapper* wrapper = (IMWrapper*)user_data;
                if(wrapper->m_callback != nullptr){
                    wrapper->m_callback->OnLogout(code, desc);
                }
            }
    }, this);

    if(nRet != TIM_SUCC){
        return false;
    }
    return true;
}

注意:アプリケーションのライフサイクルがチャットSDKのライフサイクルと一致する場合、アプリケーションを終了する前にログアウトする必要はありません。ただし、特定のインターフェースに入った後のみチャットSDKを使用し、そのインターフェースを退出した後は使用しなくなる場合は、ログアウトしてチャットSDKを初期化解除できます。

ルーム管理

APIシーケンス図

  1. ルームの作成

アンカー(ルームオーナー)がライブストリーミングを開始すると、ルームを作成する必要があります。ここでの「ルーム」の概念はチャットの「グループ」に対応します。この例では、クライアントでチャットグループを作成する方法を示しますが、サーバーでグループを作成することも可能です。

bool IMWrapper::CreateGroup(const char* name, const char* type, const char* id)
{
    Json::Value param;
    //グループID
    param[kTIMCreateGroupParamGroupId] = id;
    //グループタイプ
    if (strcmp(type, "Public") == 0) {
        param[kTIMCreateGroupParamGroupType] = kTIMGroup_Public;
    }
    else if(strcmp(type, "Work") == 0) {
        param[kTIMCreateGroupParamGroupType] = kTIMGroup_Private;
    }
    else if(strcmp(type, "Meeting") == 0) {
        param[kTIMCreateGroupParamGroupType] = kTIMGroup_ChatRoom;
    }
    else if(strcmp(type, "AVChatRoom") == 0) {
        param[kTIMCreateGroupParamGroupType] = kTIMGroup_AVChatRoom;
        // グループ参加の承認方法
        param[kTIMCreateGroupParamApproveOption] = kTIMGroupAddOpt_Forbid;//AnyJoin
    }
    //グループ名
    param[kTIMCreateGroupParamGroupName] = name;
    std::string createParams = param.toStyledString();
    int nRet = TIMGroupCreate(createParams.c_str(), [](int32_t code, const char* desc, const char* json_params, const void* user_data)  {
            if(user_data != nullptr){
                IMWrapper* wrapper = (IMWrapper*)user_data;
                if(wrapper->m_callback != nullptr){
                    wrapper->m_callback->OnCreateGroup(code, desc);
                }
            }
    }, this);

    if(nRet != TIM_SUCC){
        return false;
    }
    return true;
}

注意:

  • オンライン試験シナリオ用のチャットグループを作成する場合は、ミーティンググループタイプ:kTIMGroup_ChatRoomを使用することをお勧めします。
  • TRTCにはルームを作成するための別のステップはありません。存在しないルームに入ると、自動的にルームが作成されます。
  1. ルームに参加

チャットグループに参加します。

bool IMWrapper::JoinGroup(const char* id)
{
    int nRet = TIMGroupJoin(id, "参加希望", [](int32_t code, const char* desc, const char* json_param, const void* user_data) {
            if(user_data != nullptr){
                IMWrapper* wrapper = (IMWrapper*)user_data;
                if(wrapper->m_callback != nullptr){
                    wrapper->m_callback->OnJoinGroup(code, desc);
                }
            }
    }, this);

    if(nRet != TIM_SUCC){
        return false;
    }
    return true;
}

TRTCルームに参加します。

注意:

  • TRTCルームIDは整数型のroomIdと文字列型のstrRoomIdに分かれており、これらの2つのタイプのルームは相互接続されません。どちらか一方を選択するだけです。タイプを統一することをお勧めします。
  • TRTCルームへの入場シナリオは、リアルタイム通話(AudioCall、VideoCall)とインタラクティブライブストリーミング(Live、VoiceChatRoom)の2つの主要カテゴリに分かれます。オンライン試験シナリオでは、VideoCallモードが選択されます。
  • TRTCユーザーの役割は、インタラクティブライブストリーミングモードでのみアンカーとオーディエンスに区別されます。このモードでは、アンカーのみがストリーミングする権限を持ち、オーディエンスはストリーミングする場合、アンカー役割に切り替える必要があります。オンライン試験シナリオではVideoCallモードを使用し、アンカーとオーディエンスの区別はないため、役割パラメータは必要ありません。
  • ルーム入場のイベントコールバックで、result > 0はルーム参加にかかった時間(ミリ秒)を表し、result < 0はルーム入場失敗のエラーコードを表します。詳細はエラーコード表をご覧ください。
// ルームに入る。
void OnlineExam::EnterExamRoom(String roomId, String userId, String userName, int roleType, String userSig)
{
    TRTCParams param;
    param.sdkAppId = SDKAppID_TRTC;
    param.strRoomId = roomID.c_str();
    param.userId = userID.c_str();
    param.userSig = userSig.c_str();
    getTRTCShareInstance()->enterRoom(param, TRTCAppSceneVideoCall);
}

// ルーム入場結果のイベントコールバック。
void OnlineExam::onEnterRoom(int result)
{    
    if (result > 0) {
        // ルームに正常に入場しました。
    } else {
        // ルーム入場に失敗しました。
    }
}
  1. ルームを退出
// ルームを退出します。
void OnlineExam::ExitExamRoom()
{
   getTRTCShareInstance()->exitRoom();
}

// 退出ルームイベントコールバック。
void OnlineExam::onExitRoom(int reason)
{
    // 0: exitRoomを呼び出してルームを退出する; 1: サーバーによって現在のルームから削除された; 2: 現在のルームが解散された。
}

音声ストリーム管理

TRTC SDKは音声ストリームの自動購読をデフォルトとしており、ユーザーがルームに参加すると、リモートユーザーの音声が自動的に再生されます。音声ストリームの手動購読が必要な場合は、購読モードの設定をご覧ください。

  1. 学生側のストリーミング
// ルームに正常に入場した後、学生が音声と映像のストリーミングを開始します。
void OnlineExam::onEnterRoom(int result){
    if (result > 0) {
        // ルームに正常に入場しました。
        getTRTCShareInstance()->startLocalAudio(TRTCAudioQualitySpeech);
        getTRTCShareInstance()->startLocalPreview(hwndView);
    } else {
        // ルーム入場に失敗しました。
    }
}

// 試験終了、ストリーミングを停止します。
void OnlineExam::ExitExamRoom(){
    getTRTCShareInstance()->stopLocalAudio();
    getTRTCShareInstance()->stopLocalPreview();
    getTRTCShareInstance()->exitRoom();
}
  1. 監視側のストリーミングプル

学生がルームに入場し、ストリーミングを開始した後、監視者はルームに正常に入場した後すぐにストリームをプルできます。リモートストリームイベントコールバックを受信した後、現在のページの学生かどうかを判断できます。その場合は、影響なしにストリームプルを再呼び出すことができます。

void OnlineExam::onUserVideoAvailable(const char* userId, bool available){
    if(available){
        if(userId == student on the current page){
            getTRTCShareInstance()->startRemoteView(userId, TRTCVideoStreamTypeBig, hwndView);
        }
    }
}

高度な機能

試験室の分割

オンライン試験シナリオでは、1回の試験で数千人または数万人の学生がいる場合があります。しかし、TRTCルームには1ルーム当たり最大50人の同時ストリーマーという制限があります。そのため、学生を学生数に基づいて仮想試験室に分割する必要があります。試験がそれほど厳格でない場合は、1つのビデオストリームを使用し、監視者用に1つのストリームを確保することができます。各仮想試験室には、40〜49人の学生を同じroomIdに割り当てることをお勧めします。ルームに入場したら、学生はストリーミングのみを行い、ストリームプルは行いません。

同じ試験を同時に受ける学生は、ビジネスバックエンドで50人未満の学生ごとに仮想試験室に分割できます。各仮想試験室はTRTCルームID(roomId)にマッピングする必要があります。試験前に、学生は30分前に試験室に入るよう指導され、待機します。ルームに入ったら、学生はカメラ、マイク、スピーカーのテストを完了するように指導されます。ストリーミングは5分前から開始でき、学生のストリーミングに関する問題を早期に検出できます。

// 学生側(Webを例にとる)。

/// カメラテスト。
TRTC.startLocalVideo({ view: 'camera-video', publish: false });
/// マイクテスト。
TRTC.startLocalAudio({ publish: false });
// スピーカーテスト、再生可能なmp3 URLを準備してください。

TRTCは、デバイス検出機能を迅速に統合するためにデバイス検出 Reactコンポーネントを提供しています。

ビデオページネーション管理

監視者側では、一度にすべての学生のビデオをプルすることは推奨されません。これは非常に高い帯域幅を必要とします。例えば、360Pのビデオストリームは400〜600 kbpsの帯域幅を必要とするため、40人の学生の場合、16〜24 Mbpsの帯域幅が必要になります。同じオフィスで10人の監視者がストリームをプルしている場合、160〜240 Mbpsの帯域幅が必要になります。したがって、試験監視端末はページネーション表示を実装できます。例えば、1ページに9ストリームを表示し、次のページをクリックすると、現在の9ストリームのプルを停止し、次の9ストリームをプルします。

// 監視者側(Windowsを例にとる)。
void OnlineExam::onClickNext(){
    getTRTCShareInstance()->stopAllRemoteView();
    getTRTCShareInstance()->muteAllRemoteAudio(true);
    
    for(int i = 0; i < m_curUserList.size(); i++){
       getTRTCShareInstance()->startRemoteView(m_curUserList[i].userId, TRTCVideoStreamTypeBig, m_hwndList[i]);
    }
}

注意:基盤となるストリーミングは非同期操作であるため、遅延が生じる可能性があります。そのため、ページネーションボタンに対してクリック頻度制限を実装し、約1〜2秒間隔で制限する必要があります。頻繁にクリックすると、基盤システムの応答が遅れることがあり、予期しない例外が発生する可能性があります。

分割画面表示

通常のオンライン試験では、ウェブカメラは通常、ノートパソコンの内蔵ウェブカメラを使用し、学生の前面のみをキャプチャできます。これでは厳しい試験のニーズを満たすことができません。不正行為を防ぐために、学生の背面方向もキャプチャする必要があります。

単一のストリームでの監視とは異なり、側面の背景ビデオ監視を追加します。これは通常、携帯電話で行われ、位置調整が容易です。学生がセットアップの配置方法を指導することが重要であり、セットアップの図を提供することができます。配置が完了した後、前面と側面のビデオのフレーム画像をキャプチャし、ビジネスバックエンドに送信して判断を行い、学生の配置が適切かどうかを自動的に判断します。

例えば、ユーザーIDが1234の場合、側面ビデオのuserIdにはカスタムサフィックスを追加して1234_sideとすることができます。

// 学生側 - 前面ビデオ(Webを例にとる)。
const trtc = TRTC.create();
await trtc.enterRoom({ roomId, sdkAppId, "1234", userSig });

const localStream = TRTC.createStream({ userId, audio: true, video: true });
try {
  await localStream.initialize();
  console.log("ローカルストリームが正常に初期化されました。");
} catch (error) {
  console.error("ローカルストリームの初期化に失敗しました:" + error);
}
try {
  await client.publish(localStream);
  console.log("ローカルストリームが正常に公開されました。");
} catch (error) {
  console.error("ローカルストリームの公開に失敗しました:" + error);
}
// 学生側 - 側面ビデオ(Androidを例にとる)。
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
params.sdkAppId = SDKAPPID;
params.userId = "1234_side";
params.roomId = roomId;
params.userSig = usersig;

mCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_VIDEOCALL);  

mTRTCCloud.startLocalPreview(true, mTXCloudPreviewView);
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);

音量検出

より厳格なオンライン試験シナリオでは、受験者の前面と側面のビューを監視するだけでなく、受験者の周囲の環境音を検出することも必須です。受験者が音声を使って不正行為を試みる可能性があるため、事前に録音された資料を再生したり、他の人とコミュニケーションを取ったり、電話をかけたりする可能性があります。

TRTC SDKは音量検出コールバック機能を提供しています。この機能により、各ユーザーの音声レベルをリアルタイムで監視し、不審な不正行為を検出するのに役立ちます。例えば、受験者の声が急に大きくなる場合、事前に録音された回答を再生しているか、他の誰かと話している可能性があります。この場合、教師はこの受験者の音声を聞くことで介入できます。

APIシーケンス図

// 自動ストリームプルを無効化します。
void OnlineExam::enterExamRoom(){
    getTRTCShareInstance()->setDefaultStreamRecvMode(false, false);
    getTRTCShareInstance()->enterRoom(params);    
    getTRTCShareInstance()->enableAudioVolumeEvaluation();
}

// 現在のページネーションユーザーのストリームをプルします。
void OnlineExam::onEnterRoom(){
    for(int i = 0; i < m_curUserList.size(); i++){
       getTRTCShareInstance()->muteRemoteAudio(m_curUserList[i].userId, false);
       getTRTCShareInstance()->startRemoteView(m_curUserList[i].userId, TRTCVideoStreamTypeBig, m_hwndList[i]);
    }
}

// 音量レベルを検出します。
void OnlineExam::onUserVoiceVolume(TRTCVolumeInfo* userVolumes, uint32_t userVolumesCount, uint32_t totalVolume){
    int count = userVolumesCount;
    TRTCVolumeInfo* remoteUserVolumes = userVolumes;
    std::string userId;
    int userVolume = 0;
    for(int i = 0; i < count; i++){
        userId = remoteUserVolumes->userId;
        if(!userId.empty()){
            userVolume = remoteUserVolumes->volume;
            if(userVolume > m_maxVolume){
                // インターフェース上で学生をマークします。
            }
        }
        remoteUserVolumes++;
    }
}

今すぐ注文

クリックしてこちら に移動し、購入ページに素早く移動します。