🦁

SwiftUIでSkyWayの映像を表示する(SwiftUIでSKWVideoを使う方法)

2021/03/07に公開

SwiftUIでSkyWayの映像を表示してみました。SkyWayはWebRTCのプラットフォームです、iOSのSDKが提供されています。
https://webrtc.ecl.ntt.com/

iOSのSDKには映像を表示するためのSKWVideoというクラスが提供されています。これはUIKitで使用することを想定されたコンポーネントで、SwiftUIから使用する方法がわかりませんでした。

UIViewRepresentableを使うとSwiftUIでUIKitのコンポーネントを表示することができるのでSKWVideoに対して適用したところ表示できました。画像では丸くくり抜いたり影をつけています。

カスタムビューのコード全体です、UIViewRepresentableを継承したVideoViewを作成します。

struct VideoView: UIViewRepresentable {
    typealias UIViewType = SKWVideo
    let stream: SKWMediaStream
    let videoView = UIViewType()

    func makeUIView(context: Context) -> UIViewType {
        return videoView
    }

    func updateUIView(_ uiView: UIViewType, context: Context) {
        stream.addVideoRenderer(uiView, track: 0)
    }

    final class Coordinator: NSObject {
        let parent: VideoView
        init(_ parent: VideoView) {
            self.parent = parent
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    static func dismantleUIView(_ uiView: UIViewType, coordinator: Coordinator) {
        // perform additional clean-up work related custom view
        coordinator.parent.stream.removeVideoRenderer(uiView, track: 0)
    }
}

ポイント

  • Viewが作成されるときにmakeUIViewが呼ばれるのでSKWVideoのインスタンスをreturnする
  • Viewが表示(更新)されるときにupdateUIViewが呼ばれるのでstreamをaddVideoRendererする
  • Viewが取り除かれるときにdismantleUIViewが呼ばれるのでremoveVideoRendererを呼び出す
    • streamにアクセスするためにmakeCoordinatorでCordinatorを作成している

本体側、Viewを表示する側のコードです。

struct ContentView: View {
    @State var peer: SKWPeer?
    @State var localStream: SKWMediaStream?

    var body: some View {
        VStack {
            Text("Hello, world!")
                .padding()
            if let peer = peer {
                Button("getUserMedia") {
                    if localStream == nil {
                        SKWNavigator.initialize(peer)
                        let constraints = SKWMediaConstraints()
                        constraints.minFrameRate = 30
                        localStream = SKWNavigator.getUserMedia(constraints)
                    } else {
                        localStream?.close()
                        localStream = nil
                    }
                }
                if let localStream = localStream {
                    VideoView(stream: localStream)
                        .clipShape(Circle())
                        .overlay(Circle().stroke(Color.gray, lineWidth: 4))
                        .shadow(radius: 7)
                        .padding()
                }
            }
        }
        .onAppear {
            let option = SKWPeerOption.init()
            option.key = skywayAPIKey
            option.domain = skywayDomain
            self.peer = SKWPeer(options: option)
        }
    }
}

ポイント

  • peerを作成する
  • SKWNavigator.getUserMediaを呼び出してlocalStreamを取得する
  • VideoView(stream: localStream)でViewを宣言する

カスタムビューはSwiftUIのViewなのでclipShapeなどを使って見た目を加工することができます。

Discussion