webrtc_constraints/constraints/
track.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    constraint::SanitizedMediaTrackConstraint, MediaTrackConstraint,
6    MediaTrackSupportedConstraints, ResolvedMediaTrackConstraint,
7};
8
9use super::{
10    advanced::GenericAdvancedMediaTrackConstraints,
11    mandatory::GenericMandatoryMediaTrackConstraints,
12};
13
14/// A boolean on/off flag or bare value or constraints for a [`MediaStreamTrack`][media_stream_track] object.
15///
16/// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
17pub type BoolOrMediaTrackConstraints = GenericBoolOrMediaTrackConstraints<MediaTrackConstraint>;
18
19/// A boolean on/off flag or constraints for a [`MediaStreamTrack`][media_stream_track] object.
20///
21/// # W3C Spec Compliance
22///
23/// There exists no direct corresponding type in the
24/// W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec,
25/// since the `BoolOrMediaTrackConstraints<T>` type aims to be a
26/// generalization over multiple types in the W3C spec:
27///
28/// | Rust                          | W3C                                                                                                |
29/// | ----------------------------- | -------------------------------------------------------------------------------------------------- |
30/// | `BoolOrMediaTrackConstraints` | [`MediaStreamConstraints`][media_stream_constraints]'s [`video`][video] / [`audio`][audio] members |
31///
32/// [media_stream_constraints]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamconstraints-video
33/// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
34/// [video]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamconstraints-video
35/// [audio]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamconstraints-audio
36/// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/
37#[derive(Debug, Clone, Eq, PartialEq)]
38#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
39#[cfg_attr(feature = "serde", serde(untagged))]
40pub enum GenericBoolOrMediaTrackConstraints<T> {
41    /// Boolean track selector.
42    Bool(bool),
43    /// Constraints-based track selector.
44    Constraints(GenericMediaTrackConstraints<T>),
45}
46
47impl<T> GenericBoolOrMediaTrackConstraints<T>
48where
49    T: Clone,
50{
51    pub fn to_constraints(&self) -> Option<GenericMediaTrackConstraints<T>> {
52        self.clone().into_constraints()
53    }
54
55    pub fn into_constraints(self) -> Option<GenericMediaTrackConstraints<T>> {
56        match self {
57            Self::Bool(false) => None,
58            Self::Bool(true) => Some(GenericMediaTrackConstraints::default()),
59            Self::Constraints(constraints) => Some(constraints),
60        }
61    }
62}
63
64impl<T> Default for GenericBoolOrMediaTrackConstraints<T> {
65    fn default() -> Self {
66        Self::Bool(false)
67    }
68}
69
70impl<T> From<bool> for GenericBoolOrMediaTrackConstraints<T> {
71    fn from(flag: bool) -> Self {
72        Self::Bool(flag)
73    }
74}
75
76impl<T> From<GenericMediaTrackConstraints<T>> for GenericBoolOrMediaTrackConstraints<T> {
77    fn from(constraints: GenericMediaTrackConstraints<T>) -> Self {
78        Self::Constraints(constraints)
79    }
80}
81
82/// Media track constraints that contains either bare values or constraints.
83pub type MediaTrackConstraints = GenericMediaTrackConstraints<MediaTrackConstraint>;
84
85/// Media track constraints that contains only constraints (both, empty and non-empty).
86pub type ResolvedMediaTrackConstraints = GenericMediaTrackConstraints<ResolvedMediaTrackConstraint>;
87
88/// Media track constraints that contains only non-empty constraints.
89pub type SanitizedMediaTrackConstraints =
90    GenericMediaTrackConstraints<SanitizedMediaTrackConstraint>;
91
92/// The constraints for a [`MediaStreamTrack`][media_stream_track] object.
93///
94/// # W3C Spec Compliance
95///
96/// Corresponds to [`MediaTrackConstraints`][media_track_constraints]
97/// from the W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec.
98///
99/// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
100/// [media_track_constraints]: https://www.w3.org/TR/mediacapture-streams/#dom-mediatrackconstraints
101/// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/
102#[derive(Debug, Clone, Eq, PartialEq)]
103#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104pub struct GenericMediaTrackConstraints<T> {
105    /// Mandatory (i.e required or optional basic) constraints, as defined in the [spec][spec].
106    ///
107    /// [spec]: https://www.w3.org/TR/mediacapture-streams/#dfn-constraint
108    #[cfg_attr(feature = "serde", serde(flatten))]
109    pub mandatory: GenericMandatoryMediaTrackConstraints<T>,
110
111    /// Advanced constraints, as defined in the [spec][spec].
112    ///
113    /// [spec]: https://www.w3.org/TR/mediacapture-streams/#dfn-constraint
114    #[cfg_attr(
115        feature = "serde",
116        serde(default = "Default::default"),
117        serde(skip_serializing_if = "should_skip_advanced")
118    )]
119    pub advanced: GenericAdvancedMediaTrackConstraints<T>,
120}
121
122#[cfg(feature = "serde")]
123fn should_skip_advanced<T>(advanced: &GenericAdvancedMediaTrackConstraints<T>) -> bool {
124    advanced.is_empty()
125}
126
127impl<T> Default for GenericMediaTrackConstraints<T> {
128    fn default() -> Self {
129        Self {
130            mandatory: Default::default(),
131            advanced: Default::default(),
132        }
133    }
134}
135
136impl MediaTrackConstraints {
137    pub fn to_resolved(&self) -> ResolvedMediaTrackConstraints {
138        self.clone().into_resolved()
139    }
140
141    pub fn into_resolved(self) -> ResolvedMediaTrackConstraints {
142        let Self {
143            mandatory,
144            advanced,
145        } = self;
146        ResolvedMediaTrackConstraints {
147            mandatory: mandatory.into_resolved(),
148            advanced: advanced.into_resolved(),
149        }
150    }
151}
152
153impl ResolvedMediaTrackConstraints {
154    pub fn to_sanitized(
155        &self,
156        supported_constraints: &MediaTrackSupportedConstraints,
157    ) -> SanitizedMediaTrackConstraints {
158        self.clone().into_sanitized(supported_constraints)
159    }
160
161    pub fn into_sanitized(
162        self,
163        supported_constraints: &MediaTrackSupportedConstraints,
164    ) -> SanitizedMediaTrackConstraints {
165        let mandatory = self.mandatory.into_sanitized(supported_constraints);
166        let advanced = self.advanced.into_sanitized(supported_constraints);
167        SanitizedMediaTrackConstraints {
168            mandatory,
169            advanced,
170        }
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use std::iter::FromIterator;
177
178    use crate::{
179        constraints::mandatory::MandatoryMediaTrackConstraints, property::all::name::*,
180        AdvancedMediaTrackConstraints, ResolvedAdvancedMediaTrackConstraints,
181        ResolvedMandatoryMediaTrackConstraints, ResolvedValueConstraint,
182    };
183
184    use super::*;
185
186    type Subject = BoolOrMediaTrackConstraints;
187
188    #[test]
189    fn default() {
190        let actual = Subject::default();
191        let expected = Subject::Bool(false);
192
193        assert_eq!(actual, expected);
194    }
195
196    mod from {
197        use super::*;
198
199        #[test]
200        fn bool() {
201            for value in [false, true] {
202                let actual = Subject::from(value);
203                let expected = Subject::Bool(value);
204
205                assert_eq!(actual, expected);
206            }
207        }
208
209        #[test]
210        fn constraints() {
211            let constraints = GenericMediaTrackConstraints {
212                mandatory: MandatoryMediaTrackConstraints::from_iter([(
213                    &DEVICE_ID,
214                    "microphone".into(),
215                )]),
216                advanced: AdvancedMediaTrackConstraints::new(vec![]),
217            };
218
219            let actual = Subject::from(constraints.clone());
220            let expected = Subject::Constraints(constraints);
221
222            assert_eq!(actual, expected);
223        }
224    }
225
226    mod to_constraints {
227        use super::*;
228
229        #[test]
230        fn bool_false() {
231            let subject = Subject::Bool(false);
232
233            let actual = subject.to_constraints();
234            let expected = None;
235
236            assert_eq!(actual, expected);
237        }
238
239        #[test]
240        fn bool_true() {
241            let subject = Subject::Bool(true);
242
243            let actual = subject.to_constraints();
244            let expected = Some(GenericMediaTrackConstraints::default());
245
246            assert_eq!(actual, expected);
247        }
248
249        #[test]
250        fn constraints() {
251            let constraints = GenericMediaTrackConstraints {
252                mandatory: MandatoryMediaTrackConstraints::from_iter([(
253                    &DEVICE_ID,
254                    "microphone".into(),
255                )]),
256                advanced: AdvancedMediaTrackConstraints::new(vec![]),
257            };
258
259            let subject = Subject::Constraints(constraints.clone());
260
261            let actual = subject.to_constraints();
262            let expected = Some(constraints);
263
264            assert_eq!(actual, expected);
265        }
266    }
267
268    #[test]
269    fn to_resolved() {
270        let subject = MediaTrackConstraints {
271            mandatory: MandatoryMediaTrackConstraints::from_iter([(
272                &DEVICE_ID,
273                "microphone".into(),
274            )]),
275            advanced: AdvancedMediaTrackConstraints::new(vec![]),
276        };
277
278        let actual = subject.to_resolved();
279        let expected = ResolvedMediaTrackConstraints {
280            mandatory: ResolvedMandatoryMediaTrackConstraints::from_iter([(
281                &DEVICE_ID,
282                ResolvedValueConstraint::default()
283                    .ideal("microphone".to_owned())
284                    .into(),
285            )]),
286            advanced: ResolvedAdvancedMediaTrackConstraints::new(vec![]),
287        };
288
289        assert_eq!(actual, expected);
290    }
291}
292
293#[cfg(feature = "serde")]
294#[cfg(test)]
295mod serde_tests {
296    use std::iter::FromIterator;
297
298    use crate::{
299        constraints::mandatory::MandatoryMediaTrackConstraints, macros::test_serde_symmetry,
300        property::all::name::*, AdvancedMediaTrackConstraints, MediaTrackConstraintSet,
301    };
302
303    use super::*;
304
305    type Subject = MediaTrackConstraints;
306
307    #[test]
308    fn default() {
309        let subject = Subject::default();
310        let json = serde_json::json!({});
311
312        test_serde_symmetry!(subject: subject, json: json);
313    }
314
315    #[test]
316    fn customized() {
317        let subject = Subject {
318            mandatory: MandatoryMediaTrackConstraints::from_iter([(
319                &DEVICE_ID,
320                "microphone".into(),
321            )]),
322            advanced: AdvancedMediaTrackConstraints::new(vec![
323                MediaTrackConstraintSet::from_iter([
324                    (&AUTO_GAIN_CONTROL, true.into()),
325                    (&CHANNEL_COUNT, 2.into()),
326                ]),
327                MediaTrackConstraintSet::from_iter([(&LATENCY, 0.123.into())]),
328            ]),
329        };
330        let json = serde_json::json!({
331            "deviceId": "microphone",
332            "advanced": [
333                {
334                    "autoGainControl": true,
335                    "channelCount": 2,
336                },
337                {
338                    "latency": 0.123,
339                },
340            ]
341        });
342
343        test_serde_symmetry!(subject: subject, json: json);
344    }
345}