Skip to main content
Version: 7.1

Audio device selection

On macOS, PlanetKit lets you list audio devices and select the microphone and speaker independently for 1-to-1 and group calls through PlanetKitAudioManager.

Supported call typeMinimum SDK version
1-to-1 call, group call (conference)PlanetKit 6.0
Note
  • At startup, PlanetKit selects a preferred default for each device type. This is normally the macOS default device. If the system default is an aggregate device or cannot be obtained, PlanetKit tries the first non-aggregate device in its list with the relevant input or output channels. If no suitable device is available, the current selection is empty.
  • Audio device selection is a macOS-only feature. On iOS, use audio route control instead.

List available devices​

To list all audio devices, read the devices property of PlanetKitAudioManager. Filter the list by isCapturable or isPlayable when presenting devices that the user can select as a microphone or speaker. A device with input or output channels is not necessarily selectable for that purpose.

let audioManager = PlanetKitAudioManager.shared

let microphones = audioManager.devices.filter { $0.isCapturable }
let speakers = audioManager.devices.filter { $0.isPlayable }

for device in microphones {
print("Microphone: \(device.name ?? "Unknown") (\(device.deviceID))")
}
for device in speakers {
print("Speaker: \(device.name ?? "Unknown") (\(device.deviceID))")
}

To inspect a device, use these PlanetKitAudioDevice properties:

PropertyDescription
deviceIDDevice identifier
nameDisplay name, when available
inputChannelCount, outputChannelCountNumber of input and output channels
isCapturable, isPlayableWhether PlanetKit accepts the device as a microphone or speaker
isAggregateTypeWhether the device is an aggregate device, which PlanetKit does not allow as a microphone or speaker

Check the current selection​

To check which microphone and speaker are selected from the device list, read the micDevice and speakerDevice properties of PlanetKitAudioSession. Either property returns nil when no device is selected for that type or when a custom microphone or speaker is active for that type. A nil value alone does not indicate whether audio capture or playback is disabled.

let session = PlanetKitAudioManager.shared.session

if let mic = session.micDevice {
print("Current microphone: \(mic.name ?? "Unknown")")
}
if let speaker = session.speakerDevice {
print("Current speaker: \(speaker.name ?? "Unknown")")
}

Select a device​

Pass a device from the list to the change(micDevice:completion:) or change(speakerDevice:completion:) method of PlanetKitAudioSession. The completion handler runs on the main queue; a nil error indicates success.

let audioManager = PlanetKitAudioManager.shared
let session = audioManager.session

if let microphone = audioManager.devices.first(where: { $0.isCapturable }) {
session.change(micDevice: microphone) { error in
if let error = error {
print("Could not select microphone: \(error)")
}
}
}

if let speaker = audioManager.devices.first(where: { $0.isPlayable }) {
session.change(speakerDevice: speaker) { error in
if let error = error {
print("Could not select speaker: \(error)")
}
}
}

If you pass a device that is not selectable for the requested type, including an aggregate device, the completion handler receives an error and the previous selection remains. Changing a device also fails while a custom microphone or speaker is active for that type.

Deselect a device​

Pass nil to the corresponding change(micDevice:completion:) or change(speakerDevice:completion:) method of PlanetKitAudioSession to disable the microphone or speaker selection. This is separate from muting and does not restore the default device.

let session = PlanetKitAudioManager.shared.session

session.change(micDevice: nil) { error in
if let error = error {
print("Could not deselect microphone: \(error)")
}
}

session.change(speakerDevice: nil) { error in
if let error = error {
print("Could not deselect speaker: \(error)")
}
}

After a successful completion, the corresponding micDevice or speakerDevice is nil. A later device-list change can cause PlanetKit to select its preferred default again.

Return to the preferred default​

Call setPreferredDefaultDevice(type:) on PlanetKitAudioSession for each device type you want to reset.

let session = PlanetKitAudioManager.shared.session

// Asynchronously switches to the preferred default microphone device.
session.setPreferredDefaultDevice(type: .mic)

// Asynchronously switches to the preferred default speaker device.
session.setPreferredDefaultDevice(type: .speaker)

PlanetKit uses the current macOS default when it is suitable. If that device is an aggregate device or unavailable, it uses the first non-aggregate device in its list with the relevant channels. The selected candidate must also be isCapturable or isPlayable; otherwise the existing selection remains. This method has no completion handler. Check micDevice or speakerDevice and observe device-change events to learn the result.

Changing the macOS default device by itself does not change a still-available device that your app already selected.

Observe device changes​

Call addDeviceChangeDelegate(_:) on PlanetKitAudioManager to register a PlanetKitAudioDeviceChangeDelegate and update your device picker when the list, current selection, or macOS default changes. The data-source callback is optional and applies to built-in devices that expose distinct input sources or output destinations, such as internal speakers and headphones.

If you update the device picker or other UI from a delegate callback, dispatch the update to the main queue with DispatchQueue.main.async.

final class AudioDeviceObserver: NSObject, PlanetKitAudioDeviceChangeDelegate {
func didAudioDevicesUpdate(devices: [PlanetKitAudioDevice]) {
print("Available devices: \(devices.count)")
}

func didAudioDeviceChange(device: PlanetKitAudioDevice?, type: PlanetKitAudioDeviceType) {
print("Current \(type) changed to \(device?.name ?? "none")")
}

func didAudioDefaultSystemDeviceChange(device: PlanetKitAudioDevice?, type: PlanetKitAudioDeviceType) {
print("macOS default \(type) changed to \(device?.name ?? "none")")
}

func didAudioDeviceDataSourceChange(device: PlanetKitAudioDevice, dataSource: UInt32) {
print("Data source for \(device.name ?? "Unknown"): \(dataSource)")
}
}

let observer = AudioDeviceObserver()
PlanetKitAudioManager.shared.addDeviceChangeDelegate(observer)

// Keep observer alive while registered. When no longer needed:
PlanetKitAudioManager.shared.removeDeviceChangeDelegate(observer)

When a selected device is disconnected​

With the default configuration, if a microphone or speaker selected from the device list is disconnected, PlanetKit attempts to switch to its preferred default for that type.

PlanetKit calls didAudioDevicesUpdate(devices:) with the updated list before attempting that switch. Refresh the available-device list in this callback, but do not treat micDevice or speakerDevice read there as the final selection. Update the UI that shows the current device selection in didAudioDeviceChange(device:type:).

APIs related to audio device selection are as follows.

Classes and protocols​

Enum​

Properties​

Methods​

Events​