Skip to content

Commit

Permalink
[camera] Finish converting iOS to Pigeon (#6601)
Browse files Browse the repository at this point in the history
Converts all remaining Dart->host communication in the iOS implementation to use Pigeon. Given the boilerplate nature of many of the changes, it seemed easiest to just do the remaining calls all at once now that the structure is in place.

Some high-level notes:
- Many methods used to send the `cameraId` without it ever being used on the native side, so the Pigeon versions do not send them.
- `ThreadSafeTextureRegistry` is removed because I discovered that it was masking a bug, so was more trouble than it was worth (see inline comments in PR).
- A number of enums have been removed in favor of using the Pigeon-generated enums to pass data from the plugin class to `FLTCam`.
- In many cases where the completion callback (previously `result`) was being passed to `FLTCam` in a call, only to have it always just call `result(nil)`, that's now done in the plugin class since it's easier to reason about completions being called when they aren't passed around. (Long term we should consider moving almost all of the rest out, and using `FlutterError*` out params that the plugin class passes to `completion`, but that is more surgery than I wanted to do in this PR.)

Completes the iOS portion of flutter/flutter#117905
  • Loading branch information
stuartmorgan committed Apr 24, 2024
1 parent 890ec36 commit 59916a9
Show file tree
Hide file tree
Showing 37 changed files with 3,497 additions and 2,179 deletions.
9 changes: 7 additions & 2 deletions packages/camera/camera_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.9.16

* Converts Dart-to-host communcation to Pigeon.
* Fixes a race condition in camera disposal.

## 0.9.15+4

* Converts host-to-Dart communcation to Pigeon.
Expand Down Expand Up @@ -121,11 +126,11 @@

## 0.9.8+5

* Fixes a regression introduced in 0.9.8+4 where the stream handler is not set.
* Fixes a regression introduced in 0.9.8+4 where the stream handler is not set.

## 0.9.8+4

* Fixes a crash due to sending orientation change events when the engine is torn down.
* Fixes a crash due to sending orientation change events when the engine is torn down.

## 0.9.8+3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
E071CF7227B3061B006EF3BA /* FLTCamPhotoCaptureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E071CF7127B3061B006EF3BA /* FLTCamPhotoCaptureTests.m */; };
E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E071CF7327B31DE4006EF3BA /* FLTCamSampleBufferTests.m */; };
E0B0D2BB27DFF2AF00E71E4B /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; };
E0C6E2012770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C6E1FE2770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m */; };
E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */; };
E0CDBAC227CD9729002561D9 /* CameraTestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E0CDBAC127CD9729002561D9 /* CameraTestUtils.m */; };
E0F95E3D27A32AB900699390 /* CameraPropertiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0F95E3C27A32AB900699390 /* CameraPropertiesTests.m */; };
Expand Down Expand Up @@ -95,7 +94,6 @@
E071CF7127B3061B006EF3BA /* FLTCamPhotoCaptureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTCamPhotoCaptureTests.m; sourceTree = "<group>"; };
E071CF7327B31DE4006EF3BA /* FLTCamSampleBufferTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTCamSampleBufferTests.m; sourceTree = "<group>"; };
E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraPermissionTests.m; sourceTree = "<group>"; };
E0C6E1FE2770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadSafeTextureRegistryTests.m; sourceTree = "<group>"; };
E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadSafeEventChannelTests.m; sourceTree = "<group>"; };
E0CDBAC027CD9729002561D9 /* CameraTestUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CameraTestUtils.h; sourceTree = "<group>"; };
E0CDBAC127CD9729002561D9 /* CameraTestUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraTestUtils.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -132,7 +130,6 @@
03BB766C2665316900CE5A93 /* Info.plist */,
033B94BD269C40A200B4DF97 /* CameraMethodChannelTests.m */,
E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */,
E0C6E1FE2770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m */,
E04F108527A87CA600573D0C /* FLTSavePhotoDelegateTests.m */,
E071CF7127B3061B006EF3BA /* FLTCamPhotoCaptureTests.m */,
E071CF7327B31DE4006EF3BA /* FLTCamSampleBufferTests.m */,
Expand Down Expand Up @@ -449,7 +446,6 @@
E032F250279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m in Sources */,
788A065A27B0E02900533D74 /* StreamingTest.m in Sources */,
E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */,
E0C6E2012770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m in Sources */,
E0B0D2BB27DFF2AF00E71E4B /* CameraPermissionTests.m in Sources */,
E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,25 @@ - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition {
[self expectationWithDescription:@"dispose's result block must be called"];
XCTestExpectation *createExpectation =
[self expectationWithDescription:@"create's result block must be called"];
FlutterMethodCall *disposeCall = [FlutterMethodCall methodCallWithMethodName:@"dispose"
arguments:nil];
FlutterMethodCall *createCall = [FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{@"resolutionPreset" : @"medium", @"enableAudio" : @(1)}];
// Mimic a dispose call followed by a create call, which can be triggered by slightly dragging the
// home bar, causing the app to be inactive, and immediately regain active.
[camera handleMethodCall:disposeCall
result:^(id _Nullable result) {
[disposeExpectation fulfill];
}];
[camera createCameraOnSessionQueueWithCreateMethodCall:createCall
result:^(id _Nullable result) {
[createExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
[camera disposeCamera:0
completion:^(FlutterError *_Nullable error) {
[disposeExpectation fulfill];
}];
[camera createCameraOnSessionQueueWithName:@"acamera"
settings:[FCPPlatformMediaSettings
makeWithResolutionPreset:
FCPPlatformResolutionPresetMedium
framesPerSecond:nil
videoBitrate:nil
audioBitrate:nil
enableAudio:YES]
completion:^(NSNumber *_Nullable result,
FlutterError *_Nullable error) {
[createExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:30 handler:nil];
// `captureSessionQueue` must not be nil after `create` call. Otherwise a nil
// `captureSessionQueue` passed into `AVCaptureVideoDataOutput::setSampleBufferDelegate:queue:`
// API will cause a crash.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,9 @@ - (void)testSetFocusPointWithResult_SetsFocusPointOfInterest {
[_camera setValue:_mockDevice forKey:@"captureDevice"];

// Run test
[_camera
setFocusPointWithResult:^(id _Nullable result) {
}
x:1
y:1];
[_camera setFocusPoint:[FCPPlatformPoint makeWithX:1 y:1]
withCompletion:^(FlutterError *_Nullable error){
}];

// Verify the focus point of interest has been set
OCMVerify([_mockDevice setFocusPointOfInterest:CGPointMake(1, 1)]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,24 @@ - (void)testCreate_ShouldCallResultOnMainThread {
OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);

// Set up method call
FlutterMethodCall *call = [FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{@"resolutionPreset" : @"medium", @"enableAudio" : @(1)}];

__block id resultValue;
[camera createCameraOnSessionQueueWithCreateMethodCall:call
result:^(id _Nullable result) {
resultValue = result;
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
__block NSNumber *resultValue;
[camera createCameraOnSessionQueueWithName:@"acamera"
settings:[FCPPlatformMediaSettings
makeWithResolutionPreset:
FCPPlatformResolutionPresetMedium
framesPerSecond:nil
videoBitrate:nil
audioBitrate:nil
enableAudio:YES]
completion:^(NSNumber *_Nullable result,
FlutterError *_Nullable error) {
resultValue = result;
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:30 handler:nil];

// Verify the result
NSDictionary *dictionaryResult = (NSDictionary *)resultValue;
XCTAssertNotNil(dictionaryResult);
XCTAssert([[dictionaryResult allKeys] containsObject:@"cameraId"]);
XCTAssertNotNil(resultValue);
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,14 @@ @implementation CameraPreviewPauseTests
- (void)testPausePreviewWithResult_shouldPausePreview {
FLTCam *camera = [[FLTCam alloc] init];

[camera pausePreviewWithResult:^(id _Nullable result){
}];
[camera pausePreview];
XCTAssertTrue(camera.isPreviewPaused);
}

- (void)testResumePreviewWithResult_shouldResumePreview {
FLTCam *camera = [[FLTCam alloc] init];

[camera resumePreviewWithResult:^(id _Nullable result){
}];
[camera resumePreview];
XCTAssertFalse(camera.isPreviewPaused);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,68 +15,39 @@ @implementation CameraPropertiesTests

#pragma mark - flash mode tests

- (void)testFLTGetFLTFlashModeForString {
XCTAssertEqual(FLTFlashModeOff, FLTGetFLTFlashModeForString(@"off"));
XCTAssertEqual(FLTFlashModeAuto, FLTGetFLTFlashModeForString(@"auto"));
XCTAssertEqual(FLTFlashModeAlways, FLTGetFLTFlashModeForString(@"always"));
XCTAssertEqual(FLTFlashModeTorch, FLTGetFLTFlashModeForString(@"torch"));
XCTAssertEqual(FLTFlashModeInvalid, FLTGetFLTFlashModeForString(@"unknown"));
}

- (void)testFLTGetAVCaptureFlashModeForFLTFlashMode {
XCTAssertEqual(AVCaptureFlashModeOff, FLTGetAVCaptureFlashModeForFLTFlashMode(FLTFlashModeOff));
XCTAssertEqual(AVCaptureFlashModeAuto, FLTGetAVCaptureFlashModeForFLTFlashMode(FLTFlashModeAuto));
XCTAssertEqual(AVCaptureFlashModeOn, FLTGetAVCaptureFlashModeForFLTFlashMode(FLTFlashModeAlways));
XCTAssertEqual(-1, FLTGetAVCaptureFlashModeForFLTFlashMode(FLTFlashModeTorch));
}

#pragma mark - exposure mode tests

- (void)testFCPGetExposureModeForString {
XCTAssertEqual(FCPPlatformExposureModeAuto, FCPGetExposureModeForString(@"auto"));
XCTAssertEqual(FCPPlatformExposureModeLocked, FCPGetExposureModeForString(@"locked"));
}

#pragma mark - focus mode tests

- (void)testFLTGetFLTFocusModeForString {
XCTAssertEqual(FCPPlatformFocusModeAuto, FCPGetFocusModeForString(@"auto"));
XCTAssertEqual(FCPPlatformFocusModeLocked, FCPGetFocusModeForString(@"locked"));
}

#pragma mark - resolution preset tests

- (void)testFLTGetFLTResolutionPresetForString {
XCTAssertEqual(FLTResolutionPresetVeryLow, FLTGetFLTResolutionPresetForString(@"veryLow"));
XCTAssertEqual(FLTResolutionPresetLow, FLTGetFLTResolutionPresetForString(@"low"));
XCTAssertEqual(FLTResolutionPresetMedium, FLTGetFLTResolutionPresetForString(@"medium"));
XCTAssertEqual(FLTResolutionPresetHigh, FLTGetFLTResolutionPresetForString(@"high"));
XCTAssertEqual(FLTResolutionPresetVeryHigh, FLTGetFLTResolutionPresetForString(@"veryHigh"));
XCTAssertEqual(FLTResolutionPresetUltraHigh, FLTGetFLTResolutionPresetForString(@"ultraHigh"));
XCTAssertEqual(FLTResolutionPresetMax, FLTGetFLTResolutionPresetForString(@"max"));
XCTAssertEqual(FLTResolutionPresetInvalid, FLTGetFLTResolutionPresetForString(@"unknown"));
- (void)testFCPGetAVCaptureFlashModeForPigeonFlashMode {
XCTAssertEqual(AVCaptureFlashModeOff,
FCPGetAVCaptureFlashModeForPigeonFlashMode(FCPPlatformFlashModeOff));
XCTAssertEqual(AVCaptureFlashModeAuto,
FCPGetAVCaptureFlashModeForPigeonFlashMode(FCPPlatformFlashModeAuto));
XCTAssertEqual(AVCaptureFlashModeOn,
FCPGetAVCaptureFlashModeForPigeonFlashMode(FCPPlatformFlashModeAlways));
XCTAssertThrows(FCPGetAVCaptureFlashModeForPigeonFlashMode(FCPPlatformFlashModeTorch));
}

#pragma mark - video format tests

- (void)testFLTGetVideoFormatFromString {
XCTAssertEqual(kCVPixelFormatType_32BGRA, FLTGetVideoFormatFromString(@"bgra8888"));
- (void)testFCPGetPixelFormatForPigeonFormat {
XCTAssertEqual(kCVPixelFormatType_32BGRA,
FCPGetPixelFormatForPigeonFormat(FCPPlatformImageFormatGroupBgra8888));
XCTAssertEqual(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
FLTGetVideoFormatFromString(@"yuv420"));
XCTAssertEqual(kCVPixelFormatType_32BGRA, FLTGetVideoFormatFromString(@"unknown"));
FCPGetPixelFormatForPigeonFormat(FCPPlatformImageFormatGroupYuv420));
}

#pragma mark - device orientation tests

- (void)testFLTGetUIDeviceOrientationForString {
- (void)testFCPGetUIDeviceOrientationForPigeonDeviceOrientation {
XCTAssertEqual(UIDeviceOrientationPortraitUpsideDown,
FLTGetUIDeviceOrientationForString(@"portraitDown"));
FCPGetUIDeviceOrientationForPigeonDeviceOrientation(
FCPPlatformDeviceOrientationPortraitDown));
XCTAssertEqual(UIDeviceOrientationLandscapeLeft,
FLTGetUIDeviceOrientationForString(@"landscapeLeft"));
FCPGetUIDeviceOrientationForPigeonDeviceOrientation(
FCPPlatformDeviceOrientationLandscapeLeft));
XCTAssertEqual(UIDeviceOrientationLandscapeRight,
FLTGetUIDeviceOrientationForString(@"landscapeRight"));
XCTAssertEqual(UIDeviceOrientationPortrait, FLTGetUIDeviceOrientationForString(@"portraitUp"));
XCTAssertEqual(UIDeviceOrientationUnknown, FLTGetUIDeviceOrientationForString(@"unknown"));
FCPGetUIDeviceOrientationForPigeonDeviceOrientation(
FCPPlatformDeviceOrientationLandscapeRight));
XCTAssertEqual(UIDeviceOrientationPortrait, FCPGetUIDeviceOrientationForPigeonDeviceOrientation(
FCPPlatformDeviceOrientationPortraitUp));
}

- (void)testFLTGetStringForUIDeviceOrientation {
Expand All @@ -93,12 +64,4 @@ - (void)testFLTGetStringForUIDeviceOrientation {
FCPGetPigeonDeviceOrientationForOrientation(-1));
}

#pragma mark - file format tests

- (void)testFLTGetFileFormatForString {
XCTAssertEqual(FCPFileFormatJPEG, FCPGetFileFormatFromString(@"jpg"));
XCTAssertEqual(FCPFileFormatHEIF, FCPGetFileFormatFromString(@"heif"));
XCTAssertEqual(FCPFileFormatInvalid, FCPGetFileFormatFromString(@"unknown"));
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset {
OCMExpect([captureDeviceMock lockForConfiguration:NULL]).andReturn(YES);
OCMExpect([videoSessionMock setSessionPreset:expectedPreset]);

FLTCreateCamWithVideoDimensionsForFormat(videoSessionMock, @"max", captureDeviceMock,
FLTCreateCamWithVideoDimensionsForFormat(videoSessionMock, FCPPlatformResolutionPresetMax,
captureDeviceMock,
^CMVideoDimensions(AVCaptureDeviceFormat *format) {
CMVideoDimensions videoDimensions;
videoDimensions.width = 1;
Expand All @@ -53,7 +54,7 @@ - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionP

OCMExpect([videoSessionMock setSessionPreset:expectedPreset]);

FLTCreateCamWithVideoCaptureSession(videoSessionMock, @"max");
FLTCreateCamWithVideoCaptureSession(videoSessionMock, FCPPlatformResolutionPresetMax);

OCMVerifyAll(videoSessionMock);
}
Expand All @@ -70,7 +71,7 @@ - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSe
// Expect that setting "ultraHigh" resolutionPreset correctly updates videoCaptureSession.
OCMExpect([videoSessionMock setSessionPreset:expectedPreset]);

FLTCreateCamWithVideoCaptureSession(videoSessionMock, @"ultraHigh");
FLTCreateCamWithVideoCaptureSession(videoSessionMock, FCPPlatformResolutionPresetUltraHigh);

OCMVerifyAll(videoSessionMock);
}
Expand Down
Loading

0 comments on commit 59916a9

Please sign in to comment.