+ errors: SoundmodemErrorSender,
+ ) {
+ let _ = self.event_tx.send(SoundcardEvent::StartOutput {
+ event_tx,
+ buffer,
+ errors,
+ });
+ }
+
+ fn close(&self) {
+ let _ = self.event_tx.send(SoundcardEvent::CloseOutput);
+ }
+}
+
+fn build_input_cb<T: NumCast + WrappingNeg + Clone>(
+ samples: SyncSender<SoundmodemEvent>,
+ channels: u16,
+ rx_inverted: bool,
+) -> impl Fn(&[T], &InputCallbackInfo) {
+ move |data: &[T], _info: &cpal::InputCallbackInfo| {
+ let mut out = vec![];
+ for d in data.chunks(channels as usize) {
+ // if we were given multi-channel input we'll pick the first channel
+ let mut sample = d[0].clone();
+ if rx_inverted {
+ sample = sample.wrapping_neg();
+ }
+ out.push(NumCast::from(sample).unwrap());
+ }
+ let _ = samples.try_send(SoundmodemEvent::BasebandInput(out.into()));
+ }
+}
+
+fn build_input_stream(
+ device: &Device,
+ input_config: SupportedStreamConfig,
+ errors: SoundmodemErrorSender,
+ samples: SyncSender<SoundmodemEvent>,
+ channels: u16,
+ rx_inverted: bool,
+) -> Result<Stream, BuildStreamError> {
+ if input_config.sample_format() == SampleFormat::I16 {
+ device.build_input_stream(
+ &input_config.into(),
+ build_input_cb::<i16>(samples, channels, rx_inverted),
+ move |e| {
+ errors.send_error(SoundcardError::Stream(e));
+ },
+ None,
+ )
+ } else {
+ device.build_input_stream(
+ &input_config.into(),
+ build_input_cb::<i32>(samples, channels, rx_inverted),
+ move |e| {
+ errors.send_error(SoundcardError::Stream(e));
+ },
+ None,
+ )