livekit / client-sdk-android

LiveKit SDK for Android
https://docs.livekit.io
Apache License 2.0
176 stars 69 forks source link

Prevent initialising video renderer if room is disconnected #309

Open serhiynovos opened 11 months ago

serhiynovos commented 11 months ago

I noticed that sometimes when I finish a call right after android device has connected the room, my app crashes and it was giving next error

Fatal Exception: java.lang.RuntimeException: java.lang.RuntimeException: Invalid sharedContext at org.webrtc.EglBase14Impl.createEglContext(EglBase14Impl.java:258) at org.webrtc.EglBase14Impl.<init>(EglBase14Impl.java:63) at org.webrtc.EglBase.createEgl14(EglBase.java:213) at org.webrtc.EglBase.create(EglBase.java:156) at org.webrtc.EglRenderer.lambda$init$0$org-webrtc-EglRenderer(EglRenderer.java:241) at org.webrtc.EglRenderer$$ExternalSyntheticLambda7.run(:6) at org.webrtc.ThreadUtils$4.call(ThreadUtils.java:199) at org.webrtc.ThreadUtils$4.call(ThreadUtils.java:196) at org.webrtc.ThreadUtils$3.run(ThreadUtils.java:173) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at org.webrtc.EglRenderer$HandlerWithExceptionCallback.dispatchMessage(EglRenderer.java:103) at android.os.Looper.loop(Looper.java:223) at android.os.HandlerThread.run(HandlerThread.java:67) at org.webrtc.ThreadUtils.invokeAtFrontUninterruptibly(ThreadUtils.java:184) at org.webrtc.ThreadUtils.invokeAtFrontUninterruptibly(ThreadUtils.java:196) at org.webrtc.EglRenderer.init(EglRenderer.java:232) at org.webrtc.EglRenderer.init(EglRenderer.java:259) at org.webrtc.SurfaceEglRenderer.init(SurfaceEglRenderer.java:61) at io.livekit.android.renderer.TextureViewRenderer.init(TextureViewRenderer.kt:94) at io.livekit.android.renderer.TextureViewRenderer.init$default(TextureViewRenderer.kt:85) at io.livekit.android.room.Room.initVideoRenderer(Room.kt:882) at io.livekit.android.compose.VideoRendererKt$VideoRenderer$4.invoke(VideoRenderer.kt:71) at io.livekit.android.compose.VideoRendererKt$VideoRenderer$4.invoke(VideoRenderer.kt:67) at androidx.compose.ui.viewinterop.ViewFactoryHolder.<init>(AndroidView.android.kt:314) at androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1.invoke(AndroidView.android.kt:247) at androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1.invoke(AndroidView.android.kt:246) at androidx.compose.ui.viewinterop.AndroidView_androidKt$AndroidView$$inlined$ComposeNode$1.invoke(Composables.kt:254) at androidx.compose.runtime.ComposerImpl$createNode$2.invoke(Composer.kt:1611) at androidx.compose.runtime.ComposerImpl$createNode$2.invoke(Composer.kt:1609) at androidx.compose.runtime.ComposerImpl$recordInsert$2.invoke(Composer.kt:3548) at androidx.compose.runtime.ComposerImpl$recordInsert$2.invoke(Composer.kt:3545) at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:812) at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:843) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:617) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:536) at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34) at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109) at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41) at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:970) at android.view.Choreographer.doCallbacks(Choreographer.java:796) at android.view.Choreographer.doFrame(Choreographer.java:727) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7664) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

It happens only when other participant closes a room and looks like room is cleared, but UI still tries to render video track.

So after adding check if room DISCONNECTED it stopped crashing and in logs I saw this condition.

CLAassistant commented 11 months ago

CLA assistant check
All committers have signed the CLA.

davidliu commented 11 months ago

Hmm, sounds like room.release() has already been called, resulting in the EglBase no longer being valid? If that's the case, I think this behavior should be expected (and will need to be fixed in VideoRenderer instead to better handle the case of the Room being disconnected). Would rather not have this init fail silently.

serhiynovos commented 11 months ago

Hmm, sounds like room.release() has already been called, resulting in the EglBase no longer being valid? If that's the case, I think this behavior should be expected (and will need to be fixed in VideoRenderer instead to better handle the case of the Room being disconnected). Would rather not have this init fail silently.

Yes. Most likely it's EglBase is not valid anymore and room was cleared due to room closed signaling event.

Also one point of adding checking event to these two methods it's somebody still can use other renderers instead of which livekit provides