본문으로 건너뛰기
Version: 6.0

그룹 영상 통화

그룹 영상 통화를 구현하는 예제 코드입니다.

필수 조건

시작하기 전에 다음 작업을 수행해야 합니다.

그룹 영상 통화 구현 시 고려 사항

joinConference()를 호출한 다음에는 반환된 PlanetKitConferenceJoinResultreason 속성을 확인해야 합니다.

  • reasonPlanetKitStartFailReason.none인 경우 성공을 의미합니다.
  • 그렇지 않으면 실패를 의미하며 reason에 따라 적절한 조치를 취해야 합니다.

이벤트 대리자 구현

통화에서 사용될 이벤트 대리자(delegate)를 구현하세요.

  • PlanetKitConferenceDelegate는 그룹 통화의 상태 변경 이벤트를 처리하는 데 사용됩니다.
  • PlanetKitMyMediaStatusDelegate는 로컬 사용자의 미디어 상태 변경 이벤트를 처리하는 데 사용됩니다. 마이크가 음 소거되거나 음 소거 해제되는 경우나 오디오 설명이 업데이트되는 경우 또는 비디오 상태가 업데이트되는 경우 등 이벤트를 기반으로 로컬 사용자의 UI를 업데이트할 수 있습니다.
extension ConferenceDelegateExample : PlanetKitConferenceDelegate {
func didConnect(_ conference: PlanetKitConference, connected: PlanetKitConferenceConnectedParam) {

// This is called when the call is connected.
// Write your own code here.

}

func didDisconnect(_ conference: PlanetKitConference, disconnected: PlanetKitDisconnectedParam) {

// This is called when the call is disconnected.
// Write your own code here.

}

func peerListDidUpdate(_ conference: PlanetKitConference, updated: PlanetKitConferencePeerListUpdateParam) {

// This is called when the list of peers is updated.
// Write your own code here.

}


func peersVideoDidUpdate(_ conference: PlanetKitConference, updated: PlanetKitConferenceVideoUpdateParam) {

// This is called when the video of one or more peers is updated.
// Write your own code here.

}

//
// Also, you should implement other methods defined in the PlanetKitConferenceDelegate protocol.
//
...
}

extension MyMediaStatusDelegateExample: PlanetKitMyMediaStatusDelegate {
func didMuteMic(_ myMediaStatus: PlanetKitMyMediaStatus) {

// This is called when the local user's audio is muted.
// Write your own code here.

}

func didUnmuteMic(_ myMediaStatus: PlanetKitMyMediaStatus) {

// This is called when the local user's audio is unmuted.
// Write your own code here.

}

func didUpdateAudioDescription(_ myMediaStatus: PlanetKitMyMediaStatus, description: PlanetKitMyAudioDescription) {

// This is called when the local user's audio description is updated.
// Write your own code here.

}


func didUpdateVideoStatus(_ myMediaStatus: PlanetKitMyMediaStatus, status: PlanetKitVideoStatus) {

// This is called when the local user's video status is updated.
// Write your own code here.

}

//
// Also, you should implement other methods defined in the PlanetKitMyMediaStatusDelegate protocol.
//
...
}

로컬 사용자의 비디오 미리보기

미리보기 기능을 사용하면 로컬 사용자가 그룹 통화 세션과 관계없이 자신의 비디오를 미리 볼 수 있습니다.

로컬 사용자의 비디오 미리보기를 시작하려면 PlanetKitCameraManagerstartPreview()를 호출하세요.

func startPreviewExample(delegate: PlanetKitVideoOutputDelegate)
{
PlanetKitCameraManager.shared.startPreview(delegate)
}

로컬 사용자의 비디오 미리보기를 중지하려면 PlanetKitCameraManagerstopPreview()를 호출하세요.

func stopPreviewExample(delegate: PlanetKitVideoOutputDelegate)
{
PlanetKitCameraManager.shared.stopPreview(delegate)
}

통화 입장

그룹 통화에 입장하기 위한 절차는 다음과 같습니다.

  1. PlanetKitJoinConferenceSettingBuilder를 통해 설정 정보를 만드세요.
  2. PlanetKitConferenceDelegate를 포함하여 PlanetKitConferenceParam을 생성하고, mediaType 속성을 .audiovideo로 설정하세요.
  3. PlanetKitManager.shared.joinConference()를 호출하세요.
  4. PlanetKitConferenceJoinResult를 확인하세요.

로컬 사용자의 초기 비디오 상태는 PlanetKitConferenceParaminitialMyVideoState 속성으로 설정할 수 있습니다.

  • initialMyVideoState 속성의 기본값은 PlanetKitInitialMyVideoState.resume입니다.
  • initialMyVideoState 속성을 PlanetKitInitialMyVideoState.pause로 설정하여 로컬 사용자의 초기 비디오 상태가 일시 중지로 설정된 경우 로컬 사용자의 비디오는 전송되지 않습니다. 이 경우 로컬 사용자의 비디오는 통화가 연결된 후 resumeMyVideo()를 호출하여 전송할 수 있습니다.
Note

PlanetKit 6.0부터 iOS 애플리케이션에서는 통화 설정을 생성할 때 PlanetKitCallKitSetting에 CallKit 유형을 반드시 지정해야 합니다. CallKit 유형 지정에 대한 자세한 내용은 애플리케이션에서 CallKit 유형 설정을 참조하세요.

class ParticipantExample
{
var conference: PlanetKitConference?
var myMediaStatusDelegate: MyMediaStatusDelegateExample
}

...

extension ParticipantExample
{
func joinConferenceExample(myId: String, myServiceId: String, roomId: String, roomServiceId: String, accessToken: String, delegate: PlanetKitConferenceDelegate, initialMyVideoState: PlanetKitInitialMyVideoState) {
let myUserId = PlanetKitUserId(id: myId, serviceId: myServiceId)

// Configure CallKitSetting
let callKitSetting = createCallKitSetting()
var settingsBuilder = PlanetKitJoinConferenceSettingBuilder().withCallKitSettingsKey(setting: callKitSetting)
let settings = try! settingsBuilder.build()
let param = PlanetKitConferenceParam(myUserId: myUserId, roomId: roomId, roomServiceId: roomServiceId, displayName: nil, delegate: delegate, accessToken: accessToken)
param.mediaType = .audiovideo
param.initialMyVideoState = initialMyVideoState

let result = PlanetKitManager.shared.joinConference(param: param, settings: settings)

guard result.reason == .none else {
NSLog("Failed reason: result. \(result.reason)")
return
}

// The result.conference instance is a conference instance for calling other APIs from now on.
// You must keep this instance in your own context.
// In this example, the "conference" variable holds the instance.
conference = result.conference
}
}

로컬 사용자에 대한 미디어 상태 이벤트 대리자 설정

통화가 연결되면 로컬 사용자에 대한 미디어 상태 이벤트 대리자를 설정하세요.

extension ParticipantExample
{
func addMyMediaStatusHandlerExample() {
conference.myMediaStatus.addHandler(myMediaStatusDelegate) {
// completion callback
}
}
}

로컬 사용자를 위한 비디오 뷰 추가

로컬 사용자를 위한 비디오 뷰를 추가하려면 PlanetKitMTKView 인스턴스(myVideoView)를 생성하고 로컬 뷰에 하위 뷰로 추가한 다음 PlanetKitVideoStreamaddReceiver()로 로컬 사용자의 비디오 스트림을 받도록 설정하세요.

비디오 렌더링은 로컬 사용자의 비디오 상태에 따라 시작되거나 중지됩니다.

#if os(macOS)
typealias UIView = NSView
#endif

extension YourConferenceViewController {

@IBOutlet weak var localView: UIView!

var conference: PlanetKitConference!

...

func addMyVideoViewExample()
{
let myVideoView = PlanetKitMTKView(frame: localView.bounds, device: nil)
localView.addSubview(myVideoView)

conference.myVideoStream.addReceiver(myVideoView)
}
}

피어를 위한 비디오 뷰 추가

피어를 위한 비디오 뷰를 추가하려면 PlanetKitMTKView 인스턴스(peerVideoView)를 생성하고 피어 뷰에 하위 뷰로 추가하세요.

#if os(macOS)
typealias UIView = NSView
#endif

class YourPeerView: UIView {

@IBOutlet weak var peerView: UIView!

var peerVideoView: PlanetKitMTKView!

...

override public func awakeFromNib() {
super.awakeFromNib()

peerVideoView = PlanetKitMTKView(frame: peerView.bounds, device: nil)
peerVideoView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
peerView.addSubview(peerVideoView)
}
}

각 피어에 대한 피어 컨트롤 생성

피어 목록이 업데이트되면 새로 추가된 피어에 대해 PlanetKitPeerControl을 생성하고 PlanetKitPeerControlDelegate 객체를 등록하세요. PlanetKitPeerControlDelegate를 사용하여 각 피어의 상태 변경을 처리할 수 있습니다.

#if os(macOS)
typealias UIView = NSView
#endif

class YourPeerView: UIView {

...

var peerControl: PlanetKitPeerControl?
var peerVideoView: PlanetKitMTKView!

...

func setupPeerControl(for peer: PlanetKitConferencePeer, in conference: PlanetKitConference) {
guard let peerControl = conference.createPeerControl(peer: peer) else {
return
}

peerControl.register(self) { success in
// Write your own code here.
}
self.peerControl = peerControl
}

func setVideoEnabled(_ enable: Bool) {
if enable {
peerControl.startVideo(maxResolution: .recommended, delegate: peerVideoView) { success in
// Write your own code here.
}
}
else {
peerControl.stopVideo() { success in
// Write your own code here.
}
}
}
}

extension YourPeerView: PlanetKitPeerControlDelegate {

func didMuteMic(_ peerControl: PlanetKitPeerControl) {

// This is called when the local user's audio is muted.
// Write your own code here.

}

func didUnmuteMic(_ peerControl: PlanetKitPeerControl) {

// This is called when the local user's audio is unmuted.
// Write your own code here.

}

func didUpdateVideo(_ peerControl: PlanetKitPeerControl, subgroup: PlanetKitSubgroup, status: PlanetKitVideoStatus) {
DispatchQueue.main.async {
self.setVideoEnabled(status.isEnabled)

// This is called when the local user's video status is changed.
// Write your own code here.
}
}

//
// Also, you should implement other methods defined in the PlanetKitPeerControlDelegate protocol.
//
...
}

그룹 통화 퇴장

그룹 통화에서 퇴장하려면 leaveConference()를 호출하세요.

extension ParticipantExample
{
func leaveConferenceExample() {
conference?.leaveConference()
}
}

애플리케이션에서 CallKit 유형 설정

CallKit은 통화 인터페이스를 제공하는 Apple의 프레임워크입니다. PlanetKit SDK는 CallKit 연동을 위해 아래 세 가지 옵션을 지원합니다.

  1. 사용자 정의 CallKit 구현
  2. PlanetKit 내부 CallKit 구현
  3. CallKit 연동하지 않음

PlanetKit SDK를 사용하여 통화를 생성하거나 수신할 때, PlanetKitCallKitSetting에 CallKit 유형을 지정해야 합니다.

PlanetKitCallKitTypeuser 또는 planetkit으로 설정된 경우, PlanetKit은 마이크 표시기의 제어를 CallKit에 위임한다는 점을 유의하시기 바랍니다.

PlanetKitCallKitType 설정 예제

func createCallKitSetting() -> PlanetKitCallKitSetting  {
// Select the appropriate CallKit integration option from the examples below
// when integrating the user CallKit implementation.
let callKitSetting = PlanetKitCallKitSetting(type: .user, param: nil)

// when using PlanetKit internal CallKit implementation.
let callkitParam = PlanetKitCallKitParam(appName: "Example app", callerName: "caller name", isVideo: true, ringtoneSound: nil, icon: "example icon", addCallToList: true, supportsHolding: true)
let callKitSetting = PlanetKitCallKitSetting(type: .planetkit, param: callkitParam)

// when CallKit is not used in the app.
let callKitSetting = PlanetKitCallKitSetting(type: .none, param: nil)

return callKitSetting
}

애플리케이션에서 Apple CallKit 구현

다음 예제는 사용자 정의 CallKit 구현을 PlanetKit에 연동하는 방법에 대한 가이드입니다.

사용자 정의 CallKit 구현을 연동할 때, CallKit과 PlanetKit 간에 음 소거 상태와 같은 통화 상태를 동기화하는 것이 중요합니다.

  1. PlanetKitCallKitSetting 인스턴스를 생성하고 PlanetKitCallKitSettingtypeuser로 설정하세요.

  2. PlanetKitJoinConferenceSettingBuilderwithCallKitSettingsKey()에 인스턴스를 전달하고 설정 정보를 만드세요.

    // Code for Step 1 and Step 2

    func createJoinConferenceSettingsWithUserCallKitExample() -> [String: Any] {
    let callKitSetting = PlanetKitCallKitSetting(type: .user, param: nil)

    var settingsBuilder = PlanetKitJoinConferenceSettingBuilder().withCallKitSettingsKey(setting: callKitSetting)

    let joinConferenceSettings = try! settingsBuilder.build()

    return joinConferenceSettings
    }
  3. CallKit 동작을 처리하기 위한 CallKit 핸들러를 구현하세요. conference 변수는 그룹 통화에 입장할 때 얻은 PlanetKitConference 인스턴스입니다.

    class YourCallKitHandler {
    static let shared = YourCallKitHandler()

    private var provider: CXProvider
    private var callController: CXCallController
    private var conference: PlanetKitConference
    ...
    // Implement initialization and other features to handle CallKit operations.
    }
  4. CXProviderDelegateprovider(_:didActivate:)에서 PlanetKitConferencenotifyCallKitAudioActivation()을 호출하세요.

    extension YourCallKitHandler : CXProviderDelegate {

    ...

    func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
    conference.notifyCallKitAudioActivation()
    }

    // Implement other delegate functions to handle other CXCallActions
    ...
    }
  5. CallKit으로 CXCallAction이 수행될 때 관련 PlanetKitConference 함수를 호출하세요.

    extension YourCallKitHandler : CXProviderDelegate {

    ...

    func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
    conference.leaveConference()
    action.fulfill()
    }

    func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
    conference.muteMyAudio(action.isMuted) { success in
    guard success else {
    action.fail()
    return
    }
    action.fulfill()
    }
    }

    func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
    if action.isOnHold {
    conference.hold(reason: nil) { success in
    guard success else {
    action.fail()
    return
    }
    action.fulfill()
    }
    }
    else {
    conference.unhold() { success in
    guard success else {
    action.fail()
    return
    }
    action.fulfill()
    }
    }
    }
    // Implement other delegate functions to handle other CXCallActions
    ...
    }
  6. CallKit과 PlanetKit을 동기화하기 위해 CallKit을 통해 관련 CXCallAction을 요청하세요.

    extension YourCallViewController {
    @IBAction func muteCall(_ sender: UIButton) {
    conference.muteMyAudio() { success in
    if success {
    YourCallKitHandler.shared.muteCall()
    }
    }
    }
    @IBAction func holdCall(_sender: UIButton) {
    conference.hold(reason: nil) { success in
    if success {
    YourCallKitHandler.shared.holdCall()
    }
    }
    }
    }

    extension YourCallKitHandler {
    func muteCall() {
    let action = CXSetMutedCallAction(call: call.uuid , muted: true)
    callController.requestTransaction(with: action) { error in
    NSLog("\(error)")
    }
    }

    func holdCall() {
    let action = CXSetHeldCallAction(call: call.uuid, onHold: true)
    callController.requestTransaction(with: action) { error in
    NSLog("\(error)")
    }
    }
    }

상세한 정보는 CallKit 문서를 참고하세요.

관련 예제 코드

관련 문서