fix(audio): replace deprecated CPAL name() usage with description()

cx
This commit is contained in:
vicrodh committed 2026-03-01 10:44:54 -06:00
1 parent 0f642d0176
commit 8e104a3f3e
5 files changed
+98 -66

No files matched your search

+8 -5
View File
@@ -480,8 +480,8 @@ impl AlsaBackend {
if let Ok(output_devices) = self.host.output_devices() {
for device in output_devices {
if let Ok(name) = device.name() {
map.insert(name, device);
if let Ok(description) = device.description() {
map.insert(description.name().to_string(), device);
}
}
}
@@ -815,9 +815,9 @@ impl AudioBackend for AlsaBackend {
.output_devices()
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
.find(|d| {
d.name()
d.description()
.ok()
.map(|n| n == *device_id)
.map(|desc| desc.name() == device_id.as_str())
.unwrap_or(false)
})
.ok_or_else(|| format!("Device '{}' not found", device_id))?
@@ -828,7 +828,10 @@ impl AudioBackend for AlsaBackend {
.ok_or("No default ALSA device available")?
};
let device_name = device.name().unwrap_or_else(|_| "unknown".to_string());
let device_name = device
.description()
.map(|desc| desc.name().to_string())
.unwrap_or_else(|_| "unknown".to_string());
log::info!("[ALSA Backend] Using device: {}", device_name);
// Check if device supports this configuration
+9 -3
View File
@@ -380,16 +380,22 @@ impl AudioBackend for PipeWireBackend {
.output_devices()
.map_err(|e| format!("Failed to enumerate CPAL devices: {}", e))?
.find(|d| {
d.name()
d.description()
.ok()
.map(|n| n == "pulse" || n == "pipewire")
.map(|desc| {
let device_name = desc.name();
device_name == "pulse" || device_name == "pipewire"
})
.unwrap_or(false)
})
.ok_or_else(|| {
"Could not find 'pulse' or 'pipewire' CPAL device. Is PulseAudio/PipeWire running?".to_string()
})?;
let device_name = device.name().unwrap_or_else(|_| "unknown".to_string());
let device_name = device
.description()
.map(|desc| desc.name().to_string())
.unwrap_or_else(|_| "unknown".to_string());
log::info!("[PipeWire Backend] Using CPAL device: {}", device_name);
// Create output stream with custom sample rate configuration
+15 -8
View File
@@ -135,6 +135,13 @@ struct AudioSpecs {
channels: u16,
}
fn cpal_device_name(device: &rodio::cpal::Device) -> Option<String> {
device
.description()
.ok()
.map(|description| description.name().to_string())
}
fn decode_with_symphonia(data: &[u8]) -> Result<AudioSpecs, String> {
let source = Box::new(CursorMediaSource::new(data.to_vec())) as Box<dyn MediaSource>;
let mss = MediaSourceStream::new(source, Default::default());
@@ -867,7 +874,7 @@ impl Player {
let found = host.output_devices()
.ok()
.and_then(|mut devices| {
devices.find(|d| d.name().ok().as_ref() == Some(name))
devices.find(|d| cpal_device_name(d).as_deref() == Some(name.as_str()))
});
match found {
@@ -891,7 +898,7 @@ impl Player {
let device = match device {
Some(d) => {
if let Ok(name) = d.name() {
if let Some(name) = cpal_device_name(&d) {
log::info!("Using audio device: {}", name);
state.set_current_device(Some(name));
}
@@ -1061,7 +1068,7 @@ impl Player {
let found = host.output_devices()
.ok()
.and_then(|mut devices| {
devices.find(|d| d.name().ok().as_ref() == Some(name))
devices.find(|d| cpal_device_name(d).as_deref() == Some(name.as_str()))
});
match found {
@@ -1091,7 +1098,7 @@ impl Player {
};
// Set current device name
if let Ok(name) = device.name() {
if let Some(name) = cpal_device_name(&device) {
log::info!("Using audio device: {}", name);
thread_state.set_current_device(Some(name));
}
@@ -1111,7 +1118,7 @@ impl Player {
host.output_devices()
.ok()
.and_then(|mut devices| {
devices.find(|d| d.name().ok().as_ref() == Some(name))
devices.find(|d| cpal_device_name(d).as_deref() == Some(name.as_str()))
})
.or_else(|| {
log::warn!("Device '{}' not found, using default", name);
@@ -1128,7 +1135,7 @@ impl Player {
return;
};
if let Ok(name) = device.name() {
if let Some(name) = cpal_device_name(&device) {
thread_state.set_current_device(Some(name));
}
@@ -1405,7 +1412,7 @@ impl Player {
host.output_devices()
.ok()
.and_then(|mut devices| {
devices.find(|d| d.name().ok().as_ref() == Some(name))
devices.find(|d| cpal_device_name(d).as_deref() == Some(name.as_str()))
})
.or_else(|| host.default_output_device())
} else {
@@ -1418,7 +1425,7 @@ impl Player {
return;
};
if let Ok(name) = device.name() {
if let Some(name) = cpal_device_name(&device) {
thread_state.set_current_device(Some(name));
}
+65 -50
View File
@@ -1234,16 +1234,27 @@ fn get_pipewire_device_descriptions() -> std::collections::HashMap<String, Strin
std::collections::HashMap::new()
}
fn cpal_device_name(device: &rodio::cpal::Device) -> Option<String> {
use rodio::cpal::traits::DeviceTrait;
device
.description()
.ok()
.map(|description| description.name().to_string())
}
/// Get available audio output devices
#[tauri::command]
pub fn get_audio_devices() -> Result<Vec<AudioDevice>, String> {
log::info!("Command: get_audio_devices");
use rodio::cpal::traits::{DeviceTrait, HostTrait};
use rodio::cpal::traits::HostTrait;
let host = rodio::cpal::default_host();
let default_device_name = host.default_output_device().and_then(|d| d.name().ok());
let default_device_name = host
.default_output_device()
.and_then(|d| cpal_device_name(&d));
// Get friendly names from PipeWire/PulseAudio
let friendly_names = get_pipewire_device_descriptions();
@@ -1252,7 +1263,7 @@ pub fn get_audio_devices() -> Result<Vec<AudioDevice>, String> {
.output_devices()
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
.filter_map(|device| {
device.name().ok().map(|name| {
cpal_device_name(&device).map(|name| {
let is_default = default_device_name
.as_ref()
.map(|d| d == &name)
@@ -1376,7 +1387,9 @@ pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
let host = rodio::cpal::default_host();
// Get default device name from CPAL
let default_device_name = host.default_output_device().and_then(|d| d.name().ok());
let default_device_name = host
.default_output_device()
.and_then(|d| cpal_device_name(&d));
log::info!("CPAL default device: {:?}", default_device_name);
@@ -1386,48 +1399,48 @@ pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
.enumerate()
.filter_map(|(idx, device)| {
match device.name() {
Ok(name) => {
let is_default = default_device_name
.as_ref()
.map(|d| d == &name)
.unwrap_or(false);
// Get detailed device info for logging
let configs_info = device
.supported_output_configs()
.ok()
.map(|configs| {
let config_strs: Vec<String> = configs
.take(3) // Just first 3 configs for brevity
.map(|c| format!("{}ch/{}Hz", c.channels(), c.max_sample_rate()))
.collect();
config_strs.join(", ")
})
.unwrap_or_else(|| "no configs".to_string());
log::info!(
" [{}] Device: '{}' (default: {}) - Configs: {}",
idx,
name,
is_default,
configs_info
);
// CRITICAL: Use CPAL device name as both name and description
// This ensures the name we save is the exact name CPAL can find later
Some(PipewireSink {
name: name.clone(),
description: name, // CPAL names are already user-friendly in PipeWire
volume: None, // Volume not available via CPAL
is_default,
})
let name = match cpal_device_name(&device) {
Some(name) => name,
None => {
log::warn!(" [{}] Failed to get device description", idx);
return None;
}
Err(e) => {
log::warn!(" [{}] Failed to get device name: {}", idx, e);
None
}
}
};
let is_default = default_device_name
.as_ref()
.map(|d| d == &name)
.unwrap_or(false);
// Get detailed device info for logging
let configs_info = device
.supported_output_configs()
.ok()
.map(|configs| {
let config_strs: Vec<String> = configs
.take(3) // Just first 3 configs for brevity
.map(|c| format!("{}ch/{}Hz", c.channels(), c.max_sample_rate()))
.collect();
config_strs.join(", ")
})
.unwrap_or_else(|| "no configs".to_string());
log::info!(
" [{}] Device: '{}' (default: {}) - Configs: {}",
idx,
name,
is_default,
configs_info
);
// CRITICAL: Use CPAL device name as both name and description
// This ensures the name we save is the exact name CPAL can find later
Some(PipewireSink {
name: name.clone(),
description: name, // CPAL names are already user-friendly in PipeWire
volume: None, // Volume not available via CPAL
is_default,
})
})
.collect();
@@ -1443,17 +1456,19 @@ pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
log::info!("Command: get_pipewire_sinks (non-Linux, using cpal)");
use rodio::cpal::traits::{DeviceTrait, HostTrait};
use rodio::cpal::traits::HostTrait;
let host = rodio::cpal::default_host();
let default_device_name = host.default_output_device().and_then(|d| d.name().ok());
let default_device_name = host
.default_output_device()
.and_then(|d| cpal_device_name(&d));
let sinks: Vec<PipewireSink> = host
.output_devices()
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
.filter_map(|device| {
device.name().ok().map(|name| {
cpal_device_name(&device).map(|name| {
let is_default = default_device_name
.as_ref()
.map(|d| d == &name)
@@ -1506,7 +1521,7 @@ pub fn set_pipewire_default_sink(_sink_name: String) -> Result<(), String> {
/// DEBUG: Get CPAL device names for comparison with PipeWire sinks
#[tauri::command]
pub fn debug_get_cpal_devices() -> Result<Vec<String>, String> {
use rodio::cpal::traits::{DeviceTrait, HostTrait};
use rodio::cpal::traits::HostTrait;
log::info!("Command: debug_get_cpal_devices");
@@ -1515,7 +1530,7 @@ pub fn debug_get_cpal_devices() -> Result<Vec<String>, String> {
let devices: Vec<String> = host
.output_devices()
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
.filter_map(|device| device.name().ok())
.filter_map(|device| cpal_device_name(&device))
.collect();
log::info!("CPAL devices: {:?}", devices);
+1
View File
@@ -37,6 +37,7 @@ pub mod network;
pub mod offline;
pub mod offline_cache;
pub mod playback_context;
#[allow(deprecated)]
pub mod player;
pub mod playlist_import;
pub mod plex;