use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use std::{error::Error, sync::Arc};
pub struct AudioPlayback {
pub config: cpal::StreamConfig, pub device: cpal::Device, }
impl std::fmt::Debug for AudioPlayback {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioPlayback")
.field("device", &self.device.name().unwrap_or_default())
.field("config", &self.config)
.finish()
}
}
impl AudioPlayback {
pub fn new() -> Result<Self, Box<dyn Error>> {
let host = cpal::default_host();
let device = host
.default_output_device()
.ok_or("No default output device available")?;
Self::new_with_device(device)
}
pub fn new_with_device(device: cpal::Device) -> Result<Self, Box<dyn Error>> {
let config = device.default_output_config()?.config();
Ok(Self { device, config })
}
pub fn transmit_with_volume(
&self,
samples: &[f32],
volume: f32,
) -> Result<cpal::Stream, Box<dyn Error>> {
let channels = self.config.channels as usize;
let samples_arc = Arc::new(samples.to_vec());
self.build_output_stream(samples_arc, channels, volume)
}
pub fn transmit(
&self,
config: &cpal::StreamConfig,
samples: &[f32],
) -> Result<cpal::Stream, Box<dyn Error>> {
let channels = config.channels as usize;
let samples_arc = Arc::new(samples.to_vec());
let mut sample_clock = 0;
let stream = self.device.build_output_stream(
config, move |data: &mut [f32], _: &_| {
for frame in data.chunks_mut(channels) {
let sample_value = *samples_arc.get(sample_clock).unwrap_or(&0.0);
for sample in frame.iter_mut() {
*sample = sample_value;
}
sample_clock += 1;
}
},
|err| eprintln!("Error in output stream: {}", err),
None,
)?;
Ok(stream)
}
fn build_output_stream(
&self,
samples: Arc<Vec<f32>>,
channels: usize,
volume: f32,
) -> Result<cpal::Stream, Box<dyn Error>> {
let mut sample_clock = 0;
let stream = self.device.build_output_stream(
&self.config,
move |data: &mut [f32], _: &_| {
for frame in data.chunks_mut(channels) {
let sample_value = if sample_clock < samples.len() {
samples[sample_clock] * volume } else {
0.0 };
for sample in frame.iter_mut() {
*sample = sample_value;
}
sample_clock += 1;
}
},
|err| eprintln!("Error in output stream: {}", err),
None,
)?;
Ok(stream)
}
}