use {
crate::{GenericSample, OperationError, samples_to_f32},
cpal::{
BufferSize, Device, HostId, Stream, StreamConfig, SupportedStreamConfig, default_host,
traits::{DeviceTrait, HostTrait, StreamTrait},
},
rodio::{ChannelCount, SampleRate, buffer::SamplesBuffer, source::UniformSourceIterator},
std::{
fmt::{Debug, Error as FmtError, Formatter, Result as FmtResult},
io::Error as IoError,
mem::replace,
},
tokio::sync::mpsc::{Sender, channel},
};
pub struct AudioPlayer {
device: Device,
host_id: HostId,
stream_config: StreamConfig,
supported_stream_config: SupportedStreamConfig,
stream: Stream,
sender: Sender<f32>,
}
impl AudioPlayer {
fn create_stream(
device: &Device,
stream_config: &StreamConfig,
) -> Result<(Sender<f32>, Stream), OperationError> {
let buffer_size = match stream_config.buffer_size {
BufferSize::Default => 8192,
BufferSize::Fixed(size) => size as _,
};
let (tx, mut rx) = channel(buffer_size);
Ok((
tx,
device.build_output_stream(
stream_config,
move |buffer: &mut [f32], _| {
buffer
.iter_mut()
.for_each(|i| *i = rx.try_recv().unwrap_or_default())
},
|e| eprintln!("{}", e),
None,
)?,
))
}
fn update_stream(&mut self) -> Result<(), OperationError> {
let (sender, stream) = Self::create_stream(&self.device, &self.stream_config)?;
drop(replace(&mut self.stream, stream));
drop(replace(&mut self.sender, sender));
Ok(())
}
pub fn new() -> Result<Self, OperationError> {
let host = default_host();
let device = host
.default_output_device()
.ok_or(OperationError::NoDevice(
"No default audio output device.".to_owned(),
))?;
let host_id = host.id();
let supported_stream_config = device.default_output_config()?;
let stream_config = supported_stream_config.config();
let (sender, stream) = Self::create_stream(&device, &stream_config)?;
Ok(Self {
device,
host_id,
stream_config,
supported_stream_config,
stream,
sender,
})
}
pub fn get_name(&self) -> Result<String, OperationError> {
Ok(self.device.description()?.name().to_owned())
}
pub fn get_supported_stream_channels(&self) -> usize {
self.supported_stream_config.channels() as _
}
pub fn get_supported_stream_sample_rate(&self) -> usize {
self.supported_stream_config.sample_rate() as _
}
pub fn set_stream_channels(&mut self, channels: usize) -> Result<(), OperationError> {
self.stream_config.channels = channels as _;
self.update_stream()
}
pub fn set_stream_sample_rate(&mut self, sample_rate: usize) -> Result<(), OperationError> {
self.stream_config.sample_rate = sample_rate as _;
self.update_stream()
}
pub fn get_stream_channels(&self) -> usize {
self.stream_config.channels as _
}
pub fn get_stream_sample_rate(&self) -> usize {
self.stream_config.sample_rate as _
}
pub fn play(&self) -> Result<(), OperationError> {
Ok(self.stream.play()?)
}
pub fn pause(&self) -> Result<(), OperationError> {
Ok(self.stream.pause()?)
}
pub async fn write<const SR: usize, S>(
&mut self,
samples: &[S],
channels: usize,
) -> Result<(), OperationError>
where
S: GenericSample,
{
if self.get_stream_channels() != channels || self.get_stream_sample_rate() != SR {
let f32_samples = samples_to_f32(samples);
let iter = UniformSourceIterator::new(
SamplesBuffer::new(
ChannelCount::new(channels as _)
.ok_or(IoError::other("invalid channel count"))?,
SampleRate::new(SR as _).ok_or(IoError::other("invalid sample rate"))?,
f32_samples,
),
ChannelCount::new(self.stream_config.channels)
.ok_or(IoError::other("invalid channel count"))?,
SampleRate::new(self.stream_config.sample_rate)
.ok_or(IoError::other("invalid sample rate"))?,
);
for i in iter {
self.sender.send(i).await?;
}
return Ok(());
}
for s in samples {
self.sender.send(s.to_f32()).await?;
}
Ok(())
}
}
impl Debug for AudioPlayer {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(
f,
"AudioPlayer({}, {})",
self.host_id.name(),
self.get_name().map_err(|_| FmtError)?
)
}
}