1use std::cell::Cell;
6use std::sync::mpsc;
7
8use dom_struct::dom_struct;
9use servo_media::audio::graph::NodeId;
10use servo_media::audio::node::{AudioNodeMessage, AudioNodeType};
11use servo_media::audio::param::{ParamRate, ParamType, RampKind, UserAutomationEvent};
12
13use crate::conversions::Convert;
14use crate::dom::audio::baseaudiocontext::BaseAudioContext;
15use crate::dom::bindings::codegen::Bindings::AudioParamBinding::{
16 AudioParamMethods, AutomationRate,
17};
18use crate::dom::bindings::error::{Error, Fallible};
19use crate::dom::bindings::num::Finite;
20use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::window::Window;
23use crate::script_runtime::CanGc;
24
25#[dom_struct]
26pub(crate) struct AudioParam {
27 reflector_: Reflector,
28 context: Dom<BaseAudioContext>,
29 #[ignore_malloc_size_of = "servo_media"]
30 #[no_trace]
31 node: Option<NodeId>,
32 #[ignore_malloc_size_of = "servo_media"]
33 #[no_trace]
34 node_type: AudioNodeType,
35 #[ignore_malloc_size_of = "servo_media"]
36 #[no_trace]
37 param: ParamType,
38 automation_rate: Cell<AutomationRate>,
39 default_value: f32,
40 min_value: f32,
41 max_value: f32,
42}
43
44impl AudioParam {
45 #[allow(clippy::too_many_arguments)]
46 pub(crate) fn new_inherited(
47 context: &BaseAudioContext,
48 node: Option<NodeId>,
49 node_type: AudioNodeType,
50 param: ParamType,
51 automation_rate: AutomationRate,
52 default_value: f32,
53 min_value: f32,
54 max_value: f32,
55 ) -> AudioParam {
56 AudioParam {
57 reflector_: Reflector::new(),
58 context: Dom::from_ref(context),
59 node,
60 node_type,
61 param,
62 automation_rate: Cell::new(automation_rate),
63 default_value,
64 min_value,
65 max_value,
66 }
67 }
68
69 #[allow(clippy::too_many_arguments)]
70 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
71 pub(crate) fn new(
72 window: &Window,
73 context: &BaseAudioContext,
74 node: Option<NodeId>,
75 node_type: AudioNodeType,
76 param: ParamType,
77 automation_rate: AutomationRate,
78 default_value: f32,
79 min_value: f32,
80 max_value: f32,
81 can_gc: CanGc,
82 ) -> DomRoot<AudioParam> {
83 let audio_param = AudioParam::new_inherited(
84 context,
85 node,
86 node_type,
87 param,
88 automation_rate,
89 default_value,
90 min_value,
91 max_value,
92 );
93 reflect_dom_object(Box::new(audio_param), window, can_gc)
94 }
95
96 fn message_node(&self, message: AudioNodeMessage) {
97 if let Some(node_id) = self.node {
98 self.context
99 .audio_context_impl()
100 .lock()
101 .unwrap()
102 .message_node(node_id, message);
103 }
104 }
105
106 pub(crate) fn context(&self) -> &BaseAudioContext {
107 &self.context
108 }
109
110 pub(crate) fn node_id(&self) -> Option<NodeId> {
111 self.node
112 }
113
114 pub(crate) fn param_type(&self) -> ParamType {
115 self.param
116 }
117}
118
119impl AudioParamMethods<crate::DomTypeHolder> for AudioParam {
120 fn AutomationRate(&self) -> AutomationRate {
122 self.automation_rate.get()
123 }
124
125 fn SetAutomationRate(&self, automation_rate: AutomationRate) -> Fallible<()> {
127 if automation_rate == AutomationRate::A_rate &&
131 self.node_type == AudioNodeType::AudioBufferSourceNode &&
132 (self.param == ParamType::Detune || self.param == ParamType::PlaybackRate)
133 {
134 return Err(Error::InvalidState(None));
135 }
136
137 self.automation_rate.set(automation_rate);
138 self.message_node(AudioNodeMessage::SetParamRate(
139 self.param,
140 automation_rate.convert(),
141 ));
142
143 Ok(())
144 }
145
146 fn Value(&self) -> Finite<f32> {
148 if self.node.is_none() {
149 return Finite::wrap(self.default_value);
150 }
151 let (tx, rx) = mpsc::channel();
152 self.message_node(AudioNodeMessage::GetParamValue(self.param, tx));
153 Finite::wrap(rx.recv().unwrap())
154 }
155
156 fn SetValue(&self, value: Finite<f32>) {
158 self.message_node(AudioNodeMessage::SetParam(
159 self.param,
160 UserAutomationEvent::SetValue(*value),
161 ));
162 }
163
164 fn DefaultValue(&self) -> Finite<f32> {
166 Finite::wrap(self.default_value)
167 }
168
169 fn MinValue(&self) -> Finite<f32> {
171 Finite::wrap(self.min_value)
172 }
173
174 fn MaxValue(&self) -> Finite<f32> {
176 Finite::wrap(self.max_value)
177 }
178
179 fn SetValueAtTime(
181 &self,
182 value: Finite<f32>,
183 start_time: Finite<f64>,
184 ) -> Fallible<DomRoot<AudioParam>> {
185 if *start_time < 0. {
186 return Err(Error::Range(format!(
187 "start time {} should not be negative",
188 *start_time
189 )));
190 }
191 self.message_node(AudioNodeMessage::SetParam(
192 self.param,
193 UserAutomationEvent::SetValueAtTime(*value, *start_time),
194 ));
195 Ok(DomRoot::from_ref(self))
196 }
197
198 fn LinearRampToValueAtTime(
200 &self,
201 value: Finite<f32>,
202 end_time: Finite<f64>,
203 ) -> Fallible<DomRoot<AudioParam>> {
204 if *end_time < 0. {
205 return Err(Error::Range(format!(
206 "end time {} should not be negative",
207 *end_time
208 )));
209 }
210 self.message_node(AudioNodeMessage::SetParam(
211 self.param,
212 UserAutomationEvent::RampToValueAtTime(RampKind::Linear, *value, *end_time),
213 ));
214 Ok(DomRoot::from_ref(self))
215 }
216
217 fn ExponentialRampToValueAtTime(
219 &self,
220 value: Finite<f32>,
221 end_time: Finite<f64>,
222 ) -> Fallible<DomRoot<AudioParam>> {
223 if *end_time < 0. {
224 return Err(Error::Range(format!(
225 "end time {} should not be negative",
226 *end_time
227 )));
228 }
229 if *value == 0. {
230 return Err(Error::Range(format!(
231 "target value {} should not be 0",
232 *value
233 )));
234 }
235 self.message_node(AudioNodeMessage::SetParam(
236 self.param,
237 UserAutomationEvent::RampToValueAtTime(RampKind::Exponential, *value, *end_time),
238 ));
239 Ok(DomRoot::from_ref(self))
240 }
241
242 fn SetTargetAtTime(
244 &self,
245 target: Finite<f32>,
246 start_time: Finite<f64>,
247 time_constant: Finite<f32>,
248 ) -> Fallible<DomRoot<AudioParam>> {
249 if *start_time < 0. {
250 return Err(Error::Range(format!(
251 "start time {} should not be negative",
252 *start_time
253 )));
254 }
255 if *time_constant < 0. {
256 return Err(Error::Range(format!(
257 "time constant {} should not be negative",
258 *time_constant
259 )));
260 }
261 self.message_node(AudioNodeMessage::SetParam(
262 self.param,
263 UserAutomationEvent::SetTargetAtTime(*target, *start_time, (*time_constant).into()),
264 ));
265 Ok(DomRoot::from_ref(self))
266 }
267
268 fn SetValueCurveAtTime(
270 &self,
271 values: Vec<Finite<f32>>,
272 start_time: Finite<f64>,
273 end_time: Finite<f64>,
274 ) -> Fallible<DomRoot<AudioParam>> {
275 if *start_time < 0. {
276 return Err(Error::Range(format!(
277 "start time {} should not be negative",
278 *start_time
279 )));
280 }
281 if values.len() < 2. as usize {
282 return Err(Error::InvalidState(None));
283 }
284
285 if *end_time < 0. {
286 return Err(Error::Range(format!(
287 "end time {} should not be negative",
288 *end_time
289 )));
290 }
291 self.message_node(AudioNodeMessage::SetParam(
292 self.param,
293 UserAutomationEvent::SetValueCurveAtTime(
294 values.into_iter().map(|v| *v).collect(),
295 *start_time,
296 *end_time,
297 ),
298 ));
299 Ok(DomRoot::from_ref(self))
300 }
301
302 fn CancelScheduledValues(&self, cancel_time: Finite<f64>) -> Fallible<DomRoot<AudioParam>> {
304 if *cancel_time < 0. {
305 return Err(Error::Range(format!(
306 "cancel time {} should not be negative",
307 *cancel_time
308 )));
309 }
310 self.message_node(AudioNodeMessage::SetParam(
311 self.param,
312 UserAutomationEvent::CancelScheduledValues(*cancel_time),
313 ));
314 Ok(DomRoot::from_ref(self))
315 }
316
317 fn CancelAndHoldAtTime(&self, cancel_time: Finite<f64>) -> Fallible<DomRoot<AudioParam>> {
319 if *cancel_time < 0. {
320 return Err(Error::Range(format!(
321 "cancel time {} should not be negative",
322 *cancel_time
323 )));
324 }
325 self.message_node(AudioNodeMessage::SetParam(
326 self.param,
327 UserAutomationEvent::CancelAndHoldAtTime(*cancel_time),
328 ));
329 Ok(DomRoot::from_ref(self))
330 }
331}
332
333impl Convert<ParamRate> for AutomationRate {
335 fn convert(self) -> ParamRate {
336 match self {
337 AutomationRate::A_rate => ParamRate::ARate,
338 AutomationRate::K_rate => ParamRate::KRate,
339 }
340 }
341}