# Core features The Video SDK for Android lets users speak and hear each other in a session over VoIP using their device's microphone and speaker. Users who can't connect over VoIP can dial in by phone — see [Phone (PSTN)](/docs/video-sdk/android/pstn/). The core controls let you connect to audio, mute and unmute, disconnect, and route between the earpiece and loudspeaker. For host-only controls, see [Host audio controls](/docs/video-sdk/android/audio/host-controls/). To let users test their microphone and speaker _before_ joining a session, see [Preview](/docs/video-sdk/android/preview/). The `ZoomVideoSDKAudioHelper` provides the methods used to manage a user's audio. Before changing any audio state, check whether the user is already connected to audio. ```kotlin val audioStatus = user.audioStatus val audioType = audioStatus.audioType val audioHelper = ZoomVideoSDK.getInstance().audioHelper ``` ```java ZoomVideoSDKAudioStatus audioStatus = user.getAudioStatus(); ZoomVideoSDKAudioStatus.ZoomVideoSDKAudioType audioType = audioStatus.getAudioType(); ZoomVideoSDKAudioHelper audioHelper = ZoomVideoSDK.getInstance().getAudioHelper(); ``` `audioType` is one of the values defined on `ZoomVideoSDKAudioStatus.ZoomVideoSDKAudioType`. | Value | Meaning | | --------------------------------- | ------------------------------------------------------------------------------------------ | | `ZoomVideoSDKAudioType_None` | The user is not connected to session audio. | | `ZoomVideoSDKAudioType_VOIP` | The user is connected over VoIP (microphone and speaker). | | `ZoomVideoSDKAudioType_TELEPHONY` | The user is connected by phone dial-in. See [Phone (PSTN)](/docs/video-sdk/android/pstn/). | ## Connect to audio The SDK can't capture from the microphone until the user grants the `RECORD_AUDIO` runtime permission. Request it when the user takes an action that needs audio (a "Join audio" button is the conventional pattern), then call `startAudio()` on the `ZoomVideoSDKAudioHelper`. ```kotlin private val audioPermission = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { granted -> if (granted) { ZoomVideoSDK.getInstance().audioHelper.startAudio() } else { // Surface a message asking the user to grant the permission. } } fun onJoinAudioClicked() { audioPermission.launch(Manifest.permission.RECORD_AUDIO) } ``` ```java private final ActivityResultLauncher audioPermission = registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> { if (Boolean.TRUE.equals(granted)) { ZoomVideoSDK.getInstance().getAudioHelper().startAudio(); } else { // Surface a message asking the user to grant the permission. } }); void onJoinAudioClicked() { audioPermission.launch(Manifest.permission.RECORD_AUDIO); } ``` > **Required Android permission** > > `RECORD_AUDIO`. See the [Android permissions overview](https://developer.android.com/guide/topics/permissions/overview) and the [Best practices](/docs/video-sdk/android/audio/best-practices/) topic for the full permission flow, including Bluetooth on Android 12+. If the user might already be connected (for example, they joined audio earlier), check `audioType` before starting so you don't reconnect unnecessarily. ```kotlin if (audioType == ZoomVideoSDKAudioStatus.ZoomVideoSDKAudioType.ZoomVideoSDKAudioType_None) { audioHelper.startAudio() } else { // The user is already connected to audio. } ``` ```java if (audioType == ZoomVideoSDKAudioStatus.ZoomVideoSDKAudioType.ZoomVideoSDKAudioType_None) { audioHelper.startAudio(); } else { // The user is already connected to audio. } ``` ## Mute and unmute a user Mute the local user (or any user, if the local user is the host) by calling `muteAudio` with the associated `ZoomVideoSDKUser`. ```kotlin audioHelper.muteAudio(user) ``` ```java audioHelper.muteAudio(user); ``` Unmute in the same way with `unMuteAudio`. ```kotlin audioHelper.unMuteAudio(user) ``` ```java audioHelper.unMuteAudio(user); ``` ## Disconnect from audio To leave the audio portion of the session entirely, call `stopAudio`. Use this only when the user explicitly disconnects. To silence the user temporarily, use `muteAudio` instead. ```kotlin if (audioType == ZoomVideoSDKAudioStatus.ZoomVideoSDKAudioType.ZoomVideoSDKAudioType_VOIP) { audioHelper.stopAudio() } ``` ```java if (audioType == ZoomVideoSDKAudioStatus.ZoomVideoSDKAudioType.ZoomVideoSDKAudioType_VOIP) { audioHelper.stopAudio(); } ``` ## Route audio between the earpiece and loudspeaker On Android, the SDK can route VoIP audio through either the device's earpiece, default for in-call audio, or its loudspeaker. Use `setSpeaker` to toggle between them. ```kotlin // Route audio through the loudspeaker. audioHelper.setSpeaker(true) // Route audio through the earpiece. audioHelper.setSpeaker(false) ``` ```java // Route audio through the loudspeaker. audioHelper.setSpeaker(true); // Route audio through the earpiece. audioHelper.setSpeaker(false); ``` Use `getSpeakerStatus` to read the current routing and `canSwitchSpeaker` to check whether the device permits switching For example, the SDK returns `false` when a wired headset or Bluetooth audio device is connected and the OS owns the route. ```kotlin if (audioHelper.canSwitchSpeaker()) { val onLoudspeaker = audioHelper.speakerStatus audioHelper.setSpeaker(!onLoudspeaker) } ``` ```java if (audioHelper.canSwitchSpeaker()) { boolean onLoudspeaker = audioHelper.getSpeakerStatus(); audioHelper.setSpeaker(!onLoudspeaker); } ``` When the local user is the session host, they can also mute participants, request a participant unmute, and mute everyone at once. For more information, see [Host audio controls](/docs/video-sdk/android/audio/host-controls/).