🥷

[iOS] 新SkyWayとSFUの初歩

2024/08/27に公開

はじめに

NTT Communicationsさんが提供している新SkyWayをちょこっと触ることになったのでまとめます。

Room, Core, SFU Botの3つライブラリが用意されていますが、その中のRoomを使っていきます。
また、SFUとP2Pがありますが、そのSFUを触ります

色々

用語

  • Room

    • 通話を行うグループ。Roomを作成してRoomに参加したユーザー同士で通話を行う
  • Stream

    • Room上で送受信ができるメディアのこと
    • 3種類のStreamが提供されている
      • AudioStream
        • ユーザーのマイク音声など
      • VideoStream
        • ユーザーのカメラ映像など
      • DataStream
        • 任意のメッセージ
  • Publish

    • MemberがStreamをRoomに公開すること
    • StreamをPublishするとRoom上にStreamに対応するPublicationというリソースが作成される

具体例

  • Roomに入室する
let roominit = Room.InitOptions()
// Roomの名前
roominit.name = ""
// Roomを作成して入室する
let _ = try? await SFURoom.join(with: roominit)
// nameからRoomを探してなければ作成して入室する
let _ = try? await SFURoom.findOrCreate(with: roominit)

  • Roomから退室する
// 入室
let room = try? await SFURoom.findOrCreate(with: roominit)

try await member.leave()
// または
room.leave(member)

// Roomを閉じずにRoomインスタンスを解放する
// これ以降roomのインスタンスにアクセスするとクラッシュするので注意
room.dispose()

// delegateも解放する
room.delegate = nil
room = nil
  • Roomを閉じる
// Roomを閉じて、入室しているすべてのユーザーを退室させる
// 退室時と同様にこれ以降roomのインスタンスにアクセスするとクラッシュするので注意
try await room.close()

room.delegate = nil
room = nil

Roomが閉じられた時にRoomDelegateのfunc roomDidClose(_ room: Room)が呼ばれる

func roomDidClose(_ room: Room) {
   // この中で保持しているroomの解放を行うのがよさそう
   // delegate経由でもらうroomにアクセスしてもクラッシュするので注意
}

Publish

  • カメラから映像を取得してPublishする
// フロントカメラを取得
let camera = CameraVideoSource.supportedCameras().first(where: { $0.position == .front })
// 背面のカメラを取得
let camera = CameraVideoSource.supportedCameras().first(where: { $0.position == .back })
// Streamを作成
let localVideoStream = CameraVideoSource.shared().createStream()
let _ = try? await member.publish(localVideoStream, options: nil)
  • 端末の音声を取得してPublishする
// Streamを作成
let audioStream = MicrophoneAudioSource().createStream()
let audioPublication = try? await member?.publish(audioStream, options: nil)

// muteにする場合
audioPublication.disable()
// unmuteにする場合
audioPublication.enable()
  • DataをPublishする&送信
let dataSource = DataSource()
// Streamを作成
let localDataStream = dataSource.createStream()
let _ = try? await member?.publish(localDataStream, options: nil)

// 文字列を送る
localDataStream.write("SkyWay")
// Data型を送る
localDataStream.write(data)

Subscribe

subscribeするためにはmemberのsubscribeを実行する

member.subscribe(publicationId: "id", options: nil)

では実際にpublicationIdをどうやって取得するかですが、RoomDelegateの以下を使うのがよさそうです

// StreamがPublishされた後に呼ばれる
func room(_ room: Room, didPublishStreamOf publication: RoomPublication) {
   let publicationId = publication.id
}

// RoomのPublicationの数が変化した後に呼ばれる
func roomPublicationListDidChange(_ room: SkyWayRoom.Room) {
  let publications = room.publications
}
  • DataのSubscribe

Dataをsubscribeするには一手間必要で、RemoteDataStreamDelegateを使う必要がありそうです。(SFUでは利用できないので注意)

// StreamがPublishされた後に呼ばれる
func room(_ room: Room, didPublishStreamOf publication: RoomPublication) {
   Task {
      let subscription = try? await member?.subscribe(publicationId: publication.id, options: nil)
      // dataかどうかを確認する
      if publication.contentType == .data, let stream = subscription?.stream as? RemoteDataStream {
        // RemoteDataStreamDelegate
         stream.delegate = self
      }
   }
}

// RemoteDataStreamDelegate
func remoteDataStream(_ stream: RemoteDataStream, didReceiveData data: Data) {
 // ここで取得できる
}

Tips

  • Context Delegate

ContextのDelegateを使った場合は、必要なくなればnilを入れないとリークするので注意

Context.delegate = self

// 例えばroomをcloseするタイミング
Context.delegate = nil

...TDC

参考資料

Discussion