Group audio call
This page provides a code example for implementing a group audio call.
Prerequisites
Before you begin, you must do the following:
- Initialize PlanetKit.
- Get a proper access token.
- Check the overall API usage flow in Group call flow.
Considerations for implementing a group audio call
After calling joinConference()
, you must check the reason
property of the returned PlanetKitConferenceJoinResult
.
- If the
reason
isPlanetKitStartFailReason.none
, it means success. - Otherwise, it means failure and you must take an appropriate action based on the
reason
.
Implement event delegates
Implement the event delegates to be used on the call.
PlanetKitConferenceDelegate
is used to handle status change events of a group call.PlanetKitMyMediaStatusDelegate
is used to handle the local user's media status change events. You can update the local user's UI based on these events, such as when the mic becomes muted or unmuted, or when the audio description is updated.
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.
}
//
// 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.
}
//
// Also, you should implement other methods defined in the PlanetKitMyMediaStatusDelegate protocol.
//
...
}
Join a group call
The steps for joining a group call are as follows:
- Build a setting through
PlanetKitJoinConferenceSettingBuilder
. - Create
PlanetKitConferenceParam
withPlanetKitConferenceDelegate
. - Call
PlanetKitManager.shared.joinConference()
. - Check the
PlanetKitConferenceJoinResult
.
Starting with PlanetKit 6.0, you must specify the CallKit type in PlanetKitCallKitSetting
when building conference settings for iOS applications. For more information on specifying the CallKit type, refer to Configure CallKit type in the application.
class ParticipantExample
{
var conference: PlanetKitConference?
var myMediaStatusDelegate: MyMediaStatusDelegateExample
}
...
extension ParticipantExample
{
func joinConferenceExample(myId: String, myServiceId: String, roomId: String, roomServiceId: String, accessToken: String, delegate: PlanetKitConferenceDelegate) {
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)
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
}
}
Set the media status event delegate for the local user
Once the call is connected, add the media status event delegate for the local user.
extension ParticipantExample
{
func addMyMediaStatusHandlerExample() {
conference?.myMediaStatus.addHandler(myMediaStatusDelegate) {
// completion callback
}
}
}
Create peer control for each peer
When the peer list is updated, create PlanetKitPeerControl
for newly added peers and register a PlanetKitPeerControlDelegate
object. You can handle the status change of each peer using the 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
}
}
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.
}
//
// Also, you should implement other methods defined in the PlanetKitPeerControlDelegate protocol.
//
...
}
Leave a group call
To leave a group call, call leaveConference()
.
extension ParticipantExample
{
func leaveConferenceExample() {
conference?.leaveConference()
}
}
Configure CallKit type in the application
CallKit is an Apple framework that provides a calling interface. The PlanetKit SDK supports three CallKit integration options:
- User-defined CallKit implementation
- PlanetKit's internal CallKit implementation
- No CallKit integration
When using the PlanetKit SDK to make or verify calls, you must specify the CallKit type in PlanetKitCallKitSetting
.
Please note that when PlanetKitCallKitType
is set to either user
or planetkit
, PlanetKit delegates control of the microphone indicator to CallKit.
Example for configuring 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
}
Implement Apple CallKit in the application
The following example is a guide on how to integrate user implementation of CallKit to PlanetKit.
It's crucial to synchronize call states—such as the mute state—between CallKit and PlanetKit when integrating the user-defined CallKit implementation.
-
Create a
PlanetKitCallKitSetting
instance and settype
ofPlanetKitCallKitSetting
touser
. -
Pass the instance to
withCallKitSettingsKey()
ofPlanetKitJoinConferenceSettingBuilder
and build settings.// 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
} -
Implement a CallKit handler to handle CallKit operations. The
conference
variable is thePlanetKitConference
instance obtained from joining a group call.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.
} -
On
provider(_:didActivate:)
ofCXProviderDelegate
, callnotifyCallKitAudioActivation()
ofPlanetKitConference
.extension YourCallKitHandler : CXProviderDelegate {
...
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
conference.notifyCallKitAudioActivation()
}
// Implement other delegate functions to handle other CXCallActions
...
} -
Call the relevant
PlanetKitConference
functions when aCXCallAction
is performed with CallKit.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
...
} -
Request the relevant
CXCallAction
through CallKit to synchronize CallKit and PlanetKit.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)")
}
}
}
For more information, see CallKit documentation.