script/dom/audio/
stereopannernode.rs1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::rust::HandleObject;
8use script_bindings::reflector::reflect_dom_object_with_proto;
9use servo_media::audio::audio_node::{AudioNodeInit, AudioNodeType};
10use servo_media::audio::graph::NodeId;
11use servo_media::audio::param::ParamType;
12use servo_media::audio::stereo_panner::StereoPannerOptions as ServoMediaStereoPannerOptions;
13
14use crate::conversions::Convert;
15use crate::dom::audio::audionode::{AudioNode, AudioNodeOptionsHelper};
16use crate::dom::audio::audioparam::AudioParam;
17use crate::dom::audio::audioscheduledsourcenode::AudioScheduledSourceNode;
18use crate::dom::audio::baseaudiocontext::BaseAudioContext;
19use crate::dom::audionode::UnwrappedAudioNodeOptions;
20use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
21 ChannelCountMode, ChannelInterpretation,
22};
23use crate::dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
24use crate::dom::bindings::codegen::Bindings::StereoPannerNodeBinding::{
25 StereoPannerNodeMethods, StereoPannerOptions,
26};
27use crate::dom::bindings::error::{Error, Fallible};
28use crate::dom::bindings::root::{Dom, DomRoot};
29use crate::dom::window::Window;
30
31#[dom_struct]
32pub(crate) struct StereoPannerNode {
33 source_node: AudioScheduledSourceNode,
34 pan: Dom<AudioParam>,
35}
36
37impl StereoPannerNode {
38 fn new_inherited(
39 node_id: Option<NodeId>,
40 context: &BaseAudioContext,
41 node_options: UnwrappedAudioNodeOptions,
42 pan: &AudioParam,
43 ) -> Self {
44 StereoPannerNode {
45 source_node: AudioScheduledSourceNode::new_inherited(
46 node_id,
47 context,
48 node_options,
49 1, 1, ),
52 pan: Dom::from_ref(pan),
53 }
54 }
55}
56
57impl StereoPannerNodeMethods<crate::DomTypeHolder> for StereoPannerNode {
58 fn Constructor(
60 cx: &mut JSContext,
61 window: &Window,
62 proto: Option<HandleObject>,
63 context: &BaseAudioContext,
64 options: &StereoPannerOptions,
65 ) -> Fallible<DomRoot<StereoPannerNode>> {
66 let node_options = options.parent.unwrap_or(
67 2,
68 ChannelCountMode::Clamped_max,
69 ChannelInterpretation::Speakers,
70 );
71 if AudioNode::channel_count_check(node_options.count) {
72 return Err(Error::NotSupported(Some(String::from(
73 "Channel count not supported",
74 ))));
75 }
76 if node_options.mode == ChannelCountMode::Max {
77 return Err(Error::NotSupported(Some(
78 "Channel count mode cannot be \"max\"".into(),
79 )));
80 }
81 if node_options.count > 2 || node_options.count == 0 {
82 return Err(Error::NotSupported(Some(
83 "Channel count must be 1 or 2".into(),
84 )));
85 }
86 let pan = *options.pan;
87 let audio_node_init = AudioNodeInit::StereoPannerNode(options.convert());
88 let node_id =
89 AudioNode::generate_audio_node_id(cx, &node_options, audio_node_init, context);
90 let pan = AudioParam::new(
92 cx,
93 window,
94 context,
95 node_id,
96 AudioNodeType::StereoPannerNode,
97 ParamType::Pan,
98 AutomationRate::A_rate,
99 pan,
100 -1.,
101 1.,
102 );
103 Ok(reflect_dom_object_with_proto(
104 cx,
105 Box::new(StereoPannerNode::new_inherited(
106 node_id,
107 context,
108 node_options,
109 &pan,
110 )),
111 window,
112 proto,
113 ))
114 }
115
116 fn Pan(&self) -> DomRoot<AudioParam> {
118 DomRoot::from_ref(&self.pan)
119 }
120}
121
122impl Convert<ServoMediaStereoPannerOptions> for StereoPannerOptions {
123 fn convert(self) -> ServoMediaStereoPannerOptions {
124 ServoMediaStereoPannerOptions { pan: *self.pan }
125 }
126}