Skip to main content
Version: 7.1

Audio route control

On Android, audio routing determines whether audio plays through the speakerphone, the earpiece, a Bluetooth device, or a wired headset. PlanetKitAudioSwitch provides runtime control over the active audio route during a call.

Supported call typeMinimum SDK version
1-to-1 call, group call (conference)PlanetKit 3.7

Audio route values​

PlanetKit represents the current route with PlanetKitAudioRoute:

ValueDescription
UNDEFINEDRoute is undefined or has not been determined.
SPEAKERPhone speakerphone
HANDSETPhone earpiece
BLUETOOTHBluetooth audio device
PLUGGEDWired headset

Configure whether to control audio route​

PlanetKit manages the call audio route by default. To configure this behavior, set AudioDefaultAttributes.Builder.controlAudioRoute(), then supply the resulting attributes when you initialize PlanetKit.

val audioAttributes = AudioDefaultAttributes.Builder()
.controlAudioRoute(true) // Default: true
.build()

val configurationBuilder = PlanetKit.PlanetKitConfiguration.Builder(context)
// Configure the other required PlanetKit settings on configurationBuilder.
configurationBuilder.setAudioDefaultAttributes(audioAttributes)
val configuration = configurationBuilder.build()
// Pass configuration to PlanetKit.initialize(configuration, listener).

If you set controlAudioRoute(false), PlanetKit does not manage the call audio route. Route-selection requests through setAudioRoute() and setSpeakerOn() then return false.

To check or change the audio route during a call, obtain PlanetKitAudioSwitch from the active session.

// 1-to-1 call
val audioSwitch = call.getAudioSwitch()
// Group call
val audioSwitch = conference.getAudioSwitch()

PlanetKitAudioSwitch has the same lifetime as the PlanetKitCall or PlanetKitConference that created it.

Check the current and available routes​

Use selectedAudioRoute to read the current route and availableAudioRoutes to check the routes that are currently available.

Tip

If you only need the current selected route, use PlanetKitCall.audioRoute or PlanetKitConference.audioRoute. Each returns the same value as PlanetKitAudioSwitch.selectedAudioRoute; use PlanetKitAudioSwitch when you also need available routes or want to request a route change.

// Current active route
val current = audioSwitch.selectedAudioRoute
Log.d(TAG, "Current route: $current")

// Available routes at this moment
val available = audioSwitch.availableAudioRoutes
Log.d(TAG, "Available routes: $available")

Switch to a specific route​

Call setAudioRoute() on the PlanetKitAudioSwitch for an active call. The requested route must be in availableAudioRoutes. The return value indicates whether PlanetKit accepted the request and attempted a switch — it does not confirm that the route changed. After making the request, read selectedAudioRoute or use the route-change listener to check the route currently selected by PlanetKit. This value is PlanetKit's selection; it does not confirm that the OS has applied the route (for example, a Bluetooth SCO connection can take several seconds or fail). If PlanetKit later determines that the route is unavailable, it may deliver another route-change event.

val audioSwitch = call.getAudioSwitch()

// Request Bluetooth if available
if (audioSwitch.availableAudioRoutes.contains(PlanetKitAudioRoute.BLUETOOTH)) {
audioSwitch.setAudioRoute(PlanetKitAudioRoute.BLUETOOTH)
val selectedByPlanetKit = audioSwitch.selectedAudioRoute == PlanetKitAudioRoute.BLUETOOTH
Log.d(TAG, "Bluetooth selected by PlanetKit: $selectedByPlanetKit")
}

The return value of setAudioRoute() indicates the following:

  • true: PlanetKit accepted the request and attempted the switch. The route may still be unchanged — for example, when the OS rejects the switch.
  • false: The requested route is not in availableAudioRoutes, audio route control is disabled, or the requested route is already the current route.
Note

On Android 12 and later, a Bluetooth route can appear in availableAudioRoutes when the OS exposes it even if the app does not have Bluetooth-connect permission. In that case, PlanetKit does not select Bluetooth as the SDK audio route. Request the required Bluetooth permission before offering Bluetooth as a selectable route. Note that requesting Bluetooth route with setAudioRoute() without the permission still returns true, so use selectedAudioRoute instead of the return value to check which route PlanetKit selected.

Toggle speakerphone​

setSpeakerOn() is a convenience method that toggles between speakerphone and the highest-priority non-speaker route.

// Enable speakerphone
audioSwitch.setSpeakerOn(true)

// Disable speakerphone — falls back to highest-priority available route
audioSwitch.setSpeakerOn(false)

// Query current state
val isSpeakerOn = audioSwitch.isSpeakerOn

Configure route priority​

When PlanetKit needs to select a route automatically, it uses a priority list. Configure the list with setPreferredAudioRoutesAtDisconnect().

The priority list is used after an external device disconnects, when audio starts without an already-selected external route, when speakerphone is turned off, and when a video call is enabled without an external route. It does not determine behavior when a newly connected external device is detected: PlanetKit requests the new wired or Bluetooth route regardless of the list order.

If you do not configure a priority list, PlanetKit uses the following defaults:

Call typePriority order
Audio call/conferenceBLUETOOTH → PLUGGED → HANDSET → SPEAKER
Video call/conferenceBLUETOOTH → PLUGGED → SPEAKER → HANDSET

The list must contain all four selectable PlanetKitAudioRoute values exactly once, in your preferred priority order.

Configure the audio-call and video-call priority lists separately. Use whenOnVideoCall = true for the video-call priority list. The following example configures an audio-call priority list that prefers a wired headset when PlanetKit must choose a route automatically:

val audioSwitch = call.getAudioSwitch()

val audioCallPriority = listOf(
PlanetKitAudioRoute.PLUGGED,
PlanetKitAudioRoute.BLUETOOTH,
PlanetKitAudioRoute.HANDSET,
PlanetKitAudioRoute.SPEAKER
)

val success = audioSwitch.setPreferredAudioRoutesAtDisconnect(
whenOnVideoCall = false,
list = audioCallPriority
)

setPreferredAudioRoutesAtDisconnect() returns false if the list is invalid (wrong number of items or duplicates).

Automatic route changes​

When audio route control is enabled, PlanetKit preserves a wired or Bluetooth route already selected when audio starts. If both are connected when a call activates, Android 7 and later use Bluetooth only when the OS has selected the Bluetooth route; otherwise PlanetKit uses the wired route. Android 6 and earlier use Bluetooth. These rules require the necessary Bluetooth permission.

When a video call is enabled, PlanetKit keeps a wired or Bluetooth route; otherwise it selects the first available route from the video-call priority list. Disabling a video call does not by itself change the route.

Observe route and availability changes​

Register listeners on the PlanetKitCall or PlanetKitConference instance to receive the selected-route changes and updates to the list of available routes.

call.setOnAudioRouteChangeListener { newRoute ->
Log.d(TAG, "Audio route changed to: $newRoute")
// Update UI to reflect new route
}

// Also listen for changes to the available route list
call.setOnAudioRouteAvailableListChangeListener { availableRoutes ->
Log.d(TAG, "Available routes updated: $availableRoutes")
// Refresh route selection UI
}

// The same listener APIs are available on PlanetKitConference.

APIs related to audio route control are as follows.

Classes​

Enum​

Methods​