fix(audio): replace deprecated CPAL name() usage with description()
cx
This commit is contained in:
5 files changed
+98
-66
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user