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

🐛 Camera Preview orientation does not update when screen orientation locks #3323

Open
4 of 5 tasks
dawidzawada opened this issue Dec 6, 2024 · 4 comments
Open
4 of 5 tasks
Labels
🐛 bug Something isn't working

Comments

@dawidzawada
Copy link

dawidzawada commented Dec 6, 2024

What's happening?

I have a following scenario in my application:

  • I have a pre-recording screen with camera preview - orientation here is locked to portrait
  • After pressing Record I'm changing orientation to landscape and I'm moving to "Recording screen"
  • In "Recording screen" I have a small camera preview - this camera preview stays at portrait orientation

You can reproduce it by running the example app like so;

  1. Run the app
  2. Open permissions screen, allow app to use camera
  3. Rotate your device for landscape mode (screen is locked in portrait)
  4. Press "Go to camera"
  5. Screen will be changed to "camera" and rotated to landscape, only preview stays in wrong orientation

All videos are recorded properly, in landscape mode. I'm having issues only with preview orientation.
Sometimes camera preview flips with screen locking but most of the time it stays in previous orientation.

Also if I'll shake device a little orientation change to the right one.

I'm using expo-screen-orientation for locking orientation

IMG_0038

Example app:
https://github.com/dawidzawada/camera-bug

Reproduceable Code

import {lockPlatformAsync, Orientation} from "expo-screen-orientation";

export default function PermissionsScreen() {
    const {requestPermission} = useCameraPermission()

    useEffect(() => {
        void requestPermission()
    }, []);

    useFocusEffect(() => {
        // Set portrait orientation for permissions screen
        const asyncEffect = async () => {
            await lockPlatformAsync({screenOrientationArrayIOS: [
                    Orientation.PORTRAIT_UP,
                ]
            })
        }
        asyncEffect()
    })


    const handlePress = async () => {
        // Set landscape orientation, then go to camera screen
        const asyncEffect = async () => {
            await lockPlatformAsync({screenOrientationArrayIOS: [
                    Orientation.LANDSCAPE_LEFT,
                    Orientation.LANDSCAPE_RIGHT
                ]
            })
            router.push('/camera')
        }
        asyncEffect()

    }

    return (
        <View>
            <Text>Permissions</Text>
            <Button title="Go to camera" onPress={handlePress} />
        </View>
    )
}

export default function CameraScreen() {
    const device = useCameraDevice('back');
    return (
        <View>
            {device && <Camera device={device} style={{width:300, height: 160}} isActive={true} />}
        </View>
    )
}

Relevant log output

16:19:25.549: [info] 📸 VisionCamera.didSetProps(_:): Updating 19 props: [onPreviewStarted, preview, onViewReady, onPreviewOrientationChanged, cameraId, isMirrored, onError, width, onShutter, onInitialized, onStarted, enableBufferCompression, onStopped, height, onCodeScanned, onOutputOrientationChanged, onPreviewStopped, enableFrameProcessor, isActive]
16:19:25.549: [info] 📸 VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: portrait...
16:19:25.549: [info] 📸 VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: portrait...
16:19:25.550: [info] 📸 VisionCamera.configure(_:): configure { ... }: Waiting for lock...
16:19:25.550: [info] 📸 VisionCamera.configure(_:): configure { ... }: Updating CameraSession Configuration... Difference(inputChanged: true, outputsChanged: true, videoStabilizationChanged: true, orientationChanged: true, formatChanged: true, sidePropsChanged: true, torchChanged: true, zoomChanged: true, exposureChanged: true, audioSessionChanged: true, locationChanged: true)
16:19:25.551: [info] 📸 VisionCamera.configureDevice(configuration:): Configuring Input Device...
16:19:25.551: [info] 📸 VisionCamera.configureDevice(configuration:): Configuring Camera com.apple.avfoundation.avcapturedevice.built-in_video:0...
16:19:25.553: [info] 📸 VisionCamera.configureDevice(configuration:): Successfully configured Input Device!
16:19:25.553: [info] 📸 VisionCamera.configureOutputs(configuration:): Configuring Outputs...
16:19:25.553: [info] 📸 VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: portrait...
16:19:25.553: [info] 📸 VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: portrait...
16:19:25.553: [info] 📸 VisionCamera.configureOutputs(configuration:): Successfully configured all outputs!
16:19:25.553: [info] 📸 VisionCamera.setTargetOutputOrientation(_:): Setting target output orientation from device to device...
16:19:25.662: [debug] 📸 VisionCamera.deviceOrientation: Device Orientation changed from portrait -> landscapeLeft
16:19:25.662: [info] 📸 VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: landscapeRight...
16:19:25.824: [info] 📸 VisionCamera.init(frame:session:): Preview Layer started previewing.
16:19:25.824: [info] 📸 VisionCamera.configure(_:): Beginning AudioSession configuration...
16:19:25.824: [info] 📸 VisionCamera.configureAudioSession(configuration:): Configuring Audio Session...
16:19:25.825: [info] 📸 VisionCamera.configure(_:): Committed AudioSession configuration!
16:19:25.829: [info] 📸 VisionCamera.configure(_:): Beginning Location Output configuration...
16:19:25.830: [info] 📸 VisionCamera.configure(_:): Finished Location Output configuration!

Camera Device

"id": "com.apple.avfoundation.avcapturedevice.built-in_video:0",
  "minZoom": 1,
  "neutralZoom": 1,
  "position": "back",
  "name": "Back Camera",
  "maxZoom": 123.75,
  "minFocusDistance": 12,
  "maxExposure": 8,
  "minExposure": -8,
  "supportsFocus": true,
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "isMultiCam": false,
  "hardwareLevel": "full",
  "sensorOrientation": "portrait",
  "formats": [],
  "hasFlash": true,
  "supportsRawCapture": false,
  "supportsLowLightBoost": false,
  "hasTorch": true
}

Device

iPhone 12

VisionCamera Version

4.6.3

Can you reproduce this issue in the VisionCamera Example app?

Yes, I can reproduce the same issue in the Example app here

Additional information

@dawidzawada dawidzawada added the 🐛 bug Something isn't working label Dec 6, 2024
Copy link

maintenance-hans bot commented Dec 6, 2024

Guten Tag, Hans here 🍻

Thanks for your detailed report! It looks like a valid issue with ze camera preview orientation. Since you provided a clear reproduction path and relevant logs, mrousavy can take a look at it.

Please allow some time for mrousavy to review and address this, as he is maintaining ze project in his free time. If you have any further information or updates, feel free to share them!

Note: If you think I made a mistake, please ping @mrousavy to take a look.

@dawidzawada
Copy link
Author

I'm using latest expo-screen-orientation and there's nothing additional that could affect this preview behavior - have a look at the example app.

@motoshira
Copy link

motoshira commented Dec 11, 2024

We are also using expo-screen-orientation, and we are experiencing abnormal rotation of the preview on iOS devices.

What's happening?

You can reproduce it by running the example app like so:

  1. Run yarn ios to launch the app.
  2. Grant camera permissions.
  3. Tilt the device vertically or horizontally.
  4. The preview rotates 90 degrees from the correct orientation.

Reproduceable Code

We are using expo-sensors to detect screen tilt and expo-screen-orientation to lock the screen orientation.
For the screen lock, we use setTimeout to introduce a delay, simulating cases where in-app processing takes time. The issue does not seem to occur without this setTimeout.

App.js

import React, { useEffect, useState } from "react";
import { StyleSheet, Text, View, Platform } from "react-native";
import {
  Camera,
  useCameraPermission,
  useCameraDevice,
} from "react-native-vision-camera";
import {
  Orientation,
  OrientationLock,
  getOrientationLockAsync,
  lockAsync,
} from "expo-screen-orientation";
import { Accelerometer } from "expo-sensors";

const getNextOrientationFromAccelerometerEvent = (x, y, z) => {
  // when the device is flat, keep the current orientation
  if (Math.abs(z) > 0.5) {
    return undefined;
  }
  if (x >= 0.75) {
    return Orientation.LANDSCAPE_LEFT;
  }
  if (x <= -0.75) {
    return Orientation.LANDSCAPE_RIGHT;
  }
  if (y >= 0.75) {
    return Orientation.PORTRAIT_UP;
  }
  if (y <= -0.75) {
    return Orientation.PORTRAIT_DOWN;
  }
  return undefined;
};

// custom hook to get the current orientation of the device
const useCurrentOrientation = () => {
  const [orientation, setOrientation] = useState(Orientation.PORTRAIT_UP);
  useEffect(() => {
    Accelerometer.setUpdateInterval(16);
    console.log("register subscription");
    const subscription = Accelerometer.addListener((event) => {
      const nextOrientation = getNextOrientationFromAccelerometerEvent(
        event.x,
        event.y,
        event.z,
      );
      if (nextOrientation) {
        setOrientation(nextOrientation);
      }
    });
    return () => {
      console.log("remove subscription");
      Accelerometer.removeSubscription(subscription);
    };
  }, []);
  return orientation;
};

const getLockOrientation = (orientation) => {
  switch (orientation) {
    case Orientation.PORTRAIT_UP:
      return OrientationLock.PORTRAIT_UP;
    case Orientation.PORTRAIT_DOWN:
      return OrientationLock.PORTRAIT_UP;
    case Orientation.LANDSCAPE_RIGHT:
      return Platform.OS === "ios"
        ? OrientationLock.LANDSCAPE_RIGHT
        : OrientationLock.LANDSCAPE_LEFT;
    case Orientation.LANDSCAPE_LEFT:
      return Platform.OS === "ios"
        ? OrientationLock.LANDSCAPE_LEFT
        : OrientationLock.LANDSCAPE_RIGHT;
    default:
      return undefined;
  }
};

const App = () => {
  const device = useCameraDevice("back");
  const { hasPermission, requestPermission } = useCameraPermission();
  const orientation = useCurrentOrientation();

  useEffect(() => {
    if (!hasPermission) {
      requestPermission();
    }
  }, [hasPermission]);

  // lock screen orientation based on the current orientation
  useEffect(() => {
    const f = async () => {
      console.log("orientation changed", orientation);
      const lockOrientation = await getOrientationLockAsync();
      const nextLockOrientation = getLockOrientation(orientation);
      if (nextLockOrientation && lockOrientation !== nextLockOrientation) {
        // emulates the behavior of production apps
        setTimeout(() => {
          lockAsync(nextLockOrientation);
        }, 500);
      }
    };
    f();
  }, [orientation]);

  if (!hasPermission)
    return (
      <View>
        <Text>Camera permission required</Text>
      </View>
    );

  if (device == null)
    return (
      <View>
        <Text>No camera device found</Text>
      </View>
    );

  return (
    <Camera style={StyleSheet.absoluteFill} device={device} isActive={true} />
  );
};

export default App;

package.json

{
  "name": "vision-camera-poc-2",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "ios": "expo run:ios --device",
    "android": "expo run:android"
  },
  "dependencies": {
    "@react-navigation/native": "^7.0.9",
    "@react-navigation/native-stack": "^7.1.10",
    "expo": "~50.0.17",
    "expo-screen-orientation": "~6.4.1",
    "expo-sensors": "~12.9.1",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-native": "0.73.6",
    "react-native-orientation-locker": "^1.7.0",
    "react-native-safe-area-context": "4.8.2",
    "react-native-screens": "4",
    "react-native-vision-camera": "^4.6.3"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

Relevant log output

2024-12-11 14:16:51.938310+0900 visioncamerapoc2[782:66087] [native] Invalidating <RCTCxxBridge: 0x108706430> (parent: <RCTBridge: 0x280cbcf50>, executor: (null))
2024-12-11 14:16:52.023030+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentConstants'
2024-12-11 14:16:52.031448+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentFileSystem'
2024-12-11 14:16:52.032647+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExpoKeepAwake'
2024-12-11 14:16:52.035738+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExpoScreenOrientation'
2024-12-11 14:16:52.036204+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentAccelerometer'
2024-12-11 14:16:52.036301+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExpoBarometer'
2024-12-11 14:16:52.036425+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentDeviceMotion'
2024-12-11 14:16:52.036528+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentGyroscope'
2024-12-11 14:16:52.036625+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentMagnetometer'
2024-12-11 14:16:52.036732+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentMagnetometerUncalibrated'
2024-12-11 14:16:52.037759+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'ExponentPedometer'
2024-12-11 14:16:52.039518+0900 visioncamerapoc2[782:66087] [expo] 🟢 Registering module 'NativeModulesProxy'
Thread Performance Checker: Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions
PID: 782, TID: 66087
Backtrace
=================================================================
3   visioncamerapoc2                    0x000000010585f360 -[SRRunLoopThread runLoop] + 44
4   visioncamerapoc2                    0x000000010585989c +[NSRunLoop(SRWebSocket) SR_networkRunLoop] + 56
5   visioncamerapoc2                    0x000000010585dc90 -[SRProxyConnect _openConnection] + 72
6   visioncamerapoc2                    0x000000010585d148 -[SRProxyConnect _configureProxy] + 916
7   visioncamerapoc2                    0x000000010585c93c -[SRProxyConnect openNetworkStreamWithCompletion:] + 92
8   visioncamerapoc2                    0x00000001058610f0 -[SRWebSocket open] + 624
9   visioncamerapoc2                    0x000000010529a504 -[RCTReconnectingWebSocket start] + 148
10  visioncamerapoc2                    0x0000000105285588 -[RCTPackagerConnection init] + 416
11  visioncamerapoc2                    0x00000001052853c8 __49+[RCTPackagerConnection sharedPackagerConnection]_block_invoke + 36
12  libdispatch.dylib                   0x000000010791a038 _dispatch_client_callout + 20
13  libdispatch.dylib                   0x000000010791bb9c _dispatch_once_callout + 140
14  visioncamerapoc2                    0x000000010528537c +[RCTPackagerConnection sharedPackagerConnection] + 88
15  visioncamerapoc2                    0x0000000105313360 -[RCTDevSettings initialize] + 164
16  visioncamerapoc2                    0x0000000105270ed0 -[RCTModuleData _initializeModule] + 92
17  visioncamerapoc2                    0x0000000105270828 -[RCTModuleData setUpInstanceAndBridge:] + 2168
18  visioncamerapoc2                    0x0000000105272324 -[RCTModuleData instance] + 1168
19  visioncamerapoc2                    0x00000001052192b0 -[RCTCxxBridge moduleForName:lazilyLoadIfNecessary:] + 704
20  visioncamerapoc2                    0x000000010527aff4 -[RCTModuleRegistry moduleForName:lazilyLoadIfNecessary:] + 140
21  visioncamerapoc2                    0x000000010527af5c -[RCTModuleRegistry moduleForName:] + 48
22  visioncamerapoc2                    0x000000010532351c -[RCTPerfMonitor devMenuItem] + 92
23  visioncamerapoc2                    0x00000001053233e8 -[RCTPerfMonitor initialize] + 88
24  visioncamerapoc2                    0x0000000105270ed0 -[RCTModuleData _initializeModule] + 92
25  visioncamerapoc2                    0x0000000105270828 -[RCTModuleData setUpInstanceAndBridge:] + 2168
26  visioncamerapoc2                    0x000000010527255c __25-[RCTModuleData instance]_block_invoke + 44
27  visioncamerapoc2                    0x00000001052d3d68 RCTUnsafeExecuteOnMainQueueSync + 52
28  visioncamerapoc2                    0x00000001052721c4 -[RCTModuleData instance] + 816
29  visioncamerapoc2                    0x000000010521db90 __49-[RCTCxxBridge _prepareModulesWithDispatchGroup:]_block_invoke + 160

30  libdispatch.dylib                   0x0000000107918520 _dispatch_call_block_and_release + 32
31  libdispatch.dylib                   0x000000010791a038 _dispatch_client_callout + 20
32  libdispatch.dylib                   0x000000010792a89c _dispatch_main_queue_drain + 1456
33  libdispatch.dylib                   0x000000010792a2dc _dispatch_main_queue_callback_4CF + 44
34  CoreFoundation                      0x00000001cb413c28 A900B459-0127-379E-9CBA-0EAB9C5D559F + 625704
35  CoreFoundation                      0x00000001cb3f5560 A900B459-0127-379E-9CBA-0EAB9C5D559F + 501088
36  CoreFoundation                      0x00000001cb3fa3ec CFRunLoopRunSpecific + 612
37  GraphicsServices                    0x000000020691035c GSEventRunModal + 164
38  UIKitCore                           0x00000001cd786f58 7D57A1D1-856F-338D-97DB-880C4EC8B02E + 3788632
39  UIKitCore                           0x00000001cd786bbc UIApplicationMain + 340
40  visioncamerapoc2                    0x0000000104fc47c0 main + 96

41  dyld                                0x00000001ea92cdec C3FC2EE4-367F-3086-BEB8-420AD442BF88 + 89580
2024-12-11 14:16:53.337741+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'NativeModulesProxy'
2024-12-11 14:16:53.342762+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentConstants'
2024-12-11 14:16:53.344444+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentFileSystem'
14:16:53.381: [info] 📸 VisionCamera.constantsToExport(): Found 5 initial Camera Devices.
2024-12-11 14:16:53.409621+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExpoScreenOrientation'
2024-12-11 14:16:53.410389+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentPedometer'
2024-12-11 14:16:53.411717+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentAccelerometer'
2024-12-11 14:16:53.412346+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExpoBarometer'
2024-12-11 14:16:53.412903+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentDeviceMotion'
2024-12-11 14:16:53.413760+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentGyroscope'
2024-12-11 14:16:53.414069+0900 visioncamerapoc2[782:66644] [connection] nw_socket_handle_socket_event [C7:1] Socket SO_ERROR [61: Connection refused]
2024-12-11 14:16:53.414299+0900 visioncamerapoc2[782:67599] [connection] nw_connection_get_connected_socket_block_invoke [C7] Client called nw_connection_get_connected_socket on unconnected nw_connection
2024-12-11 14:16:53.414397+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentMagnetometer'
2024-12-11 14:16:53.414453+0900 visioncamerapoc2[782:67599] TCP Conn 0x2816a1ae0 Failed : error 0:61 [61]
2024-12-11 14:16:53.414675+0900 visioncamerapoc2[782:67599] [connection] nw_connection_copy_connected_local_endpoint_block_invoke [C7] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection
2024-12-11 14:16:53.414904+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExponentMagnetometerUncalibrated'
2024-12-11 14:16:53.415353+0900 visioncamerapoc2[782:67599] [connection] nw_connection_copy_connected_remote_endpoint_block_invoke [C7] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection
2024-12-11 14:16:53.418227+0900 visioncamerapoc2[782:67601] [native] Unbalanced calls start/end for tag 19
2024-12-11 14:16:53.419096+0900 visioncamerapoc2[782:66087] [native] Running application main ({
    initialProps =     {
    };
    rootTag = 1;
})
2024-12-11 14:16:53.424701+0900 visioncamerapoc2[782:67601] [javascript] Running "main" with {"rootTag":1,"initialProps":{}}
2024-12-11 14:16:53.561808+0900 visioncamerapoc2[782:67601] [javascript] register subscription
2024-12-11 14:16:53.564317+0900 visioncamerapoc2[782:67601] [javascript] 'orientation changed', 1
2024-12-11 14:16:53.564771+0900 visioncamerapoc2[782:67601] [expo] 🟢 Creating JS object for module 'ExpoKeepAwake'
2024-12-11 14:16:53.588793+0900 visioncamerapoc2[782:67601] [javascript] 'orientation changed', 2
14:16:58.265: [info] 📸 VisionCamera.didSetProps(_:): Updating 22 props: [onInitialized, cameraId, position, enableBufferCompression, onOutputOrientationChanged, onStarted, preview, top, onCodeScanned, right, isActive, isMirrored, onViewReady, onError, onStopped, onPreviewOrientationChanged, onPreviewStopped, enableFrameProcessor, onPreviewStarted, left, bottom, onShutter]
14:16:58.266: [info] 📸 VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: portrait...
14:16:58.267: [info] 📸 VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: portrait...
14:16:58.267: [info] 📸 VisionCamera.configure(_:): configure { ... }: Waiting for lock...
14:16:58.269: [info] 📸 VisionCamera.configure(_:): configure { ... }: Updating CameraSession Configuration... Difference(inputChanged: true, outputsChanged: true, videoStabilizationChanged: true, orientationChanged: true, formatChanged: true, sidePropsChanged: true, torchChanged: true, zoomChanged: true, exposureChanged: true, audioSessionChanged: true, locationChanged: true)
14:16:58.270: [info] 📸 VisionCamera.configureDevice(configuration:): Configuring Input Device...
14:16:58.270: [info] 📸 VisionCamera.configureDevice(configuration:): Configuring Camera com.apple.avfoundation.avcapturedevice.built-in_video:0...
14:16:58.277: [info] 📸 VisionCamera.configureDevice(configuration:): Successfully configured Input Device!
14:16:58.277: [info] 📸 VisionCamera.configureOutputs(configuration:): Configuring Outputs...
14:16:58.277: [info] 📸 VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: portrait...
14:16:58.277: [info] 📸 VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: portrait...
14:16:58.277: [info] 📸 VisionCamera.configureOutputs(configuration:): Successfully configured all outputs!
14:16:58.278: [info] 📸 VisionCamera.setTargetOutputOrientation(_:): Setting target output orientation from device to device...
14:16:58.501: [info] 📸 VisionCamera.init(frame:session:): Preview Layer started previewing.
14:16:58.502: [info] 📸 VisionCamera.configure(_:): Beginning AudioSession configuration...
14:16:58.503: [info] 📸 VisionCamera.configureAudioSession(configuration:): Configuring Audio Session...
14:16:58.504: [info] 📸 VisionCamera.configure(_:): Beginning Location Output configuration...
14:16:58.504: [info] 📸 VisionCamera.configure(_:): Committed AudioSession configuration!
14:16:58.507: [info] 📸 VisionCamera.configure(_:): Finished Location Output configuration!
2024-12-11 14:16:58.674987+0900 visioncamerapoc2[782:66087] [expo] 🟢 Posting 'appBecomesActive' event to registered modules

Camera Device

iPhone11 (iOS 16.6.1)

Device

{
  "minZoom": 1,
  "isMultiCam": false,
  "maxZoom": 16,
  "hardwareLevel": "full",
  "sensorOrientation": "portrait",
  "maxExposure": 8,
  "supportsLowLightBoost": false,
  "supportsFocus": true,
  "neutralZoom": 1,
  "supportsRawCapture": false,
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "position": "back",
  "formats": [],
  "id": "com.apple.avfoundation.avcapturedevice.built-in_video:0",
  "name": "Back Camera",
  "hasFlash": true,
  "minExposure": -8,
  "minFocusDistance": 12,
  "hasTorch": true
}

VisionCamera Version

4.6.3

RPReplay_Final1733896819.MP4

@akhlivnoy
Copy link

akhlivnoy commented Dec 18, 2024

After several attempts I found a solution that helped me:

export const CameraScreen = () => {
  const device = useCameraDevice('back');
  const isFocused = useIsFocused();
  const [orientationChanged, setOrientationChanged] = useState(false);

  useEffect(() => {
    ScreenOrientation.addOrientationChangeListener(() => {
      setOrientationChanged(true);
    });
    ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT);

    return () => {
      ScreenOrientation.removeOrientationChangeListeners();
      ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP);
    };
  }, []);

  return (
    <View style={{ flex: 1 }}>
      {orientationChanged && device && (
        <Camera
          isActive={isFocused}
          device={device}
          style={StyleSheet.absoluteFill}
        />
      )}
    </View>
  );
};

Basically, you need to rerender the Camera component after handling the OrientationChangeListener (you can also change the Camera prop "key").
I hope it will help you too.

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