Azure / azure-sdk-for-android

Android client SDKs for Microsoft Azure
https://azure.github.io/azure-sdk-for-android/
MIT License
97 stars 93 forks source link

[BUG] Crash when switching camera source while not visible #1522

Open JasonWeinzierl opened 6 months ago

JasonWeinzierl commented 6 months ago

Describe the bug

When switching video sources for a LocalVideoStream while its VideoStreamRendererView is not added to the current view, the app will crash.

Exception or Stack Trace

FATAL EXCEPTION: Thread-76
Process: com.example.videocallingquickstart, PID: 4722
java.lang.ClassCastException: android.view.TextureView cannot be cast to java.lang.Comparable
at java.util.PriorityQueue.siftUpComparable(PriorityQueue.java:652)
at java.util.PriorityQueue.siftUp(PriorityQueue.java:647)
at java.util.PriorityQueue.offer(PriorityQueue.java:344)
at java.util.PriorityQueue.add(PriorityQueue.java:321)
at com.azure.android.communication.calling.VideoStreamView.AddTextureView(VideoStreamView.java:189)
at com.azure.android.communication.calling.LocalOutgoingVideoStreamView.Init(LocalOutgoingVideoStreamView.java:63)
at com.azure.android.communication.calling.LocalOutgoingVideoStreamRenderer.onVideoBindingEventStateChanged(LocalOutgoingVideoStreamRenderer.java:141)
at com.azure.android.communication.calling.LocalVideoStream.OnBindingEventStateChangedStaticHandler(LocalVideoStream.java:175)

To Reproduce

  1. Create a new LocalVideoStream
  2. Create a new VideoStreamRenderer
  3. Get a new VideoStreamRendererView from the renderer
  4. Add the view to the current UI
  5. Remove the view from the UI, but keep a reference to the video view
  6. Call switchSource on the stream with a different camera
  7. The app will crash a few ms later with the above stack trace

Code Snippet

I was able to reproduce this by modifying the videoCallingQuickstart to always display the "Switch Source" button.

val callClient = CallClient()
val deviceManager = callClient.getDeviceManager(context).get()

// User clicks a button to show their video
val cameras = deviceManager.cameras
val localVideoStream = LocalVideoStream(cameras[0], context)
val renderer = VideoStreamRenderer(localVideoStream, context)
val view = renderer.createView(CreateViewOptions(ScalingMode.FIT))
val layout = findViewById<FrameLayout>(R.id.localvideocontainer)
runOnUiThread {
  layout.addView(view)
}

// User clicks a button to hide their video
runOnUiThread {
  layout.removeView(view)
}

// User clicks a button to switch cameras
localVideoStream.switchSource(cameras[1]).get()

// Crash!

Expected behavior

Switching sources should not crash the app.

Screenshots

N/A

Setup (please complete the following information):

Additional context

N/A

Information Checklist Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report

lucianopa-msft commented 5 months ago

Hi @JasonWeinzierl, Can you verify in the latest beta 2.6.0-beta.9? This should be fixed in that version

JasonWeinzierl commented 5 months ago

On 2.6.0-beta.9 i still get a crash. Different exception:

E  FATAL EXCEPTION: main
   Process: com.example.videocallingquickstart, PID: 18543
   java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
    at android.view.ViewGroup.addViewInner(ViewGroup.java:5247)
    at android.view.ViewGroup.addView(ViewGroup.java:5076)
    at android.view.ViewGroup.addView(ViewGroup.java:5016)
    at android.view.ViewGroup.addView(ViewGroup.java:4988)
    at com.azure.android.communication.calling.VideoStreamView.lambda$AddTextureView$1$VideoStreamView(VideoStreamView.java:203)
    at com.azure.android.communication.calling.-$$Lambda$VideoStreamView$0vHxvVlVD8MHqdQmDmXkZD9qqXA.run(Unknown Source:2)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7885)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)

this is reproducible on my fork of the videoCallingQuickstart example:

  1. open https://github.com/JasonWeinzierl/communication-services-android-quickstarts
  2. upgrade to 2.6.0-beta.9 in the build.gradle.
  3. comment out the switchSourceButton.setVisibility(View.INVISIBLE); on line 430 of MainActivity.java
  4. launch the app and press Show Video. Then press Hide Video. Then press Switch Source and the app will crash.
lucianopa-msft commented 5 months ago

Hi @JasonWeinzierl, Thank you for the response, we will check this new issue and give you an update as soon as possible

lucianopa-msft commented 3 months ago

Tracking: ADO Bug 3732686