Sora に接続する

概要

Sora への接続処理の概要について記載しています。

シグナリング

WebRTC 接続において、接続の確立や制御に必要な情報をやり取りする通信を シグナリング と呼びます。 Sora iOS SDK では、このシグナリングにより Sora との接続確立や接続制御を行います。

WebRTC SFU Sora のシグナリングの仕様については以下をご確認ください。

接続の手順

Sora への接続は次の手順で行います。

  1. Configuration を生成する。
  2. Sora オブジェクトの connect メソッド を呼ぶ。
import Sora

// シグナリング URL とチャネル ID を指定する
let url = URL(string: "wss://sora.example.com/signaling")!
let soraChannelId = "sora"
let config = Configuration(url: url,
                                channelId: soraChannelId,
                                role: .recvonly)

// 接続する
Sora.shared.connect(configuration: config) { mediaChannel, error in
    // 接続に失敗するとエラーが渡される。
    // 接続に成功すると error は nil
    if let error = error {
        // 接続エラー時の処理
        ...
    }

    // 接続成功時の処理
    // 映像を描画するビューをストリームにセットする等
    ...
}

Configuration は Sora への接続情報などの設定を保持するオブジェクトです。 Sora のシグナリング URL 、チャネル ID 、ロールをセットします。

次に Configuration を引数として Sora オブジェクトの connect メソッド を呼びます。このとき Sora オブジェクトは Sora.shared プロパティでシングルトンを取得できます。 このメソッドは Sora への接続を行い、接続の成否に関わらず handler: に指定されたブロックを実行します。 接続が成功すると MediaChannel がブロックの引数として渡されます。 MediaChannel は接続後の操作を行うためのオブジェクトです。

connect メソッド の型と引数は次の通りです。

func connect(configuration: Configuration,
             webRTCConfiguration: WebRTCConfiguration = WebRTCConfiguration(),
             handler: (_ mediaChannel: MediaChannel?, _ error: Error?) -> Void)
  • configuration: 接続情報です。シグナリング URL とチャネル ID を指定します。
  • webRTCConfiguration: WebRTC に関する設定です (省略可) 。
  • handler: 接続試行後に実行するブロックです。ブロックの型は (MediaChannel?, Error?) -> Void です。ブロックの引数は次の通りです。
    • mediaChannel: 接続に成功するとメディアチャネルが渡されます。失敗時は nil です。
    • error: 接続に失敗するとエラーが渡されます。成功時は nil です。

MediaChannel は映像データを扱うストリームを複数保持します。 映像はストリームを通じて Sora と送受信されます。

接続後の映像の送受信については 映像を描画する を参考にしてください

DataChannel 経由のシグナリング

Sora と DataChannel を経由したシグナリング通信を行うための接続方法について記載します。 詳しい仕様は Sora のドキュメント をご確認ください。

DataChannel 経由のシグナリングを有効にするには、 ConfigurationdataChannelSignaling プロパティに true をセットしてください。 WebSocket が閉じたときに Sora に接続が切断されたと判断して欲しくない場合は ignoreDisconnectWebSocket プロパティに true をセットしてください。

var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// DataChannel 経由のシグナリングを有効にする
config.dataChannelSignaling = true

// WebSocket が閉じたことを無視する
config.ignoreDisconnectWebSocket = true

イベントハンドラ

DataChannel に関するイベントハンドラは MediaChannelHandlers に用意しています。 主なイベントハンドラは以下の通りです。

/// シグナリングが DataChannel 経由に切り替わったタイミングで呼ばれるクロージャー
public var onDataChannel: ((MediaChannel) -> Void)?

/// DataChannel のメッセージ受信時に呼ばれるクロージャー
public var onDataChannelMessage: ((MediaChannel, String, Data) -> Void)?

音声の設定

音声コーデックの設定

Sora 接続時に送信する音声についてコーデックの指定ができます。

var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// 音声コーデックを opus に設定する
config.audioCodec = .opus

音声ビットレートの設定

Sora 接続時に送信する音声についてビットレートの指定ができます。

  • 音声のビットレートは ConfigurationaudioBitRate に設定します。
var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// 音声ビットレートを 32 kbps に設定する
config.audioBitRate = 32

映像の設定

映像コーデックの設定

Sora 接続時に送信する映像についてコーデックの指定ができます。

  • 映像のコーデックは ConfigurationvideoCodecVideoCodec を設定します。
  • 利用できる映像コーデックは VP8 / VP9 / H.264 / H.265 / AV1 です。未指定の場合は Sora のデフォルト値が設定されます。
var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// 映像コーデックを VP8 に設定する
config.videoCodec = .vp8

映像コーデックパラメーターの設定

送信する映像コーデックの設定と合わせて、映像コーデックのパラメーターを指定可能です。 この機能は rolesendrecv または sendonly の場合に利用できます。

指定できる値の内容については以下の Sora ドキュメントをご確認ください。

var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// 映像コーデックの設定は VP9 / AV1 / H.264 / H.265 のいずれか 1 種類のみです
// 利用しない映像コーデックパラメーターは設定しないでください

// VP9 の場合は profile_id の設定が可能です
config.videoCodec = .vp9
config.videoVp9Params = ["profile_id": 0]

// AV1 の場合は profile の設定が可能です
// config.videoCodec = .av1
// config.videoAv1Params = ["profile": 0]

// H.264 の場合は profile_level_id の設定が可能です
// config.videoCodec = .h264
// config.videoH264Params = ["profile_level_id": "42e01f"]

// H.265 の場合は profile_id、level_id、tier_flag、tx_mode の設定が可能です
// config.videoCodec = .h265
// config.videoH265Params = ["profile_id": 1, "level_id": 93, "tier_flag": 0, "tx_mode": "SRST"]

映像ビットレートの設定

Sora 接続時に送信する映像についてビットレートの指定ができます。

  • 映像のビットレートは ConfigurationvideoBitRate に設定します。
var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// ビデオビットレートを 3000 kbps に設定する
config.videoBitRate = 3000

転送フィルターの設定

転送フィルター機能は、Sora 側でクライアントへ転送する音声や映像のパケットをフィルターする機能です。 詳しくは Sora ドキュメント をご確認ください。

この機能は rolesendrecv または recvonly の場合にのみ利用できます。

フィルターを設定する

Sora 接続時に Configuration.forwardingFilters を設定します。

設定例

以下の例は、自分の接続に対して、次の条件で映像または音声の受信をブロックします。

  • connection_id が "S8YEN0TSE13JDC2991NG4XZ150" の場合は音声と映像の受信をブロックする、または client_id が "screen-share" の場合は音声の受信をブロックする
var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

let forwardingFilter = ForwardingFilter(
    action: .block,
    rules: [
        [
            ForwardingFilterRule(field: .connectionId,
                                 operator: .isIn,
                                 values: ["S8YEN0TSE13JDC2991NG4XZ150"]),
        ],
        [
            ForwardingFilterRule(field: .clientId,
                                 operator: .isIn,
                                 values: ["screen-share"]),
            ForwardingFilterRule(field: .kind,
                                 operator: .isIn,
                                 values: ["audio"]),
        ]
    ],
)

config.forwardingFilters = [forwardingFilter]

TLS 検証

WebSocket シグナリングおよび TURN-TLS のサーバー証明書検証では、既定で iOS のルートストアに含まれるルート証明書を用いて、サーバー証明書の証明書チェーンを検証します。

WebSocket シグナリングは Sora とのシグナリング接続に、 TURN-TLS は ICE で利用する TURN サーバーとの TLS 接続に利用されます。

TLSSecurityPolicy を設定する

TURN-TLS におけるサーバー証明書検証の有無は、 ICEServerInfo.tlsSecurityPolicy で制御します。 デフォルト値は TLSSecurityPolicy.secure で、この場合はサーバー証明書の証明書チェーンを検証します。 TLSSecurityPolicy.insecure を指定した場合は、 TURN-TLS のサーバー証明書検証を行いません。

設定例は次の通りです。

var webRTCConfiguration = WebRTCConfiguration()

// TURN-TLS の証明書検証を無効にする
let insecureICEServerInfo = ICEServerInfo(
    urls: ["turns:turn.example.com:5349?transport=tcp"],
    userName: "username",
    credential: "credential",
    tlsSecurityPolicy: .insecure
)

webRTCConfiguration.iceServerInfos = [secureICEServerInfo]

CA 証明書を指定する

プライベート CA で発行した CA 証明書を WebSocket シグナリングおよび TURN-TLS の接続時に利用することができます。

CA 証明書は ConfigurationcaCertificate に PEM 文字列で設定します。 また、証明書チェーンとして複数の PEM 証明書を連結して指定できます。 デフォルト値の nil の場合は、 iOS のルートストアに含まれるルート証明書による既定の検証を行います。

通常、 caCertificate には自己署名のルート証明書を指定します。信頼アンカーとして使用されるのは、このルート証明書です。 TURN-TLS では、 TLSSecurityPolicy.secure の場合に caCertificate が適用されます。 TLSSecurityPolicy.insecure を指定した場合は、 TURN-TLS のサーバー証明書検証を行わないため、 caCertificate を指定していても利用されません。

var config = Configuration(url: url,
                            channelId: channelId,
                            role: .sendrecv)

config.caCertificate = """
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
"""

caCertificate に不正な PEM 文字列を指定した場合、接続開始前に configurationError となります。

WebSocket シグナリング

WebSocket シグナリングにおいて、 SDK は URLSession を利用して接続し、内部的に認証チャレンジを用いた証明書検証を行います。 この証明書検証では CA 証明書を利用しますが、最終的な wss:// 接続可否は ATS( App Transport Security )および iOS のルートストアの影響を受ける場合があります。

URLSession 、および内部の認証チャレンジの機構については、 Apple Developer ドキュメント もご確認ください。

証明書チェーン構成によっては、 WebSocket シグナリングでは root CA に加えて中間 CA を caCertificate に含める必要がある場合があります。 この場合でも、信頼アンカーとして使用されるのは自己署名の root CA であり、中間 CA は証明書チェーンの検証に必要な中間証明書として利用されます。

TURN-TLS

TURN-TLS では、 caCertificatenil の場合、 WebSocket シグナリングと同様に iOS のルートストアに含まれるルート証明書を用いて証明書チェーンを検証します。 caCertificate を指定した場合は、指定した CA を信頼アンカーとして証明書チェーンを検証します。 ただし、 TURN-TLS では caCertificate による証明書チェーン補完は行いません。 このため、サーバーからは中間証明書を含む完全な証明書チェーンが送出されている必要があります。

TURN-TLS の証明書検証は WebSocket シグナリングとは異なる経路で行われます。 そのため、 WebSocket シグナリングと同じ形で ATS( App Transport Security )の影響を受けるものではありません。 なお、 iOS や libwebrtc の各バージョンの実装差異により、証明書検証や接続可否に影響が生じる可能性はあります。

プロキシ・サーバーの設定

プロキシ・サーバーを経由した通信を行う場合は、 Configurationproxy プロパティにプロキシ情報をセットしてください。

  • HTTP プロキシに対応しています
  • SOCKS プロキシも設定できますが、動作を確認していません
  • HTTP の CONNECT メソッドは HTTPS ではなく HTTP で送信します
  • Proxy-Authorization ヘッダーを利用した Basic 認証に対応しています
  • iOS の Wi-Fi に設定されたプロキシの項目を参照しません
var config = Configuration(url: url,
                           channelId: channelId,
                           role: .sendrecv)

// proxy 情報の設定を行う
config.proxy = Proxy(host: "proxy.example.com",
                            port: 3128,
                            agent: nil,
                            username: "ham",
                            password: "egg")

複数のシグナリング URL を指定する

Sora iOS SDK では、 urlCandidates に複数のシグナリング URL を指定することができます。

Sora iOS SDK は全ての URL に対して接続を試行し、最初に成功した接続をシグナリングに使用します。 このため、1台でも正常なサーバーが残っていれば Sora への接続が成功します。 クラスター機能は複数の URL を指定しなくても利用できますが、冗長性を高めるために複数 URL の指定を推奨します。

let urlCandidates = [
    URL(string: "wss://sora1.example.com/signaling")!,
    URL(string: "wss://sora2.example.com/signaling")!,
    URL(string: "wss://sora3.example.com/signaling")!
]
var config = Configuration(urlCandidates: urlCandidates,
                           channelId: channelId,
                           role: .sendrecv)
  • 実際にシグナリングに利用されている URL は MediaChannel クラスの connectedUrl フィールドから確認できます。

クラスター機能利用時のシグナリングのリダイレクト

クラスター機能を有効にすると、 Sora から、 type: offer の代わりに type: redirect が送られてくることがあります。 この場合、Sora iOS SDK は Sora の接続を一度切断し、 type: redirect で指定された location に再接続します。

CPU やネットワーク帯域等逼迫時における映像品質優先項目の設定

映像の配信中に、CPU やネットワーク帯域などの制約を受けて、指定された解像度やフレームレートを維持できないことがあります。 そのような場合に、優先する項目を設定することができます。

例えば、文章が中心のスライドを利用するプレゼンテーションなど、フレームレートより解像度を優先した映像の配信を行いたい場合に、解像度を優先するように設定できます。

設定は ConfigurationwebRTCConfiguration.degradationPreference から行います。 degradationPreference には以下の値を設定できます。

  • disabled ... 何もしない
  • balanced ... バランスを取る
  • maintainResolution ... 解像度の維持を優先する
  • maintainFramerate ... フレームレートの維持を優先する (デフォルトの挙動です)
let config = Configuration(url: url,
                                channelId: soraChannelId,
                                role: .sendonly)

// リソースが逼迫した場合は解像度の維持を優先する
config.webRTCConfiguration.degradationPreference = .maintainResolution