Skip to content

Commit

Permalink
[camera_avfoundation] dealloc camera on dispose (#7211)
Browse files Browse the repository at this point in the history
When is camera disposed in `disposeCamera` it calls `close` and leaves `_camera` untouched so after another call to `sessionQueueCreateCameraWithName` it calls `close` second time and only here is `_camera` disposed by assigning new value into that variable. Calling `close` 2x may be unexpected and prone to later errors if someone adds here something which expects that it will be called only once. Also having dangling `_camera` after dispose (without creating new one) can have other unintended consequences although maybe benign for now. For example there is `[_motionManager stopAccelerometerUpdates]` which is called only in `dealloc`.
  • Loading branch information
misos1 authored Aug 4, 2024
1 parent dfcc578 commit 299e616
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/camera/camera_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.9.17+3

* Fixes deallocation of camera on dispose.

## 0.9.17+2

* Fixes stopVideoRecording waiting indefinitely and lag at start of video.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,42 @@ - (void)testCreate_ShouldCallResultOnMainThread {
XCTAssertNotNil(resultValue);
}

- (void)testDisposeShouldDeallocCamera {
CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil];

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);

XCTestExpectation *createExpectation =
[self expectationWithDescription:@"create's result block must be called"];
[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];
XCTAssertNotNil(camera.camera);

XCTestExpectation *disposeExpectation =
[self expectationWithDescription:@"dispose's result block must be called"];
[camera disposeCamera:0
completion:^(FlutterError *_Nullable error) {
[disposeExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:30 handler:nil];
XCTAssertNil(camera.camera, @"camera should be deallocated after dispose");
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ - (void)disposeCamera:(NSInteger)cameraId
__weak typeof(self) weakSelf = self;
dispatch_async(self.captureSessionQueue, ^{
[weakSelf.camera close];
weakSelf.camera = nil;
completion(nil);
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera_avfoundation/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.17+2
version: 0.9.17+3

environment:
sdk: ^3.2.3
Expand Down

0 comments on commit 299e616

Please sign in to comment.