- 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)
56 lines
1.7 KiB
Rust
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(())
|
|
}
|