Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Android camera 'back' is used when camera prop is 'front' #81

Open
2 tasks done
giantslogik opened this issue May 22, 2024 · 17 comments
Open
2 tasks done
Labels
bug Something isn't working
Milestone

Comments

@giantslogik
Copy link

giantslogik commented May 22, 2024

Version

v2.0.0

Which operating systems have you used?

  • Android
  • iOS

Environment that reproduces the issue

Google Pixel 7

Is it reproducible in the example application?

Not tested

RTMP Server

NA, happens before streaming

Reproduction steps

  1. pass prop camera={'front'}
<ApiVideoLiveStreamView
         key={'ApiVideoLiveStreamView'}
         style={styles.liveStreamView}
         ref={ref}
         camera={'front'}
         enablePinchedZoom={true}
         video={{
           fps: 30,
           resolution: { width: 1080, height: 1920 },
           bitrate: 2 * 1024 * 1024, // # 2 Mbps
           gopDuration: 1 // 1 second
         }}
         audio={{
           bitrate: 128000,
           sampleRate: 44100,
           isStereo: true
         }}
         isMuted={false}
         onConnectionSuccess={onConnectionSuccess}
         onConnectionFailed={onConnectionFailed}
         onDisconnect={onDisconnect}
       />

Expected result

'front' camera is used

Actual result

'back' camera is used.

Additional context

The bug report form did not have that version v2.0.0. !!!
Works correctly on iOS.

Workaround:

  1. Set camera prop to undefined initially.
  2. Within a setTimeout (500ms - 1sec) trigger state changes to set the camera prop to 'front'.

Relevant logs output

No response

@giantslogik giantslogik added the bug Something isn't working label May 22, 2024
@ThibaultBee ThibaultBee added this to the v2.0.1 milestone May 23, 2024
@ThibaultBee
Copy link
Member

Hi,

It is a random issue.
I made changes in the Android dependency. It will be fixed in 2.0.1.

@ThibaultBee
Copy link
Member

Hi,
Could you test on main branch?

@giantslogik
Copy link
Author

@ThibaultBee , I tried to test main on Android, and it seems like the correct camera is initially used. I could not test it much as the library crashes for me with:

 E  FATAL EXCEPTION: pool-40-thread-1
 Process: com.**********, PID: 2574
 java.lang.IllegalStateException: LifecycleScope is not available
at io.github.thibaultbee.streampack.views.PreviewView.startPreviewIfReady(PreviewView.kt:272)
at io.github.thibaultbee.streampack.views.PreviewView.startPreview(PreviewView.kt:245)
at video.api.livestream.views.ApiVideoView.startPreview$livestream_release(ApiVideoView.kt:62)
at video.api.livestream.ApiVideoLiveStream$startPreview$1.invoke(ApiVideoLiveStream.kt:373)
at video.api.livestream.ApiVideoLiveStream$startPreview$1.invoke(ApiVideoLiveStream.kt:364)
at video.api.reactnative.livestream.LiveStreamView$1$1.invoke(LiveStreamView.kt:75)
at video.api.reactnative.livestream.LiveStreamView$1$1.invoke(LiveStreamView.kt:72)
at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$requestPermissions$request$1$1.invoke(SerialPermissionsManager.kt:38)
at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$requestPermissions$request$1$1.invoke(SerialPermissionsManager.kt:35)
at video.api.reactnative.livestream.utils.permissions.PermissionsManager$requestPermissions$1.onAllGranted(PermissionsManager.kt:51)
at video.api.reactnative.livestream.utils.permissions.PermissionsManager.requestPermissions(PermissionsManager.kt:76)
at video.api.reactnative.livestream.utils.permissions.PermissionsManager.requestPermissions(PermissionsManager.kt:49)
at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager.requestPermissions$lambda$1(SerialPermissionsManager.kt:35)
at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager.$r8$lambda$dzig6asy22NzT_1QrKBawhgieas(Unknown Source:0)
at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$$ExternalSyntheticLambda1.run(Unknown Source:10)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)

The scenario it crashes is either (re) Mount or unmount of ApiVideoLiveStreamView.
In my flow i have multiple screens displaying ApiVideoLiveStreamView:

  1. Screen with camera selector + next button.
  2. Screen with stream configuration. + next button
  3. Actual live streaming Screen, where users can stream by pressing a "record" button.

Screens 1 & 2 just show the camera output. 3 does the streaming.
The crash happens when moving between screen 1 & 2 above. This worked ok with2.0.0+iOS/Android and main+iOS

@ThibaultBee
Copy link
Member

@giantslogik Could you provide a sample where I can test directly?

@giantslogik
Copy link
Author

I'll try and modify the example in the repo. May take me a while to get to it.

@ThibaultBee
Copy link
Member

@ThibaultBee
Copy link
Member

Instead of throwing an exception here, we can just log an error. But that might hide other issues.

@giantslogik
Copy link
Author

This worked without an Exception with api.video-reactnative-live-stream 2.0.0 Android. I'm trying to see what has changed in streampack and api.video-reactnative-live-stream since then.
Do you have tags i can diff by. Having some trouble determining what version of streampack is used by api.video-reactnative-live-stream 2.0.0

@giantslogik
Copy link
Author

@ThibaultBee
Copy link
Member

I know but I want to be sure there isn't any side effect in the patch and if this would solve your issue.
Have you made progress on a standalone sample where I can reproduce this issue?

@giantslogik
Copy link
Author

I haven't had the time to write a sample. I will pull main again , set shouldFailSilently = true and see if that works. (i.e. try the "Instead of throwing an exception here, we can just log an error." )

@ThibaultBee
Copy link
Member

@giantslogik another way of dealing with this is to catch the exception when calling startPreview. I could create a branch with this fix. Could you test it?

@safee-cases
Copy link

safee-cases commented Sep 4, 2024

I also have this problem on my application. Only on android.

I'm currently on the main branch because I had to fix another error I had before, which can be found on this issue. #82
(java.lang.NullPointerException: Attempt to invoke virtual method 'int android.media.audiofx.AcousticEchoCanceler.setEnabled(boolean)' on a null object reference)

Now, I got the "LifecycleScope" when I start a livestream, here is my log error:

Your app just crashed. See the error below.
java.lang.IllegalStateException: LifecycleScope is not available
  io.github.thibaultbee.streampack.views.PreviewView.startPreviewIfReady(PreviewView.kt:272)
  io.github.thibaultbee.streampack.views.PreviewView.startPreview(PreviewView.kt:245)
  video.api.livestream.views.ApiVideoView.startPreview$livestream_release(ApiVideoView.kt:62)
  video.api.livestream.ApiVideoLiveStream$startPreview$1.invoke(ApiVideoLiveStream.kt:373)
  video.api.livestream.ApiVideoLiveStream$startPreview$1.invoke(ApiVideoLiveStream.kt:364)
  video.api.reactnative.livestream.LiveStreamView$1$1.invoke(LiveStreamView.kt:75)
  video.api.reactnative.livestream.LiveStreamView$1$1.invoke(LiveStreamView.kt:72)
  video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$requestPermissions$request$1$1.invoke(SerialPermissionsManager.kt:38)
  video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$requestPermissions$request$1$1.invoke(SerialPermissionsManager.kt:35)
  video.api.reactnative.livestream.utils.permissions.PermissionsManager$requestPermissions$1.onAllGranted(PermissionsManager.kt:51)
  video.api.reactnative.livestream.utils.permissions.PermissionsManager.requestPermissions(PermissionsManager.kt:76)
  video.api.reactnative.livestream.utils.permissions.PermissionsManager.requestPermissions(PermissionsManager.kt:49)
  video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager.requestPermissions$lambda$1(SerialPermissionsManager.kt:35)
  video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager.$r8$lambda$dzig6asy22NzT_1QrKBawhgieas(Unknown Source:0)
  video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$$ExternalSyntheticLambda1.run(Unknown Source:10)
  java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
  java.lang.Thread.run(Thread.java:1012)

Is the branch with the fix available? I could test it.
Thank you !

@ThibaultBee
Copy link
Member

ThibaultBee commented Sep 4, 2024

@giantslogik @safee-cases Could you test #90?
I am trying to find the source of the crash. If you find anything relevant so I can reproduce it, please tell us :)

@giantslogik
Copy link
Author

giantslogik commented Sep 5, 2024

@ThibaultBee I tested with
"@api.video/react-native-livestream": "https://github.com/apivideo/api.video-reactnative-live-stream.git#bugfix/missing_lifecycle_scope",

Still crashes.

2024-09-05 15:35:18.916 14990-15818 AndroidRuntime          ***************            E  FATAL EXCEPTION: pool-35-thread-1
                                                                                                    Process: *************, PID: 14990
                                                                                                    java.lang.IllegalStateException: LifecycleScope is not available
                                                                                                    	at io.github.thibaultbee.streampack.views.PreviewView.startPreviewIfReady(PreviewView.kt:272)
                                                                                                    	at io.github.thibaultbee.streampack.views.PreviewView.startPreview(PreviewView.kt:245)
                                                                                                    	at video.api.livestream.views.ApiVideoView.startPreview$livestream_release(ApiVideoView.kt:62)
                                                                                                    	at video.api.livestream.ApiVideoLiveStream$startPreview$1.invoke(ApiVideoLiveStream.kt:373)
                                                                                                    	at video.api.livestream.ApiVideoLiveStream$startPreview$1.invoke(ApiVideoLiveStream.kt:364)
                                                                                                    	at video.api.reactnative.livestream.LiveStreamView$1$1.invoke(LiveStreamView.kt:75)
                                                                                                    	at video.api.reactnative.livestream.LiveStreamView$1$1.invoke(LiveStreamView.kt:72)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$requestPermissions$request$1$1.invoke(SerialPermissionsManager.kt:38)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$requestPermissions$request$1$1.invoke(SerialPermissionsManager.kt:35)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.PermissionsManager$requestPermissions$1.onAllGranted(PermissionsManager.kt:51)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.PermissionsManager.requestPermissions(PermissionsManager.kt:76)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.PermissionsManager.requestPermissions(PermissionsManager.kt:49)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager.requestPermissions$lambda$1(SerialPermissionsManager.kt:35)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager.$r8$lambda$dzig6asy22NzT_1QrKBawhgieas(Unknown Source:0)
                                                                                                    	at video.api.reactnative.livestream.utils.permissions.SerialPermissionsManager$$ExternalSyntheticLambda1.run(Unknown Source:10)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
                                                                                                    	at java.lang.Thread.run(Thread.java:1012)

This is a race condition between unmounting previous LiveStreamView and mounting another LiveStreamView. (Since i display it on two consecutive screens.)
I was able to avoid the crash by using a wrapper component which implements the following logic. (Don't know if its works consistently, and it causes flicker and flashing of the screen.)

  • 1st render: Wrapper renders null and triggers an immediate re-render.
  • 2nd render: Wrapper renders ApiVideoLiveStreamView with undefined camera and triggers a re-render after 500 ms
  • 3rd render: Wrapper renders ApiVideoLiveStreamView with preferred camera

Part of this logic is my workaround for original wrong camera being used bug, as well handling issues when using other camera libs (react-native-vision-camera) which MAY have camera ownership before i display ApiVideoLiveStreamView.

enum LiveVideoStreamInitLifecycle {
  NOT_INITALIZED,
  INITIALIZING,
  INITIALIZED
}

export type LiveVideoStreamProps = {
  camera: 'front' | 'back' | undefined;
  /* Mitigate bugs by a delayed initialize.*/
  delayInit?: boolean;
  ....
};

const LiveVideoStream = forwardRef<LiveVideoStreamMethods, LiveVideoStreamProps>((props, extRef) => {
  let {
    camera,
    delayInit = true,
    ....
  } = props;

  const [initialized, setInitialized] = useState<LiveVideoStreamInitLifecycle>(
    delayInit ? LiveVideoStreamInitLifecycle.NOT_INITALIZED : LiveVideoStreamInitLifecycle.INITIALIZING
  );

  useEffect(() => {
    setTimeout(
      () => {
        setInitialized(
          initialized === LiveVideoStreamInitLifecycle.NOT_INITALIZED
            ? LiveVideoStreamInitLifecycle.INITIALIZING
            : LiveVideoStreamInitLifecycle.INITIALIZED
        );
      },
      initialized === LiveVideoStreamInitLifecycle.NOT_INITALIZED ? 0 : 500
    );
  }, [initialized]);

camera = initialized === LiveVideoStreamInitLifecycle.INITIALIZED ? camera : undefined;

return (
    <>
      {initialized ? (
        <ApiVideoLiveStreamView
          key={'ApiVideoLiveStreamView'}
          style={styles.streamstyle}
          ref={ref}
          camera={camera}
          enablePinchedZoom={true}
          video={{
            fps: 30,
            resolution: { width: 1080, height: 1920 },
            bitrate: 2 * 1024 * 1024, // # 2 Mbps
            gopDuration: 1 // 1 second
          }}
          audio={{
            bitrate: 128000,
            sampleRate: 44100,
            isStereo: true
          }}
          isMuted={false}
.....
        />
      ) : null}
   </>
  );
});

@ThibaultBee
Copy link
Member

ThibaultBee commented Sep 11, 2024

I still don't understand why it happens...
But anyway, as we don't have a way to reproduce it and their is a workaround, I am going to release the 2.0.1 without a fix and we will open an issue with this issue.

@ThibaultBee
Copy link
Member

Could you test the original issue on 2.0.1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants