feat: initiale Implementierung von corsairctl
Rust CLI-Tool für Corsair Bragi-Geräte (HS80 RGB Wireless, etc.). Implementiert Protokoll-Kern, HID-Kommunikation, BragiDevice mit RAII-Lifecycle, CLI-Subcommands (battery, sidetone, led, info, json, udev), ALSA-Sidetone-Steuerung und Waybar-JSON-Output. 24 Unit-Tests für Packet-Bau, Response-Parsing und Property-Enums.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
// ABOUTME: ALSA-Mixer Integration für Sidetone-Steuerung.
|
||||
// ABOUTME: Liest und setzt den Sidetone-Wert über den ALSA-Mixer der Corsair-Soundkarte.
|
||||
|
||||
use alsa::mixer::{Mixer, SelemChannelId, SelemId};
|
||||
|
||||
use crate::error::Result;
|
||||
|
||||
const CARD_NAME: &str = "Gaming";
|
||||
const SIDETONE_VOLUME: &str = "Sidetone Playback Volume";
|
||||
const SIDETONE_SWITCH: &str = "Sidetone Playback Switch";
|
||||
|
||||
/// Findet die ALSA-Card-Nummer für die Corsair Gaming Soundkarte.
|
||||
fn find_card() -> Result<String> {
|
||||
// ALSA-Cards durchiterieren
|
||||
for card_idx in 0..32 {
|
||||
let name = format!("hw:{card_idx}");
|
||||
if let Ok(ctl) = alsa::Ctl::new(&name, false) {
|
||||
if let Ok(info) = ctl.card_info() {
|
||||
let card_name = info.get_name().unwrap_or_default();
|
||||
if card_name.contains(CARD_NAME) {
|
||||
return Ok(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(crate::error::CorsairError::DeviceNotFound)
|
||||
}
|
||||
|
||||
/// Liest den aktuellen Sidetone-Level (0-23).
|
||||
pub fn get_level() -> Result<i64> {
|
||||
let card = find_card()?;
|
||||
let mixer = Mixer::new(&card, false)?;
|
||||
|
||||
let selem_id = SelemId::new(SIDETONE_VOLUME, 0);
|
||||
let selem = mixer
|
||||
.find_selem(&selem_id)
|
||||
.ok_or(crate::error::CorsairError::DeviceNotFound)?;
|
||||
|
||||
let value = selem.get_playback_volume(SelemChannelId::FrontLeft)?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Setzt den Sidetone-Level (0-23).
|
||||
pub fn set_level(level: i64) -> Result<()> {
|
||||
let card = find_card()?;
|
||||
let mixer = Mixer::new(&card, false)?;
|
||||
|
||||
// Volume setzen
|
||||
let volume_id = SelemId::new(SIDETONE_VOLUME, 0);
|
||||
let volume_elem = mixer
|
||||
.find_selem(&volume_id)
|
||||
.ok_or(crate::error::CorsairError::DeviceNotFound)?;
|
||||
|
||||
volume_elem.set_playback_volume_all(level)?;
|
||||
|
||||
// Switch aktivieren falls Level > 0
|
||||
let switch_id = SelemId::new(SIDETONE_SWITCH, 0);
|
||||
if let Some(switch_elem) = mixer.find_selem(&switch_id) {
|
||||
let enabled = if level > 0 { 1 } else { 0 };
|
||||
let _ = switch_elem.set_playback_switch_all(enabled);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user