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}