fun setPreferredIncomingVideoResolution(
resolution: PreferredVideoResolution?,
sessionIds: List<String>? = null,
){
//SDK's Internal implementation
}
data class PreferredVideoResolution(
val width: Int,
val height: Int,
)
Manual Video Quality Selection
By default, our SDK chooses the incoming video quality that best matches the size of a video element for a given participant. It makes less sense to waste bandwidth receiving Full HD video when it’s going to be displayed in a 320 by 240 pixel rectangle.
However, it’s still possible to override this behavior and manually request higher resolution video for better quality, or lower resolution to save bandwidth. It’s also possible to disable incoming video altogether for an audio-only experience.
Actual incoming video quality depends on a number of factors, such as the quality of the source video, and network conditions. Manual video quality selection allows you to specify your preference, while the actual resolution is automatically selected from the available resolutions to match that preference as closely as possible.
In this article we’ll build a UI control for manual video quality selection.
Prerequisites
If you haven’t already bootstrapped a video calling application (our Video Calling Tutorial is a great place to start!), here’s a very simple application showing an active call that we’ll use as a starting point:
Getting and Setting Incoming Video Settings
To set the current incoming video quality settings, we will use the setPreferredIncomingVideoResolution
method on Call
to set it, it has 2 arguments which are
resolution
- The preferred resolution. Set tonull
to switch back to auto.sessionIds
- The participant session IDs to apply the resolution to. Ifnull
, the resolution will be applied to all participants.
It’s also possible to set a preferred resolution per call participant. There’s an optional second parameter named sessionIds
, accepting List of session ids as String
:
val selectedParticipantsSessionIds = call.state.participants.map { it.sessionId }
call.setPreferredIncomingVideoResolution(PreferredVideoResolution(1280, 720), selectedParticipantsSessionIds)
However, this cookbook assumes that the preferred resolution should be applied to all call participants. With that in mind, we can build a simple UI component that allows users to manually select the desired incoming call quality.
/**
* The ManualCallQuality enum is provided as an example to
* simplify setting resolution. This enum is NOT part of the StreamVideo SDK and
* should be implemented in your app as needed.
**/
enum class ManualCallQuality(val resolution: PreferredVideoResolution?) {
AUTO(null),
FOUR_K(PreferredVideoResolution(3840, 2160)),
FULL_HD(PreferredVideoResolution(1920, 1080)),
HD(PreferredVideoResolution(1280, 720)),
SD(PreferredVideoResolution(640, 480)),
DATA_SAVER(PreferredVideoResolution(256, 144)),
}
@Composable
fun CallQualitySettingsScreen(call: Call) {
var selectedQuality by remember { mutableStateOf(ManualCallQuality.AUTO) }
val participants by call.state.participants.collectAsStateWithLifecycle()
val sessionIds = participants.map { it.sessionId }
val coroutineScope = rememberCoroutineScope()
CallQualitySelector(
modifier = Modifier,
selectedQuality = selectedQuality,
onQualitySelected = {
selectedQuality = it
coroutineScope.launch {
/**
* We are setting our desired resolution here
*/
call.setPreferredIncomingVideoResolution(
resolution = selectedQuality.resolution,
sessionIds = sessionIds)
}
}
)
}
@Composable
fun CallQualitySelector(
modifier: Modifier,
selectedQuality: ManualCallQuality,
onQualitySelected: (ManualCallQuality) -> Unit
) {
val callQualityOptions = listOf(
"Auto" to ManualCallQuality.AUTO,
"4K (2160p)" to ManualCallQuality.FOUR_K,
"Full HD (1080p)" to ManualCallQuality.FULL_HD,
"HD (720p)" to ManualCallQuality.HD,
"SD (480p)" to ManualCallQuality.SD,
"Data Saver (320x240)" to ManualCallQuality.DATA_SAVER
)
Column(
modifier = modifier
.fillMaxWidth()
.background(VideoTheme.colors.baseSheetPrimary)
.padding(16.dp)
) {
Text("Select Call Quality", color = Color.White, fontSize = 18.sp)
Spacer(modifier = Modifier.height(8.dp))
callQualityOptions.forEach { (label, quality) ->
Row(
modifier = Modifier
.fillMaxWidth()
.selectable(
selected = (quality == selectedQuality),
onClick = { onQualitySelected(quality) },
role = Role.RadioButton
)
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = (quality == selectedQuality),
onClick = null,
colors = RadioButtonDefaults.colors(
selectedColor = VideoTheme.colors.basePrimary,
unselectedColor = Color.LightGray,
)
)
Spacer(modifier = Modifier.width(12.dp))
Text(text = label, color = Color.White,)
}
}
}
}