web_audio_api/node/
media_stream_source.rs

1use crate::context::{AudioContextRegistration, BaseAudioContext};
2use crate::media_streams::MediaStream;
3use crate::resampling::Resampler;
4use crate::RENDER_QUANTUM_SIZE;
5
6use super::{AudioNode, ChannelConfig, MediaStreamRenderer};
7
8/// Options for constructing a [`MediaStreamAudioSourceNode`]
9// dictionary MediaStreamAudioSourceOptions {
10//   required MediaStream mediaStream;
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 MediaStreamAudioSourceOptions<'a> {
18    pub media_stream: &'a MediaStream,
19}
20
21/// An audio source from a [`MediaStream`] (e.g. microphone input)
22///
23/// IMPORTANT: the media stream is polled on the render thread so you must ensure the media stream
24/// iterator never blocks. Use a
25/// [`MediaElementAudioSourceNode`](crate::node::MediaElementAudioSourceNode) for real time safe
26/// media playback.
27#[derive(Debug)]
28pub struct MediaStreamAudioSourceNode {
29    registration: AudioContextRegistration,
30    channel_config: ChannelConfig,
31}
32
33impl AudioNode for MediaStreamAudioSourceNode {
34    fn registration(&self) -> &AudioContextRegistration {
35        &self.registration
36    }
37
38    fn channel_config(&self) -> &ChannelConfig {
39        &self.channel_config
40    }
41
42    fn number_of_inputs(&self) -> usize {
43        0
44    }
45
46    fn number_of_outputs(&self) -> usize {
47        1
48    }
49}
50
51impl MediaStreamAudioSourceNode {
52    /// Create a new `MediaStreamAudioSourceNode`
53    ///
54    /// # Panics
55    ///
56    /// This method will panic when the provided `MediaStream` does not contain any audio tracks.
57    pub fn new<C: BaseAudioContext>(
58        context: &C,
59        options: MediaStreamAudioSourceOptions<'_>,
60    ) -> Self {
61        context.base().register(move |registration| {
62            let node = MediaStreamAudioSourceNode {
63                registration,
64                channel_config: ChannelConfig::default(),
65            };
66
67            let resampler = Resampler::new(
68                context.sample_rate(),
69                RENDER_QUANTUM_SIZE,
70                options.media_stream.get_tracks()[0].iter(),
71            );
72
73            let render = MediaStreamRenderer::new(resampler);
74
75            (node, Box::new(render))
76        })
77    }
78}