fix: HiFi Wizard now detects real DAC sample rates from /proc/asound

v2_query_dac_capabilities was returning hardcoded sample rates
(44.1-192kHz including 176.4kHz) instead of querying the actual
hardware. This caused incorrect configuration for DACs that don't
support all rates (e.g. DacMagic Plus doesn't support 176.4kHz).

Now queries /proc/asound/cardN/stream0 via PipeWire sink mapping
or ALSA device ID to get the real discrete rates from the USB
descriptor. Falls back to defaults only if detection fails.

cc
This commit is contained in:
vicrodh committed 2026-03-19 12:41:24 -06:00
1 parent b795d59f1f
commit 1f1e729db8
2 files changed
+33 -2

No files matched your search

+1 -1
View File
@@ -79,7 +79,7 @@ impl PipeWireBackend {
/// Query the DAC's supported sample rates from /proc/asound/cardN/stream0. /// Query the DAC's supported sample rates from /proc/asound/cardN/stream0.
/// Returns None if rates can't be determined (non-USB device, continuous range, etc.) /// Returns None if rates can't be determined (non-USB device, continuous range, etc.)
fn get_sink_supported_rates(sink_name: &str) -> Option<Vec<u32>> { pub fn get_sink_supported_rates(sink_name: &str) -> Option<Vec<u32>> {
let alsa_card = Self::get_alsa_card_for_sink(sink_name)?; let alsa_card = Self::get_alsa_card_for_sink(sink_name)?;
let stream_path = format!("/proc/asound/card{}/stream0", alsa_card); let stream_path = format!("/proc/asound/card{}/stream0", alsa_card);
+32 -1
View File
@@ -2380,9 +2380,12 @@ pub fn v2_get_default_device_name(backendType: AudioBackendType) -> Result<Optio
#[tauri::command] #[tauri::command]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn v2_query_dac_capabilities(nodeName: String) -> Result<DacCapabilities, String> { pub fn v2_query_dac_capabilities(nodeName: String) -> Result<DacCapabilities, String> {
// Default fallback — only used if all detection methods fail
let fallback_rates = vec![44100, 48000, 88200, 96000, 176400, 192000];
let mut capabilities = DacCapabilities { let mut capabilities = DacCapabilities {
node_name: nodeName.clone(), node_name: nodeName.clone(),
sample_rates: vec![44100, 48000, 88200, 96000, 176400, 192000], sample_rates: fallback_rates.clone(),
formats: vec![ formats: vec![
"S16LE".to_string(), "S16LE".to_string(),
"S24LE".to_string(), "S24LE".to_string(),
@@ -2393,6 +2396,7 @@ pub fn v2_query_dac_capabilities(nodeName: String) -> Result<DacCapabilities, St
error: None, error: None,
}; };
// Try PipeWire backend: get device description and ALSA card for rate detection
if let Ok(backend) = BackendManager::create_backend(AudioBackendType::PipeWire) { if let Ok(backend) = BackendManager::create_backend(AudioBackendType::PipeWire) {
if let Ok(devices) = backend.enumerate_devices() { if let Ok(devices) = backend.enumerate_devices() {
if let Some(device) = devices if let Some(device) = devices
@@ -2407,6 +2411,33 @@ pub fn v2_query_dac_capabilities(nodeName: String) -> Result<DacCapabilities, St
} }
} }
// Detect real sample rates from /proc/asound via PipeWire sink -> ALSA card mapping
if let Some(rates) =
crate::audio::pipewire_backend::PipeWireBackend::get_sink_supported_rates(&nodeName)
{
log::info!(
"[HiFi Wizard] Detected sample rates for {}: {:?}",
nodeName,
rates
);
capabilities.sample_rates = rates;
} else {
// Fallback: try ALSA device ID directly (for ALSA Direct backend)
if let Some(rates) = qbz_audio::get_device_supported_rates(&nodeName) {
log::info!(
"[HiFi Wizard] Detected sample rates via ALSA for {}: {:?}",
nodeName,
rates
);
capabilities.sample_rates = rates;
} else {
log::warn!(
"[HiFi Wizard] Could not detect sample rates for {}, using defaults",
nodeName
);
}
}
Ok(capabilities) Ok(capabilities)
} }