Video
Create and bind video views. The binding of the views can be done before or after joining the meeting.
info
Video transmission and reception will continue even when views are not initialized. This means your application can still send and receive video data in the background or before rendering is set up.
eglBaseContext
can be obtained through the eyesonMeeting
instance
Option 1: XML Layout Implementation
<com.eyeson.sdk.webrtc.VideoRenderer
android:id="@+id/remoteVideo"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.eyeson.sdk.webrtc.VideoRenderer
android:id="@+id/localVideo"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
binding.localVideo.init(getEglContext())
binding.localVideo.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
binding.remoteVideo.init(getEglContext())
binding.remoteVideo.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
Views must be released after the meeting has ended or terminated.
binding.localVideo.release()
binding.remoteVideo.release()
Option 2: Jetpack Compose Implementation
val remoteView = rememberVideoRendererWithLifecycle(getEglContext()) {
viewModel.setRemoteVideoTarget(it)
}
val localView = rememberVideoRendererWithLifecycle(getEglContext()) {
viewModel.setLocalVideoTarget(it)
}
@Composable
fun rememberVideoRendererWithLifecycle(
eglContext: EglBase.Context?,
setTarget: (VideoRenderer?) -> Unit,
): VideoRenderer {
val currentSetTarget by rememberUpdatedState(setTarget)
val context = LocalContext.current
val videoRenderer = remember {
VideoRenderer(context).apply {
init(eglContext)
setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
}
}
val lifecycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(key1 = lifecycle, key2 = videoRenderer) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_CREATE) {
currentSetTarget(videoRenderer)
}
}
lifecycle.addObserver(observer)
onDispose {
currentSetTarget(null)
videoRenderer.release()
lifecycle.removeObserver(observer)
}
}
return videoRenderer
}
@Composable
private fun VideoViews(
showLocal: Boolean,
fullSizeRemote: Boolean,
remoteView: VideoRenderer,
localView: VideoRenderer,
setLocalTarget: (VideoRenderer?) -> Unit,
modifier: Modifier = Modifier,
modifierLocalView: Modifier = Modifier,
wideScreen: Boolean = false
) {
val remoteModifier = when {
fullSizeRemote -> {
Modifier
.fillMaxSize()
}
wideScreen -> {
Modifier.aspectRatio(16f / 9f)
}
else -> {
Modifier.aspectRatio(4f / 3f)
}
}
Box(modifier) {
AndroidView(modifier = remoteModifier.align(Alignment.Center), factory = {
remoteView
})
val localTarget = if (showLocal) {
AndroidView(modifier = modifierLocalView
.align(Alignment.BottomEnd),
factory = { localView })
localView
} else {
null
}
setLocalTarget(localTarget)
}
}