Skip to content

[camera] Dispose resources correctly on setDescription #4003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/camera/camera/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.10.5+5

* Fixes bug where old camera resources were not disposed when switching between camera descriptions.
* Fixes bug where _deviceOrientationSubscription was recreated every time the camera description was
changed.

## 0.10.5+4

* Adds pub topics to package metadata.
Expand Down
24 changes: 18 additions & 6 deletions packages/camera/camera/lib/src/camera_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ class CameraController extends ValueNotifier<CameraValue> {

bool _isDisposed = false;
StreamSubscription<CameraImageData>? _imageStreamSubscription;
FutureOr<bool>? _initCalled;
// A Future awaiting an attempt to initialize (e.g. after `initialize` was
// just called). If the controller has not been initialized at least once,
// this value is null.
Future<void>? _initializeFuture;
StreamSubscription<DeviceOrientationChangedEvent>?
_deviceOrientationSubscription;

Expand Down Expand Up @@ -294,11 +297,15 @@ class CameraController extends ValueNotifier<CameraValue> {
'initialize was called on a disposed CameraController',
);
}

final Completer<void> initializeCompleter = Completer<void>();
_initializeFuture = initializeCompleter.future;

try {
final Completer<CameraInitializedEvent> initializeCompleter =
Completer<CameraInitializedEvent>();

_deviceOrientationSubscription = CameraPlatform.instance
_deviceOrientationSubscription ??= CameraPlatform.instance
.onDeviceOrientationChanged()
.listen((DeviceOrientationChangedEvent event) {
value = value.copyWith(
Expand Down Expand Up @@ -343,9 +350,9 @@ class CameraController extends ValueNotifier<CameraValue> {
);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
} finally {
initializeCompleter.complete();
}

_initCalled = true;
}

/// Prepare the capture session for video recording.
Expand Down Expand Up @@ -402,6 +409,11 @@ class CameraController extends ValueNotifier<CameraValue> {
await CameraPlatform.instance.setDescriptionWhileRecording(description);
value = value.copyWith(description: description);
} else {
if (_initializeFuture != null) {
await _initializeFuture;
await CameraPlatform.instance.dispose(_cameraId);
}

await _initializeWithDescription(description);
}
}
Expand Down Expand Up @@ -841,8 +853,8 @@ class CameraController extends ValueNotifier<CameraValue> {
_unawaited(_deviceOrientationSubscription?.cancel());
_isDisposed = true;
super.dispose();
if (_initCalled != null) {
await _initCalled;
if (_initializeFuture != null) {
await _initializeFuture;
await CameraPlatform.instance.dispose(_cameraId);
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
Dart.
repository: https://github.com/flutter/packages/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.10.5+4
version: 0.10.5+5

environment:
sdk: ">=2.19.0 <4.0.0"
Expand Down
36 changes: 36 additions & 0 deletions packages/camera/camera/test/camera_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,42 @@ void main() {
.called(1);
});

test('setDescription waits for initialize before calling dispose',
() async {
final CameraController cameraController = CameraController(
const CameraDescription(
name: 'cam',
lensDirection: CameraLensDirection.back,
sensorOrientation: 90,
),
ResolutionPreset.max,
imageFormatGroup: ImageFormatGroup.bgra8888,
);

final Completer<void> initializeCompleter = Completer<void>();
when(CameraPlatform.instance.initializeCamera(
mockInitializeCamera,
imageFormatGroup: ImageFormatGroup.bgra8888,
)).thenAnswer(
(_) => initializeCompleter.future,
);

unawaited(cameraController.initialize());

final Future<void> setDescriptionFuture = cameraController.setDescription(
const CameraDescription(
name: 'cam2',
lensDirection: CameraLensDirection.front,
sensorOrientation: 90),
);
verifyNever(CameraPlatform.instance.dispose(mockInitializeCamera));

initializeCompleter.complete();

await setDescriptionFuture;
verify(CameraPlatform.instance.dispose(mockInitializeCamera));
});

test('prepareForVideoRecording() calls $CameraPlatform ', () async {
final CameraController cameraController = CameraController(
const CameraDescription(
Expand Down