diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 8d778252f63a..2388f101e24d 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.18+4 + +* Refactors implementations to reduce usage of OCMock in internal testing. + ## 0.9.18+3 * Refactors implementations to reduce usage of OCMock in internal testing. diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index fbcb6d2d6ece..75716ac04cf2 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FA99E582D22C75300582559 /* CameraExposureTests.m */; }; 7FCEDD352D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */; }; 7FCEDD362D43C2B900EA1CA8 /* MockCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */; }; + 7FD582352D57D97C003B1200 /* MockCaptureDeviceFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FD582342D57D97C003B1200 /* MockCaptureDeviceFormat.m */; }; 7FD582122D579650003B1200 /* MockWritableData.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FD582112D579650003B1200 /* MockWritableData.m */; }; 7FD582202D579ECC003B1200 /* MockCapturePhotoOutput.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FD5821F2D579ECC003B1200 /* MockCapturePhotoOutput.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; @@ -104,6 +105,8 @@ 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDevice.m; sourceTree = ""; }; 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; + 7FD582342D57D97C003B1200 /* MockCaptureDeviceFormat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceFormat.m; sourceTree = ""; }; + 7FD582362D57D989003B1200 /* MockCaptureDeviceFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceFormat.h; sourceTree = ""; }; 7FD582112D579650003B1200 /* MockWritableData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockWritableData.m; sourceTree = ""; }; 7FD582132D57965A003B1200 /* MockWritableData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockWritableData.h; sourceTree = ""; }; 7FD5821F2D579ECC003B1200 /* MockCapturePhotoOutput.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCapturePhotoOutput.m; sourceTree = ""; }; @@ -205,6 +208,8 @@ 7F8FD2272D4BFA8D001AF2C1 /* MockGlobalEventApi.h */, 7FCEDD312D43C2B900EA1CA8 /* MockCaptureDevice.h */, 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */, + 7FD582362D57D989003B1200 /* MockCaptureDeviceFormat.h */, + 7FD582342D57D97C003B1200 /* MockCaptureDeviceFormat.m */, 7FD582212D579ED9003B1200 /* MockCapturePhotoOutput.h */, 7FD5821F2D579ECC003B1200 /* MockCapturePhotoOutput.m */, 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */, @@ -516,6 +521,7 @@ 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, + 7FD582352D57D97C003B1200 /* MockCaptureDeviceFormat.m in Sources */, 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */, 7F8FD22F2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m in Sources */, E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */, diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index e0969ad703de..8b6b7964f9f9 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -23,12 +23,10 @@ - (void)setUp { _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; _mockDevice = mockDevice; - _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - nil, nil, nil, - ^NSObject *(void) { - return mockDevice; - }, - _mockDeviceOrientationProvider); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureDeviceFactory = ^NSObject *_Nonnull { return mockDevice; }; + configuration.deviceOrientationProvider = _mockDeviceOrientationProvider; + _camera = FLTCreateCamWithConfiguration(configuration); } - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { @@ -53,7 +51,7 @@ - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { [completionExpectation fulfill]; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; XCTAssertEqual(setPoint.x, 1.0); XCTAssertEqual(setPoint.y, 1.0); } @@ -77,7 +75,7 @@ - (void)testSetExposurePoint_WhenNotSupported_ReturnsError { }]; // Verify - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 5f52c9bc5ee1..fab96850a3a5 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -26,12 +26,10 @@ - (void)setUp { _mockDevice = mockDevice; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - nil, nil, nil, - ^NSObject *(void) { - return mockDevice; - }, - _mockDeviceOrientationProvider); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureDeviceFactory = ^NSObject *_Nonnull { return mockDevice; }; + configuration.deviceOrientationProvider = _mockDeviceOrientationProvider; + _camera = FLTCreateCamWithConfiguration(configuration); } - (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus { @@ -175,7 +173,7 @@ - (void)testSetFocusPoint_WhenNotSupported_ReturnsError { }]; // Verify - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m index 0acc392545fe..1f084f5ba750 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m @@ -8,34 +8,40 @@ #endif @import XCTest; @import AVFoundation; -#import +#import "MockCameraDeviceDiscoverer.h" +#import "MockCaptureDevice.h" +#import "MockCaptureSession.h" #import "MockFlutterBinaryMessenger.h" #import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" @interface CameraMethodChannelTests : XCTestCase @end @implementation CameraMethodChannelTests -- (CameraPlugin *)createCameraPlugin { +- (CameraPlugin *)createCameraPluginWithSession:(MockCaptureSession *)mockSession { return [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] - messenger:[[MockFlutterBinaryMessenger alloc] init]]; + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^NSObject *(NSString *name) { + return [[MockCaptureDevice alloc] init]; + } + captureSessionFactory:^NSObject *_Nonnull { + return mockSession; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; } - (void)testCreate_ShouldCallResultOnMainThread { - CameraPlugin *camera = [self createCameraPlugin]; + MockCaptureSession *avCaptureSessionMock = [[MockCaptureSession alloc] init]; + avCaptureSessionMock.canSetSessionPreset = YES; - XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; - - // Set up mocks for initWithCameraName method - id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) - .andReturn([AVCaptureInput alloc]); + CameraPlugin *camera = [self createCameraPluginWithSession:avCaptureSessionMock]; - id avCaptureSessionMock = OCMClassMock([AVCaptureSession class]); - OCMStub([avCaptureSessionMock alloc]).andReturn(avCaptureSessionMock); - OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); + XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // Set up method call __block NSNumber *resultValue; @@ -59,15 +65,10 @@ - (void)testCreate_ShouldCallResultOnMainThread { } - (void)testDisposeShouldDeallocCamera { - CameraPlugin *camera = [self createCameraPlugin]; - - id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) - .andReturn([AVCaptureInput alloc]); + MockCaptureSession *avCaptureSessionMock = [[MockCaptureSession alloc] init]; + avCaptureSessionMock.canSetSessionPreset = YES; - id avCaptureSessionMock = OCMClassMock([AVCaptureSession class]); - OCMStub([avCaptureSessionMock alloc]).andReturn(avCaptureSessionMock); - OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); + CameraPlugin *camera = [self createCameraPluginWithSession:avCaptureSessionMock]; XCTestExpectation *createExpectation = [self expectationWithDescription:@"create's result block must be called"]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 09f57551f0f3..9f988c2cdfd7 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -139,7 +139,7 @@ - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { [plugin orientationChanged: [self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testOrientationChanged_noRetainCycle { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m index ec7530381023..095b0453298e 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPermissionTests.m @@ -60,7 +60,7 @@ - (void)testRequestCameraPermission_completeWithoutErrorIfPreviouslyAuthorized { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithErrorIfPreviouslyDenied { XCTestExpectation *expectation = @@ -82,7 +82,7 @@ - (void)testRequestCameraPermission_completeWithErrorIfPreviouslyDenied { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithErrorIfRestricted { @@ -102,7 +102,7 @@ - (void)testRequestCameraPermission_completeWithErrorIfRestricted { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess { @@ -125,7 +125,7 @@ - (void)testRequestCameraPermission_completeWithoutErrorIfUserGrantAccess { [grantedExpectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestCameraPermission_completeWithErrorIfUserDenyAccess { @@ -153,7 +153,7 @@ - (void)testRequestCameraPermission_completeWithErrorIfUserDenyAccess { } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } #pragma mark - audio permissions @@ -173,7 +173,7 @@ - (void)testRequestAudioPermission_completeWithoutErrorIfPrevoiuslyAuthorized { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithErrorIfPreviouslyDenied { @@ -196,7 +196,7 @@ - (void)testRequestAudioPermission_completeWithErrorIfPreviouslyDenied { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithErrorIfRestricted { @@ -216,7 +216,7 @@ - (void)testRequestAudioPermission_completeWithErrorIfRestricted { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess { @@ -239,7 +239,7 @@ - (void)testRequestAudioPermission_completeWithoutErrorIfUserGrantAccess { [grantedExpectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testRequestAudioPermission_completeWithErrorIfUserDenyAccess { @@ -265,7 +265,7 @@ - (void)testRequestAudioPermission_completeWithErrorIfUserDenyAccess { [expectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m index 9f7092f6e52f..14b4f2e9bccf 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m @@ -9,8 +9,11 @@ @import AVFoundation; @import XCTest; -#import + #import "CameraTestUtils.h" +#import "MockCaptureDevice.h" +#import "MockCaptureDeviceFormat.h" +#import "MockCaptureSession.h" /// Includes test cases related to resolution presets setting operations for FLTCam class. @interface FLTCamSessionPresetsTest : XCTestCase @@ -20,62 +23,97 @@ @implementation FLTCamSessionPresetsTest - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPresetInputPriority; - - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); - - id captureFormatMock = OCMClassMock([AVCaptureDeviceFormat class]); - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); - OCMStub([captureDeviceMock formats]).andReturn(@[ captureFormatMock ]); - - OCMExpect([captureDeviceMock activeFormat]).andReturn(captureFormatMock); - OCMExpect([captureDeviceMock lockForConfiguration:NULL]).andReturn(YES); - OCMExpect([videoSessionMock setSessionPreset:expectedPreset]); - - FLTCreateCamWithVideoDimensionsForFormat(videoSessionMock, FCPPlatformResolutionPresetMax, - captureDeviceMock, - ^CMVideoDimensions(AVCaptureDeviceFormat *format) { - CMVideoDimensions videoDimensions; - videoDimensions.width = 1; - videoDimensions.height = 1; - return videoDimensions; - }); - - OCMVerifyAll(captureDeviceMock); - OCMVerifyAll(videoSessionMock); + XCTestExpectation *presetExpectation = [self expectationWithDescription:@"Expected preset set"]; + XCTestExpectation *lockForConfigurationExpectation = + [self expectationWithDescription:@"Expected lockForConfiguration called"]; + + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { + if (preset == expectedPreset) { + [presetExpectation fulfill]; + } + }; + + MockCaptureDeviceFormat *captureFormatMock = [[MockCaptureDeviceFormat alloc] init]; + + MockCaptureDevice *captureDeviceMock = [[MockCaptureDevice alloc] init]; + captureDeviceMock.formats = @[ captureFormatMock ]; + captureDeviceMock.activeFormat = captureFormatMock; + captureDeviceMock.lockForConfigurationStub = + ^BOOL(NSError *__autoreleasing _Nullable *_Nullable error) { + [lockForConfigurationExpectation fulfill]; + return YES; + }; + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureDeviceFactory = ^NSObject *_Nonnull { + return captureDeviceMock; + }; + configuration.videoDimensionsForFormat = + ^CMVideoDimensions(NSObject *format) { + CMVideoDimensions videoDimensions; + videoDimensions.width = 1; + videoDimensions.height = 1; + return videoDimensions; + }; + configuration.videoCaptureSession = videoSessionMock; + configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMax); + + FLTCreateCamWithConfiguration(configuration); + + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; + XCTestExpectation *expectation = [self expectationWithDescription:@"Expected preset set"]; - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; // Make sure that setting resolution preset for session always succeeds. - OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); + videoSessionMock.canSetSessionPreset = YES; - OCMExpect([videoSessionMock setSessionPreset:expectedPreset]); + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { + if (preset == expectedPreset) { + [expectation fulfill]; + } + }; - FLTCreateCamWithVideoCaptureSession(videoSessionMock, FCPPlatformResolutionPresetMax); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.videoCaptureSession = videoSessionMock; + configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMax); + configuration.captureDeviceFactory = ^NSObject * { + return [[MockCaptureDevice alloc] init]; + }; - OCMVerifyAll(videoSessionMock); + FLTCreateCamWithConfiguration(configuration); + + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; + XCTestExpectation *expectation = [self expectationWithDescription:@"Expected preset set"]; - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; // Make sure that setting resolution preset for session always succeeds. - OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); + videoSessionMock.canSetSessionPreset = YES; // Expect that setting "ultraHigh" resolutionPreset correctly updates videoCaptureSession. - OCMExpect([videoSessionMock setSessionPreset:expectedPreset]); + videoSessionMock.setSessionPresetStub = ^(NSString *preset) { + if (preset == expectedPreset) { + [expectation fulfill]; + } + }; + + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.videoCaptureSession = videoSessionMock; + configuration.mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetUltraHigh); - FLTCreateCamWithVideoCaptureSession(videoSessionMock, FCPPlatformResolutionPresetUltraHigh); + FLTCreateCamWithConfiguration(configuration); - OCMVerifyAll(videoSessionMock); + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m index 873cc212a8a1..fb07cc3c9d8a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m @@ -8,11 +8,14 @@ #endif @import XCTest; @import AVFoundation; -#import #import "CameraTestUtils.h" +#import "MockCameraDeviceDiscoverer.h" +#import "MockCaptureDevice.h" +#import "MockCaptureSession.h" #import "MockFlutterBinaryMessenger.h" #import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" static const FCPPlatformResolutionPreset gTestResolutionPreset = FCPPlatformResolutionPresetMedium; static const int gTestFramesPerSecond = 15; @@ -68,11 +71,11 @@ - (void)unlockDevice:(AVCaptureDevice *)captureDevice { [_unlockExpectation fulfill]; } -- (void)beginConfigurationForSession:(AVCaptureSession *)videoCaptureSession { +- (void)beginConfigurationForSession:(NSObject *)videoCaptureSession { [_beginConfigurationExpectation fulfill]; } -- (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { +- (void)commitConfigurationForSession:(NSObject *)videoCaptureSession { [_commitConfigurationExpectation fulfill]; } @@ -146,8 +149,10 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { TestMediaSettingsAVWrapper *injectedWrapper = [[TestMediaSettingsAVWrapper alloc] initWithTestCase:self]; - FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_create("test", NULL), settings, injectedWrapper, nil, nil); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.mediaSettingsWrapper = injectedWrapper; + configuration.mediaSettings = settings; + FLTCam *camera = FLTCreateCamWithConfiguration(configuration); // Expect FPS configuration is passed to camera device. [self waitForExpectations:@[ @@ -170,21 +175,25 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { } - (void)testSettings_ShouldBeSupportedByMethodCall { + MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; + MockCaptureSession *mockSession = [[MockCaptureSession alloc] init]; + mockSession.canSetSessionPreset = YES; + CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] - messenger:[[MockFlutterBinaryMessenger alloc] init]]; + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^NSObject *(NSString *name) { + return mockDevice; + } + captureSessionFactory:^NSObject *_Nonnull { + return mockSession; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; - // Set up mocks for initWithCameraName method - id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) - .andReturn([AVCaptureInput alloc]); - - id avCaptureSessionMock = OCMClassMock([AVCaptureSession class]); - OCMStub([avCaptureSessionMock alloc]).andReturn(avCaptureSessionMock); - OCMStub([avCaptureSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - // Set up method call FCPPlatformMediaSettings *mediaSettings = [FCPPlatformMediaSettings makeWithResolutionPreset:gTestResolutionPreset @@ -215,10 +224,12 @@ - (void)testSettings_ShouldSelectFormatWhichSupports60FPS { audioBitrate:@(gTestAudioBitrate) enableAudio:gTestEnableAudio]; - FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_create("test", NULL), settings, nil, nil, nil); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.mediaSettings = settings; + FLTCam *camera = FLTCreateCamWithConfiguration(configuration); - AVFrameRateRange *range = camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; + NSObject *range = + camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; XCTAssertLessThanOrEqual(range.minFrameRate, 60); XCTAssertGreaterThanOrEqual(range.maxFrameRate, 60); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h index c8a5b230453a..a44e3aedcd05 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h @@ -9,39 +9,18 @@ NS_ASSUME_NONNULL_BEGIN -/// Creates an `FLTCam` that runs its capture session operations on a given queue. -/// @param captureSessionQueue the capture session queue -/// @param mediaSettings media settings configuration parameters -/// @param mediaSettingsAVWrapper provider to perform media settings operations (for unit test -/// dependency injection). -/// @param captureDeviceFactory a callback to create capture device instances -/// @return an FLTCam object. -extern FLTCam *_Nullable FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_t _Nullable captureSessionQueue, - FCPPlatformMediaSettings *_Nullable mediaSettings, - FLTCamMediaSettingsAVWrapper *_Nullable mediaSettingsAVWrapper, - CaptureDeviceFactory _Nullable captureDeviceFactory, - id _Nullable deviceOrientationProvider); +/// This method provides a convenient way to create media settings with minimal configuration. +/// Audio is enabled by default, while other parameters use platform-specific defaults. +extern FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( + FCPPlatformResolutionPreset resolutionPreset); + +/// Creates a test `FLTCamConfiguration` with a default mock setup. +extern FLTCamConfiguration *FLTCreateTestCameraConfiguration(void); extern FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue); -/// Creates an `FLTCam` with a given captureSession and resolutionPreset -/// @param captureSession AVCaptureSession for video -/// @param resolutionPreset preset for camera's captureSession resolution -/// @return an FLTCam object. -extern FLTCam *FLTCreateCamWithVideoCaptureSession(NSObject *captureSession, - FCPPlatformResolutionPreset resolutionPreset); - -/// Creates an `FLTCam` with a given captureSession and resolutionPreset. -/// Allows to inject a capture device and a block to compute the video dimensions. -/// @param captureSession AVCaptureSession for video -/// @param resolutionPreset preset for camera's captureSession resolution -/// @param captureDevice AVCaptureDevice to be used -/// @param videoDimensionsForFormat custom code to determine video dimensions -/// @return an FLTCam object. -extern FLTCam *FLTCreateCamWithVideoDimensionsForFormat( - AVCaptureSession *captureSession, FCPPlatformResolutionPreset resolutionPreset, - AVCaptureDevice *captureDevice, VideoDimensionsForFormat videoDimensionsForFormat); +/// Creates an `FLTCam` with a test configuration. +extern FLTCam *FLTCreateCamWithConfiguration(FLTCamConfiguration *configuration); /// Creates a test sample buffer. /// @return a test sample buffer. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 67d4432d2f48..dbb247b53332 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -9,11 +9,11 @@ @import camera_avfoundation; #import "MockCaptureDevice.h" +#import "MockCaptureDeviceFormat.h" #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" -static FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( - FCPPlatformResolutionPreset resolutionPreset) { +FCPPlatformMediaSettings *FCPGetDefaultMediaSettings(FCPPlatformResolutionPreset resolutionPreset) { return [FCPPlatformMediaSettings makeWithResolutionPreset:resolutionPreset framesPerSecond:nil videoBitrate:nil @@ -21,105 +21,71 @@ enableAudio:YES]; } -FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue) { - return FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, nil, - nil); -} +FLTCamConfiguration *FLTCreateTestCameraConfiguration(void) { + dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); + + MockCaptureSession *videoSessionMock = [[MockCaptureSession alloc] init]; + videoSessionMock.canSetSessionPreset = YES; + + MockCaptureSession *audioSessionMock = [[MockCaptureSession alloc] init]; + audioSessionMock.canSetSessionPreset = YES; + + MockFrameRateRange *frameRateRangeMock1 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 + maxFrameRate:30]; + MockCaptureDeviceFormat *captureDeviceFormatMock1 = [[MockCaptureDeviceFormat alloc] init]; + captureDeviceFormatMock1.videoSupportedFrameRateRanges = @[ frameRateRangeMock1 ]; + + MockFrameRateRange *frameRateRangeMock2 = [[MockFrameRateRange alloc] initWithMinFrameRate:3 + maxFrameRate:60]; + MockCaptureDeviceFormat *captureDeviceFormatMock2 = [[MockCaptureDeviceFormat alloc] init]; + captureDeviceFormatMock2.videoSupportedFrameRateRanges = @[ frameRateRangeMock2 ]; + + MockCaptureDevice *captureDeviceMock = [[MockCaptureDevice alloc] init]; + captureDeviceMock.lockForConfigurationStub = ^BOOL(NSError **error) { + return YES; + }; + captureDeviceMock.formats = @[ captureDeviceFormatMock1, captureDeviceFormatMock2 ]; -FLTCam *FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_t captureSessionQueue, FCPPlatformMediaSettings *mediaSettings, - FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper, CaptureDeviceFactory captureDeviceFactory, - NSObject *deviceOrientationProvider) { - if (!mediaSettings) { - mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium); - } - - if (!mediaSettingsAVWrapper) { - mediaSettingsAVWrapper = [[FLTCamMediaSettingsAVWrapper alloc] init]; - } - - if (!deviceOrientationProvider) { - deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - } - - if (!captureSessionQueue) { - captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); - } - - id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([videoSessionMock beginConfiguration]) - .andDo(^(NSInvocation *invocation){ - }); - OCMStub([videoSessionMock commitConfiguration]) - .andDo(^(NSInvocation *invocation){ - }); - - OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - id frameRateRangeMock1 = OCMClassMock([AVFrameRateRange class]); - OCMStub([frameRateRangeMock1 minFrameRate]).andReturn(3); - OCMStub([frameRateRangeMock1 maxFrameRate]).andReturn(30); - id captureDeviceFormatMock1 = OCMClassMock([AVCaptureDeviceFormat class]); - OCMStub([captureDeviceFormatMock1 videoSupportedFrameRateRanges]).andReturn(@[ - frameRateRangeMock1 - ]); - - id frameRateRangeMock2 = OCMClassMock([AVFrameRateRange class]); - OCMStub([frameRateRangeMock2 minFrameRate]).andReturn(3); - OCMStub([frameRateRangeMock2 maxFrameRate]).andReturn(60); - id captureDeviceFormatMock2 = OCMClassMock([AVCaptureDeviceFormat class]); - OCMStub([captureDeviceFormatMock2 videoSupportedFrameRateRanges]).andReturn(@[ - frameRateRangeMock2 - ]); - - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); - OCMStub([captureDeviceMock lockForConfiguration:[OCMArg setTo:nil]]).andReturn(YES); - OCMStub([captureDeviceMock formats]).andReturn((@[ - captureDeviceFormatMock1, captureDeviceFormatMock2 - ])); - __block AVCaptureDeviceFormat *format = captureDeviceFormatMock1; - OCMStub([captureDeviceMock setActiveFormat:[OCMArg any]]).andDo(^(NSInvocation *invocation) { - [invocation retainArguments]; - [invocation getArgument:&format atIndex:2]; - }); - OCMStub([captureDeviceMock activeFormat]).andDo(^(NSInvocation *invocation) { - [invocation setReturnValue:&format]; - }); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings - mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:captureDeviceFactory ?: ^NSObject *(void) { - return captureDeviceMock; - } - captureSessionFactory:^NSObject *_Nonnull{ - return videoSessionMock; - } - captureSessionQueue:captureSessionQueue - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; - - configuration.videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { - return CMVideoFormatDescriptionGetDimensions(format.formatDescription); + __block NSObject *currentFormat = captureDeviceFormatMock1; + captureDeviceMock.activeFormatStub = ^NSObject * { + return currentFormat; }; - configuration.deviceOrientationProvider = deviceOrientationProvider; + captureDeviceMock.setActiveFormatStub = ^(NSObject *format) { + currentFormat = format; + }; + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] + initWithMediaSettings:FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory:^NSObject *(void) { + return captureDeviceMock; + } + captureSessionFactory:^NSObject *_Nonnull { + return videoSessionMock; + } + captureSessionQueue:captureSessionQueue + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; configuration.videoCaptureSession = videoSessionMock; configuration.audioCaptureSession = audioSessionMock; + configuration.orientation = UIDeviceOrientationPortrait; - id fltCam = [[FLTCam alloc] initWithConfiguration:configuration error:nil]; + return configuration; +} - id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; +FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue) { + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + return FLTCreateCamWithConfiguration(configuration); +} +FLTCam *FLTCreateCamWithConfiguration(FLTCamConfiguration *configuration) { + id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; OCMStub([captureVideoDataOutputMock new]).andReturn(captureVideoDataOutputMock); - OCMStub([captureVideoDataOutputMock recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeMPEG4]) .andReturn(@{}); - - OCMStub([captureVideoDataOutputMock sampleBufferCallbackQueue]).andReturn(captureSessionQueue); + OCMStub([captureVideoDataOutputMock sampleBufferCallbackQueue]) + .andReturn(configuration.captureSessionQueue); id videoMock = OCMClassMock([AVAssetWriterInputPixelBufferAdaptor class]); OCMStub([videoMock assetWriterInputPixelBufferAdaptorWithAssetWriterInput:OCMOCK_ANY @@ -127,7 +93,6 @@ .andReturn(videoMock); id writerInputMock = [OCMockObject niceMockForClass:[AVAssetWriterInput class]]; - OCMStub([writerInputMock assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:[OCMArg any]]) .andReturn(writerInputMock); @@ -136,71 +101,6 @@ outputSettings:[OCMArg any]]) .andReturn(writerInputMock); - return fltCam; -} - -FLTCam *FLTCreateCamWithVideoCaptureSession(NSObject *captureSession, - FCPPlatformResolutionPreset resolutionPreset) { - id inputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) - .andReturn(inputMock); - - id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] - initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^NSObject *(void) { - return captureDeviceMock; - } - captureSessionFactory:^NSObject *_Nonnull { - return captureSession; - } - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; - - configuration.orientation = UIDeviceOrientationPortrait; - configuration.videoCaptureSession = captureSession; - configuration.audioCaptureSession = audioSessionMock; - - return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; -} - -FLTCam *FLTCreateCamWithVideoDimensionsForFormat( - AVCaptureSession *captureSession, FCPPlatformResolutionPreset resolutionPreset, - AVCaptureDevice *captureDevice, VideoDimensionsForFormat videoDimensionsForFormat) { - id inputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) - .andReturn(inputMock); - - id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); - OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); - OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] - initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^NSObject *(void) { - return [[FLTDefaultCaptureDevice alloc] initWithDevice:captureDevice]; - } - captureSessionFactory:^NSObject *_Nonnull { - return [[FLTDefaultCaptureSession alloc] - initWithCaptureSession:[[AVCaptureSession alloc] init]]; - } - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; - - configuration.videoDimensionsForFormat = videoDimensionsForFormat; - configuration.deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - configuration.videoCaptureSession = - [[FLTDefaultCaptureSession alloc] initWithCaptureSession:captureSession]; - configuration.audioCaptureSession = audioSessionMock; - configuration.orientation = UIDeviceOrientationPortrait; - return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index bf6867d0d5cc..425481d263d6 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -20,6 +20,12 @@ @interface FLTCamPhotoCaptureTests : XCTestCase @implementation FLTCamPhotoCaptureTests +- (FLTCam *)createCamWithCaptureSessionQueue:(dispatch_queue_t)captureSessionQueue { + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + return FLTCreateCamWithConfiguration(configuration); +} + - (void)testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsWithError { XCTestExpectation *errorExpectation = [self expectationWithDescription: @@ -53,7 +59,7 @@ - (void)testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsW }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWithPath { @@ -64,7 +70,7 @@ - (void)testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWi dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; NSString *filePath = @"test"; @@ -87,7 +93,7 @@ - (void)testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWi [pathExpectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndFileFormatIsHEIF { @@ -97,7 +103,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndF dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; [cam setImageFileFormat:FCPPlatformImageFileFormatHeif]; MockCapturePhotoOutput *mockOutput = [[MockCapturePhotoOutput alloc] init]; @@ -120,7 +126,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndF [expectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndFileFormatIsHEIF { @@ -130,7 +136,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCam *cam = [self createCamWithCaptureSessionQueue:captureSessionQueue]; [cam setImageFileFormat:FCPPlatformImageFileFormatHeif]; MockCapturePhotoOutput *mockOutput = [[MockCapturePhotoOutput alloc] init]; @@ -152,7 +158,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF [expectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testCaptureToFile_handlesTorchMode { @@ -176,12 +182,10 @@ - (void)testCaptureToFile_handlesTorchMode { dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - captureSessionQueue, nil, nil, - ^NSObject *(void) { - return captureDeviceMock; - }, - nil); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + configuration.captureDeviceFactory = ^NSObject * { return captureDeviceMock; }; + FLTCam *cam = FLTCreateCamWithConfiguration(configuration); NSString *filePath = @"test"; @@ -207,6 +211,6 @@ - (void)testCaptureToFile_handlesTorchMode { [pathExpectation fulfill]; }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m index 2b22ce1bb699..94354df696b2 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTSavePhotoDelegateTests.m @@ -36,7 +36,7 @@ - (void)testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToCapture { photoDataProvider:^NSData * { return nil; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToWrite { @@ -67,7 +67,7 @@ - (void)testHandlePhotoCaptureResult_mustCompleteWithErrorIfFailedToWrite { photoDataProvider:^NSObject * { return mockWritableData; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testHandlePhotoCaptureResult_mustCompleteWithFilePathIfSuccessToWrite { @@ -95,7 +95,7 @@ - (void)testHandlePhotoCaptureResult_mustCompleteWithFilePathIfSuccessToWrite { photoDataProvider:^NSObject * { return mockWritableData; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testHandlePhotoCaptureResult_bothProvideDataAndSaveFileMustRunOnIOQueue { @@ -135,7 +135,7 @@ - (void)testHandlePhotoCaptureResult_bothProvideDataAndSaveFileMustRunOnIOQueue return mockWritableData; }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index 89dd1648827e..b7e803d37d0d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -18,11 +18,12 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, assign) AVCaptureDevicePosition position; // Format/Configuration -@property(nonatomic, strong) AVCaptureDeviceFormat *activeFormat; -@property(nonatomic, strong) NSArray *formats; +@property(nonatomic, strong) NSArray *> *formats; +/// Overrides the default implementation of getting the active format. +@property(nonatomic, copy) NSObject * (^activeFormatStub)(void); /// Overrides the default implementation of setting active format. /// @param format The format being set -@property(nonatomic, copy) void (^setActiveFormatStub)(AVCaptureDeviceFormat *format); +@property(nonatomic, copy) void (^setActiveFormatStub)(NSObject *format); // Flash/Torch @property(nonatomic, assign) BOOL hasFlash; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index 8114be864b7b..0f7f2de2461d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -12,7 +12,14 @@ @implementation MockCaptureDevice -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { +- (NSObject *)activeFormat { + if (self.activeFormatStub) { + return self.activeFormatStub(); + } + return nil; +} + +- (void)setActiveFormat:(NSObject *)format { if (self.setActiveFormatStub) { self.setActiveFormatStub(format); } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h new file mode 100644 index 000000000000..4e4a0221ad0f --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.h @@ -0,0 +1,39 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +NS_ASSUME_NONNULL_BEGIN + +/// A mock implementation of `FLTDeviceOrientationProviding` that allows mocking the class +/// properties. +@interface MockCaptureDeviceFormat : NSObject + +/// Initializes a `MockCaptureDeviceFormat` with the given dimensions. +- (instancetype)initWithDimensions:(CMVideoDimensions)dimensions; + +// Properties redeclared as read/write to allow mocking. +@property(nonatomic, strong) AVCaptureDeviceFormat *format; +@property(nonatomic, strong) NSArray *> *videoSupportedFrameRateRanges; +@property(nonatomic, assign) CMFormatDescriptionRef formatDescription; + +@end + +/// A mock implementation of `FLTFrameRateRange` that allows mocking the class properties. +@interface MockFrameRateRange : NSObject + +/// Initializes a `MockFrameRateRange` with the given frame rate range. +- (instancetype)initWithMinFrameRate:(float)minFrameRate maxFrameRate:(float)maxFrameRate; + +// Properties redeclared as read/write to allow mocking. +@property(nonatomic, assign) float minFrameRate; +@property(nonatomic, assign) float maxFrameRate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m new file mode 100644 index 000000000000..fb2b31a4ee64 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceFormat.m @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "MockCaptureDeviceFormat.h" + +@implementation MockCaptureDeviceFormat + +- (instancetype)initWithDimensions:(CMVideoDimensions)dimensions { + self = [super init]; + if (self) { + CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCVPixelFormatType_32BGRA, dimensions.width, + dimensions.height, NULL, &_formatDescription); + } + return self; +} + +- (void)dealloc { + if (_formatDescription) { + CFRelease(_formatDescription); + } +} + +@end + +@implementation MockFrameRateRange + +- (instancetype)initWithMinFrameRate:(float)minFrameRate maxFrameRate:(float)maxFrameRate { + self = [super init]; + if (self) { + _minFrameRate = minFrameRate; + _maxFrameRate = maxFrameRate; + } + return self; +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m index 57b508093d9f..8bcf50457874 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/QueueUtilsTests.m @@ -22,7 +22,7 @@ - (void)testShouldStayOnMainQueueIfCalledFromMainQueue { [expectation fulfill]; } }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testShouldDispatchToMainQueueIfCalledFromBackgroundQueue { @@ -35,7 +35,7 @@ - (void)testShouldDispatchToMainQueueIfCalledFromBackgroundQueue { } }); }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m index 66b47ad5bc2f..a3786b2079da 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/StreamingTest.m @@ -38,7 +38,10 @@ @implementation StreamingTests - (void)setUp { dispatch_queue_t captureSessionQueue = dispatch_queue_create("testing", NULL); - _camera = FLTCreateCamWithCaptureSessionQueue(captureSessionQueue); + FLTCamConfiguration *configuration = FLTCreateTestCameraConfiguration(); + configuration.captureSessionQueue = captureSessionQueue; + + _camera = FLTCreateCamWithConfiguration(configuration); _sampleBuffer = FLTCreateTestSampleBuffer(); } @@ -69,7 +72,7 @@ - (void)testExceedMaxStreamingPendingFramesCount { [_camera captureOutput:nil didOutputSampleBuffer:self.sampleBuffer fromConnection:nil]; } - [self waitForExpectationsWithTimeout:1.0 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testReceivedImageStreamData { @@ -99,7 +102,7 @@ - (void)testReceivedImageStreamData { [_camera receivedImageStreamData]; [_camera captureOutput:nil didOutputSampleBuffer:self.sampleBuffer fromConnection:nil]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m index 644502072664..7c845892d55e 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m @@ -39,7 +39,7 @@ - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { [mainThreadCompletionExpectation fulfill]; } }]; - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThread { @@ -67,7 +67,7 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr } }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { @@ -86,7 +86,7 @@ - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { }]; }); - [self waitForExpectationsWithTimeout:1 handler:nil]; + [self waitForExpectationsWithTimeout:30 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 87846da06e7b..b803eef852d5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -119,10 +119,11 @@ @implementation FLTCam NSString *const errorMethod = @"error"; // Returns frame rate supported by format closest to targetFrameRate. -static double bestFrameRateForFormat(AVCaptureDeviceFormat *format, double targetFrameRate) { +static double bestFrameRateForFormat(NSObject *format, + double targetFrameRate) { double bestFrameRate = 0; double minDistance = DBL_MAX; - for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) { + for (NSObject *range in format.videoSupportedFrameRateRanges) { double frameRate = MIN(MAX(targetFrameRate, range.minFrameRate), range.maxFrameRate); double distance = fabs(frameRate - targetFrameRate); if (distance < minDistance) { @@ -145,11 +146,11 @@ static void selectBestFormatForRequestedFrameRate( double targetFrameRate = mediaSettings.framesPerSecond.doubleValue; FourCharCode preferredSubType = CMFormatDescriptionGetMediaSubType(captureDevice.activeFormat.formatDescription); - AVCaptureDeviceFormat *bestFormat = captureDevice.activeFormat; + NSObject *bestFormat = captureDevice.activeFormat; double bestFrameRate = bestFrameRateForFormat(bestFormat, targetFrameRate); double minDistance = fabs(bestFrameRate - targetFrameRate); BOOL isBestSubTypePreferred = YES; - for (AVCaptureDeviceFormat *format in captureDevice.formats) { + for (NSObject *format in captureDevice.formats) { CMVideoDimensions resolution = videoDimensionsForFormat(format); if (resolution.width != targetResolution.width || resolution.height != targetResolution.height) { @@ -487,7 +488,7 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset withError:(NSError **)error { switch (resolutionPreset) { case FCPPlatformResolutionPresetMax: { - AVCaptureDeviceFormat *bestFormat = + NSObject *bestFormat = [self highestResolutionFormatForCaptureDevice:_captureDevice]; if (bestFormat) { _videoCaptureSession.sessionPreset = AVCaptureSessionPresetInputPriority; @@ -552,14 +553,14 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset /// Finds the highest available resolution in terms of pixel count for the given device. /// Preferred are formats with the same subtype as current activeFormat. -- (AVCaptureDeviceFormat *)highestResolutionFormatForCaptureDevice: +- (NSObject *)highestResolutionFormatForCaptureDevice: (NSObject *)captureDevice { FourCharCode preferredSubType = CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription); - AVCaptureDeviceFormat *bestFormat = nil; + NSObject *bestFormat = nil; NSUInteger maxPixelCount = 0; BOOL isBestSubTypePreferred = NO; - for (AVCaptureDeviceFormat *format in _captureDevice.formats) { + for (NSObject *format in _captureDevice.formats) { CMVideoDimensions res = self.videoDimensionsForFormat(format); NSUInteger height = res.height; NSUInteger width = res.width; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m index c9c2a7ca257d..2feb4d2f3be3 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m @@ -23,7 +23,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _captureDeviceFactory = captureDeviceFactory; _orientation = [[UIDevice currentDevice] orientation]; _deviceOrientationProvider = [[FLTDefaultDeviceOrientationProvider alloc] init]; - _videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { + _videoDimensionsForFormat = ^CMVideoDimensions(NSObject *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); }; _captureDeviceInputFactory = captureDeviceInputFactory; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m index d9badbfe94a4..f142a49dc4ff 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m @@ -31,12 +31,17 @@ - (AVCaptureDevicePosition)position { } // Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat { - return self.device.activeFormat; +- (NSObject *)activeFormat { + return [[FLTDefaultCaptureDeviceFormat alloc] initWithFormat:self.device.activeFormat]; } -- (NSArray *)formats { - return self.device.formats; +- (NSArray *> *)formats { + NSMutableArray> *wrappedFormats = + [NSMutableArray arrayWithCapacity:self.device.formats.count]; + for (AVCaptureDeviceFormat *format in self.device.formats) { + [wrappedFormats addObject:[[FLTDefaultCaptureDeviceFormat alloc] initWithFormat:format]]; + } + return wrappedFormats; } - (void)setActiveFormat:(AVCaptureDeviceFormat *)format { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m new file mode 100644 index 000000000000..2882c500c32f --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceFormat.m @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTCaptureDeviceFormat.h" + +@interface FLTDefaultFrameRateRange () +@property(nonatomic, strong) AVFrameRateRange *range; +@end + +@implementation FLTDefaultFrameRateRange + +- (instancetype)initWithRange:(AVFrameRateRange *)range { + self = [super init]; + if (self) { + _range = range; + } + return self; +} + +- (float)minFrameRate { + return _range.minFrameRate; +} + +- (float)maxFrameRate { + return _range.maxFrameRate; +} + +@end + +@interface FLTDefaultCaptureDeviceFormat () +@property(nonatomic, strong) AVCaptureDeviceFormat *format; +@end + +@implementation FLTDefaultCaptureDeviceFormat + +- (instancetype)initWithFormat:(AVCaptureDeviceFormat *)format { + self = [super init]; + if (self) { + _format = format; + } + return self; +} + +- (CMFormatDescriptionRef)formatDescription { + return _format.formatDescription; +} + +- (NSArray *> *)videoSupportedFrameRateRanges { + NSMutableArray> *ranges = + [NSMutableArray arrayWithCapacity:_format.videoSupportedFrameRateRanges.count]; + for (AVFrameRateRange *range in _format.videoSupportedFrameRateRanges) { + FLTDefaultFrameRateRange *wrapper = [[FLTDefaultFrameRateRange alloc] initWithRange:range]; + [ranges addObject:wrapper]; + } + return ranges; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index f175f188c611..6f1ad547273d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -7,6 +7,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCameraDeviceDiscovering.h" header "FLTCaptureDevice.h" + header "FLTCaptureDeviceFormat.h" header "FLTCapturePhotoOutput.h" header "FLTCaptureSession.h" header "FLTDeviceOrientationProviding.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h index 36393009b7a3..148818b24d57 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -22,7 +22,7 @@ typedef NSObject *_Nonnull (^CaptureSessionFactory)(void); /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. -typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); +typedef CMVideoDimensions (^VideoDimensionsForFormat)(NSObject *); /// A configuration object that centralizes dependencies for `FLTCam`. @interface FLTCamConfiguration : NSObject diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h index 09344600a86d..6f5d6df0c202 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h @@ -5,6 +5,8 @@ @import AVFoundation; @import Foundation; +#import "FLTCaptureDeviceFormat.h" + NS_ASSUME_NONNULL_BEGIN /// A protocol which is a direct passthrough to AVCaptureDevice. @@ -23,9 +25,9 @@ NS_ASSUME_NONNULL_BEGIN - (AVCaptureDevicePosition)position; // Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat; -- (NSArray *)formats; -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format; +- (NSObject *)activeFormat; +- (NSArray *> *)formats; +- (void)setActiveFormat:(NSObject *)format; // Flash/Torch - (BOOL)hasFlash; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h new file mode 100644 index 000000000000..4b8ecb58365f --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceFormat.h @@ -0,0 +1,51 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import AVFoundation; +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +/// A protocol which is a direct passthrough to `FLTFrameRateRange`. It exists to allow replacing +/// `AVFrameRateRange` in tests as it has no public initializer. +@protocol FLTFrameRateRange + +@property(readonly, nonatomic) float minFrameRate; +@property(readonly, nonatomic) float maxFrameRate; + +@end + +/// A protocol which is a direct passthrough to `AVCaptureDeviceFormat`. It exists to allow +/// replacing `AVCaptureDeviceFormat` in tests as it has no public initializer. +@protocol FLTCaptureDeviceFormat + +/// The underlying `AVCaptureDeviceFormat` instance that this object wraps. +@property(nonatomic, readonly) AVCaptureDeviceFormat *format; + +@property(nonatomic, readonly) CMFormatDescriptionRef formatDescription; +@property(nonatomic, readonly) + NSArray *> *videoSupportedFrameRateRanges; + +@end + +/// A default implementation of `FLTFrameRateRange` that wraps an `AVFrameRateRange` instance. +@interface FLTDefaultFrameRateRange : NSObject + +/// Initializes the object with an `AVFrameRateRange` instance. All method and property calls are +/// forwarded to this wrapped instance. +- (instancetype)initWithRange:(AVFrameRateRange *)range; + +@end + +/// A default implementation of `FLTCaptureDeviceFormat` that wraps an `AVCaptureDeviceFormat` +/// instance. +@interface FLTDefaultCaptureDeviceFormat : NSObject + +/// Initializes the object with an `AVCaptureDeviceFormat` instance. All method and property calls +/// are forwarded to this wrapped instance. +- (instancetype)initWithFormat:(AVCaptureDeviceFormat *)format; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 583871486536..56cd44cc6ac9 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.18+3 +version: 0.9.18+4 environment: sdk: ^3.4.0