1use std::cell::Cell;
6use std::f32;
7
8use dom_struct::dom_struct;
9use js::rust::HandleObject;
10use servo_media::audio::buffer_source_node::{
11 AudioBufferSourceNodeMessage, AudioBufferSourceNodeOptions,
12};
13use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioNodeType};
14use servo_media::audio::param::ParamType;
15
16use crate::conversions::Convert;
17use crate::dom::audio::audiobuffer::AudioBuffer;
18use crate::dom::audio::audioparam::AudioParam;
19use crate::dom::audio::audioscheduledsourcenode::AudioScheduledSourceNode;
20use crate::dom::audio::baseaudiocontext::BaseAudioContext;
21use crate::dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::{
22 AudioBufferSourceNodeMethods, AudioBufferSourceOptions,
23};
24use crate::dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
25use crate::dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
26use crate::dom::bindings::error::{Error, Fallible};
27use crate::dom::bindings::inheritance::Castable;
28use crate::dom::bindings::num::Finite;
29use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
30use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
31use crate::dom::window::Window;
32use crate::script_runtime::CanGc;
33
34#[dom_struct]
35pub(crate) struct AudioBufferSourceNode {
36 source_node: AudioScheduledSourceNode,
37 buffer: MutNullableDom<AudioBuffer>,
38 buffer_set: Cell<bool>,
39 playback_rate: Dom<AudioParam>,
40 detune: Dom<AudioParam>,
41 loop_enabled: Cell<bool>,
42 loop_start: Cell<f64>,
43 loop_end: Cell<f64>,
44}
45
46impl AudioBufferSourceNode {
47 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
48 fn new_inherited(
49 window: &Window,
50 context: &BaseAudioContext,
51 options: &AudioBufferSourceOptions,
52 can_gc: CanGc,
53 ) -> Fallible<AudioBufferSourceNode> {
54 let node_options = Default::default();
55 let source_node = AudioScheduledSourceNode::new_inherited(
56 AudioNodeInit::AudioBufferSourceNode(options.convert()),
57 context,
58 node_options,
59 0, 1, )?;
62 let node_id = source_node.node().node_id();
63 let playback_rate = AudioParam::new(
64 window,
65 context,
66 node_id,
67 AudioNodeType::AudioBufferSourceNode,
68 ParamType::PlaybackRate,
69 AutomationRate::K_rate,
70 *options.playbackRate,
71 f32::MIN,
72 f32::MAX,
73 can_gc,
74 );
75 let detune = AudioParam::new(
76 window,
77 context,
78 node_id,
79 AudioNodeType::AudioBufferSourceNode,
80 ParamType::Detune,
81 AutomationRate::K_rate,
82 *options.detune,
83 f32::MIN,
84 f32::MAX,
85 can_gc,
86 );
87 let node = AudioBufferSourceNode {
88 source_node,
89 buffer: Default::default(),
90 buffer_set: Cell::new(false),
91 playback_rate: Dom::from_ref(&playback_rate),
92 detune: Dom::from_ref(&detune),
93 loop_enabled: Cell::new(options.loop_),
94 loop_start: Cell::new(*options.loopStart),
95 loop_end: Cell::new(*options.loopEnd),
96 };
97 if let Some(Some(ref buffer)) = options.buffer {
98 node.SetBuffer(Some(buffer))?;
99 }
100 Ok(node)
101 }
102
103 pub(crate) fn new(
104 window: &Window,
105 context: &BaseAudioContext,
106 options: &AudioBufferSourceOptions,
107 can_gc: CanGc,
108 ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
109 Self::new_with_proto(window, None, context, options, can_gc)
110 }
111
112 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
113 fn new_with_proto(
114 window: &Window,
115 proto: Option<HandleObject>,
116 context: &BaseAudioContext,
117 options: &AudioBufferSourceOptions,
118 can_gc: CanGc,
119 ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
120 let node = AudioBufferSourceNode::new_inherited(window, context, options, can_gc)?;
121 Ok(reflect_dom_object_with_proto(
122 Box::new(node),
123 window,
124 proto,
125 can_gc,
126 ))
127 }
128}
129
130impl AudioBufferSourceNodeMethods<crate::DomTypeHolder> for AudioBufferSourceNode {
131 fn Constructor(
133 window: &Window,
134 proto: Option<HandleObject>,
135 can_gc: CanGc,
136 context: &BaseAudioContext,
137 options: &AudioBufferSourceOptions,
138 ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
139 AudioBufferSourceNode::new_with_proto(window, proto, context, options, can_gc)
140 }
141
142 fn GetBuffer(&self) -> Fallible<Option<DomRoot<AudioBuffer>>> {
144 Ok(self.buffer.get())
145 }
146
147 fn SetBuffer(&self, new_buffer: Option<&AudioBuffer>) -> Fallible<()> {
149 if new_buffer.is_some() {
150 if self.buffer_set.get() {
151 return Err(Error::InvalidState);
153 }
154 self.buffer_set.set(true);
156 }
157
158 self.buffer.set(new_buffer);
160
161 if self.source_node.has_start() {
163 if let Some(buffer) = self.buffer.get() {
164 let buffer = buffer.get_channels();
165 if buffer.is_some() {
166 self.source_node
167 .node()
168 .message(AudioNodeMessage::AudioBufferSourceNode(
169 AudioBufferSourceNodeMessage::SetBuffer((*buffer).clone()),
170 ));
171 }
172 }
173 }
174
175 Ok(())
176 }
177
178 fn PlaybackRate(&self) -> DomRoot<AudioParam> {
180 DomRoot::from_ref(&self.playback_rate)
181 }
182
183 fn Detune(&self) -> DomRoot<AudioParam> {
185 DomRoot::from_ref(&self.detune)
186 }
187
188 fn Loop(&self) -> bool {
190 self.loop_enabled.get()
191 }
192
193 fn SetLoop(&self, should_loop: bool) {
195 self.loop_enabled.set(should_loop);
196 let msg = AudioNodeMessage::AudioBufferSourceNode(
197 AudioBufferSourceNodeMessage::SetLoopEnabled(should_loop),
198 );
199 self.source_node.node().message(msg);
200 }
201
202 fn LoopStart(&self) -> Finite<f64> {
204 Finite::wrap(self.loop_start.get())
205 }
206
207 fn SetLoopStart(&self, loop_start: Finite<f64>) {
209 self.loop_start.set(*loop_start);
210 let msg = AudioNodeMessage::AudioBufferSourceNode(
211 AudioBufferSourceNodeMessage::SetLoopStart(*loop_start),
212 );
213 self.source_node.node().message(msg);
214 }
215
216 fn LoopEnd(&self) -> Finite<f64> {
218 Finite::wrap(self.loop_end.get())
219 }
220
221 fn SetLoopEnd(&self, loop_end: Finite<f64>) {
223 self.loop_end.set(*loop_end);
224 let msg = AudioNodeMessage::AudioBufferSourceNode(
225 AudioBufferSourceNodeMessage::SetLoopEnd(*loop_end),
226 );
227 self.source_node.node().message(msg);
228 }
229
230 fn Start(
232 &self,
233 when: Finite<f64>,
234 offset: Option<Finite<f64>>,
235 duration: Option<Finite<f64>>,
236 ) -> Fallible<()> {
237 if let Some(offset) = offset {
238 if *offset < 0. {
239 return Err(Error::Range("'offset' must be a positive value".to_owned()));
240 }
241 }
242
243 if let Some(duration) = duration {
244 if *duration < 0. {
245 return Err(Error::Range(
246 "'duration' must be a positive value".to_owned(),
247 ));
248 }
249 }
250
251 if let Some(buffer) = self.buffer.get() {
252 let buffer = buffer.get_channels();
253 if buffer.is_some() {
254 self.source_node
255 .node()
256 .message(AudioNodeMessage::AudioBufferSourceNode(
257 AudioBufferSourceNodeMessage::SetBuffer((*buffer).clone()),
258 ));
259 }
260 }
261
262 self.source_node
263 .node()
264 .message(AudioNodeMessage::AudioBufferSourceNode(
265 AudioBufferSourceNodeMessage::SetStartParams(
266 *when,
267 offset.map(|f| *f),
268 duration.map(|f| *f),
269 ),
270 ));
271
272 self.source_node
273 .upcast::<AudioScheduledSourceNode>()
274 .Start(when)
275 }
276}
277
278impl Convert<AudioBufferSourceNodeOptions> for &AudioBufferSourceOptions {
279 fn convert(self) -> AudioBufferSourceNodeOptions {
280 AudioBufferSourceNodeOptions {
281 buffer: self
282 .buffer
283 .as_ref()
284 .and_then(|b| (*b.as_ref()?.get_channels()).clone()),
285 detune: *self.detune,
286 loop_enabled: self.loop_,
287 loop_end: Some(*self.loopEnd),
288 loop_start: Some(*self.loopStart),
289 playback_rate: *self.playbackRate,
290 }
291 }
292}