RPC 機能

概要

RPC 機能は、 DataChannel 経由で JSON-RPC 2.0 による Sora の一部 HTTP API 呼び出しを行うための仕組みです。 Sora の RPC 機能については Sora のドキュメント RPC 機能 をご確認ください。

警告

この機能は実験的機能のため、正式版では仕様が変更される可能性があります。

設定

RPC 機能は DataChannel 経由のシグナリングが有効な場合に利用できます。 Sora iOS SDK では Configuration.dataChannelSignalingtrue に設定してください。

var config = Configuration(url: soraURL,
                           channelId: soraChannelId,
                           role: role)

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

RPC 用の DataChannel は Sora が label: "rpc" を持つチャネルとして作成します。 Configuration.dataChannelsrpc を指定する必要はありません。

利用できるメソッドの確認

利用可能な RPC メソッドは onReceiveSignaling で受信する Signaling.offerrpcMethods から確認できます。 rpcMethods[String]? で、メソッド名の文字列配列です。

mediaChannel.handlers.onReceiveSignaling = { signaling in
  switch signaling {
  case let .offer(offer):
    guard let rpcMethods = offer.rpcMethods else {
      return
    }
    // 例: ["2025.2.0/RequestSimulcastRid", ...]
    print(rpcMethods)
  default:
    break
  }
}

RPC を送信する

ユーザーは MediaChannel.rpc を利用して RPC を送信します。

MediaChannel.rpc の戻り値は RPCResponse<M.Result>? であり、 M.Result は呼び出したメソッドに対応した型になります。rpc 呼び出し時に is_notification_requesttrue に設定した場合は返り値が nil になります。

注釈

is_notification_request を true に設定すると Notification として利用できます。 これは Sora 側がレスポンスを返さないことを意味します。 Notification に関する詳細は https://www.jsonrpc.org/specification#notification をご確認ください。

RPC 機能のメソッドと SDK が提供する型の対応

Sora iOS SDK では以下の RPC メソッドが型として提供されます。

  • 2025.2.0/RequestSimulcastRid に対応した RequestSimulcastRid

  • 2025.2.0/RequestSpotlightRid に対応した RequestSpotlightRid

  • 2025.2.0/ResetSpotlightRid に対応した ResetSpotlightRid

  • 2025.2.0/PutSignalingNotifyMetadata に対応した PutSignalingNotifyMetadata<Metadata>

  • 2025.2.0/PutSignalingNotifyMetadataItem に対応した PutSignalingNotifyMetadataItem<Metadata, Value>

各メソッド型は RPCMethodProtocol を実装しており、メソッド固有のパラメータ型と結果型を持ちます。その型を用いて MediaChannel.rpc を呼んでください。

以下は RequestSimulcastRidPutSignalingNotifyMetadataItem を呼び出すサンプルコードです。

RequestSimulcastRid の例

import Sora

func requestSimulcastRid(mediaChannel: MediaChannel) async throws {
  // RequestSimulcastRidParams:
  //   rid: Rid
  //   senderConnectionId: String?
  let params = RequestSimulcastRidParams(
    rid: .r0,
    senderConnectionId: "YOUR-SENDER-CONNECTION-ID")

  do {
    guard
      let response = try await mediaChannel.rpc(
        method: RequestSimulcastRid.self,
        params: params,
        is_notification_request: false,
        timeout: 5.0)
    else {
      // RPC レスポンスが nil の場合
      return
    }
    // response.result は RequestSimulcastRidResult で、プロパティで直接アクセス可能
    let channelId = response.result.channelId
    let receiverConnectionId = response.result.receiverConnectionId
    let rid = response.result.rid
    let senderConnectionId = response.result.senderConnectionId
    _ = (channelId, receiverConnectionId, rid, senderConnectionId)
  } catch SoraError.rpcUnavailable(let reason) {
    // DataChannel が利用できない
    _ = reason
  } catch SoraError.rpcTimeout {
    // 応答がタイムアウトした
  } catch SoraError.rpcServerError(let detail) {
    // Sora から JSON-RPC のエラー応答が返った
    _ = detail
  } catch {
    // 予期しないエラー
    _ = error
  }
}

PutSignalingNotifyMetadataItem の例

import Sora

func putSignalingNotifyMetadataItem(mediaChannel: MediaChannel) async throws {
  // メタデータアイテムの構造を定義
  struct NewItem: Codable {
    let foo: String
  }

  // メタデータ全体の構造を定義
  struct Metadata: Codable {
    let oldItem: String
    let newItem: NewItem

    enum CodingKeys: String, CodingKey {
      case oldItem = "old_item"
      case newItem = "new_item"
    }
  }

  // PutSignalingNotifyMetadataItemParams<Value>:
  //   key: String
  //   value: Value
  //   push: Bool?
  let params = PutSignalingNotifyMetadataItemParams(
    key: "new_item",
    value: NewItem(foo: "bar"))

  do {
    guard
      let response = try await mediaChannel.rpc(
        method: PutSignalingNotifyMetadataItem<Metadata, NewItem>.self,
        params: params,
        is_notification_request: false,
        timeout: 5.0)
    else {
      // RPC レスポンスが nil の場合
      return
    }
    // response.result は Metadata 型で、更新後のメタデータ全体が返される
    let updated = response.result
    _ = updated.oldItem
    _ = updated.newItem
  } catch SoraError.rpcUnavailable(let reason) {
    // DataChannel が利用できない
    _ = reason
  } catch SoraError.rpcTimeout {
    // 応答がタイムアウトした
  } catch SoraError.rpcServerError(let detail) {
    // Sora から JSON-RPC のエラー応答が返った
    _ = detail
  } catch {
    // 予期しないエラー
    _ = error
  }
}

MediaChannel.rpc のレスポンスが不要な場合

レスポンスが不要な場合は is_notification_requesttrue にします。 この場合は JSON-RPC 2.0 の Notification として送信され、レスポンスを返しません。

do {
  let params = RequestSimulcastRidParams(
    rid: .r1,
    senderConnectionId: "EKNQ103WRD4ZZ74B6TKRM9YK78")
  _ = try await mediaChannel.rpc(
    method: RequestSimulcastRid.self,
    params: params,
    is_notification_request: true,
    timeout: 5.0)
} catch {
  // 予期しないエラー
  _ = error
}

MediaChannel.rpc について

MediaChannel.rpc はジェネリクスを使用します。

func rpc<M: RPCMethodProtocol>(
  method: M.Type,
  params: M.Params,
  is_notification_request: Bool = false,
  timeout: TimeInterval = 5.0
) async throws -> RPCResponse<M.Result>?

RPCMethodProtocol は以下のように定義されており、 ParamsResult を RPC の各メソッドと関連付ける役割を持ちます。

public protocol RPCMethodProtocol {
  associatedtype Params: Encodable
  associatedtype Result: Decodable
  static var name: String { get }
}

この関連付けにより、利用者は呼び出したメソッドに対応した結果型を扱えます。

例えば RequestSimulcastRid メソッドに対応する RequestSimulcastRid を指定した場合のレスポンスの型は RPCResponse<RequestSimulcastRidResult>? になります。

SDK で未提供の RPC メソッド型を定義する

Sora に新しい RPC メソッドが追加され、SDK 側でまだ型が提供されていない場合は、 RPCMethodProtocol を実装した型をユーザーが定義することで対応することができます。

Params は JSON-RPC 2.0 リクエストオブジェクトの params に入る値を表す型で、 Result は JSON-RPC 2.0 レスポンスオブジェクトの result に入る値を表す型です。 name には Sora に存在する RPC メソッド名を指定してください。

// リクエストパラメータ {"value": "hello"} を送信し
// {"accepted": true} のようにリザルトを受信する例です
struct CustomRPCParams: Encodable {
  let value: String
}

struct CustomRPCResult: Decodable {
  let accepted: Bool
}

struct CustomRPCMethod: RPCMethodProtocol {
  typealias Params = CustomRPCParams
  typealias Result = CustomRPCResult
  static let name = "2025.2.0/CustomRPCMethod"
}

let params = CustomRPCParams(value: "hello")
let response = try await mediaChannel.rpc(
  method: CustomRPCMethod.self,
  params: params)
_ = response?.result.accepted
© Copyright 2018-2025, Shiguredo Inc. Created using Sphinx 9.1.0