Skip to main content

script/dom/audio/
stereopannernode.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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::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, /* inputs */
61            1, /* outputs */
62        )?;
63        let node_id = source_node.node().node_id();
64        // <https://webaudio.github.io/web-audio-api/#dom-stereopannernode-pan>
65        let pan = AudioParam::new(
66            cx,
67            window,
68            context,
69            node_id,
70            AudioNodeType::StereoPannerNode,
71            ParamType::Pan,
72            AutomationRate::A_rate,
73            pan,
74            -1.,
75            1.,
76        );
77
78        Ok(StereoPannerNode {
79            source_node,
80            pan: Dom::from_ref(&pan),
81        })
82    }
83
84    pub(crate) fn new(
85        cx: &mut JSContext,
86        window: &Window,
87        context: &BaseAudioContext,
88        options: &StereoPannerOptions,
89    ) -> Fallible<DomRoot<StereoPannerNode>> {
90        Self::new_with_proto(cx, window, None, context, options)
91    }
92
93    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
94    fn new_with_proto(
95        cx: &mut JSContext,
96        window: &Window,
97        proto: Option<HandleObject>,
98        context: &BaseAudioContext,
99        options: &StereoPannerOptions,
100    ) -> Fallible<DomRoot<StereoPannerNode>> {
101        let node = StereoPannerNode::new_inherited(cx, window, context, options)?;
102        Ok(reflect_dom_object_with_proto(
103            cx,
104            Box::new(node),
105            window,
106            proto,
107        ))
108    }
109}
110
111impl StereoPannerNodeMethods<crate::DomTypeHolder> for StereoPannerNode {
112    /// <https://webaudio.github.io/web-audio-api/#dom-stereopannernode-stereopannernode>
113    fn Constructor(
114        cx: &mut JSContext,
115        window: &Window,
116        proto: Option<HandleObject>,
117        context: &BaseAudioContext,
118        options: &StereoPannerOptions,
119    ) -> Fallible<DomRoot<StereoPannerNode>> {
120        StereoPannerNode::new_with_proto(cx, window, proto, context, options)
121    }
122
123    /// <https://webaudio.github.io/web-audio-api/#dom-stereopannernode-pan>
124    fn Pan(&self) -> DomRoot<AudioParam> {
125        DomRoot::from_ref(&self.pan)
126    }
127}
128
129impl Convert<ServoMediaStereoPannerOptions> for StereoPannerOptions {
130    fn convert(self) -> ServoMediaStereoPannerOptions {
131        ServoMediaStereoPannerOptions { pan: *self.pan }
132    }
133}