@Composable
fun MyLobbyScreen(call: Call) {
val audioBitrateProfile by call.microphone.audioBitrateProfile.collectAsStateWithLifecycle()
val isMusicHighQuality = audioBitrateProfile == AudioBitrateProfile.AUDIO_BITRATE_PROFILE_MUSIC_HIGH_QUALITY
ToggleHifiAudioAction(
isMusicHighQuality = isMusicHighQuality,
onCallAction = { action: ToggleHifiAudio ->
// Handle the toggle action
handleHifiAudioToggle(call, action.isHifiAudioEnabled)
}
)
}Hi-Fi Audio
This cookbook demonstrates how to use ToggleHifiAudioAction in your Compose UI to allow users to toggle between standard and high-fidelity audio modes.
Overview
ToggleHifiAudioAction is a pre-built Compose component that provides a toggle button for switching between standard voice audio (AUDIO_BITRATE_PROFILE_VOICE_STANDARD_UNSPECIFIED) and high-fidelity music audio (AUDIO_BITRATE_PROFILE_MUSIC_HIGH_QUALITY).
Basic Usage
The simplest way to use ToggleHifiAudioAction is to provide the current audio bitrate profile state and handle the action:
Using in Lobby Screen with buildDefaultLobbyControlActions
The easiest way to add the HiFi audio toggle to your lobby screen is using the buildDefaultLobbyControlActions function:
@Composable
fun LobbyControls(
call: Call,
showHifiAudioToggle: Boolean = false,
) {
val isCameraEnabled by call.camera.isEnabled.collectAsStateWithLifecycle()
val isMicrophoneEnabled by call.microphone.isEnabled.collectAsStateWithLifecycle()
val actions = buildDefaultLobbyControlActions(
call = call,
onCallAction = { action ->
handleCallAction(call, action)
},
isCameraEnabled = isCameraEnabled,
isMicrophoneEnabled = isMicrophoneEnabled,
showHifiAudioToggle = showHifiAudioToggle,
)
// Render the actions
Row {
actions.forEach { action ->
action()
}
}
}Checking if HiFi Audio is Enabled
Before showing the toggle, check if HiFi audio is enabled in the call settings:
@Composable
fun LobbyScreen(call: Call) {
val hifiAudioEnabled by call.state.settings
.map { it?.audio?.hifiAudioEnabled ?: false }
.collectAsStateWithLifecycle(initialValue = false)
// Settings is loaded by the SDK asynchronously
val settingsLoaded by call.state.settings
.map { it != null }
.collectAsStateWithLifecycle(initialValue = false)
val showHifiAudioToggle = settingsLoaded && hifiAudioEnabled
// Use showHifiAudioToggle in your UI
LobbyControls(
call = call,
showHifiAudioToggle = showHifiAudioToggle,
)
}Handling the Toggle Action
When the user taps the toggle, you need to handle the ToggleHifiAudio action. Here’s how to implement the handler:
Using DefaultOnCallActionHandler
The SDK provides a default handler that you can use:
val actions = buildDefaultLobbyControlActions(
call = call,
onCallAction = { action ->
DefaultOnCallActionHandler.onCallAction(call, action)
},
showHifiAudioToggle = showHifiAudioToggle,
)Custom Handler Implementation
For more control, implement your own handler:
fun handleCallAction(call: Call, action: CallAction) {
when (action) {
is ToggleHifiAudio -> {
val newProfile = if (action.isHifiAudioEnabled) {
AudioBitrateProfile.AUDIO_BITRATE_PROFILE_MUSIC_HIGH_QUALITY
} else {
AudioBitrateProfile.AUDIO_BITRATE_PROFILE_VOICE_STANDARD_UNSPECIFIED
}
// Launch in a coroutine scope since setAudioBitrateProfile is suspend
CoroutineScope(SupervisorJob() + Dispatchers.Main).launch {
val result = call.microphone.setAudioBitrateProfile(newProfile)
if (result.isFailure) {
// Handle error - HiFi audio may not be enabled in dashboard settings
// or the call may already be joined
Log.e("LobbyScreen", "Failed to set audio bitrate profile: ${result.exceptionOrNull()?.message}")
}
}
}
// Handle other actions...
else -> Unit
}
}Using ViewModel (Recommended)
For better separation of concerns, handle the action in your ViewModel:
class CallLobbyViewModel(private val call: Call) : ViewModel() {
fun setAudioBitrateProfile(isHifiAudioEnabled: Boolean) {
viewModelScope.launch {
val newProfile = if (isHifiAudioEnabled) {
AudioBitrateProfile.AUDIO_BITRATE_PROFILE_MUSIC_HIGH_QUALITY
} else {
AudioBitrateProfile.AUDIO_BITRATE_PROFILE_VOICE_STANDARD_UNSPECIFIED
}
val result = call.microphone.setAudioBitrateProfile(newProfile)
if (result.isFailure) {
Log.e(
"CallLobbyViewModel",
"Failed to set audio bitrate profile: ${result.exceptionOrNull()?.message}"
)
}
}
}
}
// In your Composable
@Composable
fun LobbyScreen(viewModel: CallLobbyViewModel) {
val actions = buildDefaultLobbyControlActions(
call = viewModel.call,
onCallAction = { action ->
when (action) {
is ToggleHifiAudio -> {
viewModel.setAudioBitrateProfile(action.isHifiAudioEnabled)
}
// Handle other actions...
else -> Unit
}
},
showHifiAudioToggle = showHifiAudioToggle,
)
}Complete Example
Here’s a complete example showing how to integrate ToggleHifiAudioAction in a lobby screen:
@Composable
fun CallLobbyScreen(
call: Call,
onBack: () -> Unit,
) {
// Check if HiFi audio is enabled
val hifiAudioEnabled by call.state.settings
.map { it?.audio?.hifiAudioEnabled ?: false }
.collectAsStateWithLifecycle(initialValue = false)
val settingsLoaded by call.state.settings
.map { it != null }
.collectAsStateWithLifecycle(initialValue = false)
val showHifiAudioToggle = settingsLoaded && hifiAudioEnabled
// Get device states
val isCameraEnabled by call.camera.isEnabled.collectAsStateWithLifecycle()
val isMicrophoneEnabled by call.microphone.isEnabled.collectAsStateWithLifecycle()
// Build control actions
val actions = buildDefaultLobbyControlActions(
call = call,
onCallAction = { action ->
handleCallAction(call, action)
},
isCameraEnabled = isCameraEnabled,
isMicrophoneEnabled = isMicrophoneEnabled,
showHifiAudioToggle = showHifiAudioToggle,
)
// Render UI
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
// Your lobby content here...
// Control actions row
Row(
modifier = Modifier.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
actions.forEach { action ->
action()
}
}
}
}
private fun handleCallAction(call: Call, action: CallAction) {
when (action) {
is ToggleHifiAudio -> {
val newProfile = if (action.isHifiAudioEnabled) {
AudioBitrateProfile.AUDIO_BITRATE_PROFILE_MUSIC_HIGH_QUALITY
} else {
AudioBitrateProfile.AUDIO_BITRATE_PROFILE_VOICE_STANDARD_UNSPECIFIED
}
CoroutineScope(SupervisorJob() + Dispatchers.Main).launch {
call.microphone.setAudioBitrateProfile(newProfile)
}
}
// Handle other actions (ToggleMicrophone, ToggleCamera, etc.)
else -> Unit
}
}Customization
You can customize the appearance of ToggleHifiAudioAction using its styling parameters:
ToggleHifiAudioAction(
modifier = Modifier,
isMusicHighQuality = isMusicHighQuality,
enabled = true,
shape = RoundedCornerShape(8.dp),
enabledColor = Color.Blue,
disabledColor = Color.Gray,
enabledIconTint = Color.White,
disabledIconTint = Color.Black,
onStyle = VideoTheme.styles.buttonStyles.primaryIconButtonStyle(),
offStyle = VideoTheme.styles.buttonStyles.tertiaryIconButtonStyle(),
onCallAction = { action ->
handleHifiAudioToggle(call, action.isHifiAudioEnabled)
}
)Important Notes
Before Joining: The audio bitrate profile must be set before joining the call. Once joined, changes will be ignored.
Dashboard Settings: HiFi audio must be enabled in the dashboard settings for the call type. If not enabled,
setAudioBitrateProfilewill return a failure result.State Management: Always observe the
call.microphone.audioBitrateProfileStateFlow to keep your UI in sync with the actual audio profile.Error Handling: Always check the result of
setAudioBitrateProfileand handle failures appropriately, as the operation may fail if:- The call is already joined
- HiFi audio is not enabled in dashboard settings