すべてのプロダクト
Search
ドキュメントセンター

ApsaraVideo Live:ARTC Web SDK の使用開始

最終更新日:Sep 19, 2026

ApsaraVideo Real-time Communication (ARTC) Web SDK は、Web ベースのリアルタイムコミュニケーションアプリケーションを開発するために Alibaba Cloud が提供するツールキットです。音声/ビデオ通話やリアルタイムメッセージングなどの高品質な機能を Web アプリケーションに迅速に統合できます。このガイドでは、最初の ARTC アプリケーションをすばやく構築する方法を説明します。

ARTC Web SDK は、Web ベースのリアルタイムコミュニケーションアプリケーションを開発するために Alibaba Cloud が提供するツールキットです。音声/ビデオ通話やリアルタイムメッセージングなどの高品質な機能を Web アプリケーションに迅速に統合できます。このガイドでは、最初の ARTC アプリケーションをすばやく構築する方法を説明します。

ステップ 1:アプリケーションの作成

  1. ApsaraVideo Live console にログインします。

  2. 左側メニューで、ライブストリーム + > リアルタイムオーディオビデオ > アプリケーション を選択します。

  3. アプリケーションの作成 をクリックします。

  4. 任意の インスタンス名 を入力し、利用規約 のチェックボックスをオンにして、[Create Now] をクリックします。

  5. 成功メッセージが表示されたら、[Applications] ページを更新して、新しい ApsaraVideo Real-time Communication アプリケーションが表示されていることを確認します。

    説明

    アプリケーションの作成は無料です。実際の使用量に応じて従量課金されます。詳細については、「Billing of audio and video calls」をご参照ください。

ステップ 2:アプリケーション ID と AppKey の取得

アプリケーションを作成したら、アプリケーションリストで作成したアプリケーションを見つけます。操作 列の 管理 をクリックして 基本情報 ページを開きます。このページで [アプリケーション ID] と [AppKey] を確認できます。

ステップ 3:SDK の統合

ARTC Web SDK は標準の JavaScript SDK であり、Vue 2、Vue 3、React など、すべての主流フロントエンドフレームワークと互換性があります。本トピックのサンプルコードは、ネイティブ JavaScript で記述されています。Vue 2 などのフレームワークで開発している場合は、公式の JavaScript サンプルをフレームワークの慣習 (例:ライフサイクル管理、コンポーネントのカプセル化) に合わせてご自身で調整する必要があります。フレームワーク固有のサンプルコードは現時点では提供されていません。

  1. SDK を統合します。

    Script

    HTML ページに SDK スクリプトを含めます。

    <script src="https://g.alicdn.com/apsara-media-box/imp-web-rtc/7.3.4/aliyun-rtc-sdk.js"></script>

    NPM

    プロジェクトで次のコマンドを実行して SDK をインストールします。

    npm install aliyun-rtc-sdk --save
  2. エンジンを初期化します。

    // 次の 2 つの import 方法のいずれかを選択します。
    // npm パッケージから import する場合は、こちらを使用します。
    import AliRtcEngine from 'aliyun-rtc-sdk';
    // script タグで SDK を読み込む場合は、こちらを使用します。
    const AliRtcEngine = window.AliRtcEngine;
    // ブラウザの互換性を確認します。
    const checkResult = await AliRtcEngine.isSupported();
    if (!checkResult.support) {
      // 現在の環境はサポートされていません。ブラウザの切り替えまたはアップグレードをユーザーに促します。
    }
    // エンジンインスタンスを作成します。グローバル変数として保存できます。
    const aliRtcEngine = AliRtcEngine.getInstance();
    
  3. AliRtcEngine インスタンスを作成したら、関連イベントをリッスンし、処理します。

    // ローカルユーザーがチャンネルから退出したときに発生します。
    aliRtcEngine.on('bye', (code) => {
      // `code` は理由コードです。詳細については、API リファレンスをご参照ください。
      console.log(`bye, code=${code}`);
      // ここで、通話ページを終了するなどのビジネスロジックを処理します。
    });
    // リモートユーザーがオンラインになったときに発生します。
    aliRtcEngine.on('remoteUserOnLineNotify', (userId, elapsed) => {
      console.log(`User ${userId} joined the channel in ${elapsed} seconds.`);
      // ここで、そのユーザーのUIモジュールを表示するなどのビジネスロジックを処理します。
    });
    // リモートユーザーがオフラインになったときに発生します。
    aliRtcEngine.on('remoteUserOffLineNotify', (userId, reason) => {
      // `reason` は理由コードです。詳細については、API リファレンスをご参照ください。
      console.log(`User ${userId} left the channel. Reason code: ${reason}`);
      // ここで、そのユーザーのUIモジュールを破棄するなどのビジネスロジックを処理します。
    });
    // リモートストリームのサブスクライブ状態が変化したときに発生します。
    aliRtcEngine.on('videoSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
      // 'oldState' と 'newState' は AliRtcSubscribeState の値です。
      // 値:0 (初期化済み)、1 (サブスクライブ解除)、2 (サブスクライブ中)、3 (サブスクライブ済み)。
      // `interval` は状態変化間の時間 (ミリ秒) です。
      console.log(`Subscription state of remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}.`);
      // ここでリモートストリームを視聴するロジックを処理します。
      // `newState` が 3 になったら、setRemoteViewConfig を呼び出してリモートストリームを再生できます。
      // `newState` が 1 になったら、再生を停止できます。
    });
    // 認証情報の有効期限が切れたときに発生します。
    aliRtcEngine.on('authInfoExpired', () => {
      // このコールバックは、認証情報の有効期限切れを示します。
      // 新しいトークンなどのデータを取得してから refreshAuthInfo メソッドを呼び出し、認証データを更新します。
      aliRtcEngine.refreshAuthInfo({
        userId,
        token,
        timestamp
      });
    });
    // 認証情報の有効期限が近づいたときに発生します。
    aliRtcEngine.on('authInfoWillExpire', () => {
      // このコールバックは、認証情報が 30 秒後に失効することを示します。
      // 速やかに新しい認証情報を取得し、refreshAuthInfo メソッドを呼び出して更新してください。
    });
    
  4. (オプション) チャンネルモードを設定します。デフォルトは通信モードです。詳細については、「Set the channel mode and user role」をご参照ください。

    // チャンネルモードを設定します。有効な値:'communication' (通信モード)、'interactive_live' (インタラクティブモード)。
    aliRtcEngine.setChannelProfile('interactive_live');
    // ユーザーロールを設定します。このメソッドはインタラクティブモードでのみ有効です。
    // 有効な値:'interactive' (ストリーマー。ストリームのパブリッシュとサブスクライブが可能)、'live' (視聴者。ストリームのサブスクライブのみが可能)。
    aliRtcEngine.setClientRole('interactive');
  5. チャンネルに参加します。トークンの生成方法については、「トークンベースの認証」をご参照ください。要件に応じて、単一パラメーター、または複数パラメーターで参加できます。

    • 単一パラメーターでの参加

      const userName = 'Test User 1'; // ユーザー名に変更できます。日本語も使用可能です。
      try {
        // サーバーからBase64でエンコードされたトークンを取得する fetchToken を実装する必要があります。
        const base64Token = await fetchToken();
        await aliRtcEngine.joinChannel(base64Token, userName);
        // チャンネルへの参加に成功しました。続けて他の操作を実行します。
      } catch (error) {
        // チャンネルへの参加に失敗しました。
      }
    • 複数パラメーターでの参加

      // トークンベースの認証ガイドに従い、サーバー上またはローカルで認証情報を生成します。
      // IMPORTANT:データセキュリティのため、AppKey を含むトークン計算ロジックをエンドユーザーに公開しないでください。
      const appId = 'yourAppId'; // コンソールから取得します。
      const appKey = 'yourAppKey'; // コンソールから取得します。本番環境では AppKey を公開しないでください。
      const channelId = 'AliRtcDemo'; // チャンネルIDに変更できます。英数字のみがサポートされています。
      const userId = 'test1'; // ユーザーIDに変更できます。英数字のみがサポートされています。
      const userName = 'Test User 1'; // ユーザー名に変更できます。日本語も使用可能です。
      const timestamp = Math.floor(Date.now() / 1000) + 3600; // 有効期限は 1 時間です。
      try {
        const token = await generateToken(appId, appKey, channelId, userId, timestamp);
        // チャンネルに参加します。token や timestamp などのパラメーターは通常サーバーから返されます。
        // 注:このメソッドを呼び出す際は、channelId、userId、appId、timestamp の各パラメーターが、トークン生成時に使用した値と一致していることを確認してください。
        await aliRtcEngine.joinChannel({
          channelId,
          userId,
          appId,
          token,
          timestamp,
        }, userName);
        // チャンネルへの参加に成功しました。続けて他の操作を実行します。
      } catch (error) {
        // チャンネルへの参加に失敗しました。
      }
  6. 次の手順に従ってローカルビデオをプレビューします。デフォルトでは、チャンネル参加後にローカルの音声・ビデオデータが自動的にキャプチャされ、Global Realtime Transport Network (GRTN) にパブリッシュされます。

    1. HTML コードに、idlocalPreviewer の VIDEO 要素を追加します。

      <video
        id="localPreviewer"
        muted
        style="display: block;width: 320px;height: 180px;background-color: black;"
      ></video>
    2. setLocalViewConfig メソッドを呼び出し、要素 ID を渡してプレビューを開始します。

      // 第 1 引数には HTMLVideoElement またはその ID を指定します。停止する場合は null を渡します。
      // 第 2 引数でストリームタイプを指定します。1 はカメラストリーム、2 は画面共有ストリームです。
      aliRtcEngine.setLocalViewConfig('localPreviewer', 1);
  7. リモートの音声・ビデオストリームをサブスクライブします。デフォルトでは、チャンネル参加後に SDK が他の配信者の音声・ビデオストリームを自動的にサブスクライブします。音声ストリームは自動再生されます。カメラストリームまたは画面共有ストリームを表示するには、setRemoteViewConfig メソッドを呼び出します。

    1. HTML コードに、コンテナとして DIV 要素(idremoteVideoContainer)を追加します。

      <div id="remoteVideoContainer"></div>
    2. リモートビデオストリームのサブスクライブ変更をリッスンします。ストリームがサブスクライブされたら setRemoteViewConfig メソッドを呼び出して再生します。サブスクライブ解除されたら、ビデオ要素を削除します。

      // video 要素を保存します。
      const remoteVideoElMap = {};
      // リモートコンテナの要素。
      const remoteVideoContainer = document.querySelector('#remoteVideoContainer');
      function removeRemoteVideo(userId) {
        const el = remoteVideoElMap[userId];
        if (el) {
          aliRtcEngine.setRemoteViewConfig(null, userId, 1);
          el.pause();
          remoteVideoContainer.removeChild(el);
          delete remoteVideoElMap[userId];
        }
      }
      // `videoSubscribeStateChanged` の例は、「関連イベントをリッスンして処理する」手順と同じです。
      aliRtcEngine.on('videoSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
        // `oldState` と `newState` は AliRtcSubscribeState 型の値です。
        // 値:0 (初期化済み)、1 (サブスクライブ解除)、2 (サブスクライブ中)、3 (サブスクライブ済み)。
        // `interval` は状態変化間の時間 (ミリ秒) です。
        console.log(`Subscription state of remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}.`);
        
        // ハンドラー例
        if (newState === 3) {
          const video = document.createElement('video');
          video.autoplay = true;
          video.setAttribute('style', 'display: block;width: 320px;height: 180px;background-color: black;');
          remoteVideoElMap[userId] = video;
          remoteVideoContainer.appendChild(video);
          // 第 1 引数は HTMLVideoElement です。
          // 第 2 引数はリモートユーザー ID です。
          // 第 3 引数でストリームタイプを指定します。1 はカメラストリーム、2 は画面共有ストリームです。
          aliRtcEngine.setRemoteViewConfig(video, userId, 1);
        } else if (newState === 1) {
          removeRemoteVideo(userId);
        }
      });
  8. セッションを終了し、リソースをクリーンアップします。

    // ローカルプレビューを停止します。
    await aliRtcEngine.stopPreview();
    // チャンネルから退出します。
    await aliRtcEngine.leaveChannel();
    // インスタンスを破棄してリソースを解放します。
    aliRtcEngine.destroy();

クイックスタートデモ

重要

このデモの JavaScript には、トークンを計算する generateToken メソッドが含まれています。セキュリティ上の理由から、このコードや AppKey をクライアント側の JavaScript ファイルに公開しないでください。情報漏えいや悪用につながる可能性があります。サーバー側でトークン署名を行い、クライアント側では認証済み API を通じてトークンを取得することを推奨します。

前提条件

このデモを実行するには、開発環境に HTTP サーバーが必要です。http-server npm パッケージがない場合は、npm install --global http-server を実行してグローバルにインストールします。

ステップ 1:ディレクトリの作成

demo フォルダを作成し、quick.htmlquick.js の 2 つのファイルを格納します。

- demo
  - quick.html
  - quick.js

ステップ 2:quick.html の編集

次のコードを quick.html にコピーして、ファイルを保存します。

コード例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>aliyun-rtc-sdk quick start</title>
    <link rel="stylesheet" href="https://g.alicdn.com/code/lib/bootstrap/5.3.0/css/bootstrap.min.css" />
    <style>
      .video {
        display: inline-block;
        width: 320px;
        height: 180px;
        margin-right: 8px;
        margin-bottom: 8px;
        background-color: black;
      }
    </style>
  </head>
  <body class="container p-2">
    <h1>aliyun-rtc-sdk quick start</h1>
    <div class="toast-container position-fixed top-0 end-0 p-3">
      <div id="loginToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="toast-header">
          <strong class="me-auto">Login Message</strong>
          <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
        </div>
        <div class="toast-body" id="loginToastBody"></div>
      </div>
      <div id="onlineToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="toast-header">
          <strong class="me-auto">User Online</strong>
          <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
        </div>
        <div class="toast-body" id="onlineToastBody"></div>
      </div>
      <div id="offlineToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="toast-header">
          <strong class="me-auto">User Offline</strong>
          <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
        </div>
        <div class="toast-body" id="offlineToastBody"></div>
      </div>
    </div>
    <div class="row mt-3">
      <div class="col-6">
        <form id="loginForm">
          <div class="form-group mb-2">
            <label for="channelId" class="form-label">Channel ID</label>
            <input class="form-control" id="channelId" />
          </div>
          <div class="form-group mb-2">
            <label for="userId" class="form-label">User ID</label>
            <input class="form-control" id="userId" />
          </div>
          <button id="joinBtn" type="submit" class="btn btn-primary mb-2">Join Channel</button>
          <button id="leaveBtn" type="button" class="btn btn-secondary mb-2" disabled>Leave Channel</button>
        </form>
        <div class="mt-3">
          <h4>Local Preview</h4>
          <video
            id="localPreviewer"
            muted
            class="video"
          ></video>
        </div>
      </div>
      <div class="col-6">
        <h4>Remote Users</h4>
        <div id="remoteVideoContainer"></div>
      </div>
    </div>
    <script src="https://g.alicdn.com/code/lib/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://g.alicdn.com/code/lib/bootstrap/5.3.0/js/bootstrap.min.js"></script>
<script src="https://g.alicdn.com/apsara-media-box/imp-web-rtc/7.3.4/aliyun-rtc-sdk.js"></script>
    <script src="./quick.js"></script>
  </body>
</html>

ステップ 3:quick.js の編集

次のコードを quick.js にコピーします。指定された変数に アプリケーション IDAppKey を貼り付け、ファイルを保存します。

コード例

function hex(buffer) {
  const hexCodes = [];
  const view = new DataView(buffer);
  for (let i = 0; i < view.byteLength; i += 4) {
    const value = view.getUint32(i);
    const stringValue = value.toString(16);
    const padding = '00000000';
    const paddedValue = (padding + stringValue).slice(-padding.length);
    hexCodes.push(paddedValue);
  }
  return hexCodes.join('');
}
async function generateToken(appId, appKey, channelId, userId, timestamp) {
  const encoder = new TextEncoder();
  const data = encoder.encode(`${appId}${appKey}${channelId}${userId}${timestamp}`);
  const hash = await crypto.subtle.digest('SHA-256', data);
  return hex(hash);
}
function showToast(baseId, message) {
  $(`#${baseId}Body`).text(message);
  const toast = new bootstrap.Toast($(`#${baseId}`));
  toast.show();
}
// アプリケーション ID と AppKey を入力します。
const appId = '';
const appKey = '';
AliRtcEngine.setLogLevel(0);
let aliRtcEngine;
const remoteVideoElMap = {};
const remoteVideoContainer = document.querySelector('#remoteVideoContainer');
function removeRemoteVideo(userId, type = 'camera') {
  const vid = `${type}_${userId}`;
  const el = remoteVideoElMap[vid];
  if (el) {
    aliRtcEngine.setRemoteViewConfig(null, userId, type === 'camera' ? 1: 2);
    el.pause();
    remoteVideoContainer.removeChild(el);
    delete remoteVideoElMap[vid];
  }
}
function listenEvents() {
  if (!aliRtcEngine) {
    return;
  }
  // リモートユーザーがオンラインになったときに発生します。
  aliRtcEngine.on('remoteUserOnLineNotify', (userId, elapsed) => {
    console.log(`User ${userId} joined the channel in ${elapsed} seconds.`);
    // ここで、そのユーザーのUIモジュールを表示するなどのビジネスロジックを処理します。
    showToast('onlineToast', `User ${userId} is online.`);
  });
  // リモートユーザーがオフラインになったときに発生します。
  aliRtcEngine.on('remoteUserOffLineNotify', (userId, reason) => {
    // `reason` は理由コードです。詳細については、API リファレンスをご参照ください。
    console.log(`User ${userId} left the channel. Reason code: ${reason}`);
    // ここで、そのユーザーのUIモジュールを破棄するなどのビジネスロジックを処理します。
    showToast('offlineToast', `User ${userId} is offline.`);
    removeRemoteVideo(userId, 'camera');
    removeRemoteVideo(userId, 'screen');
  });
  aliRtcEngine.on('bye', code => {
    // `code` は理由コードです。詳細については、API リファレンスをご参照ください。
    console.log(`bye, code=${code}`);
    // ここで、通話ページを終了するなどのビジネスロジックを処理します。
    showToast('loginToast', `You have left the channel. Reason code: ${code}`);
  });
  aliRtcEngine.on('videoSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
    // 'oldState' と 'newState' は AliRtcSubscribeState の値です。
    // 値:0 (初期化済み)、1 (サブスクライブ解除)、2 (サブスクライブ中)、3 (サブスクライブ済み)。
    // `interval` は状態変化間の時間 (ミリ秒) です。
    console.log(`Subscription state of remote user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}.`);
    const vid = `camera_${userId}`;
    // ハンドラー例
    if (newState === 3) {
      const video = document.createElement('video');
      video.autoplay = true;
      video.className = 'video';
      remoteVideoElMap[vid] = video;
      remoteVideoContainer.appendChild(video);
      // 第 1 引数は HTMLVideoElement です。
      // 第 2 引数はリモートユーザー ID です。
      // 第 3 引数でストリームタイプを指定します。1 はカメラストリーム、2 は画面共有ストリームです。
      aliRtcEngine.setRemoteViewConfig(video, userId, 1);
    } else if (newState === 1) {
      removeRemoteVideo(userId, 'camera');
    }
  });
  aliRtcEngine.on('screenShareSubscribeStateChanged', (userId, oldState, newState, interval, channelId) => {
    // 'oldState' と 'newState' は AliRtcSubscribeState の値です。
    // 値:0 (初期化済み)、1 (サブスクライブ解除)、2 (サブスクライブ中)、3 (サブスクライブ済み)。
    // `interval` は状態変化間の時間 (ミリ秒) です。
    console.log(`Screen sharing stream subscription state for user ${userId} in channel ${channelId} changed from ${oldState} to ${newState}.`);
    const vid = `screen_${userId}`;
    // ハンドラー例
    if (newState === 3) {
      const video = document.createElement('video');
      video.autoplay = true;
      video.className = 'video';
      remoteVideoElMap[vid] = video;
      remoteVideoContainer.appendChild(video);
      // 第 1 引数は HTMLVideoElement です。
      // 第 2 引数はリモートユーザー ID です。
      // 第 3 引数でストリームタイプを指定します。1 はカメラストリーム、2 は画面共有ストリームです。
      aliRtcEngine.setRemoteViewConfig(video, userId, 2);
    } else if (newState === 1) {
      removeRemoteVideo(userId, 'screen');
    }
  });
}
$('#loginForm').submit(async e => {
  // フォームのデフォルトの送信動作を防ぎます。
  e.preventDefault();
  const channelId = $('#channelId').val();
  const userId = $('#userId').val();
  const timestamp = Math.floor(Date.now() / 1000) + 3600; // 有効期限は 1 時間です。
  if (!channelId || !userId) {
    showToast('loginToast', 'Incomplete information.');
    return;
  }
  aliRtcEngine = AliRtcEngine.getInstance();
  listenEvents();
  try {
    const token = await generateToken(appId, appKey, channelId, userId, timestamp);
    // チャンネルモードを設定します。有効な値:'communication' (通信モード)、'interactive_live' (インタラクティブモード)。
    aliRtcEngine.setChannelProfile('communication');
    // ユーザーロールを設定します。このメソッドはインタラクティブモードでのみ有効です。
    // 有効な値:'interactive' (ストリーマー。ストリームのパブリッシュとサブスクライブが可能)、'live' (視聴者。ストリームのサブスクライブのみが可能)。
    // await aliRtcEngine.setClientRole('interactive');
    // チャンネルに参加します。token や timestamp などのパラメーターは通常サーバーから返されます。
    await aliRtcEngine.joinChannel(
      {
        channelId,
        userId,
        appId,
        token,
        timestamp,
      },
      userId
    );
    showToast('loginToast', 'Successfully joined the channel.');
    $('#joinBtn').prop('disabled', true);
    $('#leaveBtn').prop('disabled', false);
    // ローカルプレビューを開始します。
    aliRtcEngine.setLocalViewConfig('localPreviewer', 1);
  } catch (error) {
    console.log('Failed to join the channel.', error);
    showToast('loginToast', 'Failed to join the channel.');
  }
});
$('#leaveBtn').click(async () => {
  Object.keys(remoteVideoElMap).forEach(vid => {
    const arr = vid.split('_');
    removeRemoteVideo(arr[1], arr[0]);
  });
  // ローカルプレビューを停止します。
  await aliRtcEngine.stopPreview();
  // チャンネルから退出します。
  await aliRtcEngine.leaveChannel();
  // インスタンスを破棄します。
  aliRtcEngine.destroy();
  aliRtcEngine = undefined;
  $('#joinBtn').prop('disabled', false);
  $('#leaveBtn').prop('disabled', true);
  showToast('loginToast', 'Left the channel.');
});

ステップ 4:デモの実行

  1. ターミナルで demo フォルダに移動し、http-server -p 8080 を実行して HTTP サーバーを起動します。

  2. 新しいブラウザタブを開き、localhost:8080/quick.html にアクセスします。Channel IDUser ID を入力し、Join Channel をクリックします。

  3. 2 つ目のブラウザタブを開き、localhost:8080/quick.html にアクセスします。同じ Channel ID を入力し、異なる User ID を入力してから、Join Channel をクリックします。

  4. 他のユーザーのメディアストリームが自動的にサブスクライブされ、ページ上に表示されることを確認します。

よくある質問

手動での再接続に失敗した場合、またはページ更新後に再接続できない場合はどうすればよいですか。

  • 手動での再接続で重複ストリーム作成エラーが発生する場合: SDK には再接続メカニズムが組み込まれており、コードレベルでの介入が必要なのは、再接続に失敗した場合のみです。手動で再接続をトリガーする場合は、既存のストリームを正しく破棄するか、既存のインスタンスを再利用してからチャンネルに再参加する必要があります。これにより、既存のストリームがある状態で重複したストリームが作成されるのを防げます。

  • ページ更新後に再接続できない場合: ページ更新により SDK インスタンスが破棄されるため、joinChannel を呼び出して、参加手順を最初からやり直す必要があります。connectionStatusChange イベントをリッスンし、切断または失敗を検出したら leaveChannel を呼び出し、その後チャンネルに再参加して再接続を完了することを推奨します。