servo/components/script/dom/audioscheduledsourcenode.rs
Martin Robinson 77cfca65c4
script: Eliminate code duplication in the task queue (#34798)
Instead of creating a type for each `TaskSource` variety have each `TaskSource`
hold the same kind of sender (this was inconsistent before, but each
sender was effectively the same trait object), a pipeline, and a
`TaskSourceName`. This elminates the need to reimplement the same
queuing code for every task source.

In addition, have workers hold their own `TaskManager`. This allows just
exposing the manager on the `GlobalScope`. Currently the `TaskCanceller`
is different, but this will also be eliminated in a followup change.

This is a the first step toward having a shared set of `Sender`s on
`GlobalScope`.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-01-01 13:50:52 +00:00

124 lines
4.1 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::Cell;
use dom_struct::dom_struct;
use servo_media::audio::node::{
AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage, OnEndedCallback,
};
use crate::dom::audionode::{AudioNode, UnwrappedAudioNodeOptions};
use crate::dom::baseaudiocontext::BaseAudioContext;
use crate::dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject;
#[dom_struct]
pub struct AudioScheduledSourceNode {
node: AudioNode,
has_start: Cell<bool>,
has_stop: Cell<bool>,
}
impl AudioScheduledSourceNode {
#[allow(crown::unrooted_must_root)]
pub fn new_inherited(
node_type: AudioNodeInit,
context: &BaseAudioContext,
options: UnwrappedAudioNodeOptions,
number_of_inputs: u32,
number_of_outputs: u32,
) -> Fallible<AudioScheduledSourceNode> {
Ok(AudioScheduledSourceNode {
node: AudioNode::new_inherited(
node_type,
context,
options,
number_of_inputs,
number_of_outputs,
)?,
has_start: Cell::new(false),
has_stop: Cell::new(false),
})
}
pub fn node(&self) -> &AudioNode {
&self.node
}
pub fn has_start(&self) -> bool {
self.has_start.get()
}
}
impl AudioScheduledSourceNodeMethods<crate::DomTypeHolder> for AudioScheduledSourceNode {
// https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-onended
event_handler!(ended, GetOnended, SetOnended);
// https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start
fn Start(&self, when: Finite<f64>) -> Fallible<()> {
if *when < 0. {
return Err(Error::Range("'when' must be a positive value".to_owned()));
}
if self.has_start.get() || self.has_stop.get() {
return Err(Error::InvalidState);
}
let this = Trusted::new(self);
let global = self.global();
let window = global.as_window();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let callback = OnEndedCallback::new(move || {
let _ = task_source.queue_with_canceller(
task!(ended: move || {
let this = this.root();
let global = this.global();
let window = global.as_window();
window.task_manager().dom_manipulation_task_source().queue_simple_event(
this.upcast(),
atom!("ended"),
window
);
}),
&canceller,
);
});
self.node()
.message(AudioNodeMessage::AudioScheduledSourceNode(
AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback),
));
self.has_start.set(true);
self.node
.message(AudioNodeMessage::AudioScheduledSourceNode(
AudioScheduledSourceNodeMessage::Start(*when),
));
Ok(())
}
// https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop
fn Stop(&self, when: Finite<f64>) -> Fallible<()> {
if *when < 0. {
return Err(Error::Range("'when' must be a positive value".to_owned()));
}
if !self.has_start.get() {
return Err(Error::InvalidState);
}
self.has_stop.set(true);
self.node
.message(AudioNodeMessage::AudioScheduledSourceNode(
AudioScheduledSourceNodeMessage::Stop(*when),
));
Ok(())
}
}