aboutsummaryrefslogtreecommitdiffstats
path: root/mumd/src/audio/input.rs
blob: 4a1ed3d074b9da03407e1197691caaa6cd9d7eab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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>,
    input_volume_receiver: watch::Receiver<f32>,
    phase_watcher: watch::Receiver<StatePhase>,
) -> impl FnMut(&[T], &InputCallbackInfo) + Send + 'static {
    move |data: &[T], _info: &InputCallbackInfo| {
        if !matches!(&*phase_watcher.borrow(), StatePhase::Connected(_)) {
            return;
        }
        let input_volume = *input_volume_receiver.borrow();
        for sample in data
            .iter()
            .map(|e| e.to_f32())
            .map(|e| e * input_volume) {
            if let Err(_e) = input_sender.try_send(sample) {
                warn!("Error sending audio: {}", _e);
            }
        }
    }
}

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 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 num_channels(&self) -> usize {
        self.channels as usize
    }
}