linux-rust: optimize for size and add cli options

This commit is contained in:
Kavish Devar
2025-10-22 20:02:20 +05:30
parent 221680ff32
commit e5c2419ef6
4 changed files with 165 additions and 2920 deletions

2950
linux-rust/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,20 @@ uuid = "1.18.1"
log = "0.4.28" log = "0.4.28"
dbus = "0.9.9" dbus = "0.9.9"
hex = "0.4.3" hex = "0.4.3"
iced = {version = "0.13.1", features = ["tokio", "auto-detect-theme"]} # iced = {version = "0.13.1", features = ["tokio", "auto-detect-theme"]}
libpulse-binding = "2.30.1" libpulse-binding = "2.30.1"
ksni = "0.3.1" ksni = "0.3.1"
image = "0.25.8" image = "0.25.8"
imageproc = "0.25.0" imageproc = "0.25.0"
ab_glyph = "0.2.32" ab_glyph = "0.2.32"
clap = { version = "4.5.50", features = ["derive"] }
[profile.release]
opt-level = "s"
lto = true
codegen-units = 1
panic = "abort"
[profile.release-stripped]
inherits = "release"
strip = true

View File

@@ -18,7 +18,7 @@ pub struct AirPodsDevice {
} }
impl AirPodsDevice { impl AirPodsDevice {
pub async fn new(mac_address: Address, tray_handle: Handle<MyTray>) -> Self { pub async fn new(mac_address: Address, tray_handle: Option<Handle<MyTray>>) -> Self {
info!("Creating new AirPodsDevice for {}", mac_address); info!("Creating new AirPodsDevice for {}", mac_address);
let mut aacp_manager = AACPManager::new(); let mut aacp_manager = AACPManager::new();
aacp_manager.connect(mac_address).await; aacp_manager.connect(mac_address).await;
@@ -26,7 +26,9 @@ impl AirPodsDevice {
// let mut att_manager = ATTManager::new(); // let mut att_manager = ATTManager::new();
// att_manager.connect(mac_address).await.expect("Failed to connect ATT"); // att_manager.connect(mac_address).await.expect("Failed to connect ATT");
tray_handle.update(|tray: &mut MyTray| tray.connected = true).await; if let Some(handle) = &tray_handle {
handle.update(|tray: &mut MyTray| tray.connected = true).await;
}
info!("Sending handshake"); info!("Sending handshake");
aacp_manager.send_handshake().await.expect( aacp_manager.send_handshake().await.expect(
@@ -69,7 +71,9 @@ impl AirPodsDevice {
let (command_tx, mut command_rx) = tokio::sync::mpsc::unbounded_channel(); let (command_tx, mut command_rx) = tokio::sync::mpsc::unbounded_channel();
aacp_manager.set_event_channel(tx).await; aacp_manager.set_event_channel(tx).await;
tray_handle.update(|tray: &mut MyTray| tray.command_tx = Some(command_tx.clone())).await; if let Some(handle) = &tray_handle {
handle.update(|tray: &mut MyTray| tray.command_tx = Some(command_tx.clone())).await;
}
let aacp_manager_clone = aacp_manager.clone(); let aacp_manager_clone = aacp_manager.clone();
tokio::spawn(async move { tokio::spawn(async move {
@@ -90,9 +94,11 @@ impl AirPodsDevice {
let tray_handle_clone = tray_handle.clone(); let tray_handle_clone = tray_handle.clone();
tokio::spawn(async move { tokio::spawn(async move {
while let Some(value) = listening_mode_rx.recv().await { while let Some(value) = listening_mode_rx.recv().await {
tray_handle_clone.update(|tray: &mut MyTray| { if let Some(handle) = &tray_handle_clone {
tray.listening_mode = Some(value[0]); handle.update(|tray: &mut MyTray| {
}).await; tray.listening_mode = Some(value[0]);
}).await;
}
} }
}); });
@@ -101,9 +107,11 @@ impl AirPodsDevice {
let tray_handle_clone = tray_handle.clone(); let tray_handle_clone = tray_handle.clone();
tokio::spawn(async move { tokio::spawn(async move {
while let Some(value) = allow_off_rx.recv().await { while let Some(value) = allow_off_rx.recv().await {
tray_handle_clone.update(|tray: &mut MyTray| { if let Some(handle) = &tray_handle_clone {
tray.allow_off_option = Some(value[0]); handle.update(|tray: &mut MyTray| {
}).await; tray.allow_off_option = Some(value[0]);
}).await;
}
} }
}); });
@@ -112,9 +120,11 @@ impl AirPodsDevice {
let tray_handle_clone = tray_handle.clone(); let tray_handle_clone = tray_handle.clone();
tokio::spawn(async move { tokio::spawn(async move {
while let Some(value) = conversation_detect_rx.recv().await { while let Some(value) = conversation_detect_rx.recv().await {
tray_handle_clone.update(|tray: &mut MyTray| { if let Some(handle) = &tray_handle_clone {
tray.conversation_detect_enabled = Some(value[0] == 0x01); handle.update(|tray: &mut MyTray| {
}).await; tray.conversation_detect_enabled = Some(value[0] == 0x01);
}).await;
}
} }
}); });
@@ -146,25 +156,27 @@ impl AirPodsDevice {
} }
AACPEvent::BatteryInfo(battery_info) => { AACPEvent::BatteryInfo(battery_info) => {
debug!("Received BatteryInfo event: {:?}", battery_info); debug!("Received BatteryInfo event: {:?}", battery_info);
tray_handle.update(|tray: &mut MyTray| { if let Some(handle) = &tray_handle {
for b in &battery_info { handle.update(|tray: &mut MyTray| {
match b.component as u8 { for b in &battery_info {
0x02 => { match b.component as u8 {
tray.battery_r = Some(b.level); 0x02 => {
tray.battery_r_status = Some(b.status); tray.battery_r = Some(b.level);
tray.battery_r_status = Some(b.status);
}
0x04 => {
tray.battery_l = Some(b.level);
tray.battery_l_status = Some(b.status);
}
0x08 => {
tray.battery_c = Some(b.level);
tray.battery_c_status = Some(b.status);
}
_ => {}
} }
0x04 => {
tray.battery_l = Some(b.level);
tray.battery_l_status = Some(b.status);
}
0x08 => {
tray.battery_c = Some(b.level);
tray.battery_c_status = Some(b.status);
}
_ => {}
} }
} }).await;
}).await; }
debug!("Updated tray with new battery info"); debug!("Updated tray with new battery info");
} }
AACPEvent::ControlCommand(status) => { AACPEvent::ControlCommand(status) => {

View File

@@ -15,30 +15,44 @@ use crate::airpods::AirPodsDevice;
use bluer::Address; use bluer::Address;
use ksni::TrayMethods; use ksni::TrayMethods;
use crate::ui::tray::MyTray; use crate::ui::tray::MyTray;
use clap::Parser;
#[derive(Parser)]
struct Args {
#[arg(long)]
debug: bool,
#[arg(long)]
no_tray: bool,
}
#[tokio::main] #[tokio::main]
async fn main() -> bluer::Result<()> { async fn main() -> bluer::Result<()> {
let args = Args::parse();
let log_level = if args.debug { "debug" } else { "info" };
if env::var("RUST_LOG").is_err() { if env::var("RUST_LOG").is_err() {
unsafe { env::set_var("RUST_LOG", "debug"); } unsafe { env::set_var("RUST_LOG", log_level); }
} }
env_logger::init(); env_logger::init();
let tray_handle = if args.no_tray {
let tray = MyTray { None
conversation_detect_enabled: None, } else {
battery_l: None, let tray = MyTray {
battery_l_status: None, conversation_detect_enabled: None,
battery_r: None, battery_l: None,
battery_r_status: None, battery_l_status: None,
battery_c: None, battery_r: None,
battery_c_status: None, battery_r_status: None,
connected: false, battery_c: None,
listening_mode: None, battery_c_status: None,
allow_off_option: None, connected: false,
command_tx: None, listening_mode: None,
allow_off_option: None,
command_tx: None,
};
let handle = tray.spawn().await.unwrap();
Some(handle)
}; };
let handle = tray.spawn().await.unwrap();
let session = bluer::Session::new().await?; let session = bluer::Session::new().await?;
let adapter = session.default_adapter().await?; let adapter = session.default_adapter().await?;
@@ -51,7 +65,7 @@ async fn main() -> bluer::Result<()> {
Ok(device) => { Ok(device) => {
let name = device.name().await?.unwrap_or_else(|| "Unknown".to_string()); let name = device.name().await?.unwrap_or_else(|| "Unknown".to_string());
info!("Found connected AirPods: {}, initializing.", name); info!("Found connected AirPods: {}, initializing.", name);
let _airpods_device = AirPodsDevice::new(device.address(), handle.clone()).await; let _airpods_device = AirPodsDevice::new(device.address(), tray_handle.clone()).await;
} }
Err(_) => { Err(_) => {
info!("No connected AirPods found."); info!("No connected AirPods found.");
@@ -87,7 +101,7 @@ async fn main() -> bluer::Result<()> {
let Ok(addr_str) = proxy.get::<String>("org.bluez.Device1", "Address") else { return true; }; let Ok(addr_str) = proxy.get::<String>("org.bluez.Device1", "Address") else { return true; };
let Ok(addr) = addr_str.parse::<Address>() else { return true; }; let Ok(addr) = addr_str.parse::<Address>() else { return true; };
info!("AirPods connected: {}, initializing", name); info!("AirPods connected: {}, initializing", name);
let handle_clone = handle.clone(); let handle_clone = tray_handle.clone();
tokio::spawn(async move { tokio::spawn(async move {
let _airpods_device = AirPodsDevice::new(addr, handle_clone).await; let _airpods_device = AirPodsDevice::new(addr, handle_clone).await;
}); });