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