web_audio_api/node/
media_element_source.rs

1use crate::context::{AudioContextRegistration, BaseAudioContext};
2use crate::resampling::Resampler;
3use crate::MediaElement;
4use crate::RENDER_QUANTUM_SIZE;
5
6use super::{AudioNode, ChannelConfig, MediaStreamRenderer};
7
8/// Options for constructing a [`MediaElementAudioSourceNode`]
9// dictionary MediaElementAudioSourceOptions {
10//     required HTMLMediaElement mediaElement;
11// };
12//
13// @note - Does not extend AudioNodeOptions because AudioNodeOptions are
14// useless for source nodes as they instruct how to upmix the inputs.
15// This is a common source of confusion, see e.g. https://github.com/mdn/content/pull/18472
16#[derive(Debug)]
17pub struct MediaElementAudioSourceOptions<'a> {
18    pub media_element: &'a mut MediaElement,
19}
20
21/// An audio source from an `<audio>` element
22///
23/// - MDN documentation:
24///   <https://developer.mozilla.org/en-US/docs/Web/API/MediaElementAudioSourceNode>
25/// - specification: <https://webaudio.github.io/web-audio-api/#MediaElementAudioSourceNode>
26/// - see also:
27///   [`AudioContext::create_media_element_source`](crate::context::AudioContext::create_media_element_source)
28///
29/// # Usage
30///
31/// ```no_run
32/// use web_audio_api::context::{AudioContext, BaseAudioContext};
33/// use web_audio_api::MediaElement;
34/// use web_audio_api::node::AudioNode;
35///
36/// let context = AudioContext::default();
37/// let mut media = MediaElement::new("samples/major-scale.ogg").unwrap();
38///
39/// let mut src = context.create_media_element_source(&mut media);
40/// src.connect(&context.destination());
41///
42/// media.set_loop(true); // continuously loop
43/// media.set_current_time(1.0); // seek to offset
44/// media.play(); // start playing
45///
46/// loop {}
47/// ```
48///
49/// # Examples
50///
51/// - `cargo run --release --example media_element`
52#[derive(Debug)]
53pub struct MediaElementAudioSourceNode {
54    registration: AudioContextRegistration,
55    channel_config: ChannelConfig,
56}
57
58impl AudioNode for MediaElementAudioSourceNode {
59    fn registration(&self) -> &AudioContextRegistration {
60        &self.registration
61    }
62
63    fn channel_config(&self) -> &ChannelConfig {
64        &self.channel_config
65    }
66
67    fn number_of_inputs(&self) -> usize {
68        0
69    }
70
71    fn number_of_outputs(&self) -> usize {
72        1
73    }
74}
75
76impl MediaElementAudioSourceNode {
77    /// Create a new `MediaElementAudioSourceNode`
78    ///
79    /// # Panics
80    ///
81    /// This method will panic when there already exists a source node for the given
82    /// `MediaElement`. You can only set up a single source node per element!
83    pub fn new<C: BaseAudioContext>(
84        context: &C,
85        options: MediaElementAudioSourceOptions<'_>,
86    ) -> Self {
87        context.base().register(move |registration| {
88            let node = MediaElementAudioSourceNode {
89                registration,
90                channel_config: ChannelConfig::default(),
91            };
92
93            let stream = options
94                .media_element
95                .take_stream()
96                .expect("InvalidStateError - stream already taken");
97
98            let resampler = Resampler::new(context.sample_rate(), RENDER_QUANTUM_SIZE, stream);
99
100            let render = MediaStreamRenderer::new(resampler);
101
102            (node, Box::new(render))
103        })
104    }
105}