Skip to main content

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)
}
}