chatsounds/
channel_volume.rs

1use std::{
2    f32,
3    sync::{Arc, Mutex},
4    time::Duration,
5};
6
7use rodio::{
8    cpal::FromSample, source::ChannelVolume, OutputStreamHandle, PlayError, Sample, Sink, Source,
9};
10
11pub struct ChannelVolumeSink {
12    pub sink: Sink,
13    channel_volumes: Arc<Mutex<Vec<f32>>>,
14}
15
16impl ChannelVolumeSink {
17    pub fn try_new(
18        stream: &OutputStreamHandle,
19        channel_volumes: Vec<f32>,
20    ) -> Result<Self, PlayError> {
21        Ok(Self {
22            sink: Sink::try_new(stream)?,
23            channel_volumes: Arc::new(Mutex::new(channel_volumes)),
24        })
25    }
26
27    pub fn set_channel_volumes(&self, channel_volumes: Vec<f32>) {
28        *self.channel_volumes.lock().unwrap() = channel_volumes;
29    }
30
31    pub fn append<S>(&self, source: S)
32    where
33        S: Source + Send + 'static,
34        f32: FromSample<S::Item>,
35        S::Item: Sample + Send,
36    {
37        let channel_volumes = self.channel_volumes.clone();
38        let source = ChannelVolume::new(source, self.channel_volumes.lock().unwrap().clone())
39            .periodic_access(Duration::from_millis(10), move |i| {
40                let channel_volumes = channel_volumes.lock().unwrap();
41                for (channel, volume) in channel_volumes.iter().enumerate() {
42                    i.set_volume(channel, *volume);
43                }
44            });
45        self.sink.append(source);
46    }
47}