use std::error::Error;
use crate::buffer::AudioBuffer;
use crate::context::{AudioContextRegistration, BaseAudioContext};
use crate::render::{
AudioParamValues, AudioProcessor, AudioRenderQuantum, AudioWorkletGlobalScope,
};
use super::{AudioNode, AudioNodeOptions, ChannelConfig};
use crate::media_streams::{MediaStream, MediaStreamTrack};
use crossbeam_channel::{self, Receiver, Sender};
#[derive(Debug)]
pub struct MediaStreamAudioDestinationNode {
registration: AudioContextRegistration,
channel_config: ChannelConfig,
stream: MediaStream,
}
impl AudioNode for MediaStreamAudioDestinationNode {
fn registration(&self) -> &AudioContextRegistration {
&self.registration
}
fn channel_config(&self) -> &ChannelConfig {
&self.channel_config
}
fn number_of_inputs(&self) -> usize {
1
}
fn number_of_outputs(&self) -> usize {
0
}
}
impl MediaStreamAudioDestinationNode {
pub fn new<C: BaseAudioContext>(context: &C, options: AudioNodeOptions) -> Self {
context.base().register(move |registration| {
let (send, recv) = crossbeam_channel::bounded(1);
let iter = AudioDestinationNodeStream {
receiver: recv.clone(),
};
let track = MediaStreamTrack::from_iter(iter);
let stream = MediaStream::from_tracks(vec![track]);
let node = MediaStreamAudioDestinationNode {
registration,
channel_config: options.into(),
stream,
};
let render = DestinationRenderer { send, recv };
(node, Box::new(render))
})
}
pub fn stream(&self) -> &MediaStream {
&self.stream
}
}
struct DestinationRenderer {
send: Sender<AudioBuffer>,
recv: Receiver<AudioBuffer>,
}
impl AudioProcessor for DestinationRenderer {
fn process(
&mut self,
inputs: &[AudioRenderQuantum],
_outputs: &mut [AudioRenderQuantum],
_params: AudioParamValues<'_>,
scope: &AudioWorkletGlobalScope,
) -> bool {
let input = &inputs[0];
let samples: Vec<_> = input.channels().iter().map(|c| c.to_vec()).collect();
let buffer = AudioBuffer::from(samples, scope.sample_rate);
if self.recv.try_recv().is_ok() {
log::warn!("MediaStreamDestination buffer dropped");
}
let _ = self.send.send(buffer);
false
}
}
struct AudioDestinationNodeStream {
receiver: Receiver<AudioBuffer>,
}
impl Iterator for AudioDestinationNodeStream {
type Item = Result<AudioBuffer, Box<dyn Error + Send + Sync>>;
fn next(&mut self) -> Option<Self::Item> {
match self.receiver.recv() {
Ok(buf) => Some(Ok(buf)),
Err(e) => Some(Err(Box::new(e))),
}
}
}