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_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, /* inputs */
61            1, /* outputs */
62        )?;
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    /// <https://webaudio.github.io/web-audio-api/#dom-stereopannernode-stereopannernode>
112    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    /// <https://webaudio.github.io/web-audio-api/#dom-stereopannernode-pan>
123    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}