149 lines
5.4 KiB
Rust
149 lines
5.4 KiB
Rust
|
use anyhow::{Context, Result};
|
||
|
|
||
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||
|
use cpal::{FromSample, Sample, SampleFormat};
|
||
|
|
||
|
use dasp_signal::Signal;
|
||
|
|
||
|
use tracing::{error, info, trace, warn};
|
||
|
|
||
|
use tokio::sync::mpsc::Receiver;
|
||
|
|
||
|
use crate::task_msg::{PcmFrameMessage, PcmSampleMessage};
|
||
|
|
||
|
pub fn audio_transmitter_main(
|
||
|
mut rx_for_wire: Receiver<PcmSampleMessage>,
|
||
|
cpal_output: cpal::Device,
|
||
|
) -> Result<()> {
|
||
|
trace!("audio_transmitter started");
|
||
|
let cpal_output_config = cpal_output.supported_output_configs()
|
||
|
.context("could not find a suitable audio output configuration. are you root, trying to use a normal user's audio stack? try setting the capability CAP_NET_ADMIN=ep on this binary, and running as the user who is running the audio stack.")?
|
||
|
.max_by_key(|cfg| {
|
||
|
match cfg.sample_format() {
|
||
|
SampleFormat::U8 => 10,
|
||
|
SampleFormat::I8 => 11,
|
||
|
SampleFormat::U16 => 20,
|
||
|
SampleFormat::I16 => 21,
|
||
|
SampleFormat::U32 => 30,
|
||
|
SampleFormat::I32 => 31,
|
||
|
SampleFormat::F32 => 40,
|
||
|
SampleFormat::F64 => 50,
|
||
|
SampleFormat::U64 => 60,
|
||
|
SampleFormat::I64 => 61,
|
||
|
x => { warn!("Backend offered unknown sample format {x}",); -999 }
|
||
|
}
|
||
|
}).expect("output device has no supported configurations available")
|
||
|
.with_max_sample_rate();
|
||
|
|
||
|
info!(
|
||
|
"output samples are {} @ {}hz",
|
||
|
&cpal_output_config.sample_format(),
|
||
|
&cpal_output_config.sample_rate().0,
|
||
|
);
|
||
|
|
||
|
let failed_pcm_give = move |e| {
|
||
|
warn!("dropped some PCM data on output stream?! {}", e);
|
||
|
};
|
||
|
|
||
|
let mut i = 0f64;
|
||
|
|
||
|
let output_stream = match cpal_output_config.sample_format() {
|
||
|
cpal::SampleFormat::U8 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<u8>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::I8 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<i8>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::I16 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<i16>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::I32 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<i32>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::F32 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<f32>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::F64 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<f64>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::U64 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<u64>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
cpal::SampleFormat::I64 => cpal_output
|
||
|
.build_output_stream(
|
||
|
&cpal_output_config.into(),
|
||
|
move |pcm, _: &_| give_output_pcm::<i64>(pcm, &mut rx_for_wire, &mut i),
|
||
|
failed_pcm_give,
|
||
|
None,
|
||
|
)
|
||
|
.context("failed to build output stream")?,
|
||
|
sample_format => Err(anyhow::Error::msg(format!(
|
||
|
"unsupported sample format '{}'! please ask developers to add it",
|
||
|
sample_format
|
||
|
)))?,
|
||
|
};
|
||
|
|
||
|
output_stream
|
||
|
.play()
|
||
|
.context("failed to start ingive audio stream")?;
|
||
|
|
||
|
loop{}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
fn give_output_pcm<T>(pcm: &mut [T], channel: &mut Receiver<PcmSampleMessage>, i: &mut f64)
|
||
|
where
|
||
|
T: Sample + std::fmt::Debug + FromSample<i64> + FromSample<f64>,
|
||
|
{
|
||
|
println!("wanted {} samples", pcm.len());
|
||
|
let mut signal = dasp_signal::rate(384000.0).const_hz(100.0).sine();
|
||
|
for outgoing in pcm.iter_mut() {
|
||
|
*outgoing = match channel.try_recv() {
|
||
|
Ok(sample) => sample.to_sample::<T>(),
|
||
|
//Err(_) => (std::f64::consts::PI * 2.0*(*i)/(384000.0/100.0)).sin().to_sample::<T>(), //T::EQUILIBRIUM,
|
||
|
Err(_) => {
|
||
|
signal.next().to_sample::<T>()
|
||
|
}
|
||
|
};
|
||
|
*i = *i % 384000.0 + 1.0;
|
||
|
//if *i > 200000.0 { break; }
|
||
|
}
|
||
|
//let mut ctr = 0usize;
|
||
|
}
|