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::graph::NodeId;
14use servo_media::audio::node::{
15 AudioNodeInit, AudioNodeMessage, ChannelCountMode as ServoMediaChannelCountMode, ChannelInfo,
16 ChannelInterpretation as ServoMediaChannelInterpretation,
17};
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 cx: &mut JSContext,
53 node_type: AudioNodeInit,
54 context: &BaseAudioContext,
55 options: UnwrappedAudioNodeOptions,
56 number_of_inputs: u32,
57 number_of_outputs: u32,
58 ) -> Fallible<AudioNode> {
59 if options.count == 0 || options.count > MAX_CHANNEL_COUNT {
60 return Err(Error::NotSupported(None));
61 }
62 let ch = ChannelInfo {
63 count: options.count as u8,
64 mode: options.mode.convert(),
65 interpretation: options.interpretation.convert(),
66 context_channel_count: context.channel_count() as u8,
67 };
68 let node_id = context
69 .audio_context_impl()
70 .lock()
71 .unwrap()
72 .create_node(node_type, ch);
73
74 if node_id.is_none() {
75 const MESSAGE: &str =
77 "Failed to create an AudioNode backend. The constructed AudioNode will be inert.";
78 warn!("{MESSAGE}");
79 Console::internal_warn(cx, &context.global(), MESSAGE.to_string());
80 }
81
82 Ok(AudioNode::new_inherited_for_id(
83 node_id,
84 context,
85 options,
86 number_of_inputs,
87 number_of_outputs,
88 ))
89 }
90
91 pub(crate) fn new_inherited_for_id(
92 node_id: Option<NodeId>,
93 context: &BaseAudioContext,
94 options: UnwrappedAudioNodeOptions,
95 number_of_inputs: u32,
96 number_of_outputs: u32,
97 ) -> AudioNode {
98 AudioNode {
99 eventtarget: EventTarget::new_inherited(),
100 node_id,
101 context: Dom::from_ref(context),
102 number_of_inputs,
103 number_of_outputs,
104 channel_count: Cell::new(options.count),
105 channel_count_mode: Cell::new(options.mode),
106 channel_interpretation: Cell::new(options.interpretation),
107 }
108 }
109
110 pub(crate) fn message(&self, message: AudioNodeMessage) {
111 if let Some(node_id) = self.node_id {
112 self.context
113 .audio_context_impl()
114 .lock()
115 .unwrap()
116 .message_node(node_id, message);
117 }
118 }
119
120 pub(crate) fn node_id(&self) -> Option<NodeId> {
121 self.node_id
122 }
123}
124
125impl AudioNodeMethods<crate::DomTypeHolder> for AudioNode {
126 fn Connect(
128 &self,
129 destination: &AudioNode,
130 output: u32,
131 input: u32,
132 ) -> Fallible<DomRoot<AudioNode>> {
133 if self.context != destination.context {
134 return Err(Error::InvalidAccess(None));
135 }
136
137 if output >= self.NumberOfOutputs() || input >= destination.NumberOfInputs() {
138 return Err(Error::IndexSize(None));
139 }
140
141 let Some(source_id) = self.node_id() else {
144 return Ok(DomRoot::from_ref(destination));
145 };
146 let Some(dest_id) = destination.node_id() else {
147 return Ok(DomRoot::from_ref(destination));
148 };
149
150 self.context
151 .audio_context_impl()
152 .lock()
153 .unwrap()
154 .connect_ports(source_id.output(output), dest_id.input(input));
155
156 Ok(DomRoot::from_ref(destination))
157 }
158
159 fn Connect_(&self, dest: &AudioParam, output: u32) -> Fallible<()> {
161 if self.context != dest.context() {
162 return Err(Error::InvalidAccess(None));
163 }
164
165 if output >= self.NumberOfOutputs() {
166 return Err(Error::IndexSize(None));
167 }
168
169 let Some(source_id) = self.node_id() else {
172 return Ok(());
173 };
174 let Some(param_node) = dest.node_id() else {
175 return Ok(());
176 };
177
178 self.context
179 .audio_context_impl()
180 .lock()
181 .unwrap()
182 .connect_ports(
183 source_id.output(output),
184 param_node.param(dest.param_type()),
185 );
186
187 Ok(())
188 }
189
190 fn Disconnect(&self) -> ErrorResult {
192 if let Some(node_id) = self.node_id() {
193 self.context
194 .audio_context_impl()
195 .lock()
196 .unwrap()
197 .disconnect_all_from(node_id);
198 }
199 Ok(())
200 }
201
202 fn Disconnect_(&self, out: u32) -> ErrorResult {
204 if let Some(node_id) = self.node_id() {
205 self.context
206 .audio_context_impl()
207 .lock()
208 .unwrap()
209 .disconnect_output(node_id.output(out));
210 }
211 Ok(())
212 }
213
214 fn Disconnect__(&self, to: &AudioNode) -> ErrorResult {
216 if let (Some(from_node), Some(to_node)) = (self.node_id(), to.node_id()) {
217 self.context
218 .audio_context_impl()
219 .lock()
220 .unwrap()
221 .disconnect_between(from_node, to_node);
222 }
223 Ok(())
224 }
225
226 fn Disconnect___(&self, to: &AudioNode, out: u32) -> ErrorResult {
228 if let (Some(from_node), Some(to_node)) = (self.node_id(), to.node_id()) {
229 self.context
230 .audio_context_impl()
231 .lock()
232 .unwrap()
233 .disconnect_output_between(from_node.output(out), to_node);
234 }
235 Ok(())
236 }
237
238 fn Disconnect____(&self, to: &AudioNode, out: u32, inp: u32) -> ErrorResult {
240 if let (Some(from_node), Some(to_node)) = (self.node_id(), to.node_id()) {
241 self.context
242 .audio_context_impl()
243 .lock()
244 .unwrap()
245 .disconnect_output_between_to(from_node.output(out), to_node.input(inp));
246 }
247 Ok(())
248 }
249
250 fn Disconnect_____(&self, param: &AudioParam) -> ErrorResult {
252 if let (Some(from_node), Some(param_node)) = (self.node_id(), param.node_id()) {
253 self.context
254 .audio_context_impl()
255 .lock()
256 .unwrap()
257 .disconnect_to(from_node, param_node.param(param.param_type()));
258 }
259 Ok(())
260 }
261
262 fn Disconnect______(&self, param: &AudioParam, out: u32) -> ErrorResult {
264 if let (Some(from_node), Some(param_node)) = (self.node_id(), param.node_id()) {
265 self.context
266 .audio_context_impl()
267 .lock()
268 .unwrap()
269 .disconnect_output_between_to(
270 from_node.output(out),
271 param_node.param(param.param_type()),
272 );
273 }
274 Ok(())
275 }
276
277 fn Context(&self) -> DomRoot<BaseAudioContext> {
279 DomRoot::from_ref(&self.context)
280 }
281
282 fn NumberOfInputs(&self) -> u32 {
284 self.number_of_inputs
285 }
286
287 fn NumberOfOutputs(&self) -> u32 {
289 self.number_of_outputs
290 }
291
292 fn ChannelCount(&self) -> u32 {
294 self.channel_count.get()
295 }
296
297 fn SetChannelCount(&self, value: u32) -> ErrorResult {
299 match self.upcast::<EventTarget>().type_id() {
300 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioDestinationNode) => {
301 if self.context.is_offline() {
302 return Err(Error::InvalidState(None));
303 } else if !(1..=MAX_CHANNEL_COUNT).contains(&value) {
304 return Err(Error::IndexSize(None));
305 }
306 },
307 EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) if value > 2 => {
308 return Err(Error::NotSupported(None));
309 },
310 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioScheduledSourceNode(
311 AudioScheduledSourceNodeTypeId::StereoPannerNode,
312 )) if value > 2 => {
313 return Err(Error::NotSupported(None));
314 },
315 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
316 return Err(Error::InvalidState(None));
317 },
318 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelSplitterNode) => {
319 return Err(Error::InvalidState(None));
320 },
321 _ => (),
325 };
326
327 if value == 0 || value > MAX_CHANNEL_COUNT {
328 return Err(Error::NotSupported(None));
329 }
330
331 self.channel_count.set(value);
332 self.message(AudioNodeMessage::SetChannelCount(value as u8));
333 Ok(())
334 }
335
336 fn ChannelCountMode(&self) -> ChannelCountMode {
338 self.channel_count_mode.get()
339 }
340
341 fn SetChannelCountMode(&self, value: ChannelCountMode) -> ErrorResult {
343 if self.number_of_inputs == 0 {
345 return Ok(());
346 }
347
348 match self.upcast::<EventTarget>().type_id() {
349 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioDestinationNode)
350 if self.context.is_offline() =>
351 {
352 return Err(Error::InvalidState(None));
353 },
354 EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode)
355 if value == ChannelCountMode::Max =>
356 {
357 return Err(Error::NotSupported(None));
358 },
359 EventTargetTypeId::AudioNode(AudioNodeTypeId::AudioScheduledSourceNode(
360 AudioScheduledSourceNodeTypeId::StereoPannerNode,
361 )) if value == ChannelCountMode::Max => {
362 return Err(Error::NotSupported(None));
363 },
364 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
365 return Err(Error::InvalidState(None));
366 },
367 EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelSplitterNode) => {
368 return Err(Error::InvalidState(None));
369 },
370 _ => (),
374 };
375
376 self.channel_count_mode.set(value);
377 self.message(AudioNodeMessage::SetChannelMode(value.convert()));
378 Ok(())
379 }
380
381 fn ChannelInterpretation(&self) -> ChannelInterpretation {
383 self.channel_interpretation.get()
384 }
385
386 fn SetChannelInterpretation(&self, value: ChannelInterpretation) -> ErrorResult {
388 if self.number_of_inputs == 0 {
390 return Ok(());
391 }
392
393 if let EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelSplitterNode) =
394 self.upcast::<EventTarget>().type_id()
395 {
396 return Err(Error::InvalidState(None));
397 };
398
399 self.channel_interpretation.set(value);
400 self.message(AudioNodeMessage::SetChannelInterpretation(value.convert()));
401 Ok(())
402 }
403}
404
405impl Convert<ServoMediaChannelCountMode> for ChannelCountMode {
406 fn convert(self) -> ServoMediaChannelCountMode {
407 match self {
408 ChannelCountMode::Max => ServoMediaChannelCountMode::Max,
409 ChannelCountMode::Clamped_max => ServoMediaChannelCountMode::ClampedMax,
410 ChannelCountMode::Explicit => ServoMediaChannelCountMode::Explicit,
411 }
412 }
413}
414
415impl Convert<ServoMediaChannelInterpretation> for ChannelInterpretation {
416 fn convert(self) -> ServoMediaChannelInterpretation {
417 match self {
418 ChannelInterpretation::Discrete => ServoMediaChannelInterpretation::Discrete,
419 ChannelInterpretation::Speakers => ServoMediaChannelInterpretation::Speakers,
420 }
421 }
422}
423
424pub(crate) trait AudioNodeOptionsHelper {
425 fn unwrap_or(
426 &self,
427 count: u32,
428 mode: ChannelCountMode,
429 interpretation: ChannelInterpretation,
430 ) -> UnwrappedAudioNodeOptions;
431}
432
433impl AudioNodeOptionsHelper for AudioNodeOptions {
434 fn unwrap_or(
435 &self,
436 count: u32,
437 mode: ChannelCountMode,
438 interpretation: ChannelInterpretation,
439 ) -> UnwrappedAudioNodeOptions {
440 UnwrappedAudioNodeOptions {
441 count: self.channelCount.unwrap_or(count),
442 mode: self.channelCountMode.unwrap_or(mode),
443 interpretation: self.channelInterpretation.unwrap_or(interpretation),
444 }
445 }
446}
447
448pub(crate) struct UnwrappedAudioNodeOptions {
451 pub(crate) count: u32,
452 pub(crate) mode: ChannelCountMode,
453 pub(crate) interpretation: ChannelInterpretation,
454}
455
456impl Default for UnwrappedAudioNodeOptions {
457 fn default() -> Self {
458 UnwrappedAudioNodeOptions {
459 count: 2,
460 mode: ChannelCountMode::Max,
461 interpretation: ChannelInterpretation::Speakers,
462 }
463 }
464}