webrtc_constraints/constraints/
constraint_set.rs

1use std::{
2    iter::FromIterator,
3    ops::{Deref, DerefMut},
4};
5
6use indexmap::IndexMap;
7
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11use crate::{
12    constraint::SanitizedMediaTrackConstraint, MediaTrackConstraint,
13    MediaTrackConstraintResolutionStrategy, MediaTrackProperty, MediaTrackSupportedConstraints,
14    ResolvedMediaTrackConstraint,
15};
16
17/// Media track constraint set that contains either bare values or constraints.
18pub type MediaTrackConstraintSet = GenericMediaTrackConstraintSet<MediaTrackConstraint>;
19
20/// Media track constraint set that contains only constraints (both, empty and non-empty).
21pub type ResolvedMediaTrackConstraintSet =
22    GenericMediaTrackConstraintSet<ResolvedMediaTrackConstraint>;
23
24/// Media track constraint set that contains only non-empty constraints.
25pub type SanitizedMediaTrackConstraintSet =
26    GenericMediaTrackConstraintSet<SanitizedMediaTrackConstraint>;
27
28/// The set of constraints for a [`MediaStreamTrack`][media_stream_track] object.
29///
30/// # W3C Spec Compliance
31///
32/// Corresponds to [`ResolvedMediaTrackConstraintSet`][media_track_constraint_set]
33/// from the W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec.
34///
35/// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
36/// [media_track_constraint_set]: https://www.w3.org/TR/mediacapture-streams/#dom-mediatrackconstraintset
37/// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/
38#[derive(Debug, Clone, Eq, PartialEq)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40#[cfg_attr(feature = "serde", serde(transparent))]
41pub struct GenericMediaTrackConstraintSet<T>(IndexMap<MediaTrackProperty, T>);
42
43impl<T> GenericMediaTrackConstraintSet<T> {
44    pub fn new(constraint_set: IndexMap<MediaTrackProperty, T>) -> Self {
45        Self(constraint_set)
46    }
47
48    pub fn into_inner(self) -> IndexMap<MediaTrackProperty, T> {
49        self.0
50    }
51}
52
53impl<T> Deref for GenericMediaTrackConstraintSet<T> {
54    type Target = IndexMap<MediaTrackProperty, T>;
55
56    fn deref(&self) -> &Self::Target {
57        &self.0
58    }
59}
60
61impl<T> DerefMut for GenericMediaTrackConstraintSet<T> {
62    fn deref_mut(&mut self) -> &mut Self::Target {
63        &mut self.0
64    }
65}
66
67impl<T> Default for GenericMediaTrackConstraintSet<T> {
68    fn default() -> Self {
69        Self(IndexMap::new())
70    }
71}
72
73impl<T, U> FromIterator<(U, T)> for GenericMediaTrackConstraintSet<T>
74where
75    U: Into<MediaTrackProperty>,
76{
77    fn from_iter<I>(iter: I) -> Self
78    where
79        I: IntoIterator<Item = (U, T)>,
80    {
81        Self::new(iter.into_iter().map(|(k, v)| (k.into(), v)).collect())
82    }
83}
84
85impl<T> IntoIterator for GenericMediaTrackConstraintSet<T> {
86    type Item = (MediaTrackProperty, T);
87    type IntoIter = indexmap::map::IntoIter<MediaTrackProperty, T>;
88
89    fn into_iter(self) -> Self::IntoIter {
90        self.0.into_iter()
91    }
92}
93
94impl MediaTrackConstraintSet {
95    pub fn to_resolved(
96        &self,
97        strategy: MediaTrackConstraintResolutionStrategy,
98    ) -> ResolvedMediaTrackConstraintSet {
99        self.clone().into_resolved(strategy)
100    }
101
102    pub fn into_resolved(
103        self,
104        strategy: MediaTrackConstraintResolutionStrategy,
105    ) -> ResolvedMediaTrackConstraintSet {
106        ResolvedMediaTrackConstraintSet::new(
107            self.into_iter()
108                .map(|(property, constraint)| (property, constraint.into_resolved(strategy)))
109                .collect(),
110        )
111    }
112}
113
114impl ResolvedMediaTrackConstraintSet {
115    pub fn to_sanitized(
116        &self,
117        supported_constraints: &MediaTrackSupportedConstraints,
118    ) -> SanitizedMediaTrackConstraintSet {
119        self.clone().into_sanitized(supported_constraints)
120    }
121
122    pub fn into_sanitized(
123        self,
124        supported_constraints: &MediaTrackSupportedConstraints,
125    ) -> SanitizedMediaTrackConstraintSet {
126        let index_map: IndexMap<MediaTrackProperty, _> = self
127            .into_iter()
128            .filter_map(|(property, constraint)| {
129                if supported_constraints.contains(&property) {
130                    constraint
131                        .into_sanitized()
132                        .map(|constraint| (property, constraint))
133                } else {
134                    None
135                }
136            })
137            .collect();
138        SanitizedMediaTrackConstraintSet::new(index_map)
139    }
140}
141
142#[cfg(feature = "serde")]
143#[cfg(test)]
144mod serde_tests {
145    use crate::property::all::name::*;
146
147    use super::*;
148
149    #[test]
150    fn serialize_default() {
151        let constraint_set = MediaTrackConstraintSet::default();
152        let actual = serde_json::to_value(constraint_set).unwrap();
153        let expected = serde_json::json!({});
154
155        assert_eq!(actual, expected);
156    }
157
158    #[test]
159    fn deserialize_default() {
160        let json = serde_json::json!({});
161        let actual: MediaTrackConstraintSet = serde_json::from_value(json).unwrap();
162        let expected = MediaTrackConstraintSet::default();
163
164        assert_eq!(actual, expected);
165    }
166
167    #[test]
168    fn serialize() {
169        let constraint_set = MediaTrackConstraintSet::from_iter([
170            (&DEVICE_ID, "device-id".into()),
171            (&AUTO_GAIN_CONTROL, true.into()),
172            (&CHANNEL_COUNT, 2.into()),
173            (&LATENCY, 0.123.into()),
174        ]);
175        let actual = serde_json::to_value(constraint_set).unwrap();
176        let expected = serde_json::json!({
177            "deviceId": "device-id".to_owned(),
178            "autoGainControl": true,
179            "channelCount": 2,
180            "latency": 0.123,
181        });
182
183        assert_eq!(actual, expected);
184    }
185
186    #[test]
187    fn deserialize() {
188        let json = serde_json::json!({
189            "deviceId": "device-id".to_owned(),
190            "autoGainControl": true,
191            "channelCount": 2,
192            "latency": 0.123,
193        });
194        let actual: MediaTrackConstraintSet = serde_json::from_value(json).unwrap();
195        let expected = MediaTrackConstraintSet::from_iter([
196            (&DEVICE_ID, "device-id".into()),
197            (&AUTO_GAIN_CONTROL, true.into()),
198            (&CHANNEL_COUNT, 2.into()),
199            (&LATENCY, 0.123.into()),
200        ]);
201
202        assert_eq!(actual, expected);
203    }
204}