script/dom/audio/
audioscheduledsourcenode.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use servo_media::audio::node::{
10 AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage, OnEndedCallback,
11};
12
13use crate::dom::audio::audionode::{AudioNode, UnwrappedAudioNodeOptions};
14use crate::dom::audio::baseaudiocontext::BaseAudioContext;
15use crate::dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
16use crate::dom::bindings::error::{Error, Fallible};
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::num::Finite;
19use crate::dom::bindings::refcounted::Trusted;
20use crate::dom::bindings::reflector::DomGlobal;
21
22#[dom_struct]
23pub(crate) struct AudioScheduledSourceNode {
24 node: AudioNode,
25 has_start: Cell<bool>,
26 has_stop: Cell<bool>,
27}
28
29impl AudioScheduledSourceNode {
30 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
31 pub(crate) fn new_inherited(
32 cx: &mut JSContext,
33 node_type: AudioNodeInit,
34 context: &BaseAudioContext,
35 options: UnwrappedAudioNodeOptions,
36 number_of_inputs: u32,
37 number_of_outputs: u32,
38 ) -> Fallible<AudioScheduledSourceNode> {
39 Ok(AudioScheduledSourceNode {
40 node: AudioNode::new_inherited(
41 cx,
42 node_type,
43 context,
44 options,
45 number_of_inputs,
46 number_of_outputs,
47 )?,
48 has_start: Cell::new(false),
49 has_stop: Cell::new(false),
50 })
51 }
52
53 pub(crate) fn node(&self) -> &AudioNode {
54 &self.node
55 }
56
57 pub(crate) fn has_start(&self) -> bool {
58 self.has_start.get()
59 }
60}
61
62impl AudioScheduledSourceNodeMethods<crate::DomTypeHolder> for AudioScheduledSourceNode {
63 event_handler!(ended, GetOnended, SetOnended);
65
66 fn Start(&self, when: Finite<f64>) -> Fallible<()> {
68 if *when < 0. {
69 return Err(Error::Range(c"'when' must be a positive value".to_owned()));
70 }
71
72 if self.has_start.get() || self.has_stop.get() {
73 return Err(Error::InvalidState(None));
74 }
75
76 let this = Trusted::new(self);
77 let task_source = self
78 .global()
79 .task_manager()
80 .dom_manipulation_task_source()
81 .to_sendable();
82 let callback = OnEndedCallback::new(move || {
83 task_source.queue(task!(ended: move || {
84 let this = this.root();
85 this.global().task_manager().dom_manipulation_task_source().queue_simple_event(
86 this.upcast(),
87 atom!("ended"),
88 );
89 }));
90 });
91
92 self.node()
93 .message(AudioNodeMessage::AudioScheduledSourceNode(
94 AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback),
95 ));
96
97 self.has_start.set(true);
98 self.node
99 .message(AudioNodeMessage::AudioScheduledSourceNode(
100 AudioScheduledSourceNodeMessage::Start(*when),
101 ));
102 Ok(())
103 }
104
105 fn Stop(&self, when: Finite<f64>) -> Fallible<()> {
107 if *when < 0. {
108 return Err(Error::Range(c"'when' must be a positive value".to_owned()));
109 }
110
111 if !self.has_start.get() {
112 return Err(Error::InvalidState(None));
113 }
114 self.has_stop.set(true);
115 self.node
116 .message(AudioNodeMessage::AudioScheduledSourceNode(
117 AudioScheduledSourceNodeMessage::Stop(*when),
118 ));
119 Ok(())
120 }
121}