IVS iOS Broadcast SDK での配信とサブスクライブ | Real-Time Streaming - Amazon IVS

IVS iOS Broadcast SDK での配信とサブスクライブ | Real-Time Streaming

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

概念

リアルタイム機能には、ステージストラテジーレンダラーという 3 つのコアコンセプトがあります。設計目標は、実際に動作する製品を構築するのに必要となるクライアント側ロジックの量を最小限に抑えることです。

ステージ

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

let stage = try IVSStage(token: token, strategy: self) try stage.join() stage.leave()

また、IVSStage クラスには次の IVSStageRenderer および IVSErrorDelegate をアタッチすることもできます。

let stage = try IVSStage(token: token, strategy: self) stage.errorDelegate = self stage.addRenderer(self) // multiple renderers can be added

方針

IVSStageStrategy プロトコルは、ホストアプリケーションがステージの望ましい状態を SDK に伝達する方法を提供します。shouldSubscribeToParticipantshouldPublishParticipantstreamsToPublishForParticipant の 3 つの関数を実装する必要があります。以下で、すべて説明します。

参加者へのサブスクライブ

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType

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

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

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { return .audioVideo }

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

より高度な実装も可能です。IVSParticipantInfoattributes プロパティを使用して、サーバーが提供する属性に基づいて、参加者に対して選択的にサブスクライブできます。

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { switch participant.attributes["role"] { case "moderator": return .none case "guest": return .audioVideo default: return .none } }

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

参加者へのサブスクライブの設定

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration

リモート参加者がサブスクライブしている場合 (「参加者へのサブスクライブ」を参照)、SDK はホストアプリケーションにその参加者のカスタムサブスクライブ設定についてクエリします。この設定はオプションであり、ホストアプリケーションがサブスクライバーの動作の特定の側面を制御できるようにします。設定できる内容の詳細については、SDK リファレンスドキュメントの「SubscribeConfiguration」を参照してください。

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

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration { let config = IVSSubscribeConfiguration() try! config.jitterBuffer.setMinDelay(.medium()) return config }

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

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

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

配信

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool

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

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

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool { return true }

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

配信するストリームの選択

func stage(_ stage: IVSStage, streamsToPublishForParticipant participant: IVSParticipantInfo) -> [IVSLocalStageStream]

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

ストラテジーの更新

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

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

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

レンダラー

IVSStageRenderer プロトコルはステージの状態をホストアプリケーションに伝えます。ホストアプリケーションの UI の更新は、通常、レンダラーが提供するイベントだけで行うことができます。次の関数では、以下のような結果が生成されます。

func stage(_ stage: IVSStage, participantDidJoin participant: IVSParticipantInfo) func stage(_ stage: IVSStage, participantDidLeave participant: IVSParticipantInfo) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChange publishState: IVSParticipantPublishState) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChange subscribeState: IVSParticipantSubscribeState) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didAdd streams: [IVSStageStream]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didRemove streams: [IVSStageStream]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChangeMutedStreams streams: [IVSStageStream]) func stage(_ stage: IVSStage, didChange connectionState: IVSStageConnectionState, withError error: Error?) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, stream: IVSRemoteStageStream, didChangeStreamAdaption adaption: Bool) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, stream: IVSRemoteStageStream, didChange layers: [IVSRemoteStageStreamLayer]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, stream: IVSRemoteStageStream, didSelect layer: IVSRemoteStageStreamLayer?, reason: IVSRemoteStageStream.LayerSelectedReason)

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

配信参加者のみが participantDidJoin をトリガーし、参加者が配信を停止するか、ステージセッションを終了すると、participantDidLeave がトリガーされることに注意してください。

メディアストリームを配信する

内蔵マイクやカメラなどのローカルデバイスは、IVSDeviceDiscovery を介して検出されます。以下は、前面カメラとデフォルトのマイクを選択し、それらを IVSLocalStageStreams として SDK で配信できるように戻す例です。

let devices = IVSDeviceDiscovery().listLocalDevices() // Find the camera virtual device, choose the front source, and create a stream let camera = devices.compactMap({ $0 as? IVSCamera }).first! let frontSource = camera.listAvailableInputSources().first(where: { $0.position == .front })! camera.setPreferredInputSource(frontSource) let cameraStream = IVSLocalStageStream(device: camera) // Find the microphone virtual device and create a stream let microphone = devices.compactMap({ $0 as? IVSMicrophone }).first! let microphoneStream = IVSLocalStageStream(device: microphone) // Configure the audio manager to use the videoChat preset, which is optimized for bi-directional communication, including echo cancellation. IVSStageAudioManager.sharedInstance().setPreset(.videoChat) // This is a function on IVSStageStrategy func stage(_ stage: IVSStage, streamsToPublishForParticipant participant: IVSParticipantInfo) -> [IVSLocalStageStream] { return [cameraStream, microphoneStream] }

参加者を表示、削除する

サブスクライブが完了すると、レンダラーの didAddStreams 関数を介して IVSStageStream オブジェクトの配列を受け取ります。この参加者のオーディオレベル統計をプレビューまたは受信するには、ストリームから基になる IVSDevice オブジェクトにアクセスできます。

if let imageDevice = stream.device as? IVSImageDevice { let preview = imageDevice.previewView() /* attach this UIView subclass to your view */ } else if let audioDevice = stream.device as? IVSAudioDevice { audioDevice.setStatsCallback( { stats in /* process stats.peak and stats.rms */ }) }

参加者が配信を停止するか、サブスクライブを解除すると、削除されたストリームを使用して didRemoveStreams 関数が呼び出されます。ホストアプリケーションは、これを通知として使用して、参加者のビデオストリームをビュー階層から削除する必要があります。

didRemoveStreams は、以下を含む、ストリームが削除される可能性のあるすべてのシナリオで呼び出されます。

  • リモート参加者は配信を停止します。

  • ローカルデバイスがサブスクリプションを解除するか、サブスクリプションを .audioVideo から .audioOnly に変更します。

  • リモート参加者がステージを退出します。

  • ローカルの参加者がステージを退出します。

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

メディアストリームをミュート、ミュート解除する

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

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

リモート参加者のメディアミュート状態の監視

参加者がビデオまたはオーディオストリームのミュート状態を変更すると、変更されたストリームの配列を使用してレンダラー didChangeMutedStreams 関数が呼び出されます。IVSStageStreamisMuted プロパティを使用して、次の UI を適宜更新してください。

func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChangeMutedStreams streams: [IVSStageStream]) { streams.forEach { stream in /* stream.isMuted */ } }

ステージ構成を作成する

ステージの動画設定の値をカスタマイズするには、次の IVSLocalStageStreamVideoConfiguration を使用します。

let config = IVSLocalStageStreamVideoConfiguration() try config.setMaxBitrate(900_000) try config.setMinBitrate(100_000) try config.setTargetFramerate(30) try config.setSize(CGSize(width: 360, height: 640)) config.degradationPreference = .balanced

WebRTC 統計を取得する

配信ストリームまたはサブスクライブ中のストリームの最新の WebRTC 統計情報を取得するには、IVSStageStreamrequestRTCStats を使用してください。収集が完了すると、IVSStageStreamDelegate に設定できる IVSStageStream から統計を受け取ります。WebRTC の統計を継続的に収集するには、この関数を Timer で呼び出します。

func stream(_ stream: IVSStageStream, didGenerateRTCStats stats: [String : [String : String]]) { for stat in stats { for member in stat.value { print("stat \(stat.key) has member \(member.key) with value \(member.value)") } } }

参加者属性を取得

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

func stage(_ stage: IVSStage, participantDidJoin participant: IVSParticipantInfo) { print("ID: \(participant.participantId)") for attribute in participant.attributes { print("attribute: \(attribute.key)=\(attribute.value)") } }

メッセージを埋め込む

IVSImageDevice で embedMessage メソッドを使用すると、配信中のビデオフレームにメタデータペイロードを直接挿入できます。これは、リアルタイムアプリケーションのフレーム同期型メッセージングを可能にします。メッセージの埋め込みを使用できるのは、リアルタイム配信(低レイテンシー配信ではない) の SDK を使用している場合のみです。

埋め込みメッセージは、ビデオフレーム内に直接埋め込まれ、パケット配信を保証しない UDP 経由で送信されるため、必ずしもサブスクライバーに届くとは限りません。送信中のパケット損失は、特にネットワーク状態が悪い場合において、メッセージの損失につながる可能性があります。この問題を軽減するため、embedMessage メソッドには repeatCount パラメータが含まれています。このパラメータは、連続する複数のフレーム全体でメッセージを複製することで、配信信頼性を向上させます。この機能を利用できるのはビデオストリームのみです。

embedMessage の使用

配信元のクライアントは、IVSImageDevice で embedMessage メソッドを使用して、メッセージペイロードをビデオストリームに埋め込むことができます。ペイロードサイズは 0 KB より大きく 1 KB 未満のサイズにする必要があります。挿入される埋め込みメッセージの 1 秒あたりの数が 10 KB/秒を超えないようにする必要があります。

let imageDevice: IVSImageDevice = imageStream.device as! IVSImageDevice let messageData = Data("hello world".utf8) do { try imageDevice.embedMessage(messageData, withRepeatCount: 0) } catch { print("Failed to embed message: \(error)") }

メッセージペイロードの反復

repeatCount を使用して複数のフレーム全体でメッセージを複製し、信頼性を向上させます。この値は 0 ~ 30 の範囲の値にする必要があります。受信クライアントには、メッセージを重複除外するロジックが必要です。

try imageDevice.embedMessage(messageData, withRepeatCount: 5) // repeatCount: 0-30, receiving clients should handle duplicates

埋め込みメッセージの読み取り

受信ストリームから埋め込みメッセージを読み取る方法については、以下の「補足拡張情報 (SEI) を取得する」を参照してください。

補足拡張情報 (SEI、Supplemental Enhancement Information) を取得する

補足拡張情報 (SEI) NAL ユニットは、フレーム整列メタデータを動画と一緒に保存するために使用されます。パブリッシャーの IVSImageDevice から送信される IVSImageDeviceFrame オブジェクトの embeddedMessages プロパティを調べることにより、サブスクライブしているクライアントは H.264 ビデオを配信しているパブリッシャーから SEI ペイロードを読み取ることができます。これを行うには、次の例で示すように、パブリッシャーの IVSImageDevice を取得し、setOnFrameCallback に提供されるコールバックを介して各フレームを確認します。

// in an IVSStageRenderer’s stage:participant:didAddStreams: function, after acquiring the new IVSImageStream let imageDevice: IVSImageDevice? = imageStream.device as? IVSImageDevice imageDevice?.setOnFrameCallback { frame in for message in frame.embeddedMessages { if let seiMessage = message as? IVSUserDataUnregisteredSEIMessage { let seiMessageData = seiMessage.data let seiMessageUUID = seiMessage.UUID // interpret the message's data based on the UUID } } }

セッションをバックグラウンドで続行

アプリがバックグラウンドに入っても、リモート音声を聞きながらステージにい続けることはできますが、自分の画像や音声を送信し続けることはできません。IVSStrategy 実装を更新して、配信を停止し、以下の.audioOnly (または .none、該当する場合) へサブスクライブする必要があります。

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool { return false } func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { return .audioOnly }

次に、stage.refreshStrategy() に電話をかけます。

サイマルキャストによるレイヤードエンコーディング

サイマルキャストによるレイヤードエンコーディングは、パブリッシャーが複数の異なるビデオの品質レイヤーを送信し、サブスクライバーがそれらのレイヤーを動的または手動で設定できるようにする IVS リアルタイムのストリーミング機能です。この機能は、「ストリーミング最適化」ドキュメントで詳しく説明されています。

レイヤードエンコーディングの設定 (パブリッシャー)

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

// Enable Simulcast let config = IVSLocalStageStreamVideoConfiguration() config.simulcast.enabled = true let cameraStream = IVSLocalStageStream(device: camera, configuration: config) // Other Stage implementation code

ビデオ設定で設定した解像度に応じて、「ストリーミングの最適化」の「デフォルトレイヤー、品質、フレームレート」セクションで定義されているように、設定された数のレイヤーがエンコードされて送信されます。

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

// Enable Simulcast let config = IVSLocalStageStreamVideoConfiguration() config.simulcast.enabled = true let layers = [ IVSStagePresets.simulcastLocalLayer().default720(), IVSStagePresets.simulcastLocalLayer().default180() ] try config.simulcast.setLayers(layers) let cameraStream = IVSLocalStageStream(device: camera, configuration: config) // Other Stage implementation code

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

  • setSize: CGSize;

  • setMaxBitrate: integer;

  • setMinBitrate: integer;

  • setTargetFramerate: float;

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

// Enable Simulcast let config = IVSLocalStageStreamVideoConfiguration() config.simulcast.enabled = true let customHiLayer = IVSStagePresets.simulcastLocalLayer().default720() try customHiLayer.setTargetFramerate(15) let layers = [ customHiLayer, IVSStagePresets.simulcastLocalLayer().default180() ] try config.simulcast.setLayers(layers) let cameraStream = IVSLocalStageStream(device: camera, configuration: config) // Other Stage implementation code

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

レイヤードエンコーディングの設定 (サブスクライバー)

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

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

オプション 1: 初期レイヤー品質の選択

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

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration { let config = IVSSubscribeConfiguration() config.simulcast.initialLayerPreference = .lowestQuality return config }

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

これらのオプションは InitialLayerPreference で利用できます。

  • lowestQuality — サーバーは、最初に最低品質のビデオレイヤーを配信します。帯域幅の消費とメディアの時間が最適化されます。品質はビデオのサイズ、ビットレート、フレームレートの組み合わせとして定義されます。例えば、720p ビデオは 1080p ビデオよりも品質が低くなります。

  • highestQuality — サーバーは、最初に最高品質のビデオレイヤーを配信します。品質が最適化されますが、メディアの時間が長くなる場合があります。品質はビデオのサイズ、ビットレート、フレームレートの組み合わせとして定義されます。例えば、1080p ビデオは 720p ビデオよりも高品質です。

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

オプション 2: ストリームに優先されるレイヤー

preferredLayerForStream 戦略メソッドを使用すると、ストリームの開始後にレイヤーを選択できます。この戦略メソッドは参加者とストリーム情報を受け取るため、参加者ごとにレイヤーを選択できます。このメソッドは、ストリームのレイヤーが変化したとき、参加者の状態が変化したとき、またはホストアプリケーションが戦略を更新したときなど、特定のイベントに応じて SDK が呼び出します。

この戦略メソッドは IVSRemoteStageStreamLayer オブジェクトを返します。これは次のいずれかになります。

  • IVSRemoteStageStream.layers によって返されるレイヤーオブジェクトなど。

  • レイヤーを選択せず、動的適応が優先されることを示す null。

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

func stage(_ stage: IVSStage, participant: IVSParticipantInfo, preferredLayerFor stream: IVSRemoteStageStream) -> IVSRemoteStageStreamLayer? { return stream.lowestQualityLayer }

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

func stage(_ stage: IVSStage, participant: IVSParticipantInfo, preferredLayerFor stream: IVSRemoteStageStream) -> IVSRemoteStageStreamLayer? { If appState.isAutoMode { return nil } else { return appState.layerChoice } }

オプション 3: RemoteStageStream レイヤーヘルパー

IVSRemoteStageStream には、レイヤーの選択について決定し、対応する選択をエンドユーザーに表示するために使用できるいくつかのヘルパーがあります。

  • レイヤーイベントIVSStageRenderer に加え、IVSRemoteStageStreamDelegate にはレイヤーおよびサイマルキャストの適応変更を伝えるイベントがあります。

    • func stream(_ stream: IVSRemoteStageStream, didChangeAdaption adaption: Bool)

    • func stream(_ stream: IVSRemoteStageStream, didChange layers: [IVSRemoteStageStreamLayer])

    • func stream(_ stream: IVSRemoteStageStream, didSelect layer: IVSRemoteStageStreamLayer?, reason: IVSRemoteStageStream.LayerSelectedReason)

  • レイヤーメソッドIVSRemoteStageStream には、ストリームおよび提示されるレイヤーに関する情報を取得するために使用できるいくつかのヘルパーメソッドがあります。これらのメソッドは、preferredLayerForStream 戦略で提供されるリモートストリームに加え、func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didAdd streams: [IVSStageStream]) を介して公開されるリモートストリームで利用できます。

    • stream.layers

    • stream.selectedLayer

    • stream.lowestQualityLayer

    • stream.highestQualityLayer

    • stream.layers(with: IVSRemoteStageStreamLayerConstraints)

詳細については、「SDK リファレンスドキュメント」の「IVSRemoteStageStream」クラスを参照してください。LayerSelected の理由として UNAVAILABLE が返された場合、これはリクエストされたレイヤーが選択できなかったことを示します。代わりにベストエフォートの選択が行われ、ストリームの安定性を維持するために、通常は低品質のレイヤーが選択されます。

IVS チャネルにステージをブロードキャストする

ステージをブロードキャストするには、別の IVSBroadcastSession を作成してから、前述の SDK による通常のブロードキャスト手順に従います。IVSStageStreamdevice プロパティは、上のスニペットで示すように、IVSImageDevice または IVSAudioDevice のいずれかになります。これらを IVSBroadcastSession.mixer に接続すると、カスタマイズ可能なレイアウトでステージ全体をブロードキャストできます。

オプションで、ステージを合成して IVS 低レイテンシーチャネルにブロードキャストすることで、より多くの視聴者に届けることもできます。「IVS 低レイテンシーストリーミングユーザーガイド」の「Amazon IVS ストリームでの複数のホストの有効化」を参照してください。