

# IVS Broadcast SDK: Web ガイド \$1 リアルタイムストリーミング
<a name="broadcast-web"></a>

IVS Real-Time Streaming Web Broadcast SDK は、デベロッパー向けに、Web 上でインタラクティブかつリアルタイムの体験を構築するためのツールを提供します。この SDK は、Amazon IVS を使用してウェブアプリケーションを構築するデベロッパー向けです。

Web Broadcast SDK を使用して、参加者はビデオを送受信できます。SDK は、次の操作をサポートします。
+ ステージに参加する
+ ステージ内の他の参加者にメディアを配信する
+ ステージ内の他の参加者のメディアをサブスクライブする
+ ステージに配信されたビデオとオーディオを管理および監視する
+ 各ピア接続の WebRTC 統計を取得
+ IVS 低遅延ストリーミング Web Broadcast SDK からのすべての操作

**Web Broadcast SDK の最新バージョン:** 1.33.0 ([リリースノート](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#mar12-26-broadcast-web-rt)) 

**リファレンスドキュメント:** Amazon IVS Web Broadcast SDK で利用できる最も重要なメソッドについては、[https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference) を参照してください。SDK の最新バージョンが選択されていることを確認してください。

**サンプルコード**: SDK をすぐに使い始めるには、以下のサンプルの利用が適しています。
+ [簡易再生](https://codepen.io/amazon-ivs/pen/RNwVBRK)
+ [簡易配信とサブスクライブ](https://codepen.io/amazon-ivs/pen/ZEqgrpo)
+ [包括的な React リアルタイムコラボレーションデモ](https://github.com/aws-samples/amazon-ivs-real-time-collaboration-web-demo/tree/main)

**プラットフォーム要件**: サポートされているプラットフォームのリストについては、「[Amazon IVS Broadcast SDK](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html)」を参照してください。

**注:** ブラウザからの公開は、追加のソフトウェアのインストールを必要としないため、エンドユーザーにとって便利です。ただし、ブラウザベースの公開は、ブラウザ環境の制約と変動の影響を受けます。安定性を優先する必要がある場合 (イベントストリーミングなど）、通常はシステムリソースに直接アクセスでき、ブラウザの制限を回避できる、ブラウザ以外のソース (OBS Studioやその他の専用エンコーダーなど) から公開することをお勧めします。ブラウザ以外の公開オプションの詳細については、「[ストリームの取り込み](rt-stream-ingest.md)」ドキュメントを参照してください。

# IVS Web Broadcast SDK の開始方法 \$1 Real-Time Streaming
<a name="broadcast-web-getting-started"></a>

このドキュメントでは、IVS Real-Time Streaming Web Broadcast SDK の使用を開始するためのステップについて説明します。

## インポート
<a name="broadcast-web-getting-started-imports"></a>

リアルタイムのビルディングブロックは、ルートブロードキャストモジュールとは別の名前空間に配置されています。

### スクリプトタグを使用する
<a name="broadcast-web-getting-started-imports-script"></a>

Web Broadcast SDK は JavaScript ライブラリとして分散されており、[https://web-broadcast.live-video.net/1.33.0/amazon-ivs-web-broadcast.js](https://web-broadcast.live-video.net/1.33.0/amazon-ivs-web-broadcast.js) で入手できます。

以下の例で定義されているクラスおよび列挙型はグローバルオブジェクト `IVSBroadcastClient` にあります。

```
const { Stage, SubscribeType } = IVSBroadcastClient;
```

### npmを使う
<a name="broadcast-web-getting-started-imports-npm"></a>

`npm` パッケージをインストールするには: 

```
npm install amazon-ivs-web-broadcast
```

クラス、列挙型、型はパッケージモジュールからインポートすることもできます。

```
import { Stage, SubscribeType, LocalStageStream } from 'amazon-ivs-web-broadcast'
```

### サーバーサイドレンダリングのサポート
<a name="broadcast-web-getting-started-imports-server-side-rendering"></a>

Web Broadcast SDK ステージライブラリは、ロード時にライブラリの機能に必要なブラウザプリミティブを参照するため、サーバー側のコンテキストにロードできません。これを回避するには、「[Next と React を使用した Web Broadcast デモ](https://github.com/aws-samples/amazon-ivs-broadcast-web-demo/blob/main/hooks/useBroadcastSDK.js#L26-L31)」で示されているように、ライブラリを動的にロードします。

## 必要なアクセス許可
<a name="broadcast-web-request-permissions"></a>

アプリケーションは、ユーザーのカメラとマイクへのアクセス許可をリクエストする必要があります。また、HTTPS で提供される必要があります。(これは Amazon IVS に特有ではなく、カメラやマイクにアクセスが必要なすべてのウェブサイトに必要です。)

オーディオおよびビデオデバイス両方のアクセス許可をリクエストし、キャプチャする方法を示す関数の例を次に示します。

```
async function handlePermissions() {
   let permissions = {
       audio: false,
       video: false,
   };
   try {
       const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
       for (const track of stream.getTracks()) {
           track.stop();
       }
       permissions = { video: true, audio: true };
   } catch (err) {
       permissions = { video: false, audio: false };
       console.error(err.message);
   }
   // If we still don't have permissions after requesting them display the error message
   if (!permissions.video) {
       console.error('Failed to get video permissions.');
   } else if (!permissions.audio) {
       console.error('Failed to get audio permissions.');
   }
}
```

詳細については、「[[Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)」および「MediaDevices.getUserMedia()](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)」を参照してください。

## 利用可能なデバイスのリストを表示する
<a name="broadcast-web-request-list-devices"></a>

キャプチャ可能なデバイスを確認するには、ブラウザの [MediaDevices.enumerateDevices()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) メソッドにクエリを実行します。

```
const devices = await navigator.mediaDevices.enumerateDevices();
window.videoDevices = devices.filter((d) => d.kind === 'videoinput');
window.audioDevices = devices.filter((d) => d.kind === 'audioinput');
```

## デバイスから MediaStream を取得する
<a name="broadcast-web-retrieve-mediastream"></a>

使用可能なデバイスのリストを獲得すると、任意の数のデバイスからストリームを取得できます。例えば、カメラからストリームを取得する `getUserMedia()` メソッドを利用できます。

ストリームをキャプチャするデバイスを指定する場合は、メディア制約の `audio` または `video` セクションで `deviceId` を明示的に設定できます。または、`deviceId` を省略して、ブラウザのプロンプトからユーザーにデバイスを選択させることもできます。

`width` および `height` の制約を使用して、理想的なカメラの解像度を指定することもできます。(これらの制約について詳しくは、[こちら](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#properties_of_video_tracks)をご覧ください。) SDK では、ブロードキャストの最大解像度に対応する幅および高さの制約が自動的に適用されます。しかし、ソースを SDK に追加した後ソースのアスペクト比が変更されないよう、これらもお客様ご自身で適用することをお勧めします。

リアルタイムストリーミングでは、メディアが 720p 解像度に制限されていることを確認します。具体的には、幅と高さの `getUserMedia` と `getDisplayMedia` の制約値は、乗算時に 921600 (1280 x 720) を超えることはできません。

```
const videoConfiguration = {
  maxWidth: 1280,
  maxHeight: 720,
  maxFramerate: 30,
}

window.cameraStream = await navigator.mediaDevices.getUserMedia({
   video: {
       deviceId: window.videoDevices[0].deviceId,
       width: {
           ideal: videoConfiguration.maxWidth,
       },
       height: {
           ideal:videoConfiguration.maxHeight,
       },
   },
});
window.microphoneStream = await navigator.mediaDevices.getUserMedia({
   audio: { deviceId: window.audioDevices[0].deviceId },
});
```

# IVS Web Broadcast SDK での配信とサブスクライブ \$1 Real-Time Streaming
<a name="web-publish-subscribe"></a>

このドキュメントでは、IVS Real-Time Streaming Web Broadcast SDK を使用してステージに配信とサブスクライブを行うためのステップについて説明します。

## 概念
<a name="web-publish-subscribe-concepts"></a>

リアルタイム機能の根底には、[ステージ](#web-publish-subscribe-concepts-stage)、[ストラテジー](#web-publish-subscribe-concepts-strategy)、[イベント](#web-publish-subscribe-concepts-events)という 3 つのコアコンセプトがあります。設計目標は、実際に動作する製品を構築するのに必要となるクライアント側ロジックの量を最小限に抑えることです。

### ステージ
<a name="web-publish-subscribe-concepts-stage"></a>

`Stage` クラスは、ホストアプリケーションと SDK 間の主要な相互作用のポイントです。これはステージそのものを表し、ステージへの参加とステージからの退出に使用されます。ステージの作成と参加には、コントロールプレーンからの有効で有効期限内のトークン文字列 (`token` として表示) が必要です。ステージへの参加と退出は簡単です。

```
const stage = new Stage(token, strategy)

try {
   await stage.join();
} catch (error) {
   // handle join exception
}

stage.leave();
```

### 方針
<a name="web-publish-subscribe-concepts-strategy"></a>

`StageStrategy` インターフェースは、ホストアプリケーションがステージの望ましい状態を SDK に伝える方法を提供します。`shouldSubscribeToParticipant`、`shouldPublishParticipant`、`stageStreamsToPublish` の 3 つの関数を実装する必要があります。以下で、すべて説明します。

定義済みのストラテジーを使用するには、それを `Stage` コンストラクターに渡します。以下は、参加者の Web カメラをステージに配信し、すべての参加者にサブスクライブするというストラテジーを使用したアプリケーションの完全な例です。必要な各ストラテジー機能の目的は、以下のセクションで説明します。

```
const devices = await navigator.mediaDevices.getUserMedia({ 
   audio: true,
   video: {
        width: { max: 1280 },
        height: { max: 720 },
    } 
});
const myAudioTrack = new LocalStageStream(devices.getAudioTracks()[0]);
const myVideoTrack = new LocalStageStream(devices.getVideoTracks()[0]);

// Define the stage strategy, implementing required functions
const strategy = {
   audioTrack: myAudioTrack,
   videoTrack: myVideoTrack,

   // optional
   updateTracks(newAudioTrack, newVideoTrack) {
      this.audioTrack = newAudioTrack;
      this.videoTrack = newVideoTrack;
   },

   // required
   stageStreamsToPublish() {
      return [this.audioTrack, this.videoTrack];
   },

   // required
   shouldPublishParticipant(participant) {
      return true;
   },

   // required
   shouldSubscribeToParticipant(participant) {
      return SubscribeType.AUDIO_VIDEO;
   }
};

// Initialize the stage and start publishing
const stage = new Stage(token, strategy);
await stage.join();


// To update later (e.g. in an onClick event handler)
strategy.updateTracks(myNewAudioTrack, myNewVideoTrack);
stage.refreshStrategy();
```

#### 参加者へのサブスクライブ
<a name="web-publish-subscribe-concepts-strategy-participants"></a>

```
shouldSubscribeToParticipant(participant: StageParticipantInfo): SubscribeType
```

リモート参加者がステージに参加すると、SDK はその参加者に対して希望するサブスクリプションの状態についてホストアプリケーションに問い合わせます。使用できるオプションは `NONE`、`AUDIO_ONLY`、および `AUDIO_VIDEO` です。この関数の値を返す場合、ホストアプリケーションは配信の状態、現在のサブスクリプションの状態、またはステージ接続の状態を考慮する必要はありません。`AUDIO_VIDEO` が返された場合、SDK はリモート参加者が配信するまで待ってからサブスクライブし、プロセス全体でイベントを作成してホストアプリケーションを更新します。

次に示すのは実装の例です。

```
const strategy = {
   
   shouldSubscribeToParticipant: (participant) => {
      return SubscribeType.AUDIO_VIDEO;
   }

   // ... other strategy functions
}
```

これは、ビデオチャットアプリケーションなど、すべての参加者が互いに常に可視化されているホストアプリケーション向けのの完全な実装です。

より高度な実装も可能です。例えば、CreateParticipantToken でトークンを作成するときに、アプリケーションが `role` 属性を提供しているとします。アプリケーションは、`StageParticipantInfo` の `attributes` プロパティを使用して、サーバーが提供する属性に基づいて、参加者に対して選択的にサブスクライブできます。

```
const strategy = {
   
   shouldSubscribeToParticipant(participant) {
      switch (participant.attributes.role) {
         case 'moderator':
            return SubscribeType.NONE;
         case 'guest':
            return SubscribeType.AUDIO_VIDEO;
         default:
            return SubscribeType.NONE;
      }
   }
   // . . . other strategies properties
}
```

これを使用すると、モデレーターは、自身は視聴の対象とならずに、すべてのゲストを監視できるステージを作ることができます。ホストアプリケーションでは、追加のビジネスロジックを使用して、モデレータがお互いを見えるようにしても、ゲストには見えないようにすることができます。

#### 参加者へのサブスクライブの設定
<a name="web-publish-subscribe-concepts-strategy-participants-config"></a>

```
subscribeConfiguration(participant: StageParticipantInfo): SubscribeConfiguration
```

リモート参加者がサブスクライブしている場合 (「[参加者へのサブスクライブ](#web-publish-subscribe-concepts-strategy-participants)」を参照)、SDK はホストアプリケーションにその参加者のカスタムサブスクライブ設定についてクエリします。この設定はオプションであり、ホストアプリケーションがサブスクライバーの動作の特定の側面を制御できるようにします。設定できる内容の詳細については、SDK リファレンスドキュメントの「[SubscribeConfiguration](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/SubscribeConfiguration)」を参照してください。

次に示すのは実装の例です。

```
const strategy = {
   
   subscribeConfiguration: (participant) => {
      return {
         jitterBuffer: {
            minDelay: JitterBufferMinDelay.MEDIUM
         }  
      }

   // ... other strategy functions
}
```

この実装では、サブスクライブしたすべての参加者のジッターバッファ最小遅延を `MEDIUM` のプリセットに更新します。

`shouldSubscribeToParticipant` を使用した、より高度な実装も可能です。指定された `ParticipantInfo` を使用して、特定の参加者のサブスクライブ設定を選択的に更新できます。

デフォルトの動作を使用することをお勧めします。カスタム設定は、特定の動作を変更したい場合にのみ指定します。

#### 配信
<a name="web-publish-subscribe-concepts-strategy-publishing"></a>

```
shouldPublishParticipant(participant: StageParticipantInfo): boolean
```

ステージに接続すると、SDK はホストアプリケーションにクエリを実行し、特定の参加者を配信とすべきかどうかを確認します。これは、提供されたトークンに基づいて配信する権限を持つローカル参加者においてのみ呼び出されます。

次に示すのは実装の例です。

```
const strategy = {
   
   shouldPublishParticipant: (participant) => {
      return true;
   }

   // . . . other strategies properties
}
```

これは、ユーザーは常に配信状態としたい標準的なビデオチャットアプリケーション用です。オーディオとビデオをミュートまたはミュート解除して、すぐに不可視または可視にできます。(配信/配信停止も使用できますが、この方法では大幅に遅くなります。可視性を頻繁に変更したいユースケースには、ミュート/ミュート解除が適しています。)

#### 配信するストリームの選択
<a name="web-publish-subscribe-concepts-strategy-streams"></a>

```
stageStreamsToPublish(): LocalStageStream[];
```

配信時には、これを使用して配信するオーディオストリームとビデオストリームが決定されます。これについては、後ほど「[メディアストリームの配信](#web-publish-subscribe-publish-stream)」で詳しく説明します。

#### ストラテジーの更新
<a name="web-publish-subscribe-concepts-strategy-updates"></a>

このストラテジーは動的であることを意図しており、上記の関数のいずれかから返される値はいつでも変更できます。たとえば、エンドユーザーがボタンをタップするまでホストアプリケーションが配信したくない場合、`shouldPublishParticipant` (`hasUserTappedPublishButton` など) から変数を返すことができます。その変数がエンドユーザーの相互作用に基づいて変更されたら、`stage.refreshStrategy()` を呼び出して、変更されたもののみを適用して、最新の値のストラテジーを照会する必要があることを SDK に通知します。SDK は、`shouldPublishParticipant` 値が変更されたことを確認すると、配信プロセスを開始します。SDK クエリとすべての関数が以前と同じ値を返す場合、`refreshStrategy` 呼び出しによってステージが変更されることはありません。

`shouldSubscribeToParticipant` の戻り値が `AUDIO_VIDEO` から `AUDIO_ONLY` に変更され、以前にビデオストリームが存在していた場合は、戻り値が変更されたすべての参加者のビデオストリームが削除されます。

通常、ホストアプリケーションは、適切に管理するために必要なすべての状態について考慮する必要はありません。ステージは以前のストラテジーと現在のストラテジーの違いを最も効率的に適用するストラテジーを使用します。このため、`stage.refreshStrategy()` の呼び出しはストラテジーが変わらない限り何もしないため、低コストなオペレーションとみなすことができます。

### Events
<a name="web-publish-subscribe-concepts-events"></a>

`Stage` インスタンスはイベントエミッターです。`stage.on()` を使用して、ステージの状態がホストアプリケーションに伝達されます。ホストアプリケーションの UI の更新は、通常、イベントによって完全にサポートされます。イベントは次のとおりです。

```
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participant, state) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participant, state) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {})
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED, (participant, streams) => {})
stage.on(StageEvents.STAGE_STREAM_ADAPTION_CHANGED, (participant, stream, isAdapting) => ())
stage.on(StageEvents.STAGE_STREAM_LAYERS_CHANGED, (participant, stream, layers) => ())
stage.on(StageEvents.STAGE_STREAM_LAYER_SELECTED, (participant, stream, layer, reason) => ())
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {})
stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, stream) => {})
```

これらのイベントのほとんどには、対応する `ParticipantInfo` が用意されています。

イベントによって提供される情報がストラテジーの戻り値に影響することは想定されていません。たとえば、`shouldSubscribeToParticipant` の戻り値は、`STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED` が呼び出されても変化しない想定です。ホストアプリケーションが特定の参加者をサブスクライブする場合は、その参加者の配信状態に関係なく、目的のサブスクリプションタイプを返す必要があります。SDK は、ステージの状態に基づいて、望ましいストラテジーの状態が適切なタイミングで実行されるようにする役目を担います。

## メディアストリームを配信する
<a name="web-publish-subscribe-publish-stream"></a>

マイクやカメラなどのローカルデバイスは、上記の「[デバイスからの MediaStream の取得](broadcast-web-getting-started.md#broadcast-web-retrieve-mediastream)」で説明したのと同じ手順で取得されます。この例では、`MediaStream` を使用して SDK による配信に使用される `LocalStageStream` オブジェクトのリストを作成しています。

```
try {
    // Get stream using steps outlined in document above
    const stream = await getMediaStreamFromDevice();

    let streamsToPublish = stream.getTracks().map(track => {
        new LocalStageStream(track)
    });

    // Create stage with strategy, or update existing strategy
    const strategy = {
        stageStreamsToPublish: () => streamsToPublish
    }
}
```

## スクリーン共有を配信する
<a name="web-publish-subscribe-publish-screenshare"></a>

アプリケーションでは、多くの場合、ユーザーの Web カメラに加えてスクリーン共有を配信する必要があります。スクリーン共有を配信するには、特にスクリーン共有のメディアを公開するためには、ステージ用の追加のトークンを作成する必要があります。`getDisplayMedia` を使用し、解像度を最大 720p に制限します。その後、ステップはカメラをステージに配信するのと似ています。

```
// Invoke the following lines to get the screenshare's tracks
const media = await navigator.mediaDevices.getDisplayMedia({
   video: {
      width: {
         max: 1280,
      },
      height: {
         max: 720,
      }
   }
});
const screenshare = { videoStream: new LocalStageStream(media.getVideoTracks()[0]) };
const screenshareStrategy = {
   stageStreamsToPublish: () => {
      return [screenshare.videoStream];
   },
   shouldPublishParticipant: (participant) => {
      return true;
   },
   shouldSubscribeToParticipant: (participant) => {
      return SubscribeType.AUDIO_VIDEO;
   }
}
const screenshareStage = new Stage(screenshareToken, screenshareStrategy);
await screenshareStage.join();
```

## 参加者を表示、削除する
<a name="web-publish-subscribe-participants"></a>

サブスクライブが完了すると、`STAGE_PARTICIPANT_STREAMS_ADDED` イベントを通じて `StageStream` オブジェクトの配列を受け取ります。このイベントでは、メディアストリームを表示する際に役立つ参加者情報も提供します。

```
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {
    let streamsToDisplay = streams;

    if (participant.isLocal) {
        // Ensure to exclude local audio streams, otherwise echo will occur
        streamsToDisplay = streams.filter(stream => stream.streamType === StreamType.VIDEO)
    }

    // Create or find video element already available in your application
    const videoEl = getParticipantVideoElement(participant.id);

    // Attach the participants streams
    videoEl.srcObject = new MediaStream();
    streamsToDisplay.forEach(stream => videoEl.srcObject.addTrack(stream.mediaStreamTrack));
})
```

参加者がストリームの配信を停止したり、配信登録を解除したりすると、削除されたストリームを使用して `STAGE_PARTICIPANT_STREAMS_REMOVED` 関数が呼び出されます。ホストアプリケーションは、これをシグナルとして使用して、参加者のビデオストリームを DOM から削除する必要があります。

`STAGE_PARTICIPANT_STREAMS_REMOVED` は、以下を含む、ストリームが削除される可能性のあるすべてのシナリオで呼び出されます。
+ リモート参加者は配信を停止します。
+ ローカルデバイスがサブスクリプションを解除するか、サブスクリプションを `AUDIO_VIDEO` から `AUDIO_ONLY` に変更します。
+ リモート参加者がステージを退出します。
+ ローカルの参加者がステージを退出します。

`STAGE_PARTICIPANT_STREAMS_REMOVED` はすべてのシナリオで呼び出されるため、リモートまたはローカルの離脱操作中、 UI から参加者を削除するためのカスタムのビジネスロジックは必要ありません。

## メディアストリームをミュート、ミュート解除する
<a name="web-publish-subscribe-mute-streams"></a>

`LocalStageStream` オブジェクトには、ストリームをミュートするかどうかを制御する `setMuted` 関数があります。この関数は、`stageStreamsToPublish` ストラテジー関数から返される前または後にストリームで呼び出すことができます。

**重要**: `refreshStrategy` を呼び出した後に新しい `LocalStageStream` オブジェクトインスタンスが `stageStreamsToPublish` によって返された場合、新しいストリームオブジェクトのミュート状態がステージに適用されます。新しい `LocalStageStream` インスタンスを作成するときは、想定どおりのミュート状態を維持するように注意してください。

## リモート参加者のメディアミュート状態の監視
<a name="web-publish-subscribe-mute-state"></a>

参加者がビデオまたはオーディオのミュート状態を変更すると、変更されたストリームのリストで `STAGE_STREAM_MUTE_CHANGED` イベントがトリガーされます。`StageStream` の `isMuted` プロパティを使用して、次の UI を適宜更新してください。

```
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {
   if (stream.streamType === 'video' && stream.isMuted) {
       // handle UI changes for video track getting muted
   }
})
```

また、[StageParticipantInfo](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference#stageparticipantinfo) でオーディオまたはビデオがミュートされているかどうか関する状態情報を参照することもできます。

```
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {
   if (participant.videoStopped || participant.audioMuted) {
       // handle UI changes for either video or audio
   }
})
```

## WebRTC 統計を取得する
<a name="web-publish-subscribe-webrtc-stats"></a>

`requestQualityStats()` メソッドは、ローカルストリームとリモートストリームの両方に関する詳細な WebRTC 統計情報へのアクセスを提供します。これは LocalStageStream および RemoteStageStream オブジェクトの両方で使用できます。ネットワーク品質、パケット統計、ビットレート情報、フレーム関連のメトリクスなどの包括的な品質メトリクスを返します。

これは、await または promise の連鎖によって統計を取得できる非同期メソッドです。ストリームがアクティブでない場合 (内部統計が利用できない、または統計が利用できない場合) は `undefined` が返されます。統計情報が利用可能な場合、ストリーム (リモートまたはローカル、ビデオまたはオーディオ) に応じて、メソッドは [LocalVideoStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/LocalVideoStats)、[LocalAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/LocalAudioStats)、[RemoteVideoStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteVideoStats)、または [RemoteAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteAudioStats) オブジェクトを返します。

サイマルキャストを含むビデオストリームの場合、配列には複数の統計オブジェクト (レイヤーごとに 1 つ) が含まれていることに留意してください。

**ベストプラクティス**
+ ポーリング頻度 — パフォーマンスへの影響を避けるため、妥当な間隔 (1～5 秒) で `requestQualityStats()` を呼び出します
+ エラー処理 — 処理する前に、返された値が `undefined` であるかどうかを必ず確認してください
+ メモリ管理 — ストリームが不要になったときに間隔/タイムアウトをクリアします
+ ネットワーク品質 — ネットワークによる劣化の可能性に関するユーザーフィードバックには `networkQuality` を使用します 詳細については、「[NetworkQuality](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/enumerations/NetworkQuality)」を参照してください。

**使用例**

```
// For local streams
const localStats = await localVideoStream.requestQualityStats();
const audioStats = await localAudioStream.requestQualityStats();

// For remote streams
const remoteVideoStats = await remoteVideoStream.requestQualityStats();
const remoteAudioStats = await remoteAudioStream.requestQualityStats();

// Example: Monitor stats every 10 seconds
const statsInterval = setInterval(async () => {
   const stats = await localVideoStream.requestQualityStats();
   if (stats) {
      // Note: If simulcast is enabled, you may receive multiple 
      // stats records for each layer
      stats.forEach(layer => {
         const rid = layer.rid || 'default';
         console.log(`Layer ${rid}:`, {
            active: layer.active,
            networkQuality: layer.networkQuality,
            packetsSent: layer.packetsSent,
            bytesSent: layer.bytesSent,
            resolution: `${layer.frameWidth}x${layer.frameHeight}`,
            fps: layer.framesPerSecond
         });
      });
   }
}, 10000);
```

## メディアの最適化
<a name="web-publish-subscribe-optimizing-media"></a>

最高のパフォーマンスを得るには、`getUserMedia` および `getDisplayMedia` を制限して呼び出すことをお勧めします。

```
const CONSTRAINTS = {
    video: {
        width: { ideal: 1280 }, // Note: flip width and height values if portrait is desired
        height: { ideal: 720 },
        framerate: { ideal: 30 },
    },
};
```

次の `LocalStageStream` コンストラクターに渡される追加オプションを使用して、メディアをさらに制限できます。

```
const localStreamOptions = {
    minBitrate?: number;
    maxBitrate?: number;
    maxFramerate?: number;
    simulcast: {
        enabled: boolean
    }
}
const localStream = new LocalStageStream(track, localStreamOptions)
```

上記のコードについて
+ `minBitrate` はブラウザが使用することが予想される最小ビットレートを設定します。ただし、ビデオストリームの複雑度が低いと、エンコーダがこのビットレートよりも低くなる可能性があります。
+ `maxBitrate` はこのストリームでブラウザが超えないと予想される最大ビットレートを設定します。
+ `maxFramerate` はこのストリームでブラウザが超えないと予想される最大フレームレートを設定します。
+ `simulcast` オプションは Chromium ベースのブラウザでのみ使用できます。これにより、ストリームの 3 つのレンディションレイヤーを送信できます。
  + これにより、サーバーは、ネットワークの制限に基づいて、他の参加者に送信するレンディションを選択できます。
  + `simulcast` が `maxBitrate` および/または `maxFramerate` の値とともに指定された場合、`maxBitrate` が内部 SDK の 2 番目に高レイヤーのデフォルト `maxBitrate` 値である 900 kbps を下回らない限り、これらの値を念頭に置いて最上位のレンディションレイヤーが設定されることが想定されています。
  + `maxBitrate` が 2 番目に高いレイヤーのデフォルト値と比較して低すぎるように指定された場合は、`simulcast` は無効になります。
  + `simulcast` のオンとオフを切り替えるには、`shouldPublishParticipant` が `false` を返し、`refreshStrategy` を呼び出し、`shouldPublishParticipant` が `true` を返し、`refreshStrategy` をもう一度呼ぶ組み合わせにより、メディアを再配信する必要があります。

## 参加者属性を取得
<a name="web-publish-subscribe-participant-attributes"></a>

`CreateParticipantToken` オペレーションリクエストで属性を指定した場合、`StageParticipantInfo` プロパティに属性が表示されます。

```
stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {
   console.log(`Participant ${participant.id} info:`, participant.attributes);
})
```

## 補足拡張情報 (SEI)
<a name="web-publish-subscribe-sei-attributes"></a>

補足拡張情報 (SEI) NAL ユニットは、フレーム整列メタデータを動画と一緒に保存するために使用されます。H.264 ビデオストリームに配信およびサブスクライブするときに使用できます。SEI ペイロードがサブスクライバーに届くという保証はありません (特にネットワーク状況が悪い場合)。SEI ペイロードは H.264 フレーム構造内にデータを直接保存するため、この機能はオーディオのみのストリームでは利用できません。

### SEI ペイロードの挿入
<a name="sei-attributes-inserting-sei-payloads"></a>

配信元クライアントは、`inBandMessaging` を有効化するようにビデオの LocalStageStream を設定し、その後に `insertSeiMessage` メソッド呼び出すことで、配信されているステージストリームに SEI ペイロードを挿入できます。`inBandMessaging` を有効にすると、SDK のメモリ使用量が増加することに注意してください。

ペイロードは [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) タイプである必要があります。ペイロードサイズは 0 KB より大きく 1 KB 未満のサイズにする必要があります。挿入される SEI メッセージの 1 秒あたりの数が 10 KB/秒を超えない必要があります。

```
const config = {
    inBandMessaging: { enabled: true }
};
const vidStream = new LocalStageStream(videoTrack, config);
const payload = new TextEncoder().encode('hello world').buffer;
vidStream.insertSeiMessage(payload);
```

#### SEI ペイロードの反復
<a name="sei-attributes-repeating-sei-payloads"></a>

オプションで `repeatCount` を指定して、送信される次の N 個のフレームで SEI ペイロードの挿入を反復します。これは、ビデオの送信に使用される下層 UDP トランスポートプロトコルが原因で発生する可能性のある特有の損失を軽減するために役立つ場合があります。この値は 0～30 の値にする必要があることに注意してください。受信クライアントには、メッセージを重複除外するロジックが必要です。

```
vidStream.insertSeiMessage(payload, { repeatCount: 5 }); // Optional config, repeatCount must be between 0 and 30
```

### SEI ペイロードの読み取り
<a name="sei-attributes-reading-sei-payloads"></a>

サブスクライブするクライアントは、次の例に示すように、サブスクライバー (複数可) `SubscribeConfiguration` を設定して `inBandMessaging` を有効にし、`StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED` イベントをリッスンすることで、H.264 動画を配信しているパブリッシャー (存在する場合) から SEI ペイロードを読み取ることができます。

```
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            inBandMessaging: {
                enabled: true
            }
        }
    }
    // ... other strategy functions
}

stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, seiMessage) => {
    console.log(seiMessage.payload, seiMessage.uuid);
});
```

## サイマルキャストによるレイヤードエンコーディング
<a name="web-publish-subscribe-layered-encoding-simulcast"></a>

サイマルキャストによるレイヤードエンコーディングは、パブリッシャーが複数の異なるビデオの品質レイヤーを送信し、サブスクライバーがそれらのレイヤーを動的または手動で変更できるようにする IVS リアルタイムのストリーミング機能です。この機能は、「[ストリーミング最適化](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html)」ドキュメントで詳しく説明されています。

### レイヤードエンコーディングの設定 (パブリッシャー）
<a name="web-layered-encoding-simulcast-configure-publisher"></a>

パブリッシャーとしてサイマルキャストによるレイヤードエンコーディングを有効にするには、インスタンス化時に `LocalStageStream` に次の設定を追加します。

```
// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: { enabled: true }
})
```

カメラデバイスの入力解像度に応じて、「*ストリーミングの最適化*」の「[デフォルトレイヤー、品質、フレームレート](real-time-streaming-optimization.md#real-time-streaming-optimization-default-layers)」セクションで定義されているように、設定された数のレイヤーがエンコードされて送信されます。

また、必要に応じて、サイマルキャスト設定内から個々のレイヤーを設定できます。

```
import { SimulcastLayerPresets } from ‘amazon-ivs-web-broadcast’

// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: {
      enabled: true,
      layers: [
         SimulcastLayerPresets.DEFAULT_720,
          SimulcastLayerPresets.DEFAULT_360,
          SimulcastLayerPresets.DEFAULT_180, 
   }
})
```

または、最大で 3 つのレイヤー用に独自のカスタムレイヤー設定を作成することもできます。空のアレイを指定するか、値を指定しない場合、上記のデフォルトが使用されます。レイヤーは、次の必須プロパティで説明されています。
+ `height: number;`
+ `width: number;`
+ `maxBitrateKbps: number;`
+ `maxFramerate: number;`

プリセットから、個々のプロパティを上書きするか、まったく新しい設定を作成できます。

```
import { SimulcastLayerPresets } from ‘amazon-ivs-web-broadcast’

const custom720pLayer = {
   ...SimulcastLayerPresets.DEFAULT_720,
   maxFramerate: 15,
}

const custom360pLayer = {
       maxBitrateKbps: 600,
       maxFramerate: 15,
       width: 640,
       height: 360,
}

// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: {
      enabled: true,
      layers: [
         custom720pLayer,
         custom360pLayer, 
   }
})
```

個々のレイヤーを設定するときにトリガーできる最大値、制限、エラーについては、SDK リファレンスドキュメントを参照してください。

### レイヤードエンコーディングの設定 (サブスクライバー）
<a name="web-layered-encoding-simulcast-configure-subscriber"></a>

サブスクライバーとして、レイヤードエンコーディングを有効にするために必要なものはありません。パブリッシャーがサイマルキャストレイヤーを送信している場合、デフォルトでサーバーによってレイヤー間で動的に適応され、サブスクライバーのデバイスおよびネットワークの状態に基づいて最適な品質が選択されます。

あるいは、パブリッシャーが送信している明示的なレイヤーを選択するには、以下に説明するいくつかのオプションがあります。

### オプション 1: 初期レイヤー品質の選択
<a name="web-layered-encoding-simulcast-layer-quality-preference"></a>

`subscribeConfiguration` 戦略を使用すると、サブスクライバーとして受信する初期レイヤーを選択できます。

```
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            simulcast: {
                initialLayerPreference: InitialLayerPreference.LOWEST_QUALITY
            }
        }
    }
    // ... other strategy functions
}
```

デフォルトでは、サブスクライバーは常に最初に最低品質のレイヤーが送信されます。これにより、徐々に最高品質のレイヤーにまで拡大します。エンドユーザーの帯域幅の消費量が最適化され、ビデオ再生に最適な時間が実現されるため、より貧弱なネットワーク上のユーザーに対して初期ビデオフリーズが軽減されます。

これらのオプションは `InitialLayerPreference` で利用できます。
+ `LOWEST_QUALITY` — サーバーは、最初に最低品質のビデオレイヤーを配信します。帯域幅の消費とメディアの時間が最適化されます。品質はビデオのサイズ、ビットレート、フレームレートの組み合わせとして定義されます。例えば、720p ビデオは 1080p ビデオよりも品質が低くなります。
+ `HIGHEST_QUALITY` — サーバーは、最初に最高品質のビデオレイヤーを配信します。品質が最適化されますが、メディアの時間が長くなる場合があります。品質はビデオのサイズ、ビットレート、フレームレートの組み合わせとして定義されます。例えば、1080p ビデオは 720p ビデオよりも高品質です。

**注:** 初期レイヤー設定 (`initialLayerPreference` の呼び出し) を反映させるには、再サブスクライブが必要です。これらの更新はアクティブなサブスクリプションに適用されないためです。



### オプション 2: ストリームに優先されるレイヤー
<a name="web-layered-encoding-simulcast-preferred-layer"></a>

ストリームが開始されたら、`preferredLayerForStream ` 戦略メソッドを使用できます。この戦略メソッドは、参加者およびストリーム情報を公開します。

戦略メソッドは、次の内容として返すことができます。
+ `RemoteStageStream.getLayers` が返す内容に直接的に基づくレイヤーオブジェクト 
+ `StageStreamLayer.label` に基づく、レイヤーオブジェクトのラベル文字列
+ レイヤーを選択せず、動的適応が優先されることを示す未定義または null

例えば、次の戦略ではユーザーが常に最低品質のビデオレイヤーを選択するようにします。

```
const strategy = {
    preferredLayerForStream: (participant, stream) => {
        return stream.getLowestQualityLayer();
    }
    // ... other strategy functions
}
```

レイヤーの選択をリセットして動的適応に戻るには、戦略で null または未定義を返します。この例では、`appState` は可能なアプリケーションの状態を表すダミー変数です。

```
const strategy = {
    preferredLayerForStream: (participant, stream) => {
        if (appState.isAutoMode) {
            return null;
        } else {
            return appState.layerChoice
        }
    }
    // ... other strategy functions
}
```

### オプション 3: RemoteStageStream レイヤーヘルパー
<a name="web-layered-encoding-simulcast-remotestagestream-helpers"></a>

`RemoteStageStream` には、レイヤーの選択について決定し、対応する選択をエンドユーザーに表示するために使用できるいくつかのヘルパーがあります。
+ **レイヤーイベント** - `StageEvents` に加え、`RemoteStageStream` オブジェクト自体にはレイヤーおよびサイマルキャストの適応変更を伝えるイベントがあります。
  + `stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer, reason) => {})`
+ **レイヤーメソッド** — `RemoteStageStream` には、ストリームおよび提示されるレイヤーに関する情報を取得するために使用できるいくつかのヘルパーメソッドがあります。これらのメソッドは、`preferredLayerForStream ` 戦略で提供されるリモートストリームに加え、`StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED` を介して配信されるリモートストリームで利用できます。
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`

詳細については、「[SDK リファレンスドキュメント](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference)」の「`RemoteStageStream`」クラスを参照してください。`LAYER_SELECTED` の理由として `UNAVAILABLE` が返された場合、これはリクエストされたレイヤーが選択できなかったことを示します。代わりにベストエフォートの選択が行われ、ストリームの安定性を維持するために、通常は低品質のレイヤーが選択されます。

## ネットワーク問題の処理
<a name="web-publish-subscribe-network-issues"></a>

ローカルデバイスのネットワーク接続が失われると、SDK はユーザーアクションなしで内部で再接続を試みます。場合によっては、SDK が正常に動作せず、ユーザーアクションが必要なる可能性があります。

大まかに、ステージの状態は `STAGE_CONNECTION_STATE_CHANGED` イベントを介して処理できます。

```
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {
   switch (state) {
      case StageConnectionState.DISCONNECTED:
         // handle disconnected UI
         return;
      case StageConnectionState.CONNECTING:
         // handle establishing connection UI
         return;
      case StageConnectionState.CONNECTED:
         // SDK is connected to the Stage
         return;
      case StageConnectionState.ERRORED:
         // SDK encountered an error and lost its connection to the stage. Wait for CONNECTED.
         return;
    }
})
```

通常、SDK は内部的に復旧しようとするため、ステージに正常に参加した後に発生するエラー状態を無視できます。SDK が `ERRORED` 状態を報告し、ステージが長時間 (30 秒以上) `CONNECTING` 状態のままである場合、おそらくネットワークから切断されています。

## IVS チャネルにステージをブロードキャストする
<a name="web-publish-subscribe-broadcast-stage"></a>

ステージをブロードキャストするには、`IVSBroadcastClient` セッションを作成してから、前述の SDK による通常のブロードキャスト手順に従います。次のように、`STAGE_PARTICIPANT_STREAMS_ADDED` を介して公開された `StageStream` のリストを使用して、ブロードキャストストリーム構成に適用できる参加者メディアストリームを取得できます。

```
// Setup client with preferred settings
const broadcastClient = getIvsBroadcastClient();

stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {
    streams.forEach(stream => {
        const inputStream = new MediaStream([stream.mediaStreamTrack]);
        switch (stream.streamType) {
            case StreamType.VIDEO:
                broadcastClient.addVideoInputDevice(inputStream, `video-${participant.id}`, {
                    index: DESIRED_LAYER,
                    width: MAX_WIDTH,
                    height: MAX_HEIGHT
                });
                break;
            case StreamType.AUDIO:
                broadcastClient.addAudioInputDevice(inputStream, `audio-${participant.id}`);
                break;
        }
    })
})
```

オプションで、ステージを合成して IVS 低レイテンシーチャネルにブロードキャストすることで、より多くの視聴者に届けることもできます。「IVS 低レイテンシーストリーミングユーザーガイド」の「[Amazon IVS ストリームでの複数のホストの有効化](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/multiple-hosts.html)」を参照してください。

# IVS Web Broadcast SDK の既知の問題と回避策 \$1 Real-Time Streaming
<a name="broadcast-web-known-issues"></a>

このドキュメントでは、Amazon IVS Real-Time Streaming Web Broadcast SDK を使用する際に発生する可能性のある既知の問題の一覧を示し、可能な回避策を提案します。
+ `stage.leave()` を呼び出さずにブラウザのタブを閉じたり、ブラウザを終了したりしても、ユーザーは最大 10 秒間フレームがフリーズしたり、画面が真っ暗になったりしてセッションに表示されることがあります。

  **回避策:** 該当なし。
+ セッションの開始後、Safari セッションに参加しているユーザーには、断続的に黒い画面が表示されます。

  **回避策:** ブラウザを更新して、セッションに再接続します。
+ Safari は、ネットワークを切り替えても正常に回復しません。

  **回避策:** ブラウザを更新して、セッションに再接続します。
+ 開発者コンソールは `Error: UnintentionalError at StageSocket.onClose` エラーを繰り返します。

  **回避策:** 参加者トークンごとに作成できるステージは 1 つだけです。このエラーは、`Stage` インスタンスが 1 つのデバイス上にあるか複数のデバイスにあるかに関係なく、同じ参加者トークンで複数のインスタンスが作成された場合に発生します。
+ `StageParticipantPublishState.PUBLISHED` 状態の維持に問題がある可能性があり、`StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED` イベントを聞くと`StageParticipantPublishState.ATTEMPTING_PUBLISH` 状態が繰り返される可能性があります。

  **回避策:** `getUserMedia` または `getDisplayMedia` を呼び出すときは、ビデオ解像度を 720p に制限してください。具体的には、幅と高さの `getUserMedia` と `getDisplayMedia` の制約値は、乗算時に 921600 (1280 x 720) を超えることはできません。
+ `stage.leave()` が呼び出されるか、リモート参加者が退出すると、ブラウザのデバッグコンソールに 404 DELETE エラーが表示されます。

  **回避策:** 該当なし。これは無害なエラーです。

## Safari での制限事項
<a name="broadcast-web-safari-limitations"></a>
+ アクセス許可のプロンプトを拒否するには、Safari でのウェブサイト設定のアクセス許可を OS レベルでリセットする必要があります。
+ Safari は、Firefox や Chrome ほど効果的にすべてのデバイスをネイティブに検出されません。例えば、OBS 仮想カメラは検知されません。

## Firefox での制限事項
<a name="broadcast-web-firefox-limitations"></a>
+ Firefox で画面を共有するには、システムのアクセス許可を有効にする必要があります。アクセス許可を有効にした後、正常に動作するために Firefox を再起動する必要があります。再起動しないと、アクセス許可がブロックされていると認識され、ブラウザで [NotFoundError](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#exceptions) 例外がスローされます。
+ `getCapabilities` メソッドがありません。これは、ユーザーがメディアトラックの解像度やアスペクト比を取得できないことを意味します。こちらの [Bugzilla のスレッド](https://bugzilla.mozilla.org/show_bug.cgi?id=1179084)を参照してください。
+ レイテンシーやチャネル数などの、いくつかの `AudioContext` プロパティがありません。これは、オーディオトラックを操作する上級ユーザーにとって問題になる可能性があります。
+ `getUserMedia` からのカメラフィードは、MacOS でのアスペクト比が 4:3 に制限されています。「[Bugzilla のスレッド 1](https://bugzilla.mozilla.org/show_bug.cgi?id=1193640)」および「[Bugzilla のスレッド 2](https://bugzilla.mozilla.org/show_bug.cgi?id=1306034)」を参照してください。
+ オーディオキャプチャが `getDisplayMedia` でサポートされていません。こちらの [Bugzilla のスレッド](https://bugzilla.mozilla.org/show_bug.cgi?id=1541425)を参照してください。
+ スクリーンキャプチャのフレームレートが最適ではありません (約 15 fps?)。こちらの [Bugzilla のスレッド](https://bugzilla.mozilla.org/show_bug.cgi?id=1703522)を参照してください。

## モバイルウェブの制限事項
<a name="broadcast-web-mobile-web-limitations"></a>
+ [getDisplayMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility) の画面共有はモバイルデバイスではサポートされていません。

  **回避策:** 該当なし。
+ `leave()` を呼び出さずにブラウザを閉じると、参加者が退出するまでに 15～30 秒かかります。

  **回避策**: ユーザーが正しく接続を解除するように促す UI を追加します。
+ バックグラウンドで動くアプリケーションが原因で動画の配信が停止します。

  **回避策**: パブリッシャーが一時停止しているときに UI スレートを表示します。
+ Android デバイスでカメラのミュートを解除すると、動画のフレームレートが約 5 秒間低下します。

  **回避策:** 該当なし。
+ iOS 16.0 では、ビデオフィードはローテーション時にストレッチされます。

  **回避策**: OS の既知の問題の概要を示す UI を表示します。
+ オーディオ入力デバイスを切り替えると、オーディオ出力デバイスも自動的に切り替わります。

  **回避策:** 該当なし。
+ ブラウザのバックグラウンド設定を行うと、配信ストリームが真っ暗になり、音声のみが生成されます。

  **回避策:** 該当なし。これはセキュリティ上の理由からです。

# IVS Web Broadcast SDK でのエラー処理 \$1 Real-Time Streaming
<a name="broadcast-web-error-handling"></a>

このセクションでは、エラー状態の概要、Web Broadcast SDK がエラー状態をアプリケーションに報告する方法、およびエラー発生時にアプリケーションが実行する処理について説明します。エラーは SDK によって `StageEvents.ERROR` イベントのリスナーに報告されます。

```
stage.on(StageEvents.ERROR, (error: StageError) => {
    // log or handle errors here
    console.log(`${error.code}, ${error.category}, ${error.message}`);
});
```

## ステージエラー
<a name="web-error-handling-stage-errors"></a>

StageError は、SDK が復旧できない問題に遭遇したときに報告され、通常、アプリケーションの介入やネットワークの再接続が必要になります。

報告されたそれぞれの `StageError` には、コード (または `StageErrorCode`)、メッセージ (文字列)、カテゴリ (`StageErrorCategory`) があります。それぞれが基盤となるオペレーションカテゴリに関連しています。

エラーのオペレーションカテゴリは、ステージへの接続 (`JOIN_ERROR`)、ステージへのメディアの送信 (`PUBLISH_ERROR`)、またはステージからの受信メディアストリームの受信 (`SUBSCRIBE_ERROR`) のどちらに関連しているかに基づいて決定されます。

`StageError` のコードプロパティは、特定の問題をレポートします。


| 名前 | コード | [Recommended Action] (推奨されるアクション) | 
| --- | --- | --- | 
| TOKEN\$1MALFORMED | 1 | 有効なトークンを作成し、ステージのインスタンス化を再試行してください。 | 
| TOKEN\$1EXPIRED | 2 | 有効期限が切れていないトークンを作成し、ステージのインスタンス化を再試行します。 | 
| タイムアウト | 3 | オペレーションがタイムアウトしました。ステージが存在し、トークンが有効である場合、この障害はネットワークの問題である可能性があります。この場合は、デバイスの接続が回復するまでお待ちください。 | 
| FAILED | 4 | オペレーションの試行中に致命的な状態が発生しました。エラーの詳細を確認してください。 ステージが存在し、トークンが有効である場合、この障害はネットワークの問題である可能性があります。この場合は、デバイスの接続が回復するまでお待ちください。 ネットワークの安定性に関連するほとんどの障害の場合、SDK は FAILED エラーを出力する前に最大 30 秒間内部で再試行します。 | 
| CANCELED | 5 | アプリケーションコードをチェックし、繰り返し `join`、`refreshStrategy`、または `replaceStrategy` 呼び出しがないことを確認します。これにより、完了前に繰り返しオペレーションが開始され、キャンセルされる可能性があります。 | 
| STAGE\$1AT\$1CAPACITY | 6 | このエラーは、ステージまたはアカウントのキャパシティに達していることを示します。ステージが参加者の制限に達した場合は、戦略を更新して、ステージのキャパシティが解放されたときにオペレーションを再試行してください。アカウントが同時サブスクリプションまたは同時パブリッシャーのクォータに達した場合は、[AWS Service Quotas コンソール](https://console.aws.amazon.com/servicequotas/)を使用して使用量を減らすか、クォータの引き上げをリクエストしてください。 | 
| CODEC\$1MISMATCH | 7 | コーデックはステージではサポートされていません。コーデックのサポートについては、ブラウザとプラットフォームを確認してください。IVS Real-Time Streaming の場合、ブラウザはビデオ用の H.264 コーデックとオーディオ用の Opus コーデックをサポートしている必要があります。 | 
| TOKEN\$1NOT\$1ALLOWED | 8 | トークンにはオペレーションに対するアクセス許可がありません。トークンを正しいアクセス許可で再作成し、再試行してください。 | 
| STAGE\$1DELETED | 9 | なし。削除されたステージに参加しようとすると、このエラーがトリガーされます。 | 
| PARTICIPANT\$1DISCONNECTED | 10 | なし。切断された参加者のトークンを使用して参加しようとすると、このエラーがトリガーされます。 | 

### StageError の処理の例
<a name="web-error-handling-stage-errors-example"></a>

StageError コードを使用して、エラーが期限切れのトークンによるものかどうかを判断します。

```
stage.on(StageEvents.ERROR, (error: StageError) => {
    if (error.code === StageError.TOKEN_EXPIRED) {
        // recreate the token and stage instance and re-join
    }
});
```

### 既に参加している場合のネットワークエラー
<a name="web-error-handling-stage-errors-network"></a>

デバイスのネットワーク接続が切断されると、SDK と Stages サーバーとの接続が失われる可能性があります。SDK がバックエンドサービスにアクセスできなくなるため、コンソールにエラーが表示される場合があります。https://broadcast.stats.live-video.net への POST は失敗します。

配信中/サブスクライブ中の場合は、配信/サブスクライブの試行に関連するエラーがコンソールに表示されます。

SDK は、エクスポネンシャルバックオフストラテジーを使用して内部で再接続を試みます。

**アクション**: デバイスの接続が回復するまでお待ちください。

## エラー状態
<a name="web-error-handling-errored-states"></a>

これらの状態は、アプリケーションのログ記録に使用し、特定の参加者のステージへの接続の問題を通知するメッセージをユーザーに表示することをお勧めします。

### 配信
<a name="errored-states-publish"></a>

SDK は配信が失敗したときに `ERRORED` を報告します。

```
stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participantInfo, state) => {
  if (state === StageParticipantPublishState.ERRORED) {
      // Log and/or display message to user
  }
});
```

### Subscribe
<a name="errored-states-subscribe"></a>

SDK はサブスクライブが失敗したときに `ERRORED` を報告します。これは、ネットワークの状態が原因で発生する可能性がありますが、ステージがサブスクライバーのキャパシティに達した場合にも発生することがあります。

```
stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participantInfo, state) => {
  if (state === StageParticipantSubscribeState.ERRORED) {
    // Log and/or display message to user
  }
});
```