Skip to content

Commit e193daf

Browse files
authored
[camera] Add CameraOptions used to constrain the camera audio and video (flutter#4164)
1 parent 2f5ef3d commit e193daf

File tree

5 files changed

+453
-2
lines changed

5 files changed

+453
-2
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
## 0.1.0
22

33
* Initial release
4+
* Added CameraOptions used to constrain the camera audio and video.
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ui' show hashValues;
6+
7+
/// Options used to create a camera with the given
8+
/// [audio] and [video] media constraints.
9+
///
10+
/// These options represent web `MediaStreamConstraints`
11+
/// and can be used to request the browser for media streams
12+
/// with audio and video tracks containing the requested types of media.
13+
///
14+
/// https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
15+
class CameraOptions {
16+
/// Creates a new instance of [CameraOptions]
17+
/// with the given [audio] and [video] constraints.
18+
const CameraOptions({
19+
AudioConstraints? audio,
20+
VideoConstraints? video,
21+
}) : audio = audio ?? const AudioConstraints(),
22+
video = video ?? const VideoConstraints();
23+
24+
/// The audio constraints for the camera.
25+
final AudioConstraints audio;
26+
27+
/// The video constraints for the camera.
28+
final VideoConstraints video;
29+
30+
/// Converts the current instance to a Map.
31+
Map<String, dynamic> toJson() {
32+
return {
33+
'audio': audio.toJson(),
34+
'video': video.toJson(),
35+
};
36+
}
37+
38+
@override
39+
bool operator ==(Object other) {
40+
if (identical(this, other)) return true;
41+
42+
return other is CameraOptions &&
43+
other.audio == audio &&
44+
other.video == video;
45+
}
46+
47+
@override
48+
int get hashCode => hashValues(audio, video);
49+
}
50+
51+
/// Indicates whether the audio track is requested.
52+
///
53+
/// By default, the audio track is not requested.
54+
class AudioConstraints {
55+
/// Creates a new instance of [AudioConstraints]
56+
/// with the given [enabled] constraint.
57+
const AudioConstraints({this.enabled = false});
58+
59+
/// Whether the audio track should be enabled.
60+
final bool enabled;
61+
62+
/// Converts the current instance to a Map.
63+
Object toJson() => enabled;
64+
65+
@override
66+
bool operator ==(Object other) {
67+
if (identical(this, other)) return true;
68+
69+
return other is AudioConstraints && other.enabled == enabled;
70+
}
71+
72+
@override
73+
int get hashCode => enabled.hashCode;
74+
}
75+
76+
/// Defines constraints that the video track must have
77+
/// to be considered acceptable.
78+
class VideoConstraints {
79+
/// Creates a new instance of [VideoConstraints]
80+
/// with the given constraints.
81+
const VideoConstraints({
82+
this.facingMode,
83+
this.width,
84+
this.height,
85+
this.deviceId,
86+
});
87+
88+
/// The facing mode of the video track.
89+
final FacingModeConstraint? facingMode;
90+
91+
/// The width of the video track.
92+
final VideoSizeConstraint? width;
93+
94+
/// The height of the video track.
95+
final VideoSizeConstraint? height;
96+
97+
/// The device id of the video track.
98+
final String? deviceId;
99+
100+
/// Converts the current instance to a Map.
101+
Object toJson() {
102+
final json = <String, dynamic>{};
103+
104+
if (width != null) json['width'] = width!.toJson();
105+
if (height != null) json['height'] = height!.toJson();
106+
if (facingMode != null) json['facingMode'] = facingMode!.toJson();
107+
if (deviceId != null) json['deviceId'] = {'exact': deviceId!};
108+
109+
return json;
110+
}
111+
112+
@override
113+
bool operator ==(Object other) {
114+
if (identical(this, other)) return true;
115+
116+
return other is VideoConstraints &&
117+
other.facingMode == facingMode &&
118+
other.width == width &&
119+
other.height == height &&
120+
other.deviceId == deviceId;
121+
}
122+
123+
@override
124+
int get hashCode => hashValues(facingMode, width, height, deviceId);
125+
}
126+
127+
/// The camera type used in [FacingModeConstraint].
128+
///
129+
/// Specifies whether the requested camera should be facing away
130+
/// or toward the user.
131+
class CameraType {
132+
const CameraType._(this._type);
133+
134+
final String _type;
135+
136+
@override
137+
String toString() => _type;
138+
139+
/// The camera is facing away from the user, viewing their environment.
140+
/// This includes the back camera on a smartphone.
141+
static const CameraType environment = CameraType._('environment');
142+
143+
/// The camera is facing toward the user.
144+
/// This includes the front camera on a smartphone.
145+
static const CameraType user = CameraType._('user');
146+
}
147+
148+
/// Indicates the direction in which the desired camera should be pointing.
149+
class FacingModeConstraint {
150+
/// Creates a new instance of [FacingModeConstraint]
151+
/// with the given [ideal] and [exact] constraints.
152+
const FacingModeConstraint._({this.ideal, this.exact});
153+
154+
/// Creates a new instance of [FacingModeConstraint]
155+
/// with [ideal] constraint set to [type].
156+
factory FacingModeConstraint(CameraType type) =>
157+
FacingModeConstraint._(ideal: type);
158+
159+
/// Creates a new instance of [FacingModeConstraint]
160+
/// with [exact] constraint set to [type].
161+
factory FacingModeConstraint.exact(CameraType type) =>
162+
FacingModeConstraint._(exact: type);
163+
164+
/// The ideal facing mode constraint.
165+
///
166+
/// If this constraint is used, then the camera would ideally have
167+
/// the desired facing [type] but it may be considered optional.
168+
final CameraType? ideal;
169+
170+
/// The exact facing mode constraint.
171+
///
172+
/// If this constraint is used, then the camera must have
173+
/// the desired facing [type] to be considered acceptable.
174+
final CameraType? exact;
175+
176+
/// Converts the current instance to a Map.
177+
Object? toJson() {
178+
return {
179+
if (ideal != null) 'ideal': ideal.toString(),
180+
if (exact != null) 'exact': exact.toString(),
181+
};
182+
}
183+
184+
@override
185+
bool operator ==(Object other) {
186+
if (identical(this, other)) return true;
187+
188+
return other is FacingModeConstraint &&
189+
other.ideal == ideal &&
190+
other.exact == exact;
191+
}
192+
193+
@override
194+
int get hashCode => hashValues(ideal, exact);
195+
}
196+
197+
/// The size of the requested video track used in
198+
/// [VideoConstraints.width] and [VideoConstraints.height].
199+
///
200+
/// The obtained video track will have a size between [minimum] and [maximum]
201+
/// with ideally a size of [ideal]. The size is determined by
202+
/// the capabilities of the hardware and the other specified constraints.
203+
class VideoSizeConstraint {
204+
/// Creates a new instance of [VideoSizeConstraint] with the given
205+
/// [minimum], [ideal] and [maximum] constraints.
206+
const VideoSizeConstraint({this.minimum, this.ideal, this.maximum});
207+
208+
/// The minimum video size.
209+
final int? minimum;
210+
211+
/// The ideal video size.
212+
///
213+
/// The video would ideally have the [ideal] size
214+
/// but it may be considered optional. If not possible
215+
/// to satisfy, the size will be as close as possible
216+
/// to [ideal].
217+
final int? ideal;
218+
219+
/// The maximum video size.
220+
final int? maximum;
221+
222+
/// Converts the current instance to a Map.
223+
Object toJson() {
224+
final json = <String, dynamic>{};
225+
226+
if (ideal != null) json['ideal'] = ideal;
227+
if (minimum != null) json['min'] = minimum;
228+
if (maximum != null) json['max'] = maximum;
229+
230+
return json;
231+
}
232+
233+
@override
234+
bool operator ==(Object other) {
235+
if (identical(this, other)) return true;
236+
237+
return other is VideoSizeConstraint &&
238+
other.minimum == minimum &&
239+
other.ideal == ideal &&
240+
other.maximum == maximum;
241+
}
242+
243+
@override
244+
int get hashCode => hashValues(minimum, ideal, maximum);
245+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
export 'camera_options.dart';

packages/camera/camera_web/test/tests_exist_elsewhere_test.dart renamed to packages/camera/camera_web/test/more_tests_exist_elsewhere_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import 'package:flutter_test/flutter_test.dart';
66

77
void main() {
8-
test('Tell the user where to find the real tests', () {
8+
test('Tell the user where to find more tests', () {
99
print('---');
10-
print('This package uses integration_test for its tests.');
10+
print('This package also uses integration_test for its tests.');
1111
print('See `example/README.md` for more info.');
1212
print('---');
1313
});

0 commit comments

Comments
 (0)