diff options
| author | Rubens Brandao <git@rubens.io> | 2021-04-07 14:29:23 +0200 |
|---|---|---|
| committer | Rubens Brandao <git@rubens.io> | 2021-04-07 14:29:23 +0200 |
| commit | 12554b2f6cd89ad3cd3721bbc790d7772a21c3ae (patch) | |
| tree | 03a289b3610eb5000ee3347c9a73d75da336808b /mumd/src/audio | |
| parent | 38270c4a2374c2ccc04597a28fb191af9d86b814 (diff) | |
| download | mum-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.rs | 110 |
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 + } +} |
