aboutsummaryrefslogtreecommitdiffstats
path: root/mumd/src/audio
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2021-04-07 14:29:23 +0200
committerRubens Brandao <git@rubens.io>2021-04-07 14:29:23 +0200
commit12554b2f6cd89ad3cd3721bbc790d7772a21c3ae (patch)
tree03a289b3610eb5000ee3347c9a73d75da336808b /mumd/src/audio
parent38270c4a2374c2ccc04597a28fb191af9d86b814 (diff)
downloadmum-12554b2f6cd89ad3cd3721bbc790d7772a21c3ae.tar.gz
Create a trait and default implementation for device audio input
Diffstat (limited to 'mumd/src/audio')
-rw-r--r--mumd/src/audio/input.rs110
1 files changed, 109 insertions, 1 deletions
diff --git a/mumd/src/audio/input.rs b/mumd/src/audio/input.rs
index 176747d..f4e9c4c 100644
--- a/mumd/src/audio/input.rs
+++ b/mumd/src/audio/input.rs
@@ -1,8 +1,11 @@
-use cpal::{InputCallbackInfo, Sample};
+use cpal::{InputCallbackInfo, Sample, SampleFormat, SampleRate, StreamConfig};
+use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use tokio::sync::watch;
use log::*;
use crate::state::StatePhase;
+use crate::audio::SAMPLE_RATE;
+use crate::error::{AudioError, AudioStream};
pub fn callback<T: Sample>(
mut input_sender: futures_channel::mpsc::Sender<f32>,
@@ -24,3 +27,108 @@ pub fn callback<T: Sample>(
}
}
}
+
+pub trait AudioInputDevice {
+ fn play(&self) -> Result<(), AudioError>;
+ fn pause(&self) -> Result<(), AudioError>;
+ fn set_volume(&self, volume: f32);
+ fn sample_receiver(&mut self) -> futures_channel::mpsc::Receiver<f32>;
+ fn get_num_channels(&self) -> usize;
+}
+
+pub struct DefaultAudioInputDevice {
+ _stream: cpal::Stream,
+ sample_receiver: Option<futures_channel::mpsc::Receiver<f32>>,
+ volume_sender: watch::Sender<f32>,
+ channels: u16,
+}
+
+impl DefaultAudioInputDevice {
+ pub fn new(input_volume: f32, phase_watcher: watch::Receiver<StatePhase>) -> Result<Self, AudioError> {
+ let sample_rate = SampleRate(SAMPLE_RATE);
+
+ let host = cpal::default_host();
+
+ let input_device = host
+ .default_input_device()
+ .ok_or(AudioError::NoDevice(AudioStream::Input))?;
+ let input_supported_config = input_device
+ .supported_input_configs()
+ .map_err(|e| AudioError::NoConfigs(AudioStream::Input, e))?
+ .find_map(|c| {
+ if c.min_sample_rate() <= sample_rate && c.max_sample_rate() >= sample_rate {
+ Some(c)
+ } else {
+ None
+ }
+ })
+ .ok_or(AudioError::NoSupportedConfig(AudioStream::Input))?
+ .with_sample_rate(sample_rate);
+ let input_supported_sample_format = input_supported_config.sample_format();
+ let input_config: StreamConfig = input_supported_config.into();
+
+ let err_fn = |err| error!("An error occurred on the output audio stream: {}", err);
+
+ let (sample_sender, sample_receiver) = futures_channel::mpsc::channel(1_000_000);
+
+ let (volume_sender, input_volume_receiver) = watch::channel::<f32>(input_volume);
+
+ let input_stream = match input_supported_sample_format {
+ SampleFormat::F32 => input_device.build_input_stream(
+ &input_config,
+ callback::<f32>(
+ sample_sender,
+ input_volume_receiver,
+ phase_watcher,
+ ),
+ err_fn,
+ ),
+ SampleFormat::I16 => input_device.build_input_stream(
+ &input_config,
+ callback::<i16>(
+ sample_sender,
+ input_volume_receiver,
+ phase_watcher,
+ ),
+ err_fn,
+ ),
+ SampleFormat::U16 => input_device.build_input_stream(
+ &input_config,
+ callback::<u16>(
+ sample_sender,
+ input_volume_receiver,
+ phase_watcher,
+ ),
+ err_fn,
+ ),
+ }
+ .map_err(|e| AudioError::InvalidStream(AudioStream::Input, e))?;
+
+ let res = Self {
+ _stream: input_stream,
+ sample_receiver: Some(sample_receiver),
+ volume_sender,
+ channels: input_config.channels,
+ };
+ Ok(res)
+ }
+}
+
+impl AudioInputDevice for DefaultAudioInputDevice {
+ fn play(&self) -> Result<(), AudioError> {
+ self._stream.play().map_err(|e| AudioError::InputPlayError(e))
+ }
+ fn pause(&self) -> Result<(), AudioError> {
+ self._stream.pause().map_err(|e| AudioError::InputPauseError(e))
+ }
+ fn set_volume(&self, volume: f32) {
+ self.volume_sender.send(volume).unwrap();
+ }
+ fn sample_receiver(&mut self) -> futures_channel::mpsc::Receiver<f32> {
+ let ret = self.sample_receiver.take();
+ ret.unwrap()
+ }
+ fn get_num_channels(&self) -> usize {
+ self.channels as usize
+ }
+}