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() {
|
if let Ok(output_devices) = self.host.output_devices() {
|
||||||
for device in output_devices {
|
for device in output_devices {
|
||||||
if let Ok(name) = device.name() {
|
if let Ok(description) = device.description() {
|
||||||
map.insert(name, device);
|
map.insert(description.name().to_string(), device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,9 +815,9 @@ impl AudioBackend for AlsaBackend {
|
|||||||
.output_devices()
|
.output_devices()
|
||||||
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
||||||
.find(|d| {
|
.find(|d| {
|
||||||
d.name()
|
d.description()
|
||||||
.ok()
|
.ok()
|
||||||
.map(|n| n == *device_id)
|
.map(|desc| desc.name() == device_id.as_str())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
.ok_or_else(|| format!("Device '{}' not found", device_id))?
|
.ok_or_else(|| format!("Device '{}' not found", device_id))?
|
||||||
@@ -828,7 +828,10 @@ impl AudioBackend for AlsaBackend {
|
|||||||
.ok_or("No default ALSA device available")?
|
.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);
|
log::info!("[ALSA Backend] Using device: {}", device_name);
|
||||||
|
|
||||||
// Check if device supports this configuration
|
// Check if device supports this configuration
|
||||||
|
|||||||
@@ -380,16 +380,22 @@ impl AudioBackend for PipeWireBackend {
|
|||||||
.output_devices()
|
.output_devices()
|
||||||
.map_err(|e| format!("Failed to enumerate CPAL devices: {}", e))?
|
.map_err(|e| format!("Failed to enumerate CPAL devices: {}", e))?
|
||||||
.find(|d| {
|
.find(|d| {
|
||||||
d.name()
|
d.description()
|
||||||
.ok()
|
.ok()
|
||||||
.map(|n| n == "pulse" || n == "pipewire")
|
.map(|desc| {
|
||||||
|
let device_name = desc.name();
|
||||||
|
device_name == "pulse" || device_name == "pipewire"
|
||||||
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
"Could not find 'pulse' or 'pipewire' CPAL device. Is PulseAudio/PipeWire running?".to_string()
|
"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);
|
log::info!("[PipeWire Backend] Using CPAL device: {}", device_name);
|
||||||
|
|
||||||
// Create output stream with custom sample rate configuration
|
// Create output stream with custom sample rate configuration
|
||||||
|
|||||||
@@ -135,6 +135,13 @@ struct AudioSpecs {
|
|||||||
channels: u16,
|
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> {
|
fn decode_with_symphonia(data: &[u8]) -> Result<AudioSpecs, String> {
|
||||||
let source = Box::new(CursorMediaSource::new(data.to_vec())) as Box<dyn MediaSource>;
|
let source = Box::new(CursorMediaSource::new(data.to_vec())) as Box<dyn MediaSource>;
|
||||||
let mss = MediaSourceStream::new(source, Default::default());
|
let mss = MediaSourceStream::new(source, Default::default());
|
||||||
@@ -867,7 +874,7 @@ impl Player {
|
|||||||
let found = host.output_devices()
|
let found = host.output_devices()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|mut devices| {
|
.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 {
|
match found {
|
||||||
@@ -891,7 +898,7 @@ impl Player {
|
|||||||
|
|
||||||
let device = match device {
|
let device = match device {
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
if let Ok(name) = d.name() {
|
if let Some(name) = cpal_device_name(&d) {
|
||||||
log::info!("Using audio device: {}", name);
|
log::info!("Using audio device: {}", name);
|
||||||
state.set_current_device(Some(name));
|
state.set_current_device(Some(name));
|
||||||
}
|
}
|
||||||
@@ -1061,7 +1068,7 @@ impl Player {
|
|||||||
let found = host.output_devices()
|
let found = host.output_devices()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|mut devices| {
|
.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 {
|
match found {
|
||||||
@@ -1091,7 +1098,7 @@ impl Player {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Set current device name
|
// Set current device name
|
||||||
if let Ok(name) = device.name() {
|
if let Some(name) = cpal_device_name(&device) {
|
||||||
log::info!("Using audio device: {}", name);
|
log::info!("Using audio device: {}", name);
|
||||||
thread_state.set_current_device(Some(name));
|
thread_state.set_current_device(Some(name));
|
||||||
}
|
}
|
||||||
@@ -1111,7 +1118,7 @@ impl Player {
|
|||||||
host.output_devices()
|
host.output_devices()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|mut devices| {
|
.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(|| {
|
.or_else(|| {
|
||||||
log::warn!("Device '{}' not found, using default", name);
|
log::warn!("Device '{}' not found, using default", name);
|
||||||
@@ -1128,7 +1135,7 @@ impl Player {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(name) = device.name() {
|
if let Some(name) = cpal_device_name(&device) {
|
||||||
thread_state.set_current_device(Some(name));
|
thread_state.set_current_device(Some(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1405,7 +1412,7 @@ impl Player {
|
|||||||
host.output_devices()
|
host.output_devices()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|mut devices| {
|
.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())
|
.or_else(|| host.default_output_device())
|
||||||
} else {
|
} else {
|
||||||
@@ -1418,7 +1425,7 @@ impl Player {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(name) = device.name() {
|
if let Some(name) = cpal_device_name(&device) {
|
||||||
thread_state.set_current_device(Some(name));
|
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()
|
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
|
/// Get available audio output devices
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_audio_devices() -> Result<Vec<AudioDevice>, String> {
|
pub fn get_audio_devices() -> Result<Vec<AudioDevice>, String> {
|
||||||
log::info!("Command: get_audio_devices");
|
log::info!("Command: get_audio_devices");
|
||||||
|
|
||||||
use rodio::cpal::traits::{DeviceTrait, HostTrait};
|
use rodio::cpal::traits::HostTrait;
|
||||||
|
|
||||||
let host = rodio::cpal::default_host();
|
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
|
// Get friendly names from PipeWire/PulseAudio
|
||||||
let friendly_names = get_pipewire_device_descriptions();
|
let friendly_names = get_pipewire_device_descriptions();
|
||||||
@@ -1252,7 +1263,7 @@ pub fn get_audio_devices() -> Result<Vec<AudioDevice>, String> {
|
|||||||
.output_devices()
|
.output_devices()
|
||||||
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
||||||
.filter_map(|device| {
|
.filter_map(|device| {
|
||||||
device.name().ok().map(|name| {
|
cpal_device_name(&device).map(|name| {
|
||||||
let is_default = default_device_name
|
let is_default = default_device_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|d| d == &name)
|
.map(|d| d == &name)
|
||||||
@@ -1376,7 +1387,9 @@ pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
|
|||||||
let host = rodio::cpal::default_host();
|
let host = rodio::cpal::default_host();
|
||||||
|
|
||||||
// Get default device name from CPAL
|
// 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);
|
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))?
|
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(idx, device)| {
|
.filter_map(|(idx, device)| {
|
||||||
match device.name() {
|
let name = match cpal_device_name(&device) {
|
||||||
Ok(name) => {
|
Some(name) => name,
|
||||||
let is_default = default_device_name
|
None => {
|
||||||
.as_ref()
|
log::warn!(" [{}] Failed to get device description", idx);
|
||||||
.map(|d| d == &name)
|
return None;
|
||||||
.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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
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();
|
.collect();
|
||||||
|
|
||||||
@@ -1443,17 +1456,19 @@ pub fn get_pipewire_sinks() -> Result<Vec<PipewireSink>, String> {
|
|||||||
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)");
|
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 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
|
let sinks: Vec<PipewireSink> = host
|
||||||
.output_devices()
|
.output_devices()
|
||||||
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
||||||
.filter_map(|device| {
|
.filter_map(|device| {
|
||||||
device.name().ok().map(|name| {
|
cpal_device_name(&device).map(|name| {
|
||||||
let is_default = default_device_name
|
let is_default = default_device_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|d| d == &name)
|
.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
|
/// DEBUG: Get CPAL device names for comparison with PipeWire sinks
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn debug_get_cpal_devices() -> Result<Vec<String>, String> {
|
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");
|
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
|
let devices: Vec<String> = host
|
||||||
.output_devices()
|
.output_devices()
|
||||||
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
.map_err(|e| format!("Failed to enumerate devices: {}", e))?
|
||||||
.filter_map(|device| device.name().ok())
|
.filter_map(|device| cpal_device_name(&device))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
log::info!("CPAL devices: {:?}", devices);
|
log::info!("CPAL devices: {:?}", devices);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ pub mod network;
|
|||||||
pub mod offline;
|
pub mod offline;
|
||||||
pub mod offline_cache;
|
pub mod offline_cache;
|
||||||
pub mod playback_context;
|
pub mod playback_context;
|
||||||
|
#[allow(deprecated)]
|
||||||
pub mod player;
|
pub mod player;
|
||||||
pub mod playlist_import;
|
pub mod playlist_import;
|
||||||
pub mod plex;
|
pub mod plex;
|
||||||
|
|||||||
Reference in new issue
Block a user