Release notes
This page provides the release notes of PlanetKit 6.0 for iOS/macOS.
PlanetKit 6.0
Release date: 2025-05-16
Enhance the camera delegate interface
Updated the PlanetKitCameraDelegate
protocol to provide more detailed information about video capture devices through the PlanetKitVideoCaptureDeviceInfo
parameter.
API
Changed
-
PlanetKitCameraDelegate
protocol 1-to-1 callGroup callPrevious PlanetKit 6.0 func didStart()
func didStart(_ deviceInfo: PlanetKitVideoCaptureDeviceInfo)
func didStop(_ error: NSError?)
func didStop(_ deviceInfo: PlanetKitVideoCaptureDeviceInfo)
Added
PlanetKitCameraDelegate
protocol 1-to-1 callGroup callfunc didUpdate(_ deviceInfo: PlanetKitVideoCaptureDeviceInfo?)
func didFail(_ error: NSError, deviceInfo: PlanetKitVideoCaptureDeviceInfo?)
Improve the video capability configuration API
Video capability configuration has been centralized through the PlanetKitManager
and made more consistent with clearer API naming.
- Video hardware codec settings are now configured through
PlanetKitManager
instead of setting them for each 1-to-1 call or group call individually. - Thumbnail resolution can no longer be used in video capability configuration API.
API
Changed
-
PlanetKitVideoCapability
class 1-to-1 callGroup callPrevious PlanetKit 6.0 var resolution: PlanetKitVideoResolutionCapability { get set }
var maxResolution: PlanetKitVideoResolutionCapability { get }
var fps: PlanetKitVideoFps { get set }
var maxFps: PlanetKitVideoFps { get }
init(resolution: PlanetKitVideoResolutionCapability, fps: PlanetKitVideoFps)
init(maxResolution: PlanetKitVideoResolutionCapability, maxFps: PlanetKitVideoFps)
-
Parameter renaming 1-to-1 callGroup call
Previous PlanetKit 6.0 PlanetKitCallConnectedParam.isVideoHwCodecEnabled
PlanetKitCallConnectedParam.isVideoHardwareCodecEnabled
PlanetKitConferenceConnectedParam.isVideoHwCodecEnabled
PlanetKitConferenceConnectedParam.isVideoHardwareCodecEnabled
Added
PlanetKitVideoResolutionCapability
enum 1-to-1 callGroup callcase qvga
- Maximum resolution of 320x240case vga
- Maximum resolution of 640x480case hd
- Maximum resolution of 1280x960case fhd
- Maximum resolution of 1920x1080
PlanetKitVideoCapabilityUsage
enum 1-to-1 callGroup callcase callSend
case callReceive
case conferenceSend
case conferenceReceive
PlanetKitPreferredHardwareCodec
class 1-to-1 callGroup callvar callVideoSend: Bool { get }
var callVideoReceive: Bool { get }
var conferenceVideoSend: Bool { get }
var conferenceVideoReceive: Bool { get }
init(callVideoSend: Bool, callVideoReceive: Bool, conferenceVideoSend: Bool, conferenceVideoReceive: Bool)
PlanetKitManager
class 1-to-1 callGroup callfunc getDeviceDefaultVideoCapability(usage: PlanetKitVideoCapabilityUsage) -> PlanetKitVideoCapability
func getVideoPreferredHardwareCodec() -> PlanetKitPreferredHardwareCodec
PlanetKitInitialSettingBuilder
class 1-to-1 callGroup callfunc withSetPreferredHardwareCodecKey(preferredHardwareCodec: PlanetKitPreferredHardwareCodec) -> PlanetKitInitialSettingBuilder
Removed
PlanetKitCall
class 1-to-1 callvar myVideoSendCapability: PlanetKitVideoCapability { get }
var myVideoReceiveCapability: PlanetKitVideoCapability { get }
PlanetKitConference
class Group callvar myVideoSendCapability: PlanetKitVideoCapability { get }
var myVideoRecvPreferredHwCodec: Bool { get }
PlanetKitVideoCapability
class 1-to-1 callGroup callvar preferredHwCodec: Bool
static var callSendDefault: PlanetKitVideoCapability
static var callReceiveDefault: PlanetKitVideoCapability
static var conferenceSendDefault: PlanetKitVideoCapability
PlanetKitJoinConferenceSettingBuilder
extension Group callfunc withMyVideoRecvPreferredHwCodecKey(enable: Bool) -> PlanetKitJoinConferenceSettingBuilder
Migration guide
Configure hardware codec settings on PlanetKit initialization
-
Previous version:
// Configure hardware codec for specific call/conference
let callSettings = PlanetKitMakeCallSettingBuilder()
.withVideoSendCapabilityKey(capability: capability)
.build()
let conferenceSettings = PlanetKitJoinConferenceSettingBuilder()
.withMyVideoRecvPreferredHwCodecKey(enable: true)
.build() -
New version:
// 1. Create hardware codec preferences
let preferredHardwareCodec = PlanetKitPreferredHardwareCodec(
callVideoSend: true,
callVideoReceive: true,
conferenceVideoSend: true,
conferenceVideoReceive: true
)
// 2. Configure during initialization
let initializeSettings = PlanetKitInitializeSettingsBuilder()
.withSetPreferredHardwareCodecKey(preferredHardwareCodec: preferredHardwareCodec)
.build()
PlanetKitManager.shared.initialize(initialSettings: initializeSettings)
Update hardware codec settings after initialization
// 1. Create new hardware codec preferences
let preferredHardwareCodec = PlanetKitPreferredHardwareCodec(
callVideoSend: true,
callVideoReceive: true,
conferenceVideoSend: true,
conferenceVideoReceive: true
)
// 2. Update settings
let newSettings = PlanetKitInitializeSettingsBuilder()
.withSetPreferredHardwareCodecKey(preferredHardwareCodec: preferredHardwareCodec)
.build()
PlanetKitManager.shared.update(initialSettings: newSettings)
Get the default video capability for the device
// Get default capability for call sending
let callSendCapability = PlanetKitManager.shared.getDeviceDefaultVideoCapability(usage: .callSend)
// Get default capability for conference receiving
let conferenceReceiveCapability = PlanetKitManager.shared.getDeviceDefaultVideoCapability(usage: .conferenceReceive)
Get the current hardware codec settings
let hardwareCodecSettings = PlanetKitManager.shared.getVideoPreferredHardwareCodec()
let isHardwareEnabledForCallSend = hardwareCodecSettings.callVideoSend
Improve API for setting the volume of the conference peer
Replaced the previous subgroup-based volume control with a unified volume setting API for individual peers.
- In versions prior to 6.0, volume was controlled per subgroup. Starting from version 6.0, volume can now be set independently of subgroups.
- Due to this specification change, related API modifications have been made.
API
Changed
-
PlanetKitConferencePeer
class Group callPrevious PlanetKit 6.0 func volumeLevelSetting(subgroupName: String?) throws -> PlanetKitVolumeLevel
func volumeLevelSetting() throws -> PlanetKitVolumeLevel
Added
PlanetKitConferencePeerControl
class Group callfunc setVolumeLevelSetting(_ volumeLevel: Int8, completion: @escaping (Bool)->Void)
Removed
PlanetKitSubgroupManager
class Group callfunc setPeerVolumeLevelSetting(_ volumeLevel: Int8, peerId: PlanetKitUserId, subgroupName: String?, allSubgroupsPeerSubscribed: Bool, completion: @escaping (Bool)->Void)
Control the microphone device based on microphone usage during a call
- When the microphone is not in use during a call (e.g., mute or hold), PlanetKit turns off the microphone device.
- The audio management system has been refactored to provide better separation of concerns:
PlanetKitAudioSession
maintains core audio session functionalityPlanetKitAudioManager
provides high-level audio control features
For more information, please refer to the API documentation.
Known issue
On macOS 12 and 13, the microphone indicator stays on even when the call is muted or on hold. In this state, no audio data is transmitted to the peer.
API
Changed
-
Refactored audio management system 1-to-1 callGroup call
- Core audio session functionality moved to
PlanetKitAudioSession
- High-level audio control features provided by
PlanetKitAudioManager
- Core audio session functionality moved to
-
PlanetKitAudioDeviceType
enum 1-to-1 callGroup callPrevious PlanetKit 6.0 case spk
case speaker
-
PlanetKitMakeCallSettingBuilder
class 1-to-1 callPrevious PlanetKit 6.0 func build() -> [String: Any]
func build() throws -> [String: Any]
(iOS only) -
PlanetKitVerifyCallSettingBuilder
class 1-to-1 callPrevious PlanetKit 6.0 func build() -> [String: Any]
func build() throws -> [String: Any]
(iOS only) -
PlanetKitJoinConferenceSettingBuilder
class Group callPrevious PlanetKit 6.0 func build() -> [String: Any]
func build() throws -> [String: Any]
(iOS only)
Added
PlanetKitAudioManager
class 1-to-1 callGroup callstatic var shared: PlanetKitAudioManager { get }
var session: PlanetKitAudioSession { get }
func startMicPreview(_ preview: PlanetKitAudioMicPreviewDelegate, volumeInternal: TimeInterval = 1.0) -> Bool
func stopMicPreview()
func playFile(fileResourceUrl: URL, type: String, loopCount: Int32 = -1)
func playFile(fileResourceUrl: URL, type: String, loopCount: Int32, completion: @escaping (Bool) -> Void)
func playStop(type: String)
func setCustomMic(_ customMic: PlanetKitCustomMic)
func resetCustomMicToDefaultMic()
func setCustomSpeaker(_ customSpeaker: PlanetKitCustomSpeaker)
func resetCustomSpeakerToDefaultSpeaker()
func addVolumeDelegate(_ delegate: PlanetKitAudioVolumeDelegate, for type: PlanetKitAudioDeviceType)
func removeVolumeDelegate(_ delegate: PlanetKitAudioVolumeDelegate, for type: PlanetKitAudioDeviceType)
var vpioEnabled: Bool { get set }
var defaultMicSampleRate: Float64 { get set }
var defaultSpeakerSampleRate: Float64 { get set }
var openSettings: PlanetKitAudioSessionSettings? { get set }
var closeSettings: PlanetKitAudioSessionSettings? { get set }
var defaultIOBufferDuration: Float64 { get set }
var micVolume: Float { get }
var speakerVolume: Float { get }
func setMicVolume(_ volume: Float)
func addAudioRouteChangeDelegate(_ delegate: PlanetKitAudioRouteChangeDelegate)
func removeAudioRouteChangeDelegate(_ delegate: PlanetKitAudioRouteChangeDelegate)
var isBluetoothInput: Bool { get }
var isBuiltInOutput: Bool { get }
var devices: [PlanetKitAudioDevice] { get }
func addDeviceChangeDelegate(_ delegate: PlanetKitAudioDeviceChangeDelegate)
func removeDeviceChangeDelegate(_ delegate: PlanetKitAudioDeviceChangeDelegate)
PlanetKitAudioSession
class 1-to-1 callGroup callvar micEnabled: Bool { get }
var speakerEnabled: Bool { get }
var isStarted: Bool { get }
func addMicReceiver(_ micReceiver: PlanetKitAudioMicCaptureDelegate)
func removeMicReceiver(_ micReceiver: PlanetKitAudioMicCaptureDelegate)
var micModifier: PlanetKitAudioMicCaptureDelegate? { get set }
func addSpeakerReceiver(_ speakerReceiver: PlanetKitAudioSpkPlayDelegate)
func removeSpeakerReceiver(_ speakerReceiver: PlanetKitAudioSpkPlayDelegate)
var speakerModifier: PlanetKitAudioSpkPlayDelegate? { get set }
var speakerVolumeReceiver: PlanetKitAudioDeviceVolumeDelegate? { get set }
var speakerVolumeInterval: TimeInterval { get set }
func speakerOut(_ out: Bool)
var isSpeakerOut: Bool
var micDevice: PlanetKitAudioDevice? { get }
var speakerDevice: PlanetKitAudioDevice? { get }
var micVolume: Float { get }
var speakerVolume: Float { get }
func setVolume(_ volume: Float, for type: PlanetKitAudioDeviceType)
func change(micDevice: PlanetKitAudioDevice?, completion: @escaping (NSError?)->Void)
func change(speakerDevice: PlanetKitAudioDevice?, completion: @escaping (NSError?)->Void)
func setPreferredDefaultDevice(type: PlanetKitAudioDeviceType) throws
PlanetKitCustomMic
class 1-to-1 callGroup callfunc sendAudio(audioBuffer: PlanetKitAudioBuffer)
PlanetKitCustomSpeaker
class 1-to-1 callGroup callfunc playAudio(audioBuffer: PlanetKitAudioBuffer) -> Int32
PlanetKitAudioBuffer
class 1-to-1 callGroup call- Properties for storing and managing audio data
- Multiple initializers for creating audio buffers
PlanetKitAudioMicPreviewDelegate
protocol 1-to-1 callGroup callfunc volumeDidUpdate(micVolume: Float)
Removed
PlanetKitAudioMic
class 1-to-1 callGroup callPlanetKitAudioSpk
class 1-to-1 callGroup callPlanetKitAudioMicSpk
class 1-to-1 callGroup callPlanetKitAudioMicControllable
protocol 1-to-1 callGroup callPlanetKitAudioSpkControllable
protocol 1-to-1 callGroup callPlanetKitCall
class 1-to-1 callvar audioManager: PlanetKitAudioManager { get }
weak var spkModifier: PlanetKitAudioSpkPlayDelegate? { get set }
weak var spkReceiver: PlanetKitAudioSpkPlayDelegate? { get set }
weak var micModifier: PlanetKitAudioMicCaptureDelegate? { get set }
weak var micReceiver: PlanetKitAudioMicCaptureDelegate? { get set }
PlanetKitConference
class Group callvar audioManager: PlanetKitAudioManager { get }
weak var spkModifier: PlanetKitAudioSpkPlayDelegate? { get set }
weak var spkReceiver: PlanetKitAudioSpkPlayDelegate? { get set }
weak var micModifier: PlanetKitAudioMicCaptureDelegate? { get set }
weak var micReceiver: PlanetKitAudioMicCaptureDelegate? { get set }
PlanetKitMakeCallSettingBuilder
class 1-to-1 callfunc withCustomMicKey(mic: PlanetKitAudioMicControllable) -> PlanetKitMakeCallSettingBuilder
func withCustomSpkKey(spk: PlanetKitAudioSpkControllable) -> PlanetKitMakeCallSettingBuilder
PlanetKitVerifyCallSettingBuilder
class 1-to-1 callfunc withCustomMicKey(mic: PlanetKitAudioMicControllable) -> PlanetKitVerifyCallSettingBuilder
func withCustomSpkKey(spk: PlanetKitAudioSpkControllable) -> PlanetKitVerifyCallSettingBuilder
PlanetKitJoinConferenceSettingBuilder
class Group callfunc withCustomMicKey(mic: PlanetKitAudioMicControllable) -> PlanetKitJoinConferenceSettingBuilder
func withCustomSpkKey(spk: PlanetKitAudioSpkControllable) -> PlanetKitJoinConferenceSettingBuilder
Example code
Previewing the volume of mic/speaker devices in audio settings
class ViewController: UIViewController {
....
override func viewDidLoad() {
super.viewDidLoad()
let currentMicVolume = PlanetKitAudioManager.shared.session.micVolume
let currentSpeakerVolume = PlanetKitAudioManager.shared.session.speakerVolume
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
PlanetKitAudioManager.shared.addVolumeDelegate(self, for: .mic)
PlanetKitAudioManager.shared.addVolumeDelegate(self, for: .speaker)
PlanetKitAudioManager.shared.startMicPreview(self, volumeInternal: 0.1)
}
override func viewDidDisappear() {
super.viewDidDisappear()
PlanetKitAudioManager.shared.removeVolumeDelegate(self, for: .mic)
PlanetKitAudioManager.shared.removeVolumeDelegate(self, for: .speaker)
PlanetKitAudioManager.shared.stopMicPreview()
}
}
extension ViewController: PlanetKitAudioMicPreviewDelegate {
func volumeDidUpdate(micVolume: Float) {
DispatchQueue.main.async {
// TODO: Update mic volume level in the UI.
}
}
}
extension ViewController: PlanetKitAudioVolumeDelegate {
func didChangeVolume(_ type: PlanetKitAudioDeviceType, volume: Float) {
DispatchQueue.main.async {
// TODO: Update mic/speaker volume in the UI.
}
}
}
Using the custom mic
class YourCustomMicManager {
....
func setCustomMic() {
var input = AudioFileInput(url: url, call: call)
PlanetKitAudioManager.shared.setCustomMic(input)
}
func resetMic(_ device: PlanetKitAudioDevice?) {
PlanetKitAudioManager.shared.resetCustomMicToDefaultMic()
guard device?.deviceID != PlanetKitAudioManager.shared.session.micDevice?.deviceID else {
return
}
PlanetKitAudioManager.shared.session.change(micDevice: device) { error in
if let error = error {
print(error)
}
}
}
}
// TODO: Implement your own custom mic.
class AudioFileInput: PlanetKitCustomMic {
init(url: URL, call: PlanetKitCall) {
....
}
}
(macOS only) Retrieving the list of mic/speaker devices
....
private var micDevices = [PlanetKitAudioDevice]()
private var speakerDevices = [PlanetKitAudioDevice]()
func refreshDevices() {
micDevices.removeAll()
speakerDevices.removeAll()
let devices = PlanetKitAudioManager.shared.devices
for device in devices {
if device.isCapturable {
micDevices.append(device)
}
if device.isPlayable {
speakerDevices.append(device)
}
}
if let micDevice = PlanetKitAudioManager.shared.session.micDevice {
refreshCurrentDevice(micDevice, type: .mic)
}
if let speakerDevice = PlanetKitAudioManager.shared.session.speakerDevice {
refreshCurrentDevice(speakerDevice, type: .speaker)
}
}
func refreshCurrentDevice(_ device: PlanetKitAudioDevice?, type: PlanetKitAudioDeviceType) {
// TODO: Update the current audio device in the UI.
}
(macOS only) Observing changes in mic/speaker devices
class ViewController: UIViewController {
....
override func viewWillAppear() {
super.viewWillAppear()
PlanetKitAudioManager.shared.addDeviceChangeDelegate(self)
}
override func viewDidDisappear() {
super.viewDidDisappear()
PlanetKitAudioManager.shared.removeDeviceChangeDelegate(self)
}
}
extension ViewController: PlanetKitAudioDeviceChangeDelegate {
func didAudioDevicesUpdate(devices: [PlanetKitAudioDevice]) {
DispatchQueue.main.async {
self.refreshDevices()
}
}
func didAudioDeviceChange(device: PlanetKitAudioDevice?, type: PlanetKitAudioDeviceType) {
DispatchQueue.main.async {
// TODO: Update the currently selected audio device in the UI.
}
}
....
}
(macOS only) Changing the current mic/speaker device
....
@IBAction func deviceChanged(_ sender: NSPopUpButton) {
if sender === micDevicesButton {
let device = micDevices[sender.indexOfSelectedItem]
PlanetKitAudioManager.shared.session.change(micDevice: device) { error in
if let error = error {
print(error)
}
}
}
else {
let device = speakerDevices[sender.indexOfSelectedItem]
PlanetKitAudioManager.shared.session.change(speakerDevice: device) { error in
if let error = error {
print(error)
}
}
}
}
Enhance the API for switching camera devices
When using a custom camera, it is not possible to switch from the current camera device to another camera device. The related API has been enhanced so that a corresponding error is thrown.
API
Changed
-
PlanetKitCameraManager
class 1-to-1 callGroup callPrevious PlanetKit 6.0 func change(deviceInfo: PlanetKitVideoCaptureDeviceInfo)
func change(deviceInfo: PlanetKitVideoCaptureDeviceInfo) throws
Rename custom camera API
The function name for switching from a custom camera to the default camera has been changed to have a clearer meaning.
API
Changed
-
PlanetKitCameraManager
class 1-to-1 callGroup callPrevious PlanetKit 6.0 func resetToDefaultCamera()
func resetCustomCameraToDefaultCamera()
Add a feature to check cloud call recording activation during call reception
- Added a field to
PlanetKitCCParam
to indicate whether cloud recording is activated when receiving a call.
API
Added
PlanetKitCCParam
class 1-to-1 callvar isRecordOnCloudEnabled: Bool
Remove the API to set the response type when the video call is enabled
- When a video call is activated by the peer in a 1-to-1 audio call, the local user's video is always set to paused state.
- In previous versions, you could use
withResponseOnEnableVideo()
to automatically decide whether to start sending the local user's video when the peer switched an audio call to a video call. - However, this API has been removed in version 6.0, due to privacy concerns and potential misuse, and
PlanetKitCallDelegate.videoEnabledByPeer
has been changed toPlanetKitCallDelegate.videoEnabledByPeerAndMyVideoPaused
. - From version 6.0 onward, when a video call is enabled by the peer, the local user's video will remain paused.
- In previous versions, you could use
- If you previously relied on
PlanetKitResponseOnEnableVideo.send
, please update your implementation to manually resume video after receiving thevideoEnabledByPeerAndMyVideoPaused
event.- Refer to the following example for guidance.
Example code
- To replicate the behavior of the previous
PlanetKitResponseOnEnableVideo.send
setting, do as follows:
class CallDelegate: PlanetKitCallDelegate {
func videoEnabledByPeerAndMyVideoPaused(_ call: PlanetKitCall) {
// Your existing code...
// Add this to replicate PlanetKitResponseOnEnableVideo.send behavior
call.resumeMyVideo()
}
}
API
Changed
-
PlanetKitCallDelegate
protocol 1-to-1 callPrevious PlanetKit 6.0.0 func videoEnabledByPeer(_ call: PlanetKitCall)
func videoEnabledByPeerAndMyVideoPaused(_ call: PlanetKitCall)
Removed
PlanetKitResponseOnEnableVideo
enum 1-to-1 callPlanetKitCall
class 1-to-1 callvar responseOnEnableVideo: PlanetKitResponseOnEnableVideo { get }
PlanetKitMakeCallSettingBuilder
class 1-to-1 callfunc withResponseOnEnableVideo(response: PlanetKitResponseOnEnableVideo)
PlanetKitVerifyCallSettingBuilder
class 1-to-1 callfunc withResponseOnEnableVideo(response: PlanetKitResponseOnEnableVideo)
Add PlanetKitSettingError
for error handling in settings builders
The PlanetKitSettingError
enum provides standardized error handling for setting builders.
API
Added
PlanetKitSettingError
enum 1-to-1 callGroup call
(iOS) Make PlanetKitCallKitSetting
mandatory when building call/conference settings
The PlanetKit SDK supports three CallKit integration options:
- User-defined CallKit implementation
- PlanetKit's internal CallKit implementation
- No CallKit integration
On iOS, PlanetKitCallKitSetting
must be configured with PlanetKitCallKitType
when building settings to make calls, verify calls, and join group calls. If not configured, PlanetKitSettingError.callKitSettingNotSet
will be thrown when building settings for calls with PlanetKitMakeCallSettingBuilder.build()
, PlanetKitVerifyCallSettingBuilder.build()
, or PlanetKitJoinConferenceSettingBuilder.build()
.
Please note that when PlanetKitCallKitType
is set to either .user
or .planetkit
, PlanetKit delegates control of the microphone indicator to CallKit.
API
Changed
-
PlanetKitMakeCallSettingBuilder
class 1-to-1 callPrevious PlanetKit 6.0 func build() -> [String: Any]
func build() throws -> [String: Any]
(iOS only) -
PlanetKitVerifyCallSettingBuilder
class 1-to-1 callPrevious PlanetKit 6.0 func build() -> [String: Any]
func build() throws -> [String: Any]
(iOS only) -
PlanetKitJoinConferenceSettingBuilder
class Group callPrevious PlanetKit 6.0 func build() -> [String: Any]
func build() throws -> [String: Any]
(iOS only)
Example code
Create PlanetKitCallKitSetting
depending on PlanetKitCallKitType
func createUserCallKitSetting() -> PlanetKitCallKitSetting {
// Select the appropriate CallKit integration option from the examples below
// Option 1: When integrating the user CallKit implementation
let callKitSetting = PlanetKitCallKitSetting(type: .user, param: nil)
// Option 2: 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)
// Option 3: When CallKit is not used in the app
let callKitSetting = PlanetKitCallKitSetting(type: .none, param: nil)
return callKitSetting
}