MediaChannel
public final class MediaChannel
extension MediaChannel: CustomStringConvertible
一度接続を行ったメディアチャネルは再利用できません。 同じ設定で接続を行いたい場合は、新しい接続を行う必要があります。
接続が解除されるタイミング
メディアチャネルの接続が解除される条件を以下に示します。 いずれかの条件が 1 つでも成立すると、メディアチャネルを含めたすべてのチャネル (シグナリングチャネル、ピアチャネル、 WebSocket チャネル) の接続が解除されます。
- シグナリングチャネル (
SignalingChannel) の接続が解除される。 - WebSocket チャネル (
WebSocketChannel) の接続が解除される。 - ピアチャネル (
PeerChannel) の接続が解除される。 - サーバーから受信したシグナリング
pingに対してpongを返さない。 これはピアチャネルの役目です。
-
イベントハンドラ
get / set は lock 付き storage で排他します。配送は毎回この storage から読むため、接続を 開始した後に代入しても次の配送から反映されます。配送側は lock を解放してから取得済みの closure を呼びます。この storage が排他するのは参照の差し替えだけで、各イベントハンドラの プロパティは
MediaChannelHandlersのHandlerStorageが排他します。Declaration
Swift
public var handlers: MediaChannelHandlers { get set }
-
接続イベントを購読します。
購読者ごとに独立した
AsyncStreamを返します。同じMediaChannelに対して複数回呼ぶと、 それぞれが独立した buffer / drop 方針 / 終端を持ちます (1 つのAsyncStreamを複数のIteratorで消費するとイベントが購読者間で分かれるため、購読者ごとに stream を作ります)。- イベントは接続単位の順序付きの列です。同じ接続のイベントは配送順に届きます。通し番号の 順序と一致しない場合はあります (同時に配送されたイベントのみ)。
- buffer は既定で
SoraEvent.defaultBufferSize件です。あふれた場合は最も古いイベントが 破棄されます。sequenceで欠落を検出できます。 - 購読を開始する前に配送されたイベントは届きません (buffer は購読ごとに作られます)。
接続の完了前に開始するには、
SoraHandlers.onAddMediaChannelまたはSora.mediaChannelsで 参照を取得してから購読するか、Sora.subscribeEvents(bufferingPolicy:)を使います。 connectedとconnectFailedは接続の完了と同じ配送点で発行されます。接続の完了を 待ってから購読すると取り逃すため、接続の結果を購読する場合はSoraの購読を使ってください。- payload はすべて値として確定しており、配送後も購読者が保持できます。mutable な
MediaChannel/MediaStream/ raw WebRTC object は含まれません。SoraEventはSendableのため、actor / Task 境界へそのまま渡せます。 - 購読の解除は、購読している
Taskの cancel、購読に使ったAsyncStreamへの参照の解放、 または接続の終了です。購読を解除しても他の購読者の buffer と終端は影響を受けません。 - 接続が終了すると
.disconnectedを配送した後に stream が終端します。終端後の購読には 終端済みの stream を返します。.disconnectedを配送せずに終端するのは、明示切断を経由せずMediaChannelが解放された場合だけです。 - 購読している
Taskの loop の中から同期 API (connectionId/stateなどの getter、sendMessage、disconnect) を呼べます。配送は排他区間の外で行うため deadlock しません。disconnectを呼ぶと.disconnectedの配送後に購読が終端し、以降のイベントは届きません。 - 配送 executor はイベントの発生元によって異なります (libwebrtc の callback スレッド、
signaling の受信スレッド、呼び出し元の executor など)。
AsyncStreamの再開後に実行される 購読者のコードは、購読しているTaskの executor 上で動きます。UI 更新は main actor / main queue へ束ねてください。 videoEnabledChanged/audioEnabledChangedは、並行する変更の確定順と配送順が一致しない ことがあります (MediaStreamHandlers.onSwitchVideoと同じ契約です)。この API の追加によって、既存の
handlersの callback 型・配送 executor・配送順序・ 発火回数は変わりません。
Declaration
Parameters
bufferingPolicy購読者ごとの buffer と drop 方針
Return Value
この接続のイベントを配送する stream
-
クライアントの設定
公開互換のために利用者が渡した値を返し続けます。接続開始後の非同期区間 (非同期 hop の後、WebRTC callback、
ConnectionTimer) はこの値の参照型フィールド (metadata / notify metadata / codec 別 params /dataChannels/forwardingFilter/forwardingFilters/webRTCConfiguration、および snapshot に含めないハンドラクラスとaudioDevice) を読みません。値型フィールドは接続開始時の値のままなので、公開 getter、description、公開 mute API、senderStream/receiverStreamsはこの値を読みます。Declaration
Swift
public let configuration: Configuration -
最初に type: connect メッセージを送信した URL (デバッグ用)
Sora から type: redirect メッセージを受信した場合、 contactUrl と connectedUrl には異なる値がセットされます type: redirect メッセージを受信しなかった場合、 contactUrl と connectedUrl には同じ値がセットされます
Declaration
Swift
public var contactUrl: URL? { get } -
接続中の URL
Declaration
Swift
public var connectedUrl: URL? { get } -
メディアチャンネルの内部で利用している RTCPeerConnection
Declaration
Swift
public var native: RTCPeerConnection? { get } -
クライアント ID 。接続後にセットされます。
Declaration
Swift
public var clientId: String? { get } -
バンドル ID 。接続後にセットされます。
Declaration
Swift
public var bundleId: String? { get } -
接続 ID 。接続後にセットされます。
Declaration
Swift
public var connectionId: String? { get } -
接続状態
接続状態の正本は
stateStorageだけであり、この property はそこを読む computed property です。 getter だけの宣言にはprivate(set)を付けられないためget/setを明示し、setはsetState(_:)を呼びます (storage を直接書きません)。読み書きの排他は storage のNSLockに 揃います。遷移ログは排他区間の外で出す。
didSetでは lock を保持したまま Logger を呼び得るため、connectionLifecycleLockを保持して遷移させる箇所では、遷移の直後 (lock の解放後) に 呼び出し元がlogStateChange(from:)を呼ぶ (この property は computed property のためdidSetを持たない)。接続状態の遷移は
setState(_:)を呼ぶこと。private(set)の setter はconnectionLifecycleLockを取らずにsetState(_:)へ入るため、SDK 内部からstateへ 代入してよいのはconnectionLifecycleLockを保持した区間だけです。Declaration
Swift
public private(set) var state: ConnectionState { get set } -
接続中 (
state == .connected) であればtrueDeclaration
Swift
public var isAvailable: Bool { get } -
接続開始時刻。 接続中にのみ取得可能です。
Declaration
Swift
public private(set) var connectionStartTime: Date? { get } -
接続時間 (秒) 。 接続中にのみ取得可能です。
Declaration
Swift
public var connectionTime: Int? { get }
-
同チャネルに接続中のクライアントの数。 サーバーから通知を受信可能であり、かつ接続中にのみ取得可能です。
Declaration
Swift
public private(set) var connectionCount: Int? { get } -
同チャネルに接続中のクライアントのうち、パブリッシャーの数。 サーバーから通知を受信可能であり、接続中にのみ取得可能です。
Declaration
Swift
public private(set) var publisherCount: Int? { get } -
同チャネルに接続中のクライアントの数のうち、サブスクライバーの数。 サーバーから通知を受信可能であり、接続中にのみ取得可能です。
Declaration
Swift
public private(set) var subscriberCount: Int? { get }
-
ストリームのリスト
Declaration
Swift
public var streams: [MediaStream] { get } -
最初のストリーム。 マルチストリームでは、必ずしも最初のストリームが 送信ストリームとは限りません。 送信ストリームが必要であれば
senderStreamを使用してください。Declaration
Swift
public var mainStream: MediaStream? { get } -
送信に使われるストリーム。 ストリーム ID が
configuration.publisherStreamIdに等しいストリームを返します。Declaration
Swift
public var senderStream: MediaStream? { get } -
受信ストリームのリスト。 ストリーム ID が
configuration.publisherStreamIdと異なるストリームを返します。Declaration
Swift
public var receiverStreams: [MediaStream] { get }
-
rpc(method:Asynchronousparams: isNotificationRequest: timeout: ) RPC メソッドを型安全に呼び出します
このメソッドを使用して、Sora サーバーで定義された RPC メソッドを非同期で実行できます。
actor 境界や
Taskの@Sendableclosure へ結果を渡す場合は、sendableRPC(method:params:isNotificationRequest:timeout:)を使用してください。Throws
以下のエラーが発生することがありますSoraError.rpcUnavailable: RPC チャネルが利用不可SoraError.rpcEncodingError: パラメータのエンコーディングに失敗したSoraError.rpcDecodingError: レスポンスのデコーディングに失敗したSoraError.rpcDataChannelClosed: RPC の送受信に利用する DataChannel が切断されたSoraError.rpcTimeout: レスポンスがタイムアウト時間内に返されなかったSoraError.rpcServerError: Sora からエラーレスポンスがあった (詳細はRPCErrorDetail、追加情報はJSONValue?のdata)CancellationError: タスクがキャンセルされた
使用例
do { let response = try await mediaChannel.rpc( method: RequestSimulcastRid.self, params: RequestSimulcastRidParams(rid: "r0") ) if let result = response?.result { print("Channel ID: \(result.channelId)") } } catch { print("RPC call failed: \(error)") }Declaration
Swift
public func rpc<M: RPCMethodProtocol>( method: M.Type, params: M.Params, isNotificationRequest: Bool = false, timeout: TimeInterval = 5.0 ) async throws -> RPCResponse<M.Result>?Parameters
method呼び出す RPC メソッドの型 (例:
RequestSimulcastRid.self)paramsメソッドに渡すパラメータ。型安全に検証されます
isNotificationRequesttrueの場合、送信後に Sora からのレスポンスを待ちません。デフォルトはfalsetimeoutレスポンスを待つ最大時間(秒)。デフォルトは 5.0 秒
Return Value
メソッドの実行結果。isNotificationRequest が true の場合は nil を返します
-
rpc(method:params:isNotificationRequest:timeout:)と同じ挙動で、Swift 6 言語モードの検査に対応した RPC メソッドを型安全に呼び出します引数の意味、戻り値の意味 (notification では
nilが返ること)、返るエラー、タスクキャンセルと response / timeout / DataChannel 切断が競合した場合の pending の終端はrpcと共通です (引数とエラーの詳細はrpc(method:params:isNotificationRequest:timeout:)を参照してください)。 違うのは、SendableRPCMethodProtocolに準拠したメソッドだけを呼べる点と、戻り値がSendableRPCResponse<M.Result>?になる点です。params と result がSendableであるため、 戻り値は actor 境界やTaskの@Sendableclosure を越えて受け渡せます。新旧両方の protocol へ準拠した型でも、
rpcの戻り値はRPCResponse<M.Result>?のままです (別名の API のため overload の解決先が変わりません)。使用例
do { let response = try await mediaChannel.sendableRPC( method: RequestSimulcastRid.self, params: RequestSimulcastRidParams(rid: "r0") ) if let result = response?.result { print("Channel ID: \(result.channelId)") } } catch { print("RPC call failed: \(error)") }Declaration
Swift
public func sendableRPC<M: SendableRPCMethodProtocol>( method: M.Type, params: M.Params, isNotificationRequest: Bool = false, timeout: TimeInterval = 5.0 ) async throws -> SendableRPCResponse<M.Result>?
-
接続を解除します。
Declaration
Swift
public func disconnect(error: Error?)Parameters
error接続解除の原因となったエラー
-
libwebrtc の統計情報を取得します。
非同期取得中に切断された場合でも安全になるよう、コールバック内で チャンネルの解放が始まっていないこと (
MediaChannelStateStorageの終端フラグ)、 チャンネルの生存確認、state == .connected の再確認、peerChannel.nativeChannel が 同一インスタンスかどうか、をチェックしています。handler の実行スレッドは経路で異なります。
RTCPeerConnection.statisticsの完了 block から 呼ばれる経路 (成功と、終端フラグ /state/nativeChannelの同一性判定で失敗する場合) の handler は libwebrtc 側のスレッドから呼ばれ、入口の前段判定 (未接続 /nativeChannelが nil) で失敗する経路の handler は呼び出し元のスレッドから同期的に呼ばれます。どちらの経路も 呼び出し元スレッドは保証されません。UI 更新や共有状態の変更は main queue / main actor へ 束ねてください。Swift 6 言語モードでは、handler の中で
first(where:)などの closure を呼ばず、 handler の中の closure に@Sendableを付けて Sendable な値へ詰め替えてから main actor / main queue へ渡すか、handler の先頭で main に束ねます。handler の中で closure を呼ぶと、 MainActor 隔離を継承した closure が WebRTC スレッドで実行時隔離チェックに掛かります。 handler 引数の型 (@escaping (Result<Statistics, Error>) -> Void) は変更しません。actor / Task 境界へ統計情報を渡す場合は、
getStatsSnapshot(handler:)が handler へ渡す値とgetStatsSnapshot()が返す値が immutable で deep Sendable なため、こちらを使用してください。Statisticsは mutable class のため、そのまま境界を越えて渡せません。Declaration
Swift
public func getStats(handler: @escaping (Result<Statistics, Error>) -> Void)Parameters
handler統計情報取得後に呼ばれるクロージャー
-
libwebrtc の統計情報を、actor / Task 境界へ渡せる snapshot として取得します。
getStats(handler:)と同じRTCPeerConnection.statisticsを入力源にし、戻り値だけを immutable で deep Sendable なStatisticsSnapshotに変えます。既存のgetStats(handler:)の シグネチャと挙動、Statistics/StatisticsEntryは変更しません。handler の実行スレッドは
getStats(handler:)と同じです。RTCPeerConnection.statisticsの 完了 block から呼ばれる経路 (成功と、終端フラグ /state/nativeChannelの同一性判定 / 統計値の変換で失敗する場合) の handler は libwebrtc 側のスレッドから呼ばれ、入口の前段判定 (未接続 /nativeChannelが nil) で失敗する経路の handler は呼び出し元のスレッドから 同期的に呼ばれます。どちらの経路も呼び出し元スレッドは保証されません。Swift 6 言語モードでの扱い方も
getStats(handler:)と同じです (handler の中で closure を 呼ばず、handler の中の closure に@Sendableを付けて Sendable な値へ詰め替えてから main actor / main queue へ渡すか、handler の先頭で main に束ねます)。失敗時の
SoraError.peerChannelErrorのreasonは、入口の前段判定で"MediaChannel is not connected (state: …)"と"RTCPeerConnection is unavailable (nativeChannel: nil)"、 完了 block の判定で"MediaChannel is unavailable"と"MediaChannel is not connected (state: …)"と"RTCPeerConnection is unavailable (nativeChannel changed)"になります。統計値をJSONValueへ 変換できない場合はSoraError.mediaChannelErrorになります。Declaration
Swift
public func getStatsSnapshot(handler: @escaping (Result<StatisticsSnapshot, Error>) -> Void)Parameters
handler統計情報取得後に呼ばれるクロージャー
-
getStatsSnapshot()Asynchronouslibwebrtc の統計情報を、actor / Task 境界へ渡せる snapshot として取得します。
getStatsSnapshot(handler:)の async 版です。タスクのキャンセルはCancellationErrorで 終端します。libwebrtc には統計取得をキャンセルする API が無いため、キャンセル後もRTCPeerConnection.statisticsは開始して完了 block まで走りますが、終端済みの結果は 返しません (キャンセルが要求の開始より先でも、開始の有無で終端の挙動を分けません)。このメソッドは呼び出し中
MediaChannelを保持します。そのためdeinitによる切断と 後始末は、完了 block が届くかタスクがキャンセルされるまで遅延します。完了 block が届かない 場合にawaitを終わらせる手段はタスクキャンセルだけです (既存rpcのような timeout は 持ちません)。また、呼び出し中はMediaChannelが生存するため、完了 block の終端フラグ (MediaChannelStateStorage.isTerminated) が真になることはなく、解放開始による失敗はgetStatsSnapshot(handler:)だけが返します。キャンセルは async 版だけを対象とし、キャンセル・切断・状態遷移が競合しても終端は 1 回です。 キャンセルと結果の到着が競合した場合は、先に終端した方を採用します (キャンセルが先なら
CancellationError、結果が先なら snapshot を返します)。入口の前段判定 (未接続 /nativeChannelが nil) はgetStatsSnapshot(handler:)と共通で、キャンセル済みのタスクではCancellationErrorが優先されます。Throws
SoraError.peerChannelError(未接続 /nativeChannelが nil / 接続状態の遷移後 /nativeChannelの差し替え後。reasonはgetStatsSnapshot(handler:)と同じ)、SoraError.mediaChannelError(統計値をJSONValueへ変換できない)、CancellationError(タスクがキャンセルされた)Declaration
Swift
public func getStatsSnapshot() async throws -> StatisticsSnapshotReturn Value
統計情報の snapshot
-
DataChannel を利用してメッセージを送信します
Declaration
Swift
public func sendMessage(label: String, data: Data) -> Error? -
MediaChannel の接続中にマイクをハードミュート有効化/無効化します
Declaration
Swift
public func setAudioHardMute(_ mute: Bool) -> Error?Parameters
mutetrueで有効化、falseで無効化Return Value
成功した場合は
nil、失敗した場合はSoraError.mediaChannelErrorを返します -
MediaChannel の接続中にマイクをソフトミュート有効化 / 無効化します
この呼び出し 1 回を 1 operation とし、
MediaStream.audioEnabledへの直接代入とは operation の世代 (operation の開始時に取得した順) で調停されます。後から開始した operation の 値が最新になり、より大きい世代が先に確定している場合、この呼び出しの書き込みは破棄されます (呼び出しは成功を返します)。Declaration
Swift
public func setAudioSoftMute(_ mute: Bool) -> Error?Parameters
mutetrueで有効化、falseで無効化Return Value
成功した場合は
nil、失敗した場合はSoraError.mediaChannelErrorを返します -
MediaChannel の接続中に映像をソフトミュート有効化 / 無効化します 黒塗りフレームが送信される状態になります
この呼び出し 1 回を 1 operation とし、
setVideoHardMuteとMediaStream.videoEnabledへの 直接代入とは operation の世代 (operation の開始時に取得した順) で調停されます。後から開始した operation の値が最新になり、より大きい世代が先に確定している場合、この呼び出しの書き込みは 破棄されます (呼び出しは成功を返します)。Declaration
Swift
public func setVideoSoftMute(_ mute: Bool) -> Error?Parameters
mutetrueで有効化、falseで無効化Return Value
成功した場合は
nil、失敗した場合はSoraError.mediaChannelErrorを返します -
setVideoHardMute(_:Asynchronous) MediaChannel の接続中に映像をハードミュート有効化 / 無効化します
端末カメラ利用が有効になっている必要があります 外部入力や別キャプチャ経路には対応していません
内部で Actor により、操作を排他実行します。 同時に呼び出された場合は Actor 側で
SoraError.mediaChannelErrorがスローされます映像ハードミュートは、黒塗りフレーム状態で停止させるためローカルトラックの停止を含みます 事前に映像ソフトミュートを利用していた場合は状態が上書きされます ハードミュート解除時に直前のソフトミュートの状態を復元するようなことはしません
ハードミュート有効化に失敗した場合は、
VideoHardMuteActorの直列化区間へ入った時点のsenderStream.videoEnabledを復元します。ただし操作が取り消された場合は復元せず、 黒塗り (ソフトミュート) のまま終了します。 切断の開始と同時に失敗した場合は復元されることがあります。 ただしこの基準値は呼び出し直前の値と厳密に一致する保証はありません。この呼び出し 1 回を 1 operation とし、
videoEnabledの設定・復元・ハードミュート解除後の 有効化はすべてこの呼び出しが公開 API の入口で取得した世代で確定します。setVideoSoftMuteやMediaStream.videoEnabledへの直接代入など、後から開始した operation が先に値を確定している 場合は、この操作の書き込み (解除後の有効化を含む) が破棄されます (この操作の失敗時の復元も 破棄されます)。 操作の実行中や設定前の取消により拒否された場合はvideoEnabledを変更しません。この操作の書き込みが破棄された場合でも、ハードミュートのカメラ停止・再開は実行されます。 その場合
videoEnabledの確定値と実カメラ状態が食い違うことがあり、その場合は復旧にsetVideoHardMute(false)が必要です (setVideoSoftMute(false)では復旧しません)。senderStream.videoEnabledの確定処理は値が変化したときだけ利用者 handler とVideoRendererを呼びます (BasicMediaStreamの経路は setter ではなくこの確定処理を直接呼びます)。 この書き込みが後続の operation により破棄されない場合に限り、呼び出し前が有効なときは成功時にonSwitchVideo(false)が 1 回、復元する失敗時にonSwitchVideo(false)とonSwitchVideo(true)が この順に 1 回ずつ発火します。 有効化の経路ではこれらの handler はVideoHardMuteActorの executor で発火します。 これに対しVideoRenderer.onSwitch(video:)の配送 executor は main queue であり、 handler と renderer の相対順序は保証されません。Throws
エラー時はSoraError.cameraErrorまたはSoraError.mediaChannelErrorがスローされますDeclaration
Swift
public func setVideoHardMute(_ mute: Bool) async throwsParameters
mutetrueで有効化、falseで無効化 -
startScreenCapture(settings:Asynchronous) MediaChannel の接続中に ReplayKit を利用して画面キャプチャおよび映像配信を開始します
送信フレームレートは
ScreenCaptureSettings.targetFPSで制御できます。ScreenCaptureSettings.videoSampleBufferTransformerは SDK 内部の送信キュー上で呼ばれます。targetFPSによる間引きで破棄されるフレームと、送信処理中のために破棄されるフレーム、 キャプチャ停止中と切断中のフレームでは呼ばれません。引数と戻り値のCMSampleBufferの 所有権は SDK に委ねられ、戻り値の pixel buffer は送信のために SDK が retain します。 戻り値を返した後にその buffer を書き換えないでください。同一 senderStream に対してカメラキャプチャが動作中の場合は開始できません。 接続前に
Configuration.initialCameraEnabled = falseを設定してください。 接続後にカメラを停止する場合はsetVideoHardMute(true)を先に呼んでください。Throws
エラー時はSoraError.mediaChannelErrorまたは ReplayKit 起因のエラーがスローされますDeclaration
Swift
public func startScreenCapture(settings: ScreenCaptureSettings = .init()) async throwsParameters
settings画面キャプチャ設定
-
stopScreenCapture()AsynchronousReplayKit を利用した画面キャプチャを停止します
Declaration
Swift
public func stopScreenCapture() async -
画面キャプチャが動作中かを取得します
Declaration
Swift
public func isScreenCaptureActive() -> Bool
View on GitHub
Install in Dash