[camera]manages ios camera's orientation states on capture session queue (#4748)

diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md
index f846774..c05ea24 100644
--- a/packages/camera/camera/CHANGELOG.md
+++ b/packages/camera/camera/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.9.4+11
+
+* Manages iOS camera's orientation-related states on a background queue to prevent potential race conditions. 
+
 ## 0.9.4+10
 
 * iOS performance improvement by moving file writing from the main queue to a background IO queue. 
diff --git a/packages/camera/camera/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera/example/ios/RunnerTests/CameraOrientationTests.m
index efd65a4..50f3416 100644
--- a/packages/camera/camera/example/ios/RunnerTests/CameraOrientationTests.m
+++ b/packages/camera/camera/example/ios/RunnerTests/CameraOrientationTests.m
@@ -49,6 +49,28 @@
   OCMVerifyAll(mockMessenger);
 }
 
+- (void)testOrientationUpdateMustBeOnCaptureSessionQueue {
+  XCTestExpectation *queueExpectation = [self
+      expectationWithDescription:@"Orientation update must happen on the capture session queue"];
+
+  CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil];
+  const char *captureSessionQueueSpecific = "capture_session_queue";
+  dispatch_queue_set_specific(camera.captureSessionQueue, captureSessionQueueSpecific,
+                              (void *)captureSessionQueueSpecific, NULL);
+  FLTCam *mockCam = OCMClassMock([FLTCam class]);
+  camera.camera = mockCam;
+  OCMStub([mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft])
+      .andDo(^(NSInvocation *invocation) {
+        if (dispatch_get_specific(captureSessionQueueSpecific)) {
+          [queueExpectation fulfill];
+        }
+      });
+
+  [camera orientationChanged:
+              [self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]];
+  [self waitForExpectationsWithTimeout:1 handler:nil];
+}
+
 - (void)rotate:(UIDeviceOrientation)deviceOrientation
     expectedChannelOrientation:(NSString *)channelOrientation
                   cameraPlugin:(CameraPlugin *)cameraPlugin
diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m
index a0adb70..97e9954 100644
--- a/packages/camera/camera/ios/Classes/CameraPlugin.m
+++ b/packages/camera/camera/ios/Classes/CameraPlugin.m
@@ -17,7 +17,6 @@
 @interface CameraPlugin ()
 @property(readonly, nonatomic) FLTThreadSafeTextureRegistry *registry;
 @property(readonly, nonatomic) NSObject<FlutterBinaryMessenger> *messenger;
-@property(readonly, nonatomic) FLTCam *camera;
 @property(readonly, nonatomic) FLTThreadSafeMethodChannel *deviceEventMethodChannel;
 @end
 
@@ -69,11 +68,12 @@
     return;
   }
 
-  if (_camera) {
-    [_camera setDeviceOrientation:orientation];
-  }
-
-  [self sendDeviceOrientation:orientation];
+  dispatch_async(self.captureSessionQueue, ^{
+    // `FLTCam::setDeviceOrientation` must be called on capture session queue.
+    [self.camera setDeviceOrientation:orientation];
+    // `CameraPlugin::sendDeviceOrientation` can be called on any queue.
+    [self sendDeviceOrientation:orientation];
+  });
 }
 
 - (void)sendDeviceOrientation:(UIDeviceOrientation)orientation {
diff --git a/packages/camera/camera/ios/Classes/CameraPlugin_Test.h b/packages/camera/camera/ios/Classes/CameraPlugin_Test.h
index e36b4ab..826b050 100644
--- a/packages/camera/camera/ios/Classes/CameraPlugin_Test.h
+++ b/packages/camera/camera/ios/Classes/CameraPlugin_Test.h
@@ -5,14 +5,18 @@
 // This header is available in the Test module. Import via "@import camera.Test;"
 
 #import <camera/CameraPlugin.h>
+#import <camera/FLTCam.h>
 #import <camera/FLTThreadSafeFlutterResult.h>
 
 /// Methods exposed for unit testing.
 @interface CameraPlugin ()
 
-// All FLTCam's state access and capture session related operations should be on run on this queue.
+/// All FLTCam's state access and capture session related operations should be on run on this queue.
 @property(nonatomic, strong) dispatch_queue_t captureSessionQueue;
 
+/// An internal camera object that manages camera's state and performs camera operations.
+@property(nonatomic, strong) FLTCam *camera;
+
 /// Inject @p FlutterTextureRegistry and @p FlutterBinaryMessenger for unit testing.
 - (instancetype)initWithRegistry:(NSObject<FlutterTextureRegistry> *)registry
                        messenger:(NSObject<FlutterBinaryMessenger> *)messenger
diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml
index 4516e55..f522608 100644
--- a/packages/camera/camera/pubspec.yaml
+++ b/packages/camera/camera/pubspec.yaml
@@ -4,7 +4,7 @@
   Dart.
 repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
-version: 0.9.4+10
+version: 0.9.4+11
 
 environment:
   sdk: ">=2.14.0 <3.0.0"