mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-04-28 14:31:23 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc61342af8 | |||
| fded7f7b3f | |||
| ec83680333 | |||
| 16e94e71d3 | |||
| 56040934e9 | |||
| 89975cb124 | |||
| 03e20ffa7e | |||
| 8f7ea09ef5 | |||
| c639721f2a | |||
| 84512efda8 | |||
| 6cf4a9744d | |||
| d9ced4e650 | |||
| c1f3f34169 | |||
| 6c06da7b0d | |||
| 023caa4616 | |||
| fc593f8a8e | |||
| f281ad5a78 | |||
| fe8fec4ea7 | |||
| 7583e72687 | |||
| e4b4a3d198 | |||
| a7af1caace | |||
| c5086189d6 | |||
| ac667f1273 | |||
| fdb79e609f | |||
| 531a49dbdf | |||
| 2a13c25230 | |||
| 408f5317c4 | |||
| 3672d6f43e | |||
| cc3bec0746 |
Generated
+131
-711
File diff suppressed because it is too large
Load Diff
+5
-6
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "pwsp"
|
||||
version = "1.2.0"
|
||||
version = "1.3.2"
|
||||
edition = "2024"
|
||||
authors = ["arabian"]
|
||||
description = "PWSP lets you play audio files through your microphone. Has both CLI and GUI clients."
|
||||
@@ -12,19 +12,18 @@ keywords = ["soundpad", "pipewire", "linux", "cli", "gui"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.48.0", features = ["full"] }
|
||||
futures = { version = "0.3.31", features = ["thread-pool"] }
|
||||
tokio = { version = "1.49.0", features = ["full"] }
|
||||
async-trait = "0.1.89"
|
||||
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
serde_json = "1.0.149"
|
||||
|
||||
clap = { version = "4.5.53", default-features = false, features = ["std", "suggestions", "help", "usage", "error-context", "derive"] }
|
||||
clap = { version = "4.5.54", default-features = false, features = ["std", "suggestions", "help", "usage", "error-context", "derive"] }
|
||||
dirs = "6.0.0"
|
||||
|
||||
rodio = { version = "0.21.1", default-features = false, features = ["symphonia-all", "playback"] }
|
||||
pipewire = "0.9.2"
|
||||
rfd = "0.16.0"
|
||||
rfd = { version = "0.17.2", default-features = false, features = ["xdg-portal"]}
|
||||
|
||||
egui = { version = "0.33.3", default-features = false, features = ["default_fonts", "rayon"] }
|
||||
eframe = { version = "0.33.3", default-features = false, features = ["default_fonts", "glow", "x11", "wayland"] }
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
%global cargo_install_lib 0
|
||||
|
||||
Name: pwsp
|
||||
Version: 1.2.0
|
||||
Version: 1.3.2
|
||||
Release: %autorelease
|
||||
Summary: Lets you play audio files through your microphone
|
||||
|
||||
|
||||
+12
-1
@@ -45,6 +45,8 @@ enum Actions {
|
||||
Stop,
|
||||
/// Play a file
|
||||
Play { file_path: PathBuf },
|
||||
/// Toggle loop
|
||||
ToggleLoop,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
@@ -65,6 +67,8 @@ enum GetCommands {
|
||||
Input,
|
||||
/// All audio inputs
|
||||
Inputs,
|
||||
/// Is loop enabled (true or false)
|
||||
Loop,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
@@ -75,6 +79,8 @@ enum SetCommands {
|
||||
Position { position: f32 },
|
||||
/// Audio input id (see pwsp-cli get inputs)
|
||||
Input { name: String },
|
||||
/// Enable or disable loop (true or false)
|
||||
Loop { enabled: String },
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -91,6 +97,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
Actions::TogglePause => Request::toggle_pause(),
|
||||
Actions::Stop => Request::stop(),
|
||||
Actions::Play { file_path } => Request::play(file_path.to_str().unwrap()),
|
||||
Actions::ToggleLoop => Request::toggle_loop(),
|
||||
},
|
||||
Commands::Get { parameter } => match parameter {
|
||||
GetCommands::IsPaused => Request::get_is_paused(),
|
||||
@@ -101,15 +108,19 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
GetCommands::CurrentFilePath => Request::get_current_file_path(),
|
||||
GetCommands::Input => Request::get_input(),
|
||||
GetCommands::Inputs => Request::get_inputs(),
|
||||
GetCommands::Loop => Request::get_loop(),
|
||||
},
|
||||
Commands::Set { parameter } => match parameter {
|
||||
SetCommands::Volume { volume } => Request::set_volume(volume),
|
||||
SetCommands::Position { position } => Request::seek(position),
|
||||
SetCommands::Input { name } => Request::set_input(&name),
|
||||
SetCommands::Loop { enabled } => Request::set_loop(&enabled),
|
||||
},
|
||||
};
|
||||
|
||||
let response = make_request(request).await?;
|
||||
let response = make_request(request)
|
||||
.await
|
||||
.map_err(|e| e as Box<dyn Error>)?;
|
||||
println!("{} : {}", response.status, response.message);
|
||||
|
||||
Ok(())
|
||||
|
||||
+48
-4
@@ -1,5 +1,8 @@
|
||||
use pwsp::{
|
||||
types::socket::{Request, Response},
|
||||
types::{
|
||||
audio_player::PlayerState,
|
||||
socket::{Request, Response},
|
||||
},
|
||||
utils::{
|
||||
commands::parse_command,
|
||||
daemon::{
|
||||
@@ -9,10 +12,11 @@ use pwsp::{
|
||||
pipewire::create_virtual_mic,
|
||||
},
|
||||
};
|
||||
use std::{error::Error, fs};
|
||||
use std::{error::Error, fs, time::Duration};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::UnixListener,
|
||||
time::sleep,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
@@ -44,6 +48,27 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
socket_path.to_str().unwrap_or_default()
|
||||
);
|
||||
|
||||
let commands_loop_handle = tokio::spawn(async {
|
||||
commands_loop(listener).await.ok();
|
||||
});
|
||||
|
||||
let player_loop_handle = tokio::spawn(async {
|
||||
player_loop().await;
|
||||
});
|
||||
|
||||
tokio::select! {
|
||||
_ = commands_loop_handle => {
|
||||
eprint!("Commands loop was finished, stopping program...");
|
||||
}
|
||||
_ = player_loop_handle => {
|
||||
eprint!("Audio Player loop was finished, stopping program...");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn commands_loop(listener: UnixListener) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
let (mut stream, _addr) = listener.accept().await?;
|
||||
|
||||
@@ -64,7 +89,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
let request: Request = serde_json::from_slice(&buffer).unwrap();
|
||||
println!("Received request: {:?}", request);
|
||||
// ---------- Read request (end) ----------
|
||||
|
||||
// ---------- Generate response (start) ----------
|
||||
@@ -89,8 +113,28 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
eprintln!("Failed to write response to client!");
|
||||
return;
|
||||
}
|
||||
println!("Sent response: {:?}", response);
|
||||
// ---------- Send response (end) ----------
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn player_loop() {
|
||||
loop {
|
||||
let mut audio_player = get_audio_player().await.lock().await;
|
||||
|
||||
// Start playback again if loop is enabled
|
||||
let should_play = audio_player.get_state() == PlayerState::Stopped
|
||||
&& audio_player.current_file_path.is_some()
|
||||
&& audio_player.looped;
|
||||
|
||||
if should_play {
|
||||
let file_path = audio_player.current_file_path.clone().unwrap();
|
||||
audio_player
|
||||
.play(&file_path)
|
||||
.await
|
||||
.expect("Something went wrong while trying to play the file");
|
||||
}
|
||||
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -108,13 +108,29 @@ impl SoundpadGui {
|
||||
}
|
||||
// --------------------------------
|
||||
|
||||
// ---------- Loop Button ----------
|
||||
let loop_button = Button::new(
|
||||
RichText::new(match self.audio_player_state.looped {
|
||||
true => icons::ICON_REPEAT_ONE,
|
||||
false => icons::ICON_REPEAT,
|
||||
})
|
||||
.size(18.0),
|
||||
)
|
||||
.frame(false);
|
||||
|
||||
let loop_button_response = ui.add_sized([15.0, 30.0], loop_button);
|
||||
if loop_button_response.clicked() {
|
||||
self.toggle_loop();
|
||||
}
|
||||
// --------------------------------
|
||||
|
||||
// ---------- Position Slider ----------
|
||||
let position_slider = Slider::new(
|
||||
&mut self.app_state.position_slider_value,
|
||||
0.0..=self.audio_player_state.duration,
|
||||
)
|
||||
.show_value(false)
|
||||
.step_by(1.0);
|
||||
.step_by(0.01);
|
||||
|
||||
let default_slider_width = ui.spacing().slider_width;
|
||||
let position_slider_width = ui.available_width()
|
||||
@@ -150,7 +166,7 @@ impl SoundpadGui {
|
||||
icons::ICON_VOLUME_DOWN
|
||||
};
|
||||
let volume_icon = Label::new(RichText::new(volume_icon).size(18.0));
|
||||
ui.add_sized([30.0, 25.0], volume_icon);
|
||||
ui.add_sized([30.0, 30.0], volume_icon);
|
||||
// --------------------------------
|
||||
|
||||
// ---------- Volume Slider ----------
|
||||
|
||||
+20
-12
@@ -56,20 +56,24 @@ impl SoundpadGui {
|
||||
}
|
||||
|
||||
pub fn play_toggle(&mut self) {
|
||||
let mut guard = self.audio_player_state_shared.lock().unwrap();
|
||||
guard.state = match guard.state {
|
||||
PlayerState::Playing => {
|
||||
make_request_sync(Request::pause()).ok();
|
||||
guard.new_state = Some(PlayerState::Paused);
|
||||
PlayerState::Paused
|
||||
let (new_state, request) = {
|
||||
let guard = self.audio_player_state_shared.lock().unwrap();
|
||||
match guard.state {
|
||||
PlayerState::Playing => (Some(PlayerState::Paused), Some(Request::pause())),
|
||||
PlayerState::Paused => (Some(PlayerState::Playing), Some(Request::resume())),
|
||||
PlayerState::Stopped => (None, None),
|
||||
}
|
||||
PlayerState::Paused => {
|
||||
make_request_sync(Request::resume()).ok();
|
||||
guard.new_state = Some(PlayerState::Playing);
|
||||
PlayerState::Playing
|
||||
}
|
||||
PlayerState::Stopped => PlayerState::Stopped,
|
||||
};
|
||||
|
||||
if let Some(req) = request {
|
||||
make_request_sync(req).ok();
|
||||
}
|
||||
|
||||
if let Some(state) = new_state {
|
||||
let mut guard = self.audio_player_state_shared.lock().unwrap();
|
||||
guard.new_state = Some(state.clone());
|
||||
guard.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_file(&mut self) {
|
||||
@@ -125,6 +129,10 @@ impl SoundpadGui {
|
||||
daemon_config.save_to_file().ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_loop(&mut self) {
|
||||
make_request_sync(Request::toggle_loop()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
+28
-23
@@ -33,6 +33,8 @@ pub struct AudioPlayer {
|
||||
pub duration: Option<f32>,
|
||||
|
||||
pub current_file_path: Option<PathBuf>,
|
||||
|
||||
pub looped: bool,
|
||||
}
|
||||
|
||||
impl AudioPlayer {
|
||||
@@ -62,6 +64,8 @@ impl AudioPlayer {
|
||||
duration: None,
|
||||
|
||||
current_file_path: None,
|
||||
|
||||
looped: false,
|
||||
};
|
||||
|
||||
if default_input_device.is_some() {
|
||||
@@ -75,7 +79,7 @@ impl AudioPlayer {
|
||||
if let Some(sender) = &self.input_link_sender {
|
||||
match sender.send(Terminate {}) {
|
||||
Ok(_) => println!("Sent terminate signal to link thread"),
|
||||
Err(_) => println!("Failed to send terminate signal to link thread"),
|
||||
Err(_) => eprintln!("Failed to send terminate signal to link thread"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +88,7 @@ impl AudioPlayer {
|
||||
self.abort_link_thread();
|
||||
|
||||
if self.current_input_device.is_none() {
|
||||
println!("No input device selected, skipping device linking");
|
||||
eprintln!("No input device selected, skipping device linking");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -99,29 +103,30 @@ impl AudioPlayer {
|
||||
}
|
||||
|
||||
if pwsp_daemon_input.is_none() {
|
||||
println!("Could not find pwsp-daemon input device, skipping device linking");
|
||||
eprintln!("Could not find pwsp-daemon input device, skipping device linking");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let pwsp_daemon_input = pwsp_daemon_input.unwrap();
|
||||
|
||||
let current_input_device = self.current_input_device.clone().unwrap();
|
||||
let output_fl = current_input_device
|
||||
.clone()
|
||||
.output_fl
|
||||
.expect("Failed to get pwsp-daemon output_fl");
|
||||
let output_fr = current_input_device
|
||||
.clone()
|
||||
.output_fr
|
||||
.expect("Failed to get pwsp-daemon output_fl");
|
||||
let input_fl = pwsp_daemon_input
|
||||
.clone()
|
||||
.input_fl
|
||||
.expect("Failed to get pwsp-daemon input_fl");
|
||||
let input_fr = pwsp_daemon_input
|
||||
.clone()
|
||||
.input_fr
|
||||
.expect("Failed to get pwsp-daemon input_fr");
|
||||
|
||||
let Some(output_fl) = current_input_device.output_fl.clone() else {
|
||||
eprintln!("Failed to get pwsp-daemon output_fl");
|
||||
return Ok(());
|
||||
};
|
||||
let Some(output_fr) = current_input_device.output_fr.clone() else {
|
||||
eprintln!("Failed to get pwsp-daemon output_fr");
|
||||
return Ok(());
|
||||
};
|
||||
let Some(input_fl) = pwsp_daemon_input.input_fl.clone() else {
|
||||
eprintln!("Failed to get pwsp-daemon input_fl");
|
||||
return Ok(());
|
||||
};
|
||||
let Some(input_fr) = pwsp_daemon_input.input_fr.clone() else {
|
||||
eprintln!("Failed to get pwsp-daemon input_fr");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.input_link_sender = Some(create_link(output_fl, output_fr, input_fl, input_fr)?);
|
||||
|
||||
Ok(())
|
||||
@@ -147,7 +152,7 @@ impl AudioPlayer {
|
||||
self.sink.is_paused()
|
||||
}
|
||||
|
||||
pub fn get_state(&mut self) -> PlayerState {
|
||||
pub fn get_state(&self) -> PlayerState {
|
||||
if self.sink.len() == 0 {
|
||||
return PlayerState::Stopped;
|
||||
}
|
||||
@@ -164,7 +169,7 @@ impl AudioPlayer {
|
||||
self.sink.set_volume(volume);
|
||||
}
|
||||
|
||||
pub fn get_position(&mut self) -> f32 {
|
||||
pub fn get_position(&self) -> f32 {
|
||||
if self.get_state() == PlayerState::Stopped {
|
||||
return 0.0;
|
||||
}
|
||||
@@ -222,7 +227,7 @@ impl AudioPlayer {
|
||||
}
|
||||
|
||||
pub fn get_current_file_path(&mut self) -> &Option<PathBuf> {
|
||||
if self.get_state() == PlayerState::Stopped {
|
||||
if self.get_state() == PlayerState::Stopped && !self.looped {
|
||||
self.current_file_path = None;
|
||||
}
|
||||
&self.current_file_path
|
||||
|
||||
+42
-2
@@ -52,6 +52,14 @@ pub struct SetCurrentInputCommand {
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
pub struct GetLoopCommand {}
|
||||
|
||||
pub struct SetLoopCommand {
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
pub struct ToggleLoopCommand {}
|
||||
|
||||
#[async_trait]
|
||||
impl Executable for PingCommand {
|
||||
async fn execute(&self) -> Response {
|
||||
@@ -117,7 +125,7 @@ impl Executable for IsPausedCommand {
|
||||
#[async_trait]
|
||||
impl Executable for GetStateCommand {
|
||||
async fn execute(&self) -> Response {
|
||||
let mut audio_player = get_audio_player().await.lock().await;
|
||||
let audio_player = get_audio_player().await.lock().await;
|
||||
let state = audio_player.get_state();
|
||||
Response::new(true, serde_json::to_string(&state).unwrap())
|
||||
}
|
||||
@@ -148,7 +156,7 @@ impl Executable for SetVolumeCommand {
|
||||
#[async_trait]
|
||||
impl Executable for GetPositionCommand {
|
||||
async fn execute(&self) -> Response {
|
||||
let mut audio_player = get_audio_player().await.lock().await;
|
||||
let audio_player = get_audio_player().await.lock().await;
|
||||
let position = audio_player.get_position();
|
||||
Response::new(true, position.to_string())
|
||||
}
|
||||
@@ -256,3 +264,35 @@ impl Executable for SetCurrentInputCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Executable for GetLoopCommand {
|
||||
async fn execute(&self) -> Response {
|
||||
let audio_player = get_audio_player().await.lock().await;
|
||||
Response::new(true, audio_player.looped.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Executable for SetLoopCommand {
|
||||
async fn execute(&self) -> Response {
|
||||
let mut audio_player = get_audio_player().await.lock().await;
|
||||
|
||||
match self.enabled {
|
||||
Some(enabled) => {
|
||||
audio_player.looped = enabled;
|
||||
Response::new(true, format!("Loop was set to {}", enabled))
|
||||
}
|
||||
None => Response::new(false, "Invalid enabled value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Executable for ToggleLoopCommand {
|
||||
async fn execute(&self) -> Response {
|
||||
let mut audio_player = get_audio_player().await.lock().await;
|
||||
audio_player.looped = !audio_player.looped;
|
||||
Response::new(true, format!("Loop was set to {}", audio_player.looped))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ pub struct AudioPlayerState {
|
||||
pub current_file_path: PathBuf,
|
||||
|
||||
pub is_paused: bool,
|
||||
pub looped: bool,
|
||||
|
||||
pub volume: f32,
|
||||
pub new_volume: Option<f32>,
|
||||
|
||||
@@ -87,6 +87,18 @@ impl Request {
|
||||
pub fn set_input(name: &str) -> Self {
|
||||
Request::new("set_input", vec![("input_name", name)])
|
||||
}
|
||||
|
||||
pub fn get_loop() -> Self {
|
||||
Request::new("get_loop", vec![])
|
||||
}
|
||||
|
||||
pub fn set_loop(enabled: &str) -> Self {
|
||||
Request::new("set_loop", vec![("enabled", enabled)])
|
||||
}
|
||||
|
||||
pub fn toggle_loop() -> Self {
|
||||
Request::new("toggle_loop", vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -48,6 +48,17 @@ pub fn parse_command(request: &Request) -> Option<Box<dyn Executable + Send>> {
|
||||
let name = Some(request.args.get("input_name").unwrap_or(&String::new())).cloned();
|
||||
Some(Box::new(SetCurrentInputCommand { name }))
|
||||
}
|
||||
"get_loop" => Some(Box::new(GetLoopCommand {})),
|
||||
"set_loop" => {
|
||||
let enabled = request
|
||||
.args
|
||||
.get("enabled")
|
||||
.unwrap_or(&String::new())
|
||||
.parse::<bool>()
|
||||
.ok();
|
||||
Some(Box::new(SetLoopCommand { enabled }))
|
||||
}
|
||||
"toggle_loop" => Some(Box::new(ToggleLoopCommand {})),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -47,7 +47,7 @@ pub async fn link_player_to_virtual_mic() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
if pwsp_daemon_output.is_none() {
|
||||
println!("Could not find pwsp-daemon output device, skipping device linking");
|
||||
eprintln!("Could not find pwsp-daemon output device, skipping device linking");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ pub async fn link_player_to_virtual_mic() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
if pwsp_daemon_input.is_none() {
|
||||
println!("Could not find pwsp-daemon input device, skipping device linking");
|
||||
eprintln!("Could not find pwsp-daemon input device, skipping device linking");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ pub async fn wait_for_daemon() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn make_request(request: Request) -> Result<Response, Box<dyn Error>> {
|
||||
pub async fn make_request(request: Request) -> Result<Response, Box<dyn Error + Send + Sync>> {
|
||||
let socket_path = get_runtime_dir().join("daemon.sock");
|
||||
let mut stream = UnixStream::connect(socket_path).await?;
|
||||
|
||||
|
||||
+43
-10
@@ -24,7 +24,11 @@ pub fn get_gui_config() -> GuiConfig {
|
||||
}
|
||||
|
||||
pub fn make_request_sync(request: Request) -> Result<Response, Box<dyn Error>> {
|
||||
futures::executor::block_on(make_request(request))
|
||||
tokio::task::block_in_place(|| {
|
||||
tokio::runtime::Handle::current()
|
||||
.block_on(make_request(request))
|
||||
.map_err(|e| e as Box<dyn Error>)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn format_time_pair(position: f32, duration: f32) -> String {
|
||||
@@ -40,7 +44,7 @@ pub fn format_time_pair(position: f32, duration: f32) -> String {
|
||||
|
||||
pub fn start_app_state_thread(audio_player_state_shared: Arc<Mutex<AudioPlayerState>>) {
|
||||
tokio::spawn(async move {
|
||||
let sleep_duration = Duration::from_millis(100);
|
||||
let sleep_duration = Duration::from_secs_f32(1.0 / 60.0);
|
||||
|
||||
loop {
|
||||
wait_for_daemon().await.ok();
|
||||
@@ -53,15 +57,39 @@ pub fn start_app_state_thread(audio_player_state_shared: Arc<Mutex<AudioPlayerSt
|
||||
let duration_req = Request::get_duration();
|
||||
let current_input_req = Request::get_input();
|
||||
let all_inputs_req = Request::get_inputs();
|
||||
let looped_req = Request::get_loop();
|
||||
|
||||
let state_res = make_request(state_req).await.unwrap_or_default();
|
||||
let file_path_res = make_request(file_path_req).await.unwrap_or_default();
|
||||
let is_paused_res = make_request(is_paused_req).await.unwrap_or_default();
|
||||
let volume_res = make_request(volume_req).await.unwrap_or_default();
|
||||
let position_res = make_request(position_req).await.unwrap_or_default();
|
||||
let duration_res = make_request(duration_req).await.unwrap_or_default();
|
||||
let current_input_res = make_request(current_input_req).await.unwrap_or_default();
|
||||
let all_inputs_res = make_request(all_inputs_req).await.unwrap_or_default();
|
||||
let (
|
||||
state_res,
|
||||
file_path_res,
|
||||
is_paused_res,
|
||||
volume_res,
|
||||
position_res,
|
||||
duration_res,
|
||||
current_input_res,
|
||||
all_inputs_res,
|
||||
looped_res,
|
||||
) = tokio::join!(
|
||||
make_request(state_req),
|
||||
make_request(file_path_req),
|
||||
make_request(is_paused_req),
|
||||
make_request(volume_req),
|
||||
make_request(position_req),
|
||||
make_request(duration_req),
|
||||
make_request(current_input_req),
|
||||
make_request(all_inputs_req),
|
||||
make_request(looped_req),
|
||||
);
|
||||
|
||||
let state_res = state_res.unwrap_or_default();
|
||||
let file_path_res = file_path_res.unwrap_or_default();
|
||||
let is_paused_res = is_paused_res.unwrap_or_default();
|
||||
let volume_res = volume_res.unwrap_or_default();
|
||||
let position_res = position_res.unwrap_or_default();
|
||||
let duration_res = duration_res.unwrap_or_default();
|
||||
let current_input_res = current_input_res.unwrap_or_default();
|
||||
let all_inputs_res = all_inputs_res.unwrap_or_default();
|
||||
let looped_res = looped_res.unwrap_or_default();
|
||||
|
||||
let state = match state_res.status {
|
||||
true => serde_json::from_str::<PlayerState>(&state_res.message).unwrap(),
|
||||
@@ -116,6 +144,10 @@ pub fn start_app_state_thread(audio_player_state_shared: Arc<Mutex<AudioPlayerSt
|
||||
.collect::<HashMap<String, String>>(),
|
||||
false => HashMap::new(),
|
||||
};
|
||||
let looped = match looped_res.status {
|
||||
true => looped_res.message.parse::<bool>().unwrap_or_default(),
|
||||
false => false,
|
||||
};
|
||||
|
||||
{
|
||||
let mut guard = audio_player_state_shared.lock().unwrap();
|
||||
@@ -146,6 +178,7 @@ pub fn start_app_state_thread(audio_player_state_shared: Arc<Mutex<AudioPlayerSt
|
||||
guard.duration = if duration > 0.0 { duration } else { 1.0 };
|
||||
guard.current_input = current_input;
|
||||
guard.all_inputs = all_inputs;
|
||||
guard.looped = looped;
|
||||
}
|
||||
|
||||
sleep(sleep_duration).await;
|
||||
|
||||
@@ -165,8 +165,8 @@ pub async fn get_all_devices() -> Result<(Vec<AudioDevice>, Vec<AudioDevice>), B
|
||||
input_device.input_fr = Some(port)
|
||||
}
|
||||
"capture_MONO" => {
|
||||
input_device.input_fl = Some(port.clone());
|
||||
input_device.input_fr = Some(port);
|
||||
input_device.output_fl = Some(port.clone());
|
||||
input_device.output_fr = Some(port);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user