corsairctl/src/sidetone.rs
nevaforget a9d526023d fix: Audit-Findings behoben (Perf, Security, Quality)
- Sleep vor HID-Reads entfernt — read_timeout reicht als
  Synchronisation, spart ~300ms pro Aufruf
- udev-Regel: MODE 0660 + GROUP plugdev statt world-writable 0666
- Eigener CorsairError::SidetoneNotFound für fehlende ALSA-Controls
- Response-Validierung vorbereitet (parse_response_validated),
  Korrelation noch deaktiviert da Response-Format andere Endpoint-IDs
  nutzt als das Request-Format (0x00/0x01 vs 0x08/0x09)
- Protokoll-Doku zum Response-Format korrigiert
- 18 neue Tests für output.rs (Waybar-JSON Formatierung + Grenzwerte)
2026-03-27 23:11:50 +01:00

56 lines
1.7 KiB
Rust

// 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 SIDETONE_CONTROL: &str = "Sidetone";
/// Findet die ALSA-Card mit einem Sidetone-Control.
///
/// Sucht nach der Karte, die ein "Sidetone" Control hat,
/// statt sich auf den Kartennamen zu verlassen (der kann abgeschnitten sein).
fn find_card() -> Result<String> {
for card in alsa::card::Iter::new().flatten() {
let name = format!("hw:{}", card.get_index());
if let Ok(mixer) = Mixer::new(&name, false) {
let selem_id = SelemId::new(SIDETONE_CONTROL, 0);
if mixer.find_selem(&selem_id).is_some() {
return Ok(name);
}
}
}
Err(crate::error::CorsairError::SidetoneNotFound)
}
/// 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_CONTROL, 0);
let selem = mixer
.find_selem(&selem_id)
.ok_or(crate::error::CorsairError::SidetoneNotFound)?;
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_CONTROL, 0);
let volume_elem = mixer
.find_selem(&volume_id)
.ok_or(crate::error::CorsairError::SidetoneNotFound)?;
volume_elem.set_playback_volume_all(level)?;
Ok(())
}