1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use log::warn;
10use script_bindings::codegen::InheritTypes::{
11 AudioNodeTypeId, AudioScheduledSourceNodeTypeId, EventTargetTypeId,
12};
13use servo_media::audio::audio_node::{
14 AudioNodeInit, AudioNodeMessage, ChannelCountMode as ServoMediaChannelCountMode, ChannelInfo,
15 ChannelInterpretation as ServoMediaChannelInterpretation,
16};
17use servo_media::audio::graph::NodeId;
18
19use crate::conversions::Convert;
20use crate::dom::audio::audioparam::AudioParam;
21use crate::dom::audio::baseaudiocontext::BaseAudioContext;
22use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
23 AudioNodeMethods, AudioNodeOptions, ChannelCountMode, ChannelInterpretation,
24};
25use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
26use crate::dom::bindings::inheritance::Castable;
27use crate::dom::bindings::reflector::DomGlobal;
28use crate::dom::bindings::root::{Dom, DomRoot};
29use crate::dom::console::Console;
30use crate::dom::eventtarget::EventTarget;
31
32pub(crate) const MAX_CHANNEL_COUNT: u32 = 32;
36
37#[dom_struct]
38pub(crate) struct AudioNode {
39 eventtarget: EventTarget,
40 #[no_trace]
41 node_id: Option<NodeId>,
42 context: Dom<BaseAudioContext>,
43 number_of_inputs: u32,
44 number_of_outputs: u32,
45 channel_count: Cell<u32>,
46 channel_count_mode: Cell<ChannelCountMode>,
47 channel_interpretation: Cell<ChannelInterpretation>,
48}
49
50impl AudioNode {
51 pub(crate) fn new_inherited(
52 node_id: Option<NodeId>,
53 context: &BaseAudioContext,
54 options: UnwrappedAudioNodeOptions,
55 number_of_inputs: u32,
56 number_of_outputs: u32,
57 ) -> AudioNode {
58 AudioNode {
59 eventtarget: EventTarget::new_inherited(),
60 node_id,
61 context: Dom::from_ref(context),
62 number_of_inputs,
63 number_of_outputs,
64 channel_count: Cell::new(options.count),
65 channel_count_mode: Cell::new(options.mode),
66 channel_interpretation: Cell::new(options.interpretation),
67 }
68 }
69
70 pub(crate) fn channel_count_check(count: u32) -> bool {
74 count == 0 || count > MAX_CHANNEL_COUNT
75 }
76
77 pub(crate) fn generate_audio_node_id(
78 cx: &mut JSContext,
79 node_options: &UnwrappedAudioNodeOptions,
80 audio_node_init: AudioNodeInit,
81 context: &BaseAudioContext,
82 ) -> Option<NodeId> {
83 let ch = ChannelInfo {
84 count: node_options.count as u8,
85 mode: node_options.mode.convert(),
86 interpretation: node_options.interpretation.convert(),
87 context_channel_count: context.channel_count() as u8,
88 };
89 let node_id = context
90 .audio_context_impl()
91 .lock()
92 .unwrap()
93 .create_node(audio_node_init, ch);
94 if node_id.is_none() {
95 const MESSAGE: &str =
97 "Failed to create an AudioNode backend. The constructed AudioNode will be inert.";
98 warn!("{MESSAGE}");
99 Console::internal_warn(cx, &context.global(), MESSAGE.to_string());
100 }
101 node_id
102 }
103
104 pub(crate) fn message(&self, message: AudioNodeMessage) {
105 if let Some(node_id) = self.node_id {
106 self.context
107 .audio_context_impl()
108 .lock()
109 .unwrap()
110 .message_node(node_id, message);
111 }
112 }
113
114 pub(crate) fn node_id(&self) -> Option<NodeId> {
115 self.node_id
116 }
117}
118
119impl AudioNodeMethods<crate::DomTypeHolder> for AudioNode {
120 fn Connect(
122 &self,
123 destination: &AudioNode,
124 output: u32,
125 input: u32,
126 ) -> Fallible<DomRoot<AudioNode>> {
127 if self.context != destination.context {
128 return Err(Error::InvalidAccess(Some(
129 "Destination node belongs to a different AudioContext".into(),
130 )));
131 }
132
133 if output >= self.NumberOfOutputs() || input >= destination.NumberOfInputs() {
134 return Err(Error::IndexSize(Some(
135 "Output or input index is out of range".into(),
136 )));
137 }
138
139 let Some(source_id) = self.node_id() else {
142 return Ok(DomRoot::from_ref(destination));
143 };
144 let Some(dest_id) = destination.node_id() else {
145 return Ok(DomRoot::from_ref(destination));
146 };
147
148 self.context
149 .audio_context_impl()
150 .lock()
151 .unwrap()
152 .connect_ports(source_id.output(output), dest_id.input(input));
153
154 Ok(DomRoot::from_ref(destination))
155 }
156
157 fn Connect_(&self, dest: &AudioParam, output: u32) -> Fallible<()> {
159 if self.context != dest.context() {
160 return Err(Error::InvalidAccess(Some(
161 "Destination AudioParam belongs to a different AudioContext".into(),
162 )));
163 }
164
165 if output >= self.NumberOfOutputs() {
166 return Err(Error::IndexSize(Some(
167 "Output index is out of range".into(),
168 )));
169 }
170
171 let Some(source_id) = self.node_id() else {
174 return Ok(());
175 };
176 let Some(param_node) = dest.node_id() else {
177 return Ok(());
178 };
179
180 self.context
181 .audio_context_impl()
182 .lock()
183 .unwrap()
184 .connect_ports(
185 source_id.output(output),
186 param_node.param(dest.param_type()),
187 );
188
189 Ok(())
190 }
191
192 fn Disconnect(&self) -> ErrorResult {
194 if let Some(node_id) = self.node_id() {
195 self.context
196 .audio_context_impl()
197 .lock()
198 .unwrap()
199 .disconnect_all_from(node_id);
200 }
201 Ok(())
202 }
203
204 fn Disconnect_(&self, out: u32) -> ErrorResult {
206 if let Some(node_id) = self.node_id() {
207 self.context
208 .audio_context_impl()
209 .lock()
210 .unwrap()
211 .disconnect_output(node_id.output(out));
212 }
213 Ok(())
214 }
215
216 fn Disconnect__(&self, to: &AudioNode) -> ErrorResult {
218 if let (Some(from_node), Some(to_node)) = (self.node_id(), to.node_id()) {
219 self.context
220 .audio_context_impl()
221 .lock()
222 .unwrap()
223 .disconnect_between(from_node, to_node);
224 }
225 Ok(())
226 }
227
228 fn Disconnect___(&self, to: &AudioNode, out: u32) -> ErrorResult {
230 if let (Some(from_node), Some(to_node)) = (self.node_id(), to.node_id()) {
231 self.context
232 .audio_context_impl()
233 .lock()
234 .unwrap()
235 .disconnect_output_between(from_node.output(out), to_node);
236 }
237 Ok(())
238 }
239
240 fn Disconnect____(&self, to: &AudioNode, out: u32, inp: u32) -> ErrorResult {
242 if let (Some(from_node), Some(to_node)) = (self.node_id(), to.node_id()) {
243 self.context
244 .audio_context_impl()
245 .lock()
246 .unwrap()
247 .disconnect_output_between_to(from_node.output(out), to_node.input(inp));
248 }
249 Ok(())
250 }
251
252 fn Disconnect_____(&self, param: &AudioParam) -> ErrorResult {
254 if let (Some(from_node), Some(param_node)) = (self.node_id(), param.node_id()) {
255 self.context
256 .audio_context_impl()
257 .lock()
258 .unwrap()
259 .disconnect_to(from_node, param_node.param(param.param_type()));
260 }
261 Ok(())
262 }
263
264 fn Disconnect______(&self, param: &AudioParam, out: u32) -> ErrorResult {
266 if let (Some(from_node), Some(param_node)) = (self.node_id(), param.node_id()) {
267 self.context
268 .audio_context_impl()
269 .lock()
270 .unwrap()
271 .disconnect_output_between_to(
272 from_node.output(out),
273 param_node.param(param.param_type()),
274 );
275 }
276 Ok(())
277 }
278
279 fn Context(&self) -> DomRoot<BaseAudioContext> {
281 DomRoot::from_ref(&self.context)
282 }
283
284 fn NumberOfInputs(&self) -> u32 {
286 self.number_of_inputs
287 }
288
289 fn NumberOfOutputs(&self) -> u32 {
291 self.number_of_outputs
292 }
293
294 fn ChannelCount(&self) -> u32 {
296 self.channel_count.get()
297 }
298
299 fn SetChannelCount(&self, value: u32) -> ErrorResult {
301 match self.upcast::<EventTarget>().type_id() {
302 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioDestinationNode) => {
303 if self.context.is_offline() {
304 return Err(Error::InvalidState(Some(
305 "Cannot change channel count".into(),
306 )));
307 } else if !(1..=MAX_CHANNEL_COUNT).contains(&value) {
308 return Err(Error::IndexSize(Some(
309 "Channel count is out of range".into(),
310 )));
311 }
312 },
313 EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) if value > 2 => {
314 return Err(Error::NotSupported(Some(
315 "PannerNode channel count cannot be greater than 2".into(),
316 )));
317 },
318 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioScheduledSourceNode(
319 AudioScheduledSourceNodeTypeId::StereoPannerNode,
320 )) if value > 2 => {
321 return Err(Error::NotSupported(Some(
322 "StereoPannerNode channel count cannot be greater than 2".into(),
323 )));
324 },
325 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
326 return Err(Error::InvalidState(Some(
327 "Cannot change channel count of a ChannelMergerNode".into(),
328 )));
329 },
330 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelSplitterNode) => {
331 return Err(Error::InvalidState(Some(
332 "Cannot change channel count of a ChannelSplitterNode".into(),
333 )));
334 },
335 _ => (),
339 };
340
341 if value == 0 || value > MAX_CHANNEL_COUNT {
342 return Err(Error::NotSupported(Some(
343 "Channel count is out of range".into(),
344 )));
345 }
346
347 self.channel_count.set(value);
348 self.message(AudioNodeMessage::SetChannelCount(value as u8));
349 Ok(())
350 }
351
352 fn ChannelCountMode(&self) -> ChannelCountMode {
354 self.channel_count_mode.get()
355 }
356
357 fn SetChannelCountMode(&self, value: ChannelCountMode) -> ErrorResult {
359 if self.number_of_inputs == 0 {
361 return Ok(());
362 }
363
364 match self.upcast::<EventTarget>().type_id() {
365 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioDestinationNode)
366 if self.context.is_offline() =>
367 {
368 return Err(Error::InvalidState(Some(
369 "Cannot change channel count mode".into(),
370 )));
371 },
372 EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode)
373 if value == ChannelCountMode::Max =>
374 {
375 return Err(Error::NotSupported(Some(
376 "PannerNode channel count mode cannot be \"max\"".into(),
377 )));
378 },
379 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioScheduledSourceNode(
380 AudioScheduledSourceNodeTypeId::StereoPannerNode,
381 )) if value == ChannelCountMode::Max => {
382 return Err(Error::NotSupported(Some(
383 "StereoPannerNode channel count mode cannot be \"max\"".into(),
384 )));
385 },
386 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
387 return Err(Error::InvalidState(Some(
388 "Cannot change channel count mode of a ChannelMergerNode".into(),
389 )));
390 },
391 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelSplitterNode) => {
392 return Err(Error::InvalidState(Some(
393 "Cannot change channel count mode of a ChannelSplitterNode".into(),
394 )));
395 },
396 _ => (),
400 };
401
402 self.channel_count_mode.set(value);
403 self.message(AudioNodeMessage::SetChannelMode(value.convert()));
404 Ok(())
405 }
406
407 fn ChannelInterpretation(&self) -> ChannelInterpretation {
409 self.channel_interpretation.get()
410 }
411
412 fn SetChannelInterpretation(&self, value: ChannelInterpretation) -> ErrorResult {
414 if self.number_of_inputs == 0 {
416 return Ok(());
417 }
418
419 if let EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelSplitterNode) =
420 self.upcast::<EventTarget>().type_id()
421 {
422 return Err(Error::InvalidState(Some(
423 "Cannot change channel interpretation of a ChannelSplitterNode".into(),
424 )));
425 };
426
427 self.channel_interpretation.set(value);
428 self.message(AudioNodeMessage::SetChannelInterpretation(value.convert()));
429 Ok(())
430 }
431}
432
433impl Convert<ServoMediaChannelCountMode> for ChannelCountMode {
434 fn convert(self) -> ServoMediaChannelCountMode {
435 match self {
436 ChannelCountMode::Max => ServoMediaChannelCountMode::Max,
437 ChannelCountMode::Clamped_max => ServoMediaChannelCountMode::ClampedMax,
438 ChannelCountMode::Explicit => ServoMediaChannelCountMode::Explicit,
439 }
440 }
441}
442
443impl Convert<ServoMediaChannelInterpretation> for ChannelInterpretation {
444 fn convert(self) -> ServoMediaChannelInterpretation {
445 match self {
446 ChannelInterpretation::Discrete => ServoMediaChannelInterpretation::Discrete,
447 ChannelInterpretation::Speakers => ServoMediaChannelInterpretation::Speakers,
448 }
449 }
450}
451
452pub(crate) trait AudioNodeOptionsHelper {
453 fn unwrap_or(
454 &self,
455 count: u32,
456 mode: ChannelCountMode,
457 interpretation: ChannelInterpretation,
458 ) -> UnwrappedAudioNodeOptions;
459}
460
461impl AudioNodeOptionsHelper for AudioNodeOptions {
462 fn unwrap_or(
463 &self,
464 count: u32,
465 mode: ChannelCountMode,
466 interpretation: ChannelInterpretation,
467 ) -> UnwrappedAudioNodeOptions {
468 UnwrappedAudioNodeOptions {
469 count: self.channelCount.unwrap_or(count),
470 mode: self.channelCountMode.unwrap_or(mode),
471 interpretation: self.channelInterpretation.unwrap_or(interpretation),
472 }
473 }
474}
475
476pub(crate) struct UnwrappedAudioNodeOptions {
479 pub(crate) count: u32,
480 pub(crate) mode: ChannelCountMode,
481 pub(crate) interpretation: ChannelInterpretation,
482}
483
484impl Default for UnwrappedAudioNodeOptions {
485 fn default() -> Self {
486 UnwrappedAudioNodeOptions {
487 count: 2,
488 mode: ChannelCountMode::Max,
489 interpretation: ChannelInterpretation::Speakers,
490 }
491 }
492}