script/dom/audio/
audioscheduledsourcenode.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use servo_media::audio::audio_node::{
9 AudioNodeMessage, AudioScheduledSourceNodeMessage, OnEndedCallback,
10};
11use servo_media::audio::graph::NodeId;
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 pub(crate) fn new_inherited(
31 node_id: Option<NodeId>,
32 context: &BaseAudioContext,
33 options: UnwrappedAudioNodeOptions,
34 number_of_inputs: u32,
35 number_of_outputs: u32,
36 ) -> AudioScheduledSourceNode {
37 AudioScheduledSourceNode {
38 node: AudioNode::new_inherited(
39 node_id,
40 context,
41 options,
42 number_of_inputs,
43 number_of_outputs,
44 ),
45 has_start: Cell::new(false),
46 has_stop: Cell::new(false),
47 }
48 }
49
50 pub(crate) fn node(&self) -> &AudioNode {
51 &self.node
52 }
53
54 pub(crate) fn has_start(&self) -> bool {
55 self.has_start.get()
56 }
57}
58
59impl AudioScheduledSourceNodeMethods<crate::DomTypeHolder> for AudioScheduledSourceNode {
60 event_handler!(ended, GetOnended, SetOnended);
62
63 fn Start(&self, when: Finite<f64>) -> Fallible<()> {
65 if *when < 0. {
66 return Err(Error::Range(c"'when' must be a positive value".to_owned()));
67 }
68
69 if self.has_start.get() || self.has_stop.get() {
70 return Err(Error::InvalidState(Some(
71 "Node has already been started".into(),
72 )));
73 }
74
75 let this = Trusted::new(self);
76 let task_source = self
77 .global()
78 .task_manager()
79 .dom_manipulation_task_source()
80 .to_sendable();
81 let callback = OnEndedCallback::new(move || {
82 task_source.queue(task!(ended: move || {
83 let this = this.root();
84 this.global().task_manager().dom_manipulation_task_source().queue_simple_event(
85 this.upcast(),
86 atom!("ended"),
87 );
88 }));
89 });
90
91 self.node()
92 .message(AudioNodeMessage::AudioScheduledSourceNode(
93 AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback),
94 ));
95
96 self.has_start.set(true);
97 self.node
98 .message(AudioNodeMessage::AudioScheduledSourceNode(
99 AudioScheduledSourceNodeMessage::Start(*when),
100 ));
101 Ok(())
102 }
103
104 fn Stop(&self, when: Finite<f64>) -> Fallible<()> {
106 if *when < 0. {
107 return Err(Error::Range(c"'when' must be a positive value".to_owned()));
108 }
109
110 if !self.has_start.get() {
111 return Err(Error::InvalidState(Some(
112 "Cannot stop a node that has not been started".into(),
113 )));
114 }
115 self.has_stop.set(true);
116 self.node
117 .message(AudioNodeMessage::AudioScheduledSourceNode(
118 AudioScheduledSourceNodeMessage::Stop(*when),
119 ));
120 Ok(())
121 }
122}