出版する診断学

このガイドでは、パブリッシャーの診断を収集し、一般的な問題を解決する方法を説明します。

パブリッシャーのストリームに関する統計情報の取得

Vonage Video SDKは、ほとんどのユースケースで推奨される高レベルの統計APIを通じて、詳細なストリーム品質メトリクスを公開します。このAPIは、音声、ビデオ、ネットワーク、および送信者側の統計を、ピア接続の遷移をまたいで安定したまま、統一されたセッション認識形式で提供します。高度なデバッグのために、SDKは未処理のピア接続データを反映する生のWebRTC統計レポートへのアクセスも提供します。

参照 クライアント観測可能性開発者ガイド をご覧ください。

テストストリーム

テストストリームを公開し、そのオーディオとビデオの統計情報を確認することで、接続でサポートされるストリームのタイプ(高解像度やオーディオのみなど)を判断できます。

ローカルクライアントがパブリッシュしたストリームの統計情報を取得するには、メディアルーターを使用するセッション(メディアモードがroutedに設定されたセッション)を使用する必要があります。 testNetwork プロパティ true での options オブジェクトに渡します。 Session.subscribe() メソッドを使用します。その後 getStats() メソッドを使用して、公開するストリームのオーディオとビデオの統計情報を取得します。

を使用することができます。 SubscriberKit.setAudioStatsListener(AudioStatsListenerリスナー) そして SubscriberKit.setVideoStatsListener(VideoStatsListener listener) メソッドを使用して、公開するストリームのオーディオとビデオの統計情報を取得します。

参照 本題 をご覧ください。

を使用することができます。 networkStatsDelegate メソッドを使用して、公開するストリームのオーディオとビデオの統計情報を取得します。

について Vonage-Video-API-Network-テストサンプル レポには、セッションに公開する前にテストストリームの統計情報を使用する方法を示すサンプルコードが含まれています。

を使用することができます。 networkStatsDelegate メソッドを使用して、公開するストリームのオーディオとビデオの統計情報を取得します。

について Vonage-Video-API-Network-テストサンプル レポには、セッションに公開する前にテストストリームの統計情報を使用する方法を示すサンプルコードが含まれています。

その後、ストリームを購読して Subscriber.AudioStatsUpdated そして Subscriber.VideoStatsUpdated イベントを使用して、公開したストリームのオーディオとビデオの統計情報を取得できます。

出版時のベストプラクティス

このセクションでは、ストリームをうまく公開するためのヒントを紹介します。

デバイスへのアクセスを許可する

カメラとマイクへのアクセスを許可するよう求められることをユーザーに知らせるのがベストプラクティスです。

公開に失敗するのは、ユーザーが "拒否 "ボタンをクリックしたり、"許可 "ボタンをまったくクリックしなかったりした結果です。私たちは、ユーザーをこのプロセスに導くために必要なすべてのイベントを提供します:

publisher.on({
  accessDialogOpened: function (event) {
    // Show allow camera message
    pleaseAllowCamera.style.display = 'block';
  },
  accessDialogClosed: function (event) {
    // Hide allow camera message
    pleaseAllowCamera.style.display = 'none';
  }
});

また、ウェブサイトをSSLで提供するのも良いアイデアです。なぜなら、Chromeでは、SSLで提供されるドメインであれば、ユーザーがデバイスへのアクセスを許可するかどうかをクリックする必要があるのは、ドメインごとに1回だけだからです。つまり、(Chromeを使用している場合)ユーザーは、ページを読み込むたびに不便な許可/拒否ダイアログボックスに対処する必要がないのです。

OT.initPublisher()とSession.publish()を分割する。

もうひとつお勧めするのは OT.initPublisher() そして Session.publish() ステップを実行します。これは、ユーザーが許可ボタンをクリックするのを待っている間にセッションに接続するため、最初の接続時間を短縮します。ですから、代わりに

session.connect(token, function (err) {
{... your error handling code ...}
if (!err) {
    var publisher = OT.initPublisher();
    session.publish(publisher);
  }
});

を動かす。 OT.initPublisher() のように、接続する前にステップを踏む:

var publisher = OT.initPublisher();
session.connect(token, function (err) {
{... your error handling code ...}
  if (!err) {
    session.publish(publisher);
  }
});

解像度とフレームレート

パブリッシャーの解像度とフレーム・レートは、初期化時に設定できます:

OT.initPublisher(divId, {
  resolution: '320x240',
  frameRate: 15
});

デフォルトではPublisherの解像度は640x480ですが、1920x1080、1280x720、320x240に設定することもできます。解像度をビデオが表示されるサイズに合わせることをお勧めします。320x240ピクセルでしかビデオを表示しないのであれば、1280x720や1920x1080でストリーミングする意味はありません。解像度を下げることで、帯域幅を節約し、輻輳や接続の切断を減らすことができます。

デフォルトでは、ビデオのフレームレートは毎秒30フレームですが、15、7、1にも設定できます。フレームレートを下げると、必要な帯域幅を減らすことができます。解像度が低い動画は、フレームレートを低くしても、ユーザーにはそれほど違いが感じられません。そのため、低解像度を使用する場合は、低フレームレートの使用も検討するとよいでしょう。

トラブルシューティング

このセクションのヒントに従って、公開時の接続性の問題を回避してください。トラブルシューティングの一般的な情報については、「デバッグ - Web」を参照してください。

エラー処理

の両方にコールバック・メソッドがあります。 Session.publish() そして OT.initPublisher().これら両方のメソッドに対するエラー応答を処理することを推奨する。前述したように、これらのステップを分割して OT.initPublisher() セッションへの接続を開始する前にまた、これらのメソッドの両方を同時に呼び出さない方が、エラー処理が簡単になります。これは、エラーが発行されると、両方のエラーハンドラが発火するからです。を待つのが最善です。 OT.initPublisher() を完了し Session.connect() を呼び出す。 Session.publish().こうすることで、ハードウェアに関連するすべての問題を OT.initPublisher() コールバックと、ネットワークに関連するすべての問題を Session.publish() コールバック。

var connected = false,
  publisherInitialized = false;

var publisher = OT.initPublisher(function(err) {
  if (err) {
    // handle error
  } else {
    publisherInitialized = true;
    publish();
  }
});

var publish = function() {
  if (connected && publisherInitialized) {
    session.publish(publisher);
  }
};

session.connect(token, function(err) {
  if (err) {
    // handle error
  } else {
    connected = true;
    publish();
  }
});

アクセス拒否

のNumbersが最も多かった。 OT.initPublisher() は、エンドユーザーがカメラとマイクへのアクセスを拒否した結果である。これは accessDenied イベントか、OT.initPublisher() メソッドへのエラー・レスポンスを code プロパティを1500に設定し message プロパティが "Publisher Access Denied: "に設定されています。この場合、ユーザに対して、再度パブリッシュを試み、カメラへのアクセスを許可するようにメッセージを表示することをお勧めします。

publisher.on({
  'accessDenied': function() {
    showMessage('Please allow access to the Camera and Microphone and try publishing again.');
  }
});

デバイスアクセス

もうひとつの理由は OT.initPublisher() が失敗するのは、OpenTok がカメラやマイクにアクセスできない場合です。これは、カメラやマイクがマシンに接続されていない場合、カメラやマイクのドライバに問題がある場合、または他のアプリケーションがカメラやマイクを使用している場合に起こります (これは Windows でのみ起こります)。ハードウェア・セットアップ・コンポーネントまたは OT.getDevices() メソッドを直接呼び出します。しかし OT.initPublisher() というのも、まだ何か問題が起こる可能性があるからだ。例えば、ユーザーがカメラやマイクへのアクセスを拒否した可能性がある。この場合 error.name プロパティが "OT_USER_MEDIA_ACCESS_DENIED":

publisher = OT.initPublisher('publisher', {}, function (err) {
  if (err) {
    if (err.name === 'OT_USER_MEDIA_ACCESS_DENIED') {
      // Access denied can also be handled by the accessDenied event
      showMessage('Please allow access to the Camera and Microphone and try publishing again.');
    } else {
      showMessage('Failed to get access to your camera or microphone. Please check that your webcam'
        + ' is connected and not being used by another application and try again.');
    }
    publisher.destroy();
    publisher = null;
  }
});

ネットワークエラー

パブリッシングに失敗するその他の理由は、通常、何らかのネットワーク障害によるものです。へのコールバックで処理します。 Session.publish().ユーザーがネットワークに接続されていない場合、コールバック関数にエラーオブジェクトが渡されます。 name プロパティを "OT_NOT_CONNECTED".ユーザーがWebRTC接続を許可しない非常に制限されたネットワーク接続を使用している場合、Publisherは接続に失敗し、Publisher要素にクルクル回る車輪が表示されます。このエラーには name プロパティを "OT_CREATE_PEER_CONNECTION_FAILED".この場合、公開に失敗したのでネットワーク接続を確認するようにというメッセージをユーザーに表示することをお勧めします。このようなエラーの処理は次のようになります:

session.publish(publisher, function(err) {
  if (err) {
    switch (err.name) {
      case "OT_NOT_CONNECTED":
        showMessage("Publishing your video failed. You are not connected to the internet.");
        break;
      case "OT_CREATE_PEER_CONNECTION_FAILED":
        showMessage("Publishing your video failed. This could be due to a restrictive firewall.");
        break;
      default:
        showMessage("An unknown error occurred while trying to publish your video. Please try again later.");
    }
    publisher.destroy();
    publisher = null;
  }
});

接続性の喪失

パブリッシャは、接続に成功した後に接続を失うこともあります。多くの場合、セッションも接続を切断しますが、必ずしもそうなるとは限りません。をリッスンすることで、パブリッシャの切断を処理できます。 streamDestroyed イベントを reason プロパティを "networkDisconnected "に設定する:

publisher.on({
  streamDestroyed: function (event) {
    if (event.reason === 'networkDisconnected') {
      showMessage('Your publisher lost its connection. Please check your internet connection and try publishing again.');
    }
  }
});

セッション公開の再試行の実装

Video API JS SDK では、特にモバイルブラウザにおいて、一時的な公開失敗が既知の繰り返し発生する現象として確認されています。この現象は、 session.publish() 失敗した場合、SDKはコンプリートハンドラのコールバックを通じてエラーを返します。推奨されるアプローチは、試行の間に遅延を設けたアプリケーションレベルのリトライロジックを実装することです。

注: 以下の機能に対するリトライ機能の組み込みサポート session.publish() これはSDKのロードマップに含まれています。それがリリースされるまでは、ご自身で実装する必要があります。

どのように session.publish() 作品

session.publish() 呼び出し方は2通りあります:

  • あらかじめ初期化済みのパブリッシャーの場合: session.publish(publisher, callback) — 電話して OT.initPublisher() まず、その結果として得られたパブリッシャーインスタンスを session.publish(). これが 推奨されるアプローチ メディアの取得とストリームの生成を分離することで、エラー処理がより明確になります。
  • パブリッシャーインスタンスがない場合: session.publish(targetElement, options, callback) — SDKは内部で以下を呼び出します OT.initPublisher() あなたのために。この場合、メディア取得エラーとストリーム作成エラーの両方が、単一の session.publish() コールバック。

ベストプラクティス: スプリット OT.initPublisher() そして session.publish() 個別のステップに分割します。これにより、 OT.initPublisher() におけるコールバックおよびネットワーク/シグナリングエラー session.publish() コールバック — リトライ処理を大幅に簡素化し、より的確なものにします。

// Recommended: split initialization from publishing
let publisherReady = false;
let sessionConnected = false;

const publisher = OT.initPublisher('publisher-container', publisherOptions, (err) => {
  if (err) {
    handleInitPublisherError(err); // hardware/media errors — see OT.initPublisher() errors below
    return;
  }
  publisherReady = true;
  maybePublish();
});

session.connect(token, (err) => {
  if (err) { /* handle connection error */ return; }
  sessionConnected = true;
  maybePublish();
});

function maybePublish() {
  if (sessionConnected && publisherReady) {
    publishWithRetry(session, publisher);
  }
}

出版の失敗が起こる理由

一時的な公開失敗の最も一般的な根本原因は、以下の通りです:

  • StreamCreateRequest のタイムアウト(エラー 1500): パブリッシャーが妥当な時間内にストリームの作成を完了できなかった。これは通常、ICE/SDPネゴシエーション中のネットワーク遅延が原因である。
  • mediaStopped 公開フロー中のイベント、そこでメディアデバイスへのアクセスが中断される可能性があります。
  • 適切なクリーンアップを行わないままPublisherオブジェクトを再利用すること — 異なる制約で初期化されたパブリッシャーインスタンスを、呼び出さずに再利用する unpublish そして、再初期化を行います。
  • OT_NOT_CONNECTED — セッションが完全に接続される前に公開しようとしています。
  • OT_PERMISSION_DENIED — トークンには「publish」ロールが割り当てられていません(再試行不可)。

エラーの原因は OT.initPublisher()

パブリッシャーを次のように事前初期化する場合 OT.initPublisher(), すべてのハードウェアおよびメディア取得エラーは、その完了ハンドラに渡されます — 以前 session.publish() が呼び出されることがあります。このコールバック内で、以下のエラーごとの対処法に従って処理を行ってください。エラーによってはユーザーの操作やコードの修正が必要になるものもあれば、一時的なメディアエラーの場合はパブリッシャーを再初期化することで対処できる場合もあります。

注: もし電話をかけるなら session.publish() 事前に初期化されていないパブリッシャーがある場合、これらの同じエラーが session.publish() その代わりにコールバックを使用します。

error.name 説明 推奨される対応
OT_HARDWARE_UNAVAILABLE そのハードウェアは存在しますが、取得できませんでした(例:別のアプリケーションで使用中)。 ユーザーに、そのデバイスで実行中の他の Applications を閉じるよう促してから、次の関数を呼び出します。 OT.initPublisher() また。
OT_INVALID_PARAMETER に引数として渡された1つ以上のパラメータ OT.initPublisher() 無効でした。 に渡しされるオプションオブジェクトを修正する OT.initPublisher().
OT_MEDIA_ENDED について ended 初期化中にvideo要素で発生したイベント。 パブリッシャーを再初期化してください。
OT_MEDIA_ERR_ABORTED video要素のストリームの取得が中断されました。 少し時間を置いてから、パブリッシャーを再初期化してください。
OT_MEDIA_ERR_DECODE video要素でストリームを再生しようとした際に、デコードエラーが発生しました。 少し時間を置いてから、パブリッシャーを再初期化してください。
OT_MEDIA_ERR_NETWORK ネットワークエラーが発生したため、ストリームの取得が停止しました。 少し時間を置いてから、パブリッシャーを再初期化してください。
OT_MEDIA_ERR_SRC_NOT_SUPPORTED このストリームは、再生に適していないと判定されました。 パブリッシャーの映像・音声ソースの設定を確認し、再初期化してください。
OT_NOT_SUPPORTED ユーザーからのメディアリクエストに含まれる一部の要素が、このブラウザではサポートされていません。 ユーザーに通知し、再試行は行わない。
OT_NO_DEVICES_FOUND 音声または映像の入力デバイスが検出されませんでした。 再試行する前に、ユーザーにデバイスの接続を促す。
OT_NO_VALID_CONSTRAINTS 動画と音声の両方が無効になっています。少なくとも片方は有効にする必要があります。 確保する publishAudio または publishVideotrue 「パブリッシャー設定」で。
OT_PROXY_URL_ALREADY_SET_ERROR について proxyUrl すでに設定されています。再度設定しても何の効果もありません。 プロキシURLの設定は、SessionオブジェクトやPublisherオブジェクトを初期化する前に、一度だけ行ってください。
OT_REQUESTED_DEVICE_PERMISSION_DENIED 指定されたオーディオデバイスには、使用するための権限がありません。 ユーザーにデバイスの権限を許可するよう促します。
OT_USER_MEDIA_ACCESS_DENIED ユーザーは、カメラ、マイク、または画面へのアクセスを拒否しました。 ブラウザの設定でアクセスを許可するようユーザーに促す。自動的に再試行しない。
OT_SCREEN_SHARING_NOT_SUPPORTED お使いのブラウザでは、画面共有機能はサポートされていません。 ユーザーに通知し、再試行は行わない。
OT_UNABLE_TO_CAPTURE_SCREEN 画面共有の依頼がありましたが、対応していません(例: videoSource に設定する。 "screen", "application"あるいは "window"). 電話 OT.checkScreenSharingCapability() 画面共有パブリッシャーを初期化する前に。
OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED 画面共有にはブラウザ拡張機能が必要ですが、登録されているものはありません。 呼び出す前に拡張機能を登録してください OT.initPublisher().
OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED 画面共有にはブラウザ拡張機能が必要ですが、それがインストールされていません。 ユーザーに必要な拡張機能をインストールするよう案内してください。
const publisher = OT.initPublisher('publisher-container', publisherOptions, (err) => {
  if (!err) {
    publisherReady = true;
    maybePublish();
    return;
  }

  // Hardware/media errors — handle before session.publish() is called
  switch (err.name) {
    case 'OT_REQUESTED_DEVICE_PERMISSION_DENIED':
      showMessage('Please allow access to your camera and microphone and try again.');
      break;
    case 'OT_HARDWARE_UNAVAILABLE':
    case 'OT_NO_DEVICES_FOUND':
      showMessage('Could not access your camera or microphone. Please check your devices.');
      break;
    case 'OT_SCREEN_SHARING_NOT_SUPPORTED':
    case 'OT_UNABLE_TO_CAPTURE_SCREEN':
    case 'OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED':
    case 'OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED':
      showMessage('Screen sharing is not available. Please check your browser settings.');
      break;
    default:
      showMessage('Could not initialize the publisher. Please try again.');
  }

  publisher.destroy();
});

以下の原因による回復可能なエラーと回復不可能なエラー session.publish()

すべてではない session.publish() エラーはすべて同じというわけではありません。リトライロジックを実装する前に、エラーを正しく分類することが不可欠です。回復不可能なエラーに対してリトライを行うと、時間を浪費し、ユーザー体験を損なうだけでなく、別の対応を必要とする真の障害を見逃してしまう恐れがあります。

注: エラーコード 1500 分類メカニズムとしては非推奨となっています。常に error.name このプロパティは、特定の障害シナリオに対応しているため、プログラムからエラーを特定するために使用できます。

注: いつ session.publish() は、次のように呼ばれます ~なし 事前に初期化されたパブリッシャー、および OT.initPublisher() (上記に記載されたもの)は、以下の経路を通じて表面化する可能性もあります。 session.publish() コールバック。その場合は、それらを再試行不可として扱い、前述と同じ処理を適用してください。

回復不可能なエラー — 再試行しないでください

これらのエラーは、プログラマーのミス、厳しい権限の制約、または無効な呼び出しコンテキストに起因するものです。再試行しても解決しません。代わりに、ユーザーにわかりやすいメッセージを表示するか、アプリケーションのロジックを修正してください。

error.name 説明 推奨される対応
OT_NOT_CONNECTED session.publish() セッションが接続される前に呼び出されました。 確保する session.connect() 公開前に正常に完了しています。
OT_PERMISSION_DENIED このトークンの役割では公開は許可されていません(必ず publisher または moderator). ユーザーに、公開権限がないことを通知してください。再試行は行わず、正しいロールを指定してトークンを生成してください。
OT_INVALID_PARAMETER 指定されたパブリッシャーは無効であるか、すでに公開されているか、あるいは別のセッションにすでに紐付けられています。 アプリケーションロジックを修正する:呼び出し session.unpublish(publisher) 再公開する前に、または新しいパブリッシャーを初期化してください。
OT_USER_MEDIA_ACCESS_DENIED ユーザーがカメラまたはマイク(画面共有ストリームの場合は画面)へのアクセスを拒否しました。 ユーザーに、ブラウザの設定でデバイスへのアクセスを許可するよう促し、再度試みてください。自動的に再試行しないでください。
OT_CHROME_MICROPHONE_ACQUISITION_ERROR 既知のブラウザの不具合により、ブラウザがマイクへのアクセスを取得できませんでした。この問題を解決するには、エンドユーザーがブラウザを再起動し、ページを再読み込みする必要があります。 ユーザーに通知し、再試行は行わない。
OT_SCREEN_SHARING_NOT_SUPPORTED お使いのブラウザでは、画面共有機能はサポートされていません。 ユーザーに通知し、再試行は行わない。
OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED 画面共有にはブラウザ拡張機能が必要ですが、登録されているものはありません。 画面共有ストリームの公開を試みる前に、拡張機能を登録してください。
OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED 画面共有にはブラウザ拡張機能が必要ですが、それがインストールされていません。 ユーザーに必要な拡張機能をインストールするよう案内してください。
OT_CONSTRAINTS_NOT_SATISFIED 要求されたメディアの制約(解像度、フレームレート、デバイス)を、このブラウザでは満たすことができませんでした。 パブリッシャーの制約条件を調整し、再初期化してください。
OT_NO_VALID_CONSTRAINTS 動画と音声の両方が無効になっています。少なくとも片方は有効にする必要があります。 確保する publishAudio または publishVideotrue を呼び出す前に session.publish().
OT_NOT_SUPPORTED ユーザーからのメディアリクエストに含まれる一部の要素が、このブラウザではサポートされていません。 ユーザーに通知し、再試行は行わない。
OT_STREAM_CREATE_FAILED ユーザーが、暗号化キーを指定せずにエンドツーエンド暗号化(E2EE)が有効なセッションで公開を試みたか、またはサーバーモデルでストリームを作成できなかった可能性があります。 E2EEセッションについては、以下を通じて暗号化シークレットが設定されていることを確認してください。 session.setEncryptionSecret() 公開する前に。
OT_INVALID_AUDIO_OUTPUT_SOURCE 無効なオーディオ出力デバイス ID が指定されました。 再試行する前に、そのデバイスIDが有効なオーディオ出力デバイスであることをVerifyしてください。
OT_UNABLE_TO_CAPTURE_MEDIA メディアをキャプチャできませんでした — 不明なエラーが発生しました。 ユーザーに通知し、デバイスの利用可能状況を確認するよう促します。

回復可能なエラー — 再試行しても問題ありません

これらのエラーは、通常、一時的なネットワークの状態、シグナリングのタイムアウト、またはプラットフォームの一時的な利用不能によって引き起こされます。これらは、再試行ロジックの主な対象となります。

error.name 説明 推奨される対応
OT_TIMEOUT (コード 1500) session.publish() タイムアウトしました — the StreamCreateRequest 期限内に完了しなかった。最も一般的な原因は、ICE/SDPネゴシエーションの遅延、あるいは mediaStopped のイベントがある。 指数関数的なバックオフを用いて再試行する(最大3回)。パブリッシャーインスタンスが破棄されていない場合は、同じインスタンスを再利用する。
OT_ICE_WORKFLOW_FAILED ICEネゴシエーションに失敗しました — ピア接続を確立できませんでした。制限の厳しいネットワークでは、しばしば一時的な現象として発生します。 再試行してください。すべての試行を行っても問題が解決しない場合は、ネットワークまたはファイアウォールの問題の可能性があることをユーザーに伝えてください。
OT_CREATE_PEER_CONNECTION_FAILED WebRTCのピア接続を確立できませんでした。ファイアウォールの制限や、一時的なプラットフォームの問題が考えられます。 もう一度試してください。それでも問題が解決しない場合は、ユーザーにネットワーク接続を確認するよう促すメッセージを表示してください。
OT_MEDIA_ERR_ABORTED / OT_MEDIA_ERR_NETWORK ネットワークエラーにより、メディアの取得が中止または中断されました。 少し時間を置いてから、もう一度試してください。
OT_MEDIA_ERR_DECODE video要素でストリームを再生しようとした際に、デコードエラーが発生しました。 少し時間を置いてから、もう一度お試しください。それでも問題が解決しない場合は、メディアのフォーマットが互換性がない可能性があります。
OT_MEDIA_ERR_SRC_NOT_SUPPORTED このストリームは、再生に適していないと判定されました。 もう一度試してみてください。それでも問題が解決しない場合は、パブリッシャーの映像・音声ソースの設定を確認してください。
OT_SET_REMOTE_DESCRIPTION_FAILED WebRTC接続が、以下の処理中に失敗しました。 setRemoteDescription. 通常、一時的な通信の問題です。 バックオフを行いながら再試行してください。すべての試行を終えても問題が解決しない場合は、ネットワークに問題がある可能性があるとユーザーに通知してください。
OT_UNEXPECTED_SERVER_RESPONSE サーバーから予期せぬエラーが返されました。 少し時間を置いてから、もう一度試してください。それでも問題が解決しない場合は、エラーを記録し、ユーザーにその旨を伝えてください。

別の対応が必要なエラー(単純な再試行では済まないもの)

エラーの中には、単純な再試行でも完全な停止でもないものがあり、再試行を行う前に特定の是正措置を講じる必要があります。

error.name 説明 推奨される対応
OT_HARDWARE_UNAVAILABLE カメラまたはマイクが利用できません(例:別のアプリケーションで使用中、または接続が切断されています)。 ユーザーに対し、そのデバイスで実行中の他のアプリケーションを閉じるよう促し、その後、以下のコマンドでパブリッシャーを再初期化します。 OT.initPublisher() 再試行する前に。
OT_NO_DEVICES_FOUND 音声または映像の入力デバイスが検出されませんでした。 ユーザーにデバイスの接続を促します。ユーザーがデバイスが利用可能であることを確認するまで、再試行しないでください。

まとめ:エラー分類を用いた推奨リトライパターン

async function publishWithRetry(session, publisher, attempt = 1) {
  const MAX_RETRIES = 3;
  const RETRY_DELAY_MS = 2000;

  const error = await new Promise((resolve) => {
    session.publish(publisher, resolve);
  });

  if (!error) {
    console.log('Publishing started successfully.');
    return;
  }

  // Non-recoverable: programmer error or hard permission constraint
  const nonRetryable = [
    'OT_NOT_CONNECTED',
    'OT_PERMISSION_DENIED',
    'OT_INVALID_PARAMETER',
    'OT_USER_MEDIA_ACCESS_DENIED',
    'OT_CHROME_MICROPHONE_ACQUISITION_ERROR',
    'OT_SCREEN_SHARING_NOT_SUPPORTED',
    'OT_SCREEN_SHARING_EXTENSION_NOT_REGISTERED',
    'OT_SCREEN_SHARING_EXTENSION_NOT_INSTALLED',
    'OT_CONSTRAINTS_NOT_SATISFIED',
    'OT_NO_VALID_CONSTRAINTS',
    'OT_NOT_SUPPORTED',
    'OT_STREAM_CREATE_FAILED',
    'OT_INVALID_AUDIO_OUTPUT_SOURCE',
    'OT_UNABLE_TO_CAPTURE_MEDIA',
  ];

  // Requires corrective action before retrying
  const requiresAction = [
    'OT_HARDWARE_UNAVAILABLE',
    'OT_NO_DEVICES_FOUND',
  ];

  if (nonRetryable.includes(error.name)) {
    console.error('Non-retryable error — user action or code fix required:', error.name);
    handleNonRecoverableError(error);
    return;
  }

  if (requiresAction.includes(error.name)) {
    console.warn('Device error — prompting user before retrying:', error.name);
    handleDeviceError(error);
    return;
  }

  // Recoverable: retry with backoff
  if (attempt < MAX_RETRIES) {
    console.warn(`Publish attempt ${attempt} failed (${error.name}), retrying...`);
    await delay(RETRY_DELAY_MS * attempt);
    await publishWithRetry(session, publisher, attempt + 1);
  } else {
    console.error('All publish attempts failed. Disconnecting user.');
    handlePublishFailure(session);
  }
}

function handleNonRecoverableError(error) {
  // Surface a meaningful message to the user based on error.name
  // e.g. for OT_USER_MEDIA_ACCESS_DENIED: "Please allow camera/mic access"
}

function handleDeviceError(error) {
  // Prompt the user to check their device, then allow them to retry manually
}

function handlePublishFailure(session) {
  session.disconnect();
}

使用方法:

const publisher = OT.initPublisher('publisher-container', publisherOptions);

// Wait for session to be connected before publishing
session.connect(token, (err) => {
  if (err) { /* handle connection error */ return; }
  publishWithRetry(session, publisher);
});

重要:再試行前のパブリッシャーのクリーンアップ

ほとんどの障害シナリオにおいて――以下を含む OT_TIMEOUT / OT_ICE_WORKFLOW_FAILED — パブリッシャー・インスタンス 再利用可能 次の分については直接 session.publish() call。再初期化する必要はありません。

公開の試行が失敗した場合、SDK は作成しようとしていたストリームを解放し、 streamDestroyed パブリッシャーでのイベントで reason: "reset". これは想定内のクリーンアップ処理であり、 違う パブリッシャーの再初期化が必要になる場合がありますが、同じインスタンスで再試行できます。なお、 "reset" これは、「パブリッシャーのストリームが破棄された」という一般的な理由です(また、 publisher.destroy())、したがって、これを専用の公開失敗インジケーターではなく、クリーンアップのシグナルとして扱ってください。 error.name より session.publish() 再試行するかどうかを決定するためのコールバック。

このSDKは 違う 自動的に再試行する session.publish() ユーザーに代わって――上記のように、再試行ロジックはアプリケーションレベルで実装する必要があります。

以下のコマンドでパブリッシャーを再初期化しなければならないのは、次の場合のみです。 OT.initPublisher() 再試行する前に、パブリッシャー自身の destroyed イベントが発生します。このイベントは最終的なものであり、パブリッシャーオブジェクト自体が使用できなくなったことを示します。

publisher.on('destroyed', () => {
  // Publisher object is no longer usable — reinitialize before retrying
  publisher = OT.initPublisher('publisher-container', publisherOptions);
});

// A streamDestroyed event with reason 'reset' is emitted by the SDK when it tears
// down the stream (during a failed publish attempt, or when you call publisher.destroy()).
// A 'reset' during a failed publish does NOT require reinitializing the publisher.
publisher.on('streamDestroyed', (event) => {
  if (event.reason === 'reset') {
    // Expected cleanup — reuse the same publisher instance
    return;
  }
  // Handle other streamDestroyed reasons as appropriate for your application
});

やってはいけないこと

  • を行う。 違う コール OT.initPublisher() 同じパブリッシャー・オブジェクトに対して、最初にクリーンアップを行わずに異なる制約を2回適用すると(session.unpublish() → 待つ streamDestroyed → その後、再初期化します)。
  • を行う。 違う 再試行する OT_PERMISSION_DENIED (ユーザーがカメラ/マイクへのアクセスを拒否しました) — これは再試行ではなく、ユーザーによる対応が必要です。
  • を行う。 違う 再試行する OT_NOT_CONNECTED — 公開する前に、セッションが接続されていることを確認してください。
  • を行う。 違う 無制限に再試行する — 再試行回数を3回に制限し、失敗時には適切に対処する。

の取り扱いについて mediaStopped イベント

メディアトラックの再生は、公開途中で停止させることができます。このイベントを検知し、再試行のトリガーとして処理してください:

publisher.on('mediaStopped', async () => {
  console.warn('Media stopped during publish — retrying...');
  // Unpublish if already publishing, then retry
  try { session.unpublish(publisher); } catch (e) { /* ignore */ }
  await delay(2000);
  publishWithRetry(session, publisher);
});

推奨パラメータの概要

パラメータ 推奨値 備考
最大再試行回数 3 回復力とユーザーの待ち時間のバランスをとる
再試行の遅延時間 2秒 × 試行回数(2秒、4秒、6秒) プラットフォームが回復する時間を確保する
すべての再試行で失敗する ユーザーの接続を切断する 「ゴースト参加者」の状態を回避する
再試行不可能なエラー OT_NOT_CONNECTED, OT_PERMISSION_DENIED これらについては、早めに失敗しよう

音声キャプチャに関する問題の対処法: audioAcquisitionProblem そして audioAcquisitionProblemResolved

パブリッシュレベルでの再試行とは別に、アクティブなパブリッシャーに影響を及ぼす可能性のある別の種類のオーディオの問題があります。それは、パブリッシュが成功した後でも、クライアントのオーディオデバイスがオーディオデータを配信できない場合です。Video API JS SDK では、このシナリオに特化した 2 つのイベントが提供されています。

よくある原因

について audioAcquisitionProblem SDKがパブリッシャーの統計情報を通じて、オーディオトラックがピア接続へのバイト送信を停止したことを検出した際に、このイベントがトリガーされます。たとえ getUserMedia 成功し、パブリッシャーはアクティブな状態のようです。最も一般的な根本原因は以下の通りです:

  • セッションの途中でBluetoothオーディオデバイスが接続または切断された場合: セッションがアクティブな状態で、ユーザーがイヤホンを接続または取り外したり、Bluetoothヘッドホン(AirPodsなど)を接続したりすると、OSによってデフォルトのオーディオデバイスが切り替わる場合があります。その結果、ブラウザのオーディオパイプラインが新しいデバイス上のマイクを再取得できなくなり、送信されるオーディオバイト数がゼロになってしまうことがあります。
  • セッション開始時のオーディオデバイスの変更: セッションの非常に早い段階――公開後1~2秒以内――でオーディオ入力を切り替えると、この問題が発生しやすくなります。
  • ブラウザまたはOSによってオーディオトラックが終了しました(trackEndedEvent): ブラウザは、ユーザーの操作とは無関係に、基盤となるオーディオトラックを終了させることができます。SDKは、これを track.ended イベントおよびレイズ audioAcquisitionProblemmethod: trackEndedEvent.
  • 統計に基づく検出(音声バイトの流通なし): ピア間の接続が「接続済み」状態になると、SDKは約数秒ごとにパブリッシャーのステータスをポーリングします。オーディオトラックの送信 bytesSent 連続する世論調査の間で増加しない、 audioAcquisitionProblem が設定される( method: getStats). いつ bytesSent 再び増加し始め、 audioAcquisitionProblemResolved が提起される。

注: この事象が必ずしも致命的な障害を示すわけではありません。セッションによっては、音声が自然に回復することもあります(そして audioAcquisitionProblemResolved が呼び出される);一方、他のケースでは、オーディオストリームが回復せず、下流のサブスクライバーは最終的にタイムアウトとなる可能性があります。

イベント

これらのイベントは、パブリッシャーインスタンスで発生します:

  • audioAcquisitionProblem — SDKが(パブリッシャーの統計情報に基づき)パブリッシャーによる音声送信が停止したことを検出したとき、または基になるオーディオトラックが ended イベント。これは必ずしもストリームが失敗することを意味するわけではありませんが、オーディオのキャプチャが中断されたことを示す指標となります。
  • audioAcquisitionProblemResolved — 以前の…の後、音声伝送が回復した際に発火する audioAcquisitionProblem. このイベントが発生しても、是正措置は必要ありません。

注: これらのイベントは現在、 文書化済み/型指定済みの公開APIの一部ではない (これらはSDKのTypeScript定義には宣言されていません)。これらはバージョンごとに変更される可能性のある「可能な限り提供される」シグナルとして扱い、本番環境でこれらに依存する前に、お使いのSDKのバージョンで利用可能かどうかを確認してください。パブリッシャーで発行される際、これらには method 問題がどのように検出されたかを示すプロパティ('getStats' または 'trackEndedEvent').

注: オーディオ取得のチェックはパブリッシャーの統計情報に基づいているため、実際のオーディオ中断とイベントが発生するまでの間に、わずかな遅延が生じる場合があります。

推奨されるリカバリパターン

受信時にショートタイマーを開始する audioAcquisitionProblem.もし audioAcquisitionProblemResolved タイマーが切れる前に問題が解消された場合、音声は自動的に復旧しているため、何も操作する必要はありません。タイマーが切れても問題が解決しない場合は、復旧措置として音声ソースを切り替えてください。

publisher.on('audioAcquisitionProblem', () => {
  // Start a 3-second timer
  const timeout = setTimeout(() => {
    // Problem not resolved — attempt recovery by switching audio source
    publisher.setAudioSource(newDeviceId);
  }, 3000);

  publisher.on('audioAcquisitionProblemResolved', () => {
    // Audio recovered — clear the timer, no action needed
    clearTimeout(timeout);
  });
});

主な検討事項

  • 必ずしも失敗の兆候とは限らない: audioAcquisitionProblem 必ずしもサブスクリプションの失敗につながるわけではありません。これを決定的な失敗事象としてではなく、監視や必要に応じた対応を行うための早期の兆候として活用してください。
  • パブリッシャーのオーディオ統計情報を監視する: 受け取った後 audioAcquisitionProblem、また、パブリッシャーのオーディオ統計情報を監視することもできます(例: publisher.getStats()) 措置を講じる前に、音声の送信が本当に停止したかどうかを確認してください。
  • 復旧措置: 呼び出し publisher.setAudioSource(newDeviceId) これが主要な復旧メカニズムです。これにより、公開の解除と再公開という完全なサイクルを経ることなく、オーディオ入力デバイスを切り替えることができます。
  • サブスクリプションのタイムアウトとの関係: 音声が復旧せず、配信元が引き続き音声パケットを送信しない場合、加入者は最終的に OT_TIMEOUT (1501). 積極的な対応 audioAcquisitionProblem これにより、下流での不具合を防ぐことができます。