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