Add grouped device dropdown for PipeWire with USB/HDMI categorization
Backend changes: - Add device_bus and is_hardware fields to AudioDevice - Parse PipeWire Flags (HARDWARE) and device.bus property from pactl output Frontend changes: - DeviceDropdown now supports both ALSA and PipeWire backends - ALSA grouping: Defaults, Bit-perfect, Plugin Hardware, Other - PipeWire grouping: Defaults, USB Audio (BP capable), HDMI/DisplayPort, Other HW, Virtual - BP badge shown for USB Audio devices in PipeWire mode
This commit is contained in:
1 parent
0ccdd9981f
commit
f67b13e27e
5 files changed
+110
-48
No files matched your search
@@ -204,6 +204,8 @@ impl AlsaBackend {
|
||||
is_default: false,
|
||||
max_sample_rate: Some(384000), // Assume high sample rate capability
|
||||
supported_sample_rates: None, // Can't detect without CPAL access
|
||||
device_bus: None,
|
||||
is_hardware: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -235,6 +237,8 @@ impl AlsaBackend {
|
||||
is_default: false,
|
||||
max_sample_rate,
|
||||
supported_sample_rates,
|
||||
device_bus: None,
|
||||
is_hardware: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -247,6 +251,8 @@ impl AlsaBackend {
|
||||
is_default: false,
|
||||
max_sample_rate: Some(384000),
|
||||
supported_sample_rates: None, // plughw can convert, so all rates are "supported"
|
||||
device_bus: None,
|
||||
is_hardware: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -326,6 +332,8 @@ impl AlsaBackend {
|
||||
is_default,
|
||||
max_sample_rate,
|
||||
supported_sample_rates,
|
||||
device_bus: None,
|
||||
is_hardware: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,12 @@ pub struct AudioDevice {
|
||||
/// Supported sample rates (common audio rates that the device supports)
|
||||
/// Contains values like 44100, 48000, 88200, 96000, 176400, 192000, etc.
|
||||
pub supported_sample_rates: Option<Vec<u32>>,
|
||||
|
||||
/// Device bus type (for PipeWire): "usb", "pci", "bluetooth", or None
|
||||
pub device_bus: Option<String>,
|
||||
|
||||
/// Whether this is a hardware device (has HARDWARE flag in PipeWire)
|
||||
pub is_hardware: bool,
|
||||
}
|
||||
|
||||
/// Audio backend configuration
|
||||
|
||||
@@ -59,6 +59,8 @@ impl PipeWireBackend {
|
||||
let mut current_name: Option<String> = None;
|
||||
let mut current_description: Option<String> = None;
|
||||
let mut current_max_rate: Option<u32> = None;
|
||||
let mut current_is_hardware: bool = false;
|
||||
let mut current_device_bus: Option<String> = None;
|
||||
|
||||
for line in stdout.lines() {
|
||||
let line = line.trim();
|
||||
@@ -74,13 +76,20 @@ impl PipeWireBackend {
|
||||
is_default,
|
||||
max_sample_rate: current_max_rate.take(),
|
||||
supported_sample_rates: None, // PipeWire handles sample rate conversion
|
||||
device_bus: current_device_bus.take(),
|
||||
is_hardware: current_is_hardware,
|
||||
});
|
||||
}
|
||||
current_max_rate = None;
|
||||
current_is_hardware = false;
|
||||
current_device_bus = None;
|
||||
} else if line.starts_with("Name:") {
|
||||
current_name = Some(line.trim_start_matches("Name:").trim().to_string());
|
||||
} else if line.starts_with("Description:") {
|
||||
current_description = Some(line.trim_start_matches("Description:").trim().to_string());
|
||||
} else if line.starts_with("Flags:") {
|
||||
// Check for HARDWARE flag
|
||||
current_is_hardware = line.contains("HARDWARE");
|
||||
} else if line.contains("Sample Specification:") {
|
||||
// Try to parse sample rate from lines like "Sample Specification: s32le 2ch 192000Hz"
|
||||
if let Some(hz_pos) = line.find("Hz") {
|
||||
@@ -91,6 +100,10 @@ impl PipeWireBackend {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if line.starts_with("device.bus = ") {
|
||||
// Parse device.bus property (e.g., "usb", "pci", "bluetooth")
|
||||
let bus = line.trim_start_matches("device.bus = ").trim_matches('"').to_string();
|
||||
current_device_bus = Some(bus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,13 +117,15 @@ impl PipeWireBackend {
|
||||
is_default,
|
||||
max_sample_rate: current_max_rate,
|
||||
supported_sample_rates: None, // PipeWire handles sample rate conversion
|
||||
device_bus: current_device_bus,
|
||||
is_hardware: current_is_hardware,
|
||||
});
|
||||
}
|
||||
|
||||
log::info!("[PipeWire Backend] Enumerated {} devices via pactl", devices.len());
|
||||
for (idx, dev) in devices.iter().enumerate() {
|
||||
log::info!(" [{}] {} (id: {}, max_rate: {:?})",
|
||||
idx, dev.name, dev.id, dev.max_sample_rate);
|
||||
log::info!(" [{}] {} (id: {}, bus: {:?}, hw: {})",
|
||||
idx, dev.name, dev.id, dev.device_bus, dev.is_hardware);
|
||||
}
|
||||
|
||||
Ok(devices)
|
||||
|
||||
Reference in new issue
Block a user