feat: ✨ controlling volume capability
This commit is contained in:
parent
68b270451f
commit
d44cfb37bf
4 changed files with 118 additions and 16 deletions
|
@ -1,15 +1,18 @@
|
|||
use std::fs::File;
|
||||
use std::{fs::File, sync::Arc};
|
||||
|
||||
use iced::{
|
||||
alignment,
|
||||
widget::{column, container, row, text::LineHeight, Container, Rule},
|
||||
widget::{column, container, row, slider, text::LineHeight, Container, Rule},
|
||||
window, Color, Command, Subscription,
|
||||
};
|
||||
use tokio::sync::broadcast::{channel, Receiver, Sender};
|
||||
use tokio::sync::{
|
||||
broadcast::{channel, Receiver, Sender},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gui_components::{button_with_centered_text, text_centered},
|
||||
gui_utils,
|
||||
gui_utils::{self, change_audio_volume, change_microphone_volume},
|
||||
utils::get_config,
|
||||
Config, BUFFER_LENGTH,
|
||||
};
|
||||
|
@ -45,6 +48,8 @@ pub enum Event {
|
|||
StopAudio,
|
||||
PauseAudio,
|
||||
ContinueAudio,
|
||||
ChangeMicrophoneVolume(f32),
|
||||
ChangeAudioVolume(f32),
|
||||
LoadConfig(Config),
|
||||
IcedEvent(iced::Event),
|
||||
CloseWindow(window::Id),
|
||||
|
@ -61,6 +66,8 @@ pub enum State {
|
|||
StopAudio,
|
||||
PausedAudio,
|
||||
ContinuedAudio,
|
||||
MicrophoneVolumeChanged,
|
||||
AudioVolumeChanged,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -89,12 +96,19 @@ enum Condition {
|
|||
Passive,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ChangeableValue {
|
||||
value: Arc<Mutex<f32>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GUIStatus {
|
||||
are_we_connect: Condition,
|
||||
are_we_record: Condition,
|
||||
are_we_play_audio: Condition,
|
||||
are_we_paused_audio: Condition,
|
||||
microphone_volume: ChangeableValue,
|
||||
audio_volume: ChangeableValue,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct Streamer {
|
||||
|
@ -135,6 +149,12 @@ impl Streamer {
|
|||
are_we_record: Condition::Passive,
|
||||
are_we_play_audio: Condition::Passive,
|
||||
are_we_paused_audio: Condition::Passive,
|
||||
microphone_volume: ChangeableValue {
|
||||
value: Arc::new(1.0.into()),
|
||||
},
|
||||
audio_volume: ChangeableValue {
|
||||
value: Arc::new(1.0.into()),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +176,8 @@ impl Streamer {
|
|||
.communication_channel
|
||||
.base_to_streaming_sender
|
||||
.subscribe();
|
||||
|
||||
let microphone_stream_volume = self.gui_status.microphone_volume.value.clone();
|
||||
let audio_stream_volume = self.gui_status.audio_volume.value.clone();
|
||||
Command::perform(
|
||||
async move {
|
||||
gui_utils::connect(
|
||||
|
@ -165,6 +186,8 @@ impl Streamer {
|
|||
streamer_config,
|
||||
streaming_to_base_sender,
|
||||
base_to_streaming_receiver,
|
||||
microphone_stream_volume,
|
||||
audio_stream_volume,
|
||||
)
|
||||
.await
|
||||
},
|
||||
|
@ -286,6 +309,9 @@ impl Streamer {
|
|||
|
||||
let decoded_to_playing_sender_for_is_finished =
|
||||
self.audio_file.decoded_to_playing_sender.clone().unwrap();
|
||||
|
||||
let audio_volume = self.gui_status.audio_volume.value.clone();
|
||||
|
||||
let playing_command = Command::perform(
|
||||
async move {
|
||||
gui_utils::start_playing(
|
||||
|
@ -294,6 +320,7 @@ impl Streamer {
|
|||
file,
|
||||
playing_to_base_sender,
|
||||
base_to_playing_receiver,
|
||||
audio_volume,
|
||||
)
|
||||
.await
|
||||
},
|
||||
|
@ -380,6 +407,22 @@ impl Streamer {
|
|||
Message::State,
|
||||
)
|
||||
}
|
||||
Event::ChangeMicrophoneVolume(value) => {
|
||||
*self.gui_status.microphone_volume.value.blocking_lock() = value;
|
||||
let microphone_volume = self.gui_status.microphone_volume.value.clone();
|
||||
Command::perform(
|
||||
async move { change_microphone_volume(value, microphone_volume).await },
|
||||
Message::State,
|
||||
)
|
||||
}
|
||||
Event::ChangeAudioVolume(value) => {
|
||||
*self.gui_status.audio_volume.value.blocking_lock() = value;
|
||||
let audio_volume = self.gui_status.audio_volume.value.clone();
|
||||
Command::perform(
|
||||
async move { change_audio_volume(value, audio_volume).await },
|
||||
Message::State,
|
||||
)
|
||||
}
|
||||
Event::LoadConfig(config) => {
|
||||
self.config = Some(config);
|
||||
Command::none()
|
||||
|
@ -434,6 +477,8 @@ impl Streamer {
|
|||
self.gui_status.are_we_paused_audio = Condition::Passive;
|
||||
Command::none()
|
||||
}
|
||||
State::MicrophoneVolumeChanged => Command::none(),
|
||||
State::AudioVolumeChanged => Command::none(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -528,6 +573,20 @@ impl Streamer {
|
|||
button_with_centered_text("No Purpose")
|
||||
};
|
||||
|
||||
let microphone_volume_slider = slider(
|
||||
0.0..=1.0,
|
||||
*self.gui_status.microphone_volume.value.blocking_lock(),
|
||||
|value| Message::Event(Event::ChangeMicrophoneVolume(value)),
|
||||
)
|
||||
.step(0.01);
|
||||
|
||||
let audio_volume_slider = slider(
|
||||
0.0..=1.0,
|
||||
*self.gui_status.audio_volume.value.blocking_lock(),
|
||||
|value| Message::Event(Event::ChangeAudioVolume(value)),
|
||||
)
|
||||
.step(0.01);
|
||||
|
||||
let header_content = row![header].width(350).height(50);
|
||||
let text_content = row![
|
||||
connection_text,
|
||||
|
@ -558,12 +617,15 @@ impl Streamer {
|
|||
connect_button,
|
||||
record_button,
|
||||
play_audio_button,
|
||||
pause_audio_button
|
||||
pause_audio_button,
|
||||
]
|
||||
.spacing(5)
|
||||
.width(350)
|
||||
.height(35);
|
||||
|
||||
let volume_content = row![microphone_volume_slider, audio_volume_slider,]
|
||||
.spacing(5)
|
||||
.width(350)
|
||||
.height(35);
|
||||
let content = column![
|
||||
header_content,
|
||||
Rule::horizontal(1),
|
||||
|
@ -571,6 +633,7 @@ impl Streamer {
|
|||
button_content,
|
||||
status_content,
|
||||
Rule::horizontal(1),
|
||||
volume_content,
|
||||
]
|
||||
.spacing(20)
|
||||
.width(350)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::{fs::File, time::Duration};
|
||||
use std::{fs::File, sync::Arc, time::Duration};
|
||||
|
||||
use tokio::sync::broadcast::{Receiver, Sender};
|
||||
use tokio::sync::{
|
||||
broadcast::{Receiver, Sender},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gui::{Player, State},
|
||||
|
@ -13,6 +16,8 @@ pub async fn connect(
|
|||
streamer_config: Config,
|
||||
streaming_to_base_sender: Sender<bool>,
|
||||
base_to_streaming_receiver: Receiver<bool>,
|
||||
microphone_stream_volume: Arc<Mutex<f32>>,
|
||||
audio_stream_volume: Arc<Mutex<f32>>,
|
||||
) -> State {
|
||||
let mut streaming_to_base_receiver = streaming_to_base_sender.subscribe();
|
||||
tokio::spawn(streaming::connect(
|
||||
|
@ -21,6 +26,8 @@ pub async fn connect(
|
|||
streamer_config,
|
||||
base_to_streaming_receiver,
|
||||
streaming_to_base_sender.clone(),
|
||||
microphone_stream_volume,
|
||||
audio_stream_volume,
|
||||
));
|
||||
let answer = streaming_to_base_receiver.recv().await;
|
||||
drop(streaming_to_base_receiver);
|
||||
|
@ -124,6 +131,7 @@ pub async fn start_playing(
|
|||
file: File,
|
||||
playing_to_base_sender: Sender<Player>,
|
||||
base_to_playing_receiver: Receiver<Player>,
|
||||
audio_volume: Arc<Mutex<f32>>,
|
||||
) -> State {
|
||||
let mut playing_to_base_receiver = playing_to_base_sender.subscribe();
|
||||
tokio::spawn(playing::play(
|
||||
|
@ -132,6 +140,7 @@ pub async fn start_playing(
|
|||
decoded_to_playing_sender,
|
||||
playing_to_base_sender,
|
||||
base_to_playing_receiver,
|
||||
audio_volume,
|
||||
));
|
||||
let answer = playing_to_base_receiver.recv().await;
|
||||
drop(playing_to_base_receiver);
|
||||
|
@ -291,3 +300,19 @@ pub async fn continue_playing(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn change_microphone_volume(
|
||||
desired_value: f32,
|
||||
microphone_stream_volume: Arc<Mutex<f32>>,
|
||||
) -> State {
|
||||
*microphone_stream_volume.lock().await = desired_value;
|
||||
State::MicrophoneVolumeChanged
|
||||
}
|
||||
|
||||
pub async fn change_audio_volume(
|
||||
desired_value: f32,
|
||||
audio_stream_volume: Arc<Mutex<f32>>,
|
||||
) -> State {
|
||||
*audio_stream_volume.lock().await = desired_value;
|
||||
State::AudioVolumeChanged
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::fs::File;
|
||||
use std::{fs::File, sync::Arc};
|
||||
|
||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||
use rubato::{
|
||||
|
@ -13,7 +13,10 @@ use symphonia::core::{
|
|||
probe::Hint,
|
||||
};
|
||||
use tokio::{
|
||||
sync::broadcast::{Receiver, Sender},
|
||||
sync::{
|
||||
broadcast::{Receiver, Sender},
|
||||
Mutex,
|
||||
},
|
||||
task,
|
||||
};
|
||||
|
||||
|
@ -25,6 +28,7 @@ pub async fn play(
|
|||
decoded_to_playing_sender: Sender<f32>,
|
||||
playing_to_base_sender: Sender<Player>,
|
||||
mut base_to_playing_receiver: Receiver<Player>,
|
||||
audio_volume: Arc<Mutex<f32>>,
|
||||
) {
|
||||
let host = cpal::default_host();
|
||||
let output_device = host.default_output_device().unwrap();
|
||||
|
@ -50,7 +54,7 @@ pub async fn play(
|
|||
for sample in data {
|
||||
if decoded_to_playing_receiver.len() > 0 {
|
||||
let single = match decoded_to_playing_receiver.blocking_recv() {
|
||||
Ok(single) => single,
|
||||
Ok(single) => single * *audio_volume.blocking_lock(),
|
||||
Err(_) => 0.0,
|
||||
};
|
||||
if audio_stream_sender.receiver_count() > 0 {
|
||||
|
|
|
@ -4,7 +4,10 @@ use brotli::CompressorWriter;
|
|||
use futures_util::SinkExt;
|
||||
use ringbuf::HeapRb;
|
||||
use tokio::{
|
||||
sync::broadcast::{channel, Receiver, Sender},
|
||||
sync::{
|
||||
broadcast::{channel, Receiver, Sender},
|
||||
Mutex,
|
||||
},
|
||||
task::JoinHandle,
|
||||
};
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
|
@ -18,6 +21,8 @@ pub async fn connect(
|
|||
streamer_config: Config,
|
||||
mut base_to_streaming: Receiver<bool>,
|
||||
streaming_to_base: Sender<bool>,
|
||||
microphone_stream_volume: Arc<Mutex<f32>>,
|
||||
audio_stream_volume: Arc<Mutex<f32>>,
|
||||
) {
|
||||
let connect_addr = match streamer_config.tls {
|
||||
true => format!("wss://{}", streamer_config.address),
|
||||
|
@ -59,6 +64,8 @@ pub async fn connect(
|
|||
let mixer_task = tokio::spawn(mixer(
|
||||
microphone_stream_receiver,
|
||||
audio_stream_receiver,
|
||||
microphone_stream_volume,
|
||||
audio_stream_volume,
|
||||
flow_sender,
|
||||
streamer_config.latency,
|
||||
));
|
||||
|
@ -82,6 +89,8 @@ pub async fn connect(
|
|||
async fn mixer(
|
||||
mut microphone_stream_receiver: Receiver<f32>,
|
||||
mut audio_stream_receiver: Receiver<f32>,
|
||||
microphone_stream_volume: Arc<Mutex<f32>>,
|
||||
audio_stream_volume: Arc<Mutex<f32>>,
|
||||
flow_sender: Sender<f32>,
|
||||
latency: u16,
|
||||
) {
|
||||
|
@ -120,13 +129,14 @@ async fn mixer(
|
|||
let mut flow = vec![];
|
||||
|
||||
for element in microphone_stream {
|
||||
flow.push(element * 0.5);
|
||||
flow.push(element * (*microphone_stream_volume.lock().await));
|
||||
}
|
||||
for (i, element) in audio_stream.iter().enumerate() {
|
||||
let audio_volumized = element * (*audio_stream_volume.lock().await);
|
||||
if flow.len() > i && flow.len() != 0 {
|
||||
flow[i] = flow[i] + element * 0.5;
|
||||
flow[i] = flow[i] + audio_volumized;
|
||||
} else {
|
||||
flow.push(element * 0.5);
|
||||
flow.push(audio_volumized);
|
||||
}
|
||||
}
|
||||
for element in flow {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue