This commit is contained in:
Moritz Ruth 2024-02-01 17:48:25 +01:00
parent bf48f12c8c
commit 66c86df2a4
Signed by: moritzruth
GPG key ID: C9BBAB79405EE56D
8 changed files with 104 additions and 107 deletions

View file

@ -145,43 +145,6 @@ fn state_matches(target: &Target, state: &PaEntityState) -> bool {
});
}
pub struct Handler {
events_sender: broadcast::Sender<(KnobPath, KnobEvent)>,
#[allow(unused)]
runtime: tokio::runtime::Runtime,
}
impl Handler {
pub fn new(data: InitialHandlerMessage<(), KnobConfig>) -> Result<Self, HandlerInitializationError> {
let (events_sender, _) = broadcast::channel::<(KnobPath, KnobEvent)>(5);
let pa_volume_interface = Arc::new(PaVolumeInterface::spawn_thread("deckster handler".to_owned()));
let runtime = tokio::runtime::Builder::new_multi_thread().worker_threads(1).build().unwrap();
for (path, (mode, config)) in data.knob_configs {
if !mode.is_empty() {
return Err(HandlerInitializationError::InvalidModeString {
message: "No mode string allowed.".into(),
});
}
let events_receiver = events_sender.subscribe();
let a = Arc::clone(&pa_volume_interface);
runtime.spawn(manage_knob(path, config, events_receiver, a));
}
Ok(Handler { events_sender, runtime })
}
}
impl DecksterHandler for Handler {
fn handle(&mut self, event: HandlerEvent) {
if let HandlerEvent::Knob { path, event } = event {
self.events_sender.send((path, event)).unwrap();
}
}
}
async fn manage_knob(path: KnobPath, config: KnobConfig, mut events: broadcast::Receiver<(KnobPath, KnobEvent)>, pa_volume_interface: Arc<PaVolumeInterface>) {
let mut entity_state: Option<Arc<PaEntityState>> = None;
@ -299,3 +262,33 @@ async fn manage_knob(path: KnobPath, config: KnobConfig, mut events: broadcast::
}
}
}
pub struct Handler {
events_sender: broadcast::Sender<(KnobPath, KnobEvent)>,
#[allow(unused)]
runtime: tokio::runtime::Runtime,
}
impl Handler {
pub fn new(data: InitialHandlerMessage<(), KnobConfig>) -> Result<Self, HandlerInitializationError> {
let (events_sender, _) = broadcast::channel::<(KnobPath, KnobEvent)>(5);
let pa_volume_interface = Arc::new(PaVolumeInterface::spawn_thread("deckster handler".to_owned()));
let runtime = tokio::runtime::Builder::new_multi_thread().worker_threads(1).build().unwrap();
for (path, config) in data.knob_configs {
let events_receiver = events_sender.subscribe();
runtime.spawn(manage_knob(path, config, events_receiver, Arc::clone(&pa_volume_interface)));
}
Ok(Handler { events_sender, runtime })
}
}
impl DecksterHandler for Handler {
fn handle(&mut self, event: HandlerEvent) {
if let HandlerEvent::Knob { path, event } = event {
self.events_sender.send((path, event)).unwrap();
}
}
}

View file

@ -9,24 +9,34 @@ use std::time::Duration;
use log::{error, warn};
use once_cell::sync::Lazy;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
use tokio::sync::broadcast::error::RecvError;
use deckster_mode::shared::handler_communication::{HandlerCommand, HandlerEvent, InitialHandlerMessage, KeyEvent};
use deckster_mode::shared::handler_communication::{HandlerCommand, HandlerEvent, HandlerInitializationError, InitialHandlerMessage, KeyEvent};
use deckster_mode::shared::path::KeyPath;
use deckster_mode::shared::state::KeyStyleByStateMap;
use deckster_mode::{send_command, DecksterHandler};
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "mode", rename_all = "kebab-case")]
pub enum KeyConfig {
Play(ButtonConfig),
Pause(ButtonConfig),
PlayPause(ButtonConfig),
Previous(ButtonConfig),
Next(ButtonConfig),
Shuffle(ShuffleConfig),
Loop(LoopConfig),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ButtonConfig {
#[serde(default)]
pub style: KeyStyleByStateMap<ButtonState>,
pub command: ButtonCommand,
}
#[derive(Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[derive(Debug, Eq, PartialEq)]
pub enum ButtonCommand {
PlayPause,
Play,
@ -35,7 +45,7 @@ pub enum ButtonCommand {
Next,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Deserialize)]
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ButtonState {
Inactive,
@ -43,13 +53,13 @@ pub enum ButtonState {
Paused,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ShuffleConfig {
#[serde(default)]
pub style: KeyStyleByStateMap<ShuffleState>,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Deserialize)]
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ShuffleState {
Inactive,
@ -57,13 +67,13 @@ pub enum ShuffleState {
On,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LoopConfig {
#[serde(default)]
pub style: KeyStyleByStateMap<LoopState>,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Deserialize)]
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum LoopState {
Inactive,
@ -163,11 +173,11 @@ static STATE_WATCHER_LOOP: Lazy<PlayerctlStateWatcher<LoopState>> = Lazy::new(||
})
});
pub async fn handle_button(path: KeyPath, config: Arc<ButtonConfig>, mut events: broadcast::Receiver<KeyEvent>) {
pub async fn manage_button(path: KeyPath, config: ButtonConfig, mut events: broadcast::Receiver<(KeyPath, KeyEvent)>, command: ButtonCommand) {
let mut is_active = false;
let mut state = STATE_WATCHER_PLAYING.subscribe_to_state();
let command = match config.command {
let command = match command {
ButtonCommand::PlayPause => "play-pause",
ButtonCommand::Play => "play",
ButtonCommand::Pause => "pause",
@ -192,7 +202,11 @@ pub async fn handle_button(path: KeyPath, config: Arc<ButtonConfig>, mut events:
}
}
Ok(event) = events.recv() => {
Ok((p, event)) = events.recv() => {
if p != path {
continue
}
if event == KeyEvent::Press && is_active {
let status = std::process::Command::new("playerctl").arg(command).status().unwrap();
@ -205,7 +219,7 @@ pub async fn handle_button(path: KeyPath, config: Arc<ButtonConfig>, mut events:
}
}
pub async fn handle_shuffle(path: KeyPath, config: Arc<ShuffleConfig>, mut events: broadcast::Receiver<KeyEvent>) {
pub async fn manage_shuffle(path: KeyPath, config: ShuffleConfig, mut events: broadcast::Receiver<(KeyPath, KeyEvent)>) {
let mut state = STATE_WATCHER_SHUFFLE.subscribe_to_state();
loop {
@ -223,7 +237,11 @@ pub async fn handle_shuffle(path: KeyPath, config: Arc<ShuffleConfig>, mut event
}
}
Ok(event) = events.recv() => {
Ok((p, event)) = events.recv() => {
if p != path {
continue
}
if event == KeyEvent::Press {
let current = *STATE_WATCHER_SHUFFLE.state.read().unwrap();
let new = match current {
@ -242,7 +260,7 @@ pub async fn handle_shuffle(path: KeyPath, config: Arc<ShuffleConfig>, mut event
}
}
pub async fn handle_loop(path: KeyPath, config: Arc<LoopConfig>, mut events: broadcast::Receiver<KeyEvent>) {
pub async fn manage_loop(path: KeyPath, config: LoopConfig, mut events: broadcast::Receiver<(KeyPath, KeyEvent)>) {
let mut state = STATE_WATCHER_LOOP.subscribe_to_state();
loop {
@ -260,7 +278,11 @@ pub async fn handle_loop(path: KeyPath, config: Arc<LoopConfig>, mut events: bro
}
}
Ok(event) = events.recv() => {
Ok((p, event)) = events.recv() => {
if p != path {
continue
}
if event == KeyEvent::Press {
let current = *STATE_WATCHER_LOOP.state.read().unwrap();
let new = match current {
@ -287,22 +309,23 @@ pub struct Handler {
}
impl Handler {
pub fn new(data: InitialHandlerMessage<()>) -> Result<Self, HandlerInitializationError> {
let (events_sender, _) = broadcast::channel::<(KnobPath, KnobEvent)>(5);
let pa_volume_interface = Arc::new(PaVolumeInterface::spawn_thread("deckster handler".to_owned()));
pub fn new(data: InitialHandlerMessage<KeyConfig, ()>) -> Result<Self, HandlerInitializationError> {
let (events_sender, _) = broadcast::channel::<(KeyPath, KeyEvent)>(5);
let runtime = tokio::runtime::Builder::new_multi_thread().worker_threads(1).build().unwrap();
for (path, (mode, config)) in data.knob_configs {
if !mode.is_empty() {
return Err(HandlerInitializationError::InvalidModeString {
message: "No mode string allowed.".into(),
});
}
for (path, config) in data.key_configs {
let events = events_sender.subscribe();
let events_receiver = events_sender.subscribe();
let a = Arc::clone(&pa_volume_interface);
runtime.spawn(manage_knob(path, config, events_receiver, a));
match config {
KeyConfig::Loop(config) => runtime.spawn(manage_loop(path, config, events)),
KeyConfig::Shuffle(config) => runtime.spawn(manage_shuffle(path, config, events)),
KeyConfig::Previous(config) => runtime.spawn(manage_button(path, config, events, ButtonCommand::Previous)),
KeyConfig::Next(config) => runtime.spawn(manage_button(path, config, events, ButtonCommand::Next)),
KeyConfig::Pause(config) => runtime.spawn(manage_button(path, config, events, ButtonCommand::Pause)),
KeyConfig::Play(config) => runtime.spawn(manage_button(path, config, events, ButtonCommand::Play)),
KeyConfig::PlayPause(config) => runtime.spawn(manage_button(path, config, events, ButtonCommand::PlayPause)),
};
}
Ok(Handler { events_sender, runtime })
@ -311,7 +334,7 @@ impl Handler {
impl DecksterHandler for Handler {
fn handle(&mut self, event: HandlerEvent) {
if let HandlerEvent::Knob { path, event } = event {
if let HandlerEvent::Key { path, event } = event {
self.events_sender.send((path, event)).unwrap();
}
}

View file

@ -1,6 +1,8 @@
use clap::Parser;
use color_eyre::Result;
use crate::handler::Handler;
mod handler;
#[derive(Debug, Parser)]