xref: /webrtc/constraints/src/settings/track.rs (revision 86143b07)
1 use std::{
2     collections::HashMap,
3     iter::FromIterator,
4     ops::{Deref, DerefMut},
5 };
6 
7 #[cfg(feature = "serde")]
8 use serde::{Deserialize, Serialize};
9 
10 use 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))]
33 pub struct MediaTrackSettings(HashMap<MediaTrackProperty, MediaTrackSetting>);
34 
35 impl MediaTrackSettings {
36     /// Creates a settings value from its inner hashmap.
new(settings: HashMap<MediaTrackProperty, MediaTrackSetting>) -> Self37     pub fn new(settings: HashMap<MediaTrackProperty, MediaTrackSetting>) -> Self {
38         Self(settings)
39     }
40 
41     /// Consumes the value, returning its inner hashmap.
into_inner(self) -> HashMap<MediaTrackProperty, MediaTrackSetting>42     pub fn into_inner(self) -> HashMap<MediaTrackProperty, MediaTrackSetting> {
43         self.0
44     }
45 }
46 
47 impl Deref for MediaTrackSettings {
48     type Target = HashMap<MediaTrackProperty, MediaTrackSetting>;
49 
deref(&self) -> &Self::Target50     fn deref(&self) -> &Self::Target {
51         &self.0
52     }
53 }
54 
55 impl DerefMut for MediaTrackSettings {
deref_mut(&mut self) -> &mut Self::Target56     fn deref_mut(&mut self) -> &mut Self::Target {
57         &mut self.0
58     }
59 }
60 
61 impl<T> FromIterator<(T, MediaTrackSetting)> for MediaTrackSettings
62 where
63     T: Into<MediaTrackProperty>,
64 {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = (T, MediaTrackSetting)>,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 
73 impl IntoIterator for MediaTrackSettings {
74     type Item = (MediaTrackProperty, MediaTrackSetting);
75     type IntoIter = std::collections::hash_map::IntoIter<MediaTrackProperty, MediaTrackSetting>;
76 
into_iter(self) -> Self::IntoIter77     fn into_iter(self) -> Self::IntoIter {
78         self.0.into_iter()
79     }
80 }
81 
82 #[cfg(test)]
83 mod tests {
84     use crate::property::all::name::*;
85 
86     use super::*;
87 
88     type Subject = MediaTrackSettings;
89 
90     #[test]
into_inner()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]
into_iter()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]
deref_and_deref_mut()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)]
140 mod serde_tests {
141     use crate::{macros::test_serde_symmetry, property::all::name::*};
142 
143     use super::*;
144 
145     type Subject = MediaTrackSettings;
146 
147     #[test]
default()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]
customized()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 }
173