webrtc_constraints/capabilities/
track.rs

1use std::{
2    collections::HashMap,
3    iter::FromIterator,
4    ops::{Deref, DerefMut},
5};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::{MediaTrackCapability, MediaTrackProperty};
11
12/// The capabilities of a [`MediaStreamTrack`][media_stream_track] object.
13///
14/// # W3C Spec Compliance
15///
16/// Corresponds to [`MediaTrackCapabilities`][media_track_capabilities]
17/// from the W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec.
18///
19/// The W3C spec defines `MediaTrackSettings` in terma of a dictionary,
20/// which per the [WebIDL spec][webidl_spec] is an ordered map (e.g. `IndexMap<K, V>`).
21/// Since the spec however does not make use of the order of items
22/// in the map we use a simple `HashMap<K, V>`.
23///
24/// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
25/// [media_track_capabilities]: https://www.w3.org/TR/mediacapture-streams/#dom-mediatrackcapabilities
26/// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams
27/// [webidl_spec]: https://webidl.spec.whatwg.org/#idl-dictionaries
28#[derive(Debug, Clone, Default, PartialEq)]
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30#[cfg_attr(feature = "serde", serde(transparent))]
31pub struct MediaTrackCapabilities(HashMap<MediaTrackProperty, MediaTrackCapability>);
32
33impl MediaTrackCapabilities {
34    /// Creates a capabilities value from its inner hashmap.
35    pub fn new(capabilities: HashMap<MediaTrackProperty, MediaTrackCapability>) -> Self {
36        Self(capabilities)
37    }
38
39    /// Consumes the value, returning its inner hashmap.
40    pub fn into_inner(self) -> HashMap<MediaTrackProperty, MediaTrackCapability> {
41        self.0
42    }
43}
44
45impl Deref for MediaTrackCapabilities {
46    type Target = HashMap<MediaTrackProperty, MediaTrackCapability>;
47
48    fn deref(&self) -> &Self::Target {
49        &self.0
50    }
51}
52
53impl DerefMut for MediaTrackCapabilities {
54    fn deref_mut(&mut self) -> &mut Self::Target {
55        &mut self.0
56    }
57}
58
59impl<T> FromIterator<(T, MediaTrackCapability)> for MediaTrackCapabilities
60where
61    T: Into<MediaTrackProperty>,
62{
63    fn from_iter<I>(iter: I) -> Self
64    where
65        I: IntoIterator<Item = (T, MediaTrackCapability)>,
66    {
67        Self::new(iter.into_iter().map(|(k, v)| (k.into(), v)).collect())
68    }
69}
70
71impl IntoIterator for MediaTrackCapabilities {
72    type Item = (MediaTrackProperty, MediaTrackCapability);
73    type IntoIter = std::collections::hash_map::IntoIter<MediaTrackProperty, MediaTrackCapability>;
74
75    fn into_iter(self) -> Self::IntoIter {
76        self.0.into_iter()
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use crate::property::all::name::*;
83
84    use super::*;
85
86    type Subject = MediaTrackCapabilities;
87
88    #[test]
89    fn into_inner() {
90        let hash_map = HashMap::from_iter([
91            (DEVICE_ID.clone(), "device-id".into()),
92            (AUTO_GAIN_CONTROL.clone(), true.into()),
93            (CHANNEL_COUNT.clone(), (12..=34).into()),
94            (LATENCY.clone(), (1.2..=3.4).into()),
95        ]);
96
97        let subject = Subject::new(hash_map.clone());
98
99        let actual = subject.into_inner();
100
101        let expected = hash_map;
102
103        assert_eq!(actual, expected);
104    }
105
106    #[test]
107    fn into_iter() {
108        let hash_map = HashMap::from_iter([
109            (DEVICE_ID.clone(), "device-id".into()),
110            (AUTO_GAIN_CONTROL.clone(), true.into()),
111            (CHANNEL_COUNT.clone(), (12..=34).into()),
112            (LATENCY.clone(), (1.2..=3.4).into()),
113        ]);
114
115        let subject = Subject::new(hash_map.clone());
116
117        let actual: HashMap<_, _> = subject.into_iter().collect();
118
119        let expected = hash_map;
120
121        assert_eq!(actual, expected);
122    }
123
124    #[test]
125    fn deref_and_deref_mut() {
126        let mut subject = Subject::default();
127
128        // Deref mut:
129        subject.insert(DEVICE_ID.clone(), "device-id".into());
130
131        // Deref:
132        assert!(subject.contains_key(&DEVICE_ID));
133    }
134}
135
136#[cfg(feature = "serde")]
137#[cfg(test)]
138mod serde_tests {
139    use crate::{macros::test_serde_symmetry, property::all::name::*};
140
141    use super::*;
142
143    type Subject = MediaTrackCapabilities;
144
145    #[test]
146    fn default() {
147        let subject = Subject::default();
148        let json = serde_json::json!({});
149
150        test_serde_symmetry!(subject: subject, json: json);
151    }
152
153    #[test]
154    fn customized() {
155        let subject = Subject::from_iter([
156            (&DEVICE_ID, "device-id".into()),
157            (&AUTO_GAIN_CONTROL, true.into()),
158            (&CHANNEL_COUNT, (12..=34).into()),
159            (&LATENCY, (1.2..=3.4).into()),
160        ]);
161        let json = serde_json::json!({
162            "deviceId": "device-id".to_owned(),
163            "autoGainControl": true,
164            "channelCount": { "min": 12, "max": 34 },
165            "latency": { "min": 1.2, "max": 3.4 },
166        });
167
168        test_serde_symmetry!(subject: subject, json: json);
169    }
170}