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