Skip to content

Commit

Permalink
Refactor skipping disconnected outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
maximbaz committed Aug 7, 2023
1 parent 0038d82 commit 4767519
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 104 deletions.
2 changes: 1 addition & 1 deletion src/brightness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use controller::Controller;
pub use ddcutil::DdcUtil;

#[cfg_attr(test, automock)]
pub trait Brightness {
pub trait Brightness: Send {
fn get(&mut self) -> Result<u64, Box<dyn Error>>;
fn set(&mut self, value: u64) -> Result<u64, Box<dyn Error>>;
}
16 changes: 16 additions & 0 deletions src/config/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,19 @@ pub struct Config {
pub als: Als,
pub output: Vec<Output>,
}

impl Output {
pub fn name(&self) -> &str {
match self {
self::Output::Backlight(cfg) => &cfg.name,
self::Output::DdcUtil(cfg) => &cfg.name,
}
}

pub fn capturer(&self) -> &Capturer {
match self {
self::Output::Backlight(cfg) => &cfg.capturer,
self::Output::DdcUtil(cfg) => &cfg.capturer,
}
}
}
2 changes: 1 addition & 1 deletion src/frame/capturer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub mod none;
pub mod wlroots;

pub trait Capturer {
pub trait Capturer: Send {
fn run(&mut self);
}
8 changes: 4 additions & 4 deletions src/frame/capturer/wlroots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ pub struct Capturer {
}

impl Capturer {
pub fn new(output_name: &str, controller: Controller) -> Self {
pub fn new(output_name: &str, controller: Controller) -> Result<Self, Box<dyn Error>> {
let connection = Connection::connect_to_env().expect("Unable to connect to Wayland");

Self {
Ok(Self {
vulkan: Vulkan::new().expect("Unable to initialize Vulkan"),
output: find_output(&connection, output_name).expect("Unable to find output"),
output: find_output(&connection, output_name)?,
connection,
controller,
pending_frame: None,
}
})
}
}

Expand Down
192 changes: 94 additions & 98 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use config::Output;
use itertools::Itertools;
use std::error::Error;
use std::sync::mpsc;

mod als;
Expand Down Expand Up @@ -30,109 +32,103 @@ fn main() {
let als_txs = config
.output
.iter()
.filter_map(|output| {
let output = output.clone();

let (als_tx, als_rx) = mpsc::channel();
let (user_tx, user_rx) = mpsc::channel();
let (prediction_tx, prediction_rx) = mpsc::channel();

let (output_name, output_capturer) = match output.clone() {
config::Output::Backlight(cfg) => (cfg.name, cfg.capturer),
config::Output::DdcUtil(cfg) => (cfg.name, cfg.capturer),
};

let brightness = match output {
config::Output::Backlight(cfg) => {
brightness::Backlight::new(&cfg.path, cfg.min_brightness)
.map(|b| Box::new(b) as Box<dyn brightness::Brightness + Send>)
}
config::Output::DdcUtil(cfg) => {
brightness::DdcUtil::new(&cfg.name, cfg.min_brightness)
.map(|b| Box::new(b) as Box<dyn brightness::Brightness + Send>)
}
};

match brightness {
Ok(b) => {
let thread_name = format!("backlight-{}", output_name);
std::thread::Builder::new()
.name(thread_name.clone())
.spawn(move || {
brightness::Controller::new(b, user_tx, prediction_rx).run();
})
.unwrap_or_else(|_| panic!("Unable to start thread: {}", thread_name));

let thread_name = format!("predictor-{}", output_name);
std::thread::Builder::new()
.name(thread_name.clone())
.spawn(move || {
let controller = predictor::Controller::new(
prediction_tx,
user_rx,
als_rx,
true,
&output_name,
);

let mut frame_capturer: Box<dyn frame::capturer::Capturer> =
match output_capturer {
config::Capturer::Wlroots => {
Box::new(frame::capturer::wlroots::Capturer::new(
&output_name,
controller,
))
}
config::Capturer::None => {
Box::new(frame::capturer::none::Capturer::new(controller))
}
};

frame_capturer.run();
})
.unwrap_or_else(|_| panic!("Unable to start thread: {}", thread_name));

Some(als_tx)
}
Err(err) => {
log::warn!(
"Skipping '{}' as it might be disconnected: {}",
output_name,
err
);

None
}
.filter_map(|output| match init_output(output) {
Ok((mut brightness_controller, mut frame_capturer, als_tx)) => {
spawn(format!("backlight-{}", output.name()), move || {
brightness_controller.run()
});
spawn(format!("predictor-{}", output.name()), move || {
frame_capturer.run();
});

Some(als_tx)
}
Err(err) => {
log::warn!(
"Skipping '{}' as it might be disconnected: {}",
output.name(),
err
);

None
}
})
.collect_vec();

std::thread::Builder::new()
.name("als".to_string())
.spawn(move || {
let als: Box<dyn als::Als> = match config.als {
config::Als::Iio { path, thresholds } => Box::new(
als::iio::Als::new(&path, thresholds)
.expect("Unable to initialize ALS IIO sensor"),
),
config::Als::Time { thresholds } => Box::new(als::time::Als::new(thresholds)),
config::Als::Webcam { video, thresholds } => Box::new({
let (webcam_tx, webcam_rx) = mpsc::channel();
std::thread::Builder::new()
.name("als-webcam".to_string())
.spawn(move || {
als::webcam::Webcam::new(webcam_tx, video).run();
})
.expect("Unable to start thread: als-webcam");
als::webcam::Als::new(webcam_rx, thresholds)
}),
config::Als::None => Box::<als::none::Als>::default(),
};

als::controller::Controller::new(als, als_txs).run();
})
.expect("Unable to start thread: als");
spawn("als".to_string(), move || {
let als: Box<dyn als::Als> = match config.als {
config::Als::Iio { path, thresholds } => Box::new(
als::iio::Als::new(&path, thresholds).expect("Unable to initialize ALS IIO sensor"),
),
config::Als::Time { thresholds } => Box::new(als::time::Als::new(thresholds)),
config::Als::Webcam { video, thresholds } => Box::new({
let (webcam_tx, webcam_rx) = mpsc::channel();
std::thread::Builder::new()
.name("als-webcam".to_string())
.spawn(move || {
als::webcam::Webcam::new(webcam_tx, video).run();
})
.expect("Unable to start thread: als-webcam");
als::webcam::Als::new(webcam_rx, thresholds)
}),
config::Als::None => Box::<als::none::Als>::default(),
};

als::controller::Controller::new(als, als_txs).run();
});

log::info!("Continue adjusting brightness and wluma will learn your preference over time.");
std::thread::park();
}

fn spawn<F, T>(thread_name: String, handler: F)
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
std::thread::Builder::new()
.name(thread_name.clone())
.spawn(handler)
.unwrap_or_else(|_| panic!("Unable to start thread: {}", thread_name));
}

type OutputHandler = (
brightness::Controller,
Box<dyn frame::capturer::Capturer>,
std::sync::mpsc::Sender<std::string::String>,
);

fn init_output(output: &Output) -> Result<OutputHandler, Box<dyn Error>> {
let output = output.clone();

let (als_tx, als_rx) = mpsc::channel();
let (user_tx, user_rx) = mpsc::channel();
let (prediction_tx, prediction_rx) = mpsc::channel();

let brightness = match &output {
config::Output::Backlight(cfg) => {
brightness::Backlight::new(&cfg.path, cfg.min_brightness).map(|b| Box::new(b) as Box<_>)
}
config::Output::DdcUtil(cfg) => {
brightness::DdcUtil::new(&cfg.name, cfg.min_brightness).map(|b| Box::new(b) as Box<_>)
}
}?;

let brightness_controller = brightness::Controller::new(brightness, user_tx, prediction_rx);

let predictor_controller =
predictor::Controller::new(prediction_tx, user_rx, als_rx, true, output.name());

let frame_capturer: Box<dyn frame::capturer::Capturer> = match output.capturer() {
config::Capturer::Wlroots => {
frame::capturer::wlroots::Capturer::new(output.name(), predictor_controller)
.map(|b| Box::new(b) as Box<_>)?
}
config::Capturer::None => {
Box::new(frame::capturer::none::Capturer::new(predictor_controller))
}
};

Ok((brightness_controller, frame_capturer, als_tx))
}

0 comments on commit 4767519

Please sign in to comment.