X-Git-Url: https://code.octet-stream.net/m17rt/blobdiff_plain/bc4b6ea4290384cd8c380af2a9014f162fd43683..bc6fb90d7053082e7aaf261f4da8905c49e9fe01:/m17app/src/soundmodem.rs diff --git a/m17app/src/soundmodem.rs b/m17app/src/soundmodem.rs index dced157..974fd45 100644 --- a/m17app/src/soundmodem.rs +++ b/m17app/src/soundmodem.rs @@ -1,8 +1,4 @@ use crate::tnc::{Tnc, TncError}; -use cpal::traits::DeviceTrait; -use cpal::traits::HostTrait; -use cpal::traits::StreamTrait; -use cpal::{SampleFormat, SampleRate}; use log::debug; use m17core::kiss::MAX_FRAME_LEN; use m17core::modem::{Demodulator, Modulator, ModulatorAction, SoftDemodulator, SoftModulator}; @@ -239,72 +235,6 @@ pub trait InputSource: Send + Sync + 'static { fn close(&self); } -pub struct InputSoundcard { - // TODO: allow for inversion both here and in output - cpal_name: Option, - end_tx: Mutex>>, -} - -impl InputSoundcard { - pub fn new() -> Self { - Self { - cpal_name: None, - end_tx: Mutex::new(None), - } - } - - pub fn new_with_card(card_name: String) -> Self { - Self { - cpal_name: Some(card_name), - end_tx: Mutex::new(None), - } - } -} - -impl InputSource for InputSoundcard { - fn start(&self, samples: SyncSender) { - let (end_tx, end_rx) = channel(); - let cpal_name = self.cpal_name.clone(); - std::thread::spawn(move || { - let host = cpal::default_host(); - let device = if let Some(name) = cpal_name.as_deref() { - host.input_devices() - .unwrap() - .find(|d| d.name().unwrap() == name) - .unwrap() - } else { - host.default_input_device().unwrap() - }; - let mut configs = device.supported_input_configs().unwrap(); - let config = configs - .find(|c| c.channels() == 1 && c.sample_format() == SampleFormat::I16) - .unwrap() - .with_sample_rate(SampleRate(48000)); - let stream = device - .build_input_stream( - &config.into(), - move |data: &[i16], _info: &cpal::InputCallbackInfo| { - let out: Vec = data.iter().map(|s| *s).collect(); - let _ = samples.try_send(SoundmodemEvent::BasebandInput(out.into())); - }, - |e| { - // TODO: abort? - debug!("error occurred in soundcard input: {e:?}"); - }, - None, - ) - .unwrap(); - stream.play().unwrap(); - let _ = end_rx.recv(); - }); - *self.end_tx.lock().unwrap() = Some(end_tx); - } - - fn close(&self) { - let _ = self.end_tx.lock().unwrap().take(); - } -} - pub struct InputRrcFile { path: PathBuf, end_tx: Mutex>>, @@ -347,7 +277,7 @@ impl InputSource for InputRrcFile { if let Err(e) = samples.try_send(SoundmodemEvent::BasebandInput(buf.into())) { debug!("overflow feeding soundmodem: {e:?}"); } - next_tick = next_tick + TICK; + next_tick += TICK; idx = 0; std::thread::sleep(next_tick.duration_since(Instant::now())); } @@ -387,7 +317,7 @@ impl InputSource for NullInputSource { loop { std::thread::sleep(next_tick.duration_since(Instant::now())); - next_tick = next_tick + TICK; + next_tick += TICK; if end_rx.try_recv() != Err(TryRecvError::Empty) { break; } @@ -406,11 +336,17 @@ impl InputSource for NullInputSource { } } +impl Default for NullInputSource { + fn default() -> Self { + Self::new() + } +} + pub struct OutputBuffer { - idling: bool, + pub idling: bool, // TODO: something more efficient - samples: VecDeque, - latency: Duration, + pub samples: VecDeque, + pub latency: Duration, } impl OutputBuffer { @@ -423,6 +359,12 @@ impl OutputBuffer { } } +impl Default for OutputBuffer { + fn default() -> Self { + Self::new() + } +} + pub trait OutputSink: Send + Sync + 'static { fn start(&self, event_tx: SyncSender, buffer: Arc>); fn close(&self); @@ -460,7 +402,7 @@ impl OutputSink for OutputRrcFile { loop { std::thread::sleep(next_tick.duration_since(Instant::now())); - next_tick = next_tick + TICK; + next_tick += TICK; if end_rx.try_recv() != Err(TryRecvError::Empty) { break; } @@ -510,6 +452,12 @@ impl NullOutputSink { } } +impl Default for NullOutputSink { + fn default() -> Self { + Self::new() + } +} + impl OutputSink for NullOutputSink { fn start(&self, event_tx: SyncSender, buffer: Arc>) { let (end_tx, end_rx) = channel(); @@ -521,7 +469,7 @@ impl OutputSink for NullOutputSink { loop { std::thread::sleep(next_tick.duration_since(Instant::now())); - next_tick = next_tick + TICK; + next_tick += TICK; if end_rx.try_recv() != Err(TryRecvError::Empty) { break; } @@ -529,7 +477,7 @@ impl OutputSink for NullOutputSink { let mut buffer = buffer.write().unwrap(); let mut taken = 0; for _ in 0..SAMPLES_PER_TICK { - if !buffer.samples.pop_front().is_some() { + if buffer.samples.pop_front().is_none() { if !buffer.idling { debug!("null output had underrun"); let _ = event_tx.send(SoundmodemEvent::OutputUnderrun); @@ -553,96 +501,6 @@ impl OutputSink for NullOutputSink { } } -pub struct OutputSoundcard { - // TODO: allow for inversion both here and in output - cpal_name: Option, - end_tx: Mutex>>, -} - -impl OutputSoundcard { - pub fn new() -> Self { - Self { - cpal_name: None, - end_tx: Mutex::new(None), - } - } - - pub fn new_with_card(card_name: String) -> Self { - Self { - cpal_name: Some(card_name), - end_tx: Mutex::new(None), - } - } -} - -impl OutputSink for OutputSoundcard { - fn start(&self, event_tx: SyncSender, buffer: Arc>) { - let (end_tx, end_rx) = channel(); - let cpal_name = self.cpal_name.clone(); - std::thread::spawn(move || { - let host = cpal::default_host(); - let device = if let Some(name) = cpal_name.as_deref() { - host.output_devices() - .unwrap() - .find(|d| d.name().unwrap() == name) - .unwrap() - } else { - host.default_output_device().unwrap() - }; - let mut configs = device.supported_output_configs().unwrap(); - // TODO: more error handling - let config = configs - .find(|c| c.channels() == 1 && c.sample_format() == SampleFormat::I16) - .unwrap() - .with_sample_rate(SampleRate(48000)); - let stream = device - .build_output_stream( - &config.into(), - move |data: &mut [i16], info: &cpal::OutputCallbackInfo| { - let mut taken = 0; - let ts = info.timestamp(); - let latency = ts - .playback - .duration_since(&ts.callback) - .unwrap_or(Duration::ZERO); - let mut buffer = buffer.write().unwrap(); - buffer.latency = latency; - for out in data.iter_mut() { - if let Some(s) = buffer.samples.pop_front() { - *out = s; - taken += 1; - } else if buffer.idling { - *out = 0; - } else { - debug!("output soundcard had underrun"); - let _ = event_tx.send(SoundmodemEvent::OutputUnderrun); - break; - } - } - //debug!("latency is {} ms, taken {taken}", latency.as_millis()); - let _ = event_tx.send(SoundmodemEvent::DidReadFromOutputBuffer { - len: taken, - timestamp: Instant::now(), - }); - }, - |e| { - // TODO: abort? - debug!("error occurred in soundcard output: {e:?}"); - }, - None, - ) - .unwrap(); - stream.play().unwrap(); - let _ = end_rx.recv(); - }); - *self.end_tx.lock().unwrap() = Some(end_tx); - } - - fn close(&self) { - let _ = self.end_tx.lock().unwrap().take(); - } -} - pub trait Ptt: Send + 'static { fn ptt_on(&mut self); fn ptt_off(&mut self); @@ -657,6 +515,12 @@ impl NullPtt { } } +impl Default for NullPtt { + fn default() -> Self { + Self::new() + } +} + impl Ptt for NullPtt { fn ptt_on(&mut self) {} fn ptt_off(&mut self) {}