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_and_cx;
9use servo_media::audio::node::{AudioNodeInit, AudioNodeType};
10use servo_media::audio::param::ParamType;
11use servo_media::audio::stereo_panner::StereoPannerOptions as ServoMediaStereoPannerOptions;
12
13use crate::conversions::Convert;
14use crate::dom::audio::audionode::AudioNodeOptionsHelper;
15use crate::dom::audio::audioparam::AudioParam;
16use crate::dom::audio::audioscheduledsourcenode::AudioScheduledSourceNode;
17use crate::dom::audio::baseaudiocontext::BaseAudioContext;
18use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
19 ChannelCountMode, ChannelInterpretation,
20};
21use crate::dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
22use crate::dom::bindings::codegen::Bindings::StereoPannerNodeBinding::{
23 StereoPannerNodeMethods, StereoPannerOptions,
24};
25use crate::dom::bindings::error::{Error, Fallible};
26use crate::dom::bindings::root::{Dom, DomRoot};
27use crate::dom::window::Window;
28
29#[dom_struct]
30pub(crate) struct StereoPannerNode {
31 source_node: AudioScheduledSourceNode,
32 pan: Dom<AudioParam>,
33}
34
35impl StereoPannerNode {
36 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
37 pub(crate) fn new_inherited(
38 cx: &mut JSContext,
39 window: &Window,
40 context: &BaseAudioContext,
41 options: &StereoPannerOptions,
42 ) -> Fallible<StereoPannerNode> {
43 let node_options = options.parent.unwrap_or(
44 2,
45 ChannelCountMode::Clamped_max,
46 ChannelInterpretation::Speakers,
47 );
48 if node_options.mode == ChannelCountMode::Max {
49 return Err(Error::NotSupported(None));
50 }
51 if node_options.count > 2 || node_options.count == 0 {
52 return Err(Error::NotSupported(None));
53 }
54 let pan = *options.pan;
55 let source_node = AudioScheduledSourceNode::new_inherited(
56 cx,
57 AudioNodeInit::StereoPannerNode(options.convert()),
58 context,
59 node_options,
60 1, 1, )?;
63 let node_id = source_node.node().node_id();
64 let pan = AudioParam::new(
65 cx,
66 window,
67 context,
68 node_id,
69 AudioNodeType::StereoPannerNode,
70 ParamType::Pan,
71 AutomationRate::A_rate,
72 pan,
73 -1.,
74 1.,
75 );
76
77 Ok(StereoPannerNode {
78 source_node,
79 pan: Dom::from_ref(&pan),
80 })
81 }
82
83 pub(crate) fn new(
84 cx: &mut JSContext,
85 window: &Window,
86 context: &BaseAudioContext,
87 options: &StereoPannerOptions,
88 ) -> Fallible<DomRoot<StereoPannerNode>> {
89 Self::new_with_proto(cx, window, None, context, options)
90 }
91
92 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
93 fn new_with_proto(
94 cx: &mut JSContext,
95 window: &Window,
96 proto: Option<HandleObject>,
97 context: &BaseAudioContext,
98 options: &StereoPannerOptions,
99 ) -> Fallible<DomRoot<StereoPannerNode>> {
100 let node = StereoPannerNode::new_inherited(cx, window, context, options)?;
101 Ok(reflect_dom_object_with_proto_and_cx(
102 Box::new(node),
103 window,
104 proto,
105 cx,
106 ))
107 }
108}
109
110impl StereoPannerNodeMethods<crate::DomTypeHolder> for StereoPannerNode {
111 fn Constructor(
113 cx: &mut JSContext,
114 window: &Window,
115 proto: Option<HandleObject>,
116 context: &BaseAudioContext,
117 options: &StereoPannerOptions,
118 ) -> Fallible<DomRoot<StereoPannerNode>> {
119 StereoPannerNode::new_with_proto(cx, window, proto, context, options)
120 }
121
122 fn Pan(&self) -> DomRoot<AudioParam> {
124 DomRoot::from_ref(&self.pan)
125 }
126}
127
128impl Convert<ServoMediaStereoPannerOptions> for StereoPannerOptions {
129 fn convert(self) -> ServoMediaStereoPannerOptions {
130 ServoMediaStereoPannerOptions { pan: *self.pan }
131 }
132}