fix(audio): return format_id from play_track and set device name for backend system
1. play_track now returns PlayTrackResult with format_id from Qobuz API - Returns actual format (5=MP3, 6=FLAC16, 7=FLAC24, 27=Hi-Res) - Returns None for cache hits (format unknown) 2. Frontend updates track.format based on format_id - QualityBadge can now correctly show "MP3" when format_id=5 - Previously badge showed "CD" even for MP3 because format was empty 3. Device name now set after backend system init - PipeWire and ALSA backends now set current_device from settings - Fixes tooltip showing no device when using backend system
This commit is contained in:
1 parent
e08593af41
commit
52bde38d9f
3 files changed
+68
-10
No files matched your search
@@ -24,6 +24,14 @@ fn parse_quality(quality_str: Option<&str>) -> Quality {
|
||||
}
|
||||
}
|
||||
|
||||
/// Result from play_track command with format info
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct PlayTrackResult {
|
||||
/// The actual format_id returned by Qobuz (5=MP3, 6=FLAC 16-bit, 7=24-bit, 27=Hi-Res)
|
||||
/// None when playing from cache (format unknown)
|
||||
pub format_id: Option<u32>,
|
||||
}
|
||||
|
||||
/// Play a track by ID (with caching support)
|
||||
#[tauri::command]
|
||||
pub async fn play_track(
|
||||
@@ -33,7 +41,7 @@ pub async fn play_track(
|
||||
state: State<'_, AppState>,
|
||||
offline_cache: State<'_, OfflineCacheState>,
|
||||
audio_settings: State<'_, AudioSettingsState>,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<PlayTrackResult, String> {
|
||||
let preferred_quality = parse_quality(quality.as_deref());
|
||||
log::info!(
|
||||
"Command: play_track {} (duration: {:?}s, quality_str={:?}, parsed={:?}, format_id={})",
|
||||
@@ -73,7 +81,7 @@ pub async fn play_track(
|
||||
skip_prefetch,
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
return Ok(PlayTrackResult { format_id: None });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +108,7 @@ pub async fn play_track(
|
||||
skip_prefetch,
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
return Ok(PlayTrackResult { format_id: None });
|
||||
}
|
||||
|
||||
// Check if track is in playback cache (L2 - disk)
|
||||
@@ -128,7 +136,7 @@ pub async fn play_track(
|
||||
skip_prefetch,
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
return Ok(PlayTrackResult { format_id: None });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +219,9 @@ pub async fn play_track(
|
||||
}
|
||||
});
|
||||
|
||||
// Capture format_id before returning
|
||||
let actual_format_id = stream_url.format_id;
|
||||
|
||||
// Prefetch next track in background
|
||||
spawn_prefetch(
|
||||
state.client.clone(),
|
||||
@@ -220,7 +231,7 @@ pub async fn play_track(
|
||||
streaming_only,
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
return Ok(PlayTrackResult { format_id: Some(actual_format_id) });
|
||||
}
|
||||
|
||||
// Standard download path (streaming disabled)
|
||||
@@ -255,7 +266,7 @@ pub async fn play_track(
|
||||
streaming_only,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
Ok(PlayTrackResult { format_id: Some(stream_url.format_id) })
|
||||
}
|
||||
|
||||
/// Prefetch a track into the in-memory cache without starting playback
|
||||
|
||||
@@ -682,7 +682,11 @@ impl Player {
|
||||
log::info!("Initializing backend system with {}Hz/{}ch", sample_rate, channels);
|
||||
match try_init_stream_with_backend(&settings, sample_rate, channels) {
|
||||
Some(Ok(stream_type)) => {
|
||||
log::info!("Audio output initialized via backend system at {}Hz", sample_rate);
|
||||
// Set device name from settings for backend system
|
||||
let device_name = settings.output_device.clone()
|
||||
.unwrap_or_else(|| "Default".to_string());
|
||||
log::info!("Audio output initialized via backend system at {}Hz (device: {})", sample_rate, device_name);
|
||||
state.set_current_device(Some(device_name));
|
||||
return Some(stream_type);
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
@@ -854,7 +858,13 @@ impl Player {
|
||||
let stream_result = if let Some(settings) = thread_settings.lock().ok() {
|
||||
match try_init_stream_with_backend(&settings, sample_rate, channels) {
|
||||
Some(result) => {
|
||||
// Backend system handled it - no need for CPAL device search
|
||||
// Backend system handled it - set device name from settings
|
||||
if result.is_ok() {
|
||||
let device_name = settings.output_device.clone()
|
||||
.unwrap_or_else(|| "Default".to_string());
|
||||
log::info!("Backend system using device: {}", device_name);
|
||||
thread_state.set_current_device(Some(device_name));
|
||||
}
|
||||
result
|
||||
}
|
||||
None => {
|
||||
@@ -1151,7 +1161,16 @@ impl Player {
|
||||
|
||||
let stream_result = if let Some(settings) = thread_settings.lock().ok() {
|
||||
match try_init_stream_with_backend(&settings, sample_rate, channels) {
|
||||
Some(result) => result,
|
||||
Some(result) => {
|
||||
// Set device name from settings for backend system
|
||||
if result.is_ok() {
|
||||
let device_name = settings.output_device.clone()
|
||||
.unwrap_or_else(|| "Default".to_string());
|
||||
log::info!("Streaming backend using device: {}", device_name);
|
||||
thread_state.set_current_device(Some(device_name));
|
||||
}
|
||||
result
|
||||
}
|
||||
None => {
|
||||
log::info!("Backend system not configured, using legacy CPAL path");
|
||||
let device = if let Some(ref name) = *current_device_name {
|
||||
|
||||
@@ -49,6 +49,26 @@ import {
|
||||
|
||||
// ============ Types ============
|
||||
|
||||
/** Result from play_track command */
|
||||
interface PlayTrackResult {
|
||||
format_id: number | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Qobuz format_id to format string for QualityBadge
|
||||
* 5=MP3, 6=FLAC 16-bit (CD), 7=FLAC 24-bit (Hi-Res), 27=FLAC 24-bit Hi-Res+
|
||||
*/
|
||||
function formatIdToString(formatId: number | null): string | undefined {
|
||||
if (formatId === null) return undefined;
|
||||
switch (formatId) {
|
||||
case 5: return 'mp3';
|
||||
case 6: return 'flac';
|
||||
case 7: return 'flac24';
|
||||
case 27: return 'flac24';
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export interface PlayTrackOptions {
|
||||
isLocal?: boolean;
|
||||
showLoadingToast?: boolean;
|
||||
@@ -128,11 +148,19 @@ export async function playTrack(
|
||||
if (isLocal) {
|
||||
await invoke('library_play_track', { trackId: track.id });
|
||||
} else {
|
||||
await invoke('play_track', {
|
||||
const result = await invoke<PlayTrackResult>('play_track', {
|
||||
trackId: track.id,
|
||||
durationSecs: track.duration,
|
||||
quality: getStreamingQuality()
|
||||
});
|
||||
|
||||
// Update track format based on actual stream format_id from Qobuz
|
||||
const actualFormat = formatIdToString(result.format_id);
|
||||
if (actualFormat) {
|
||||
track.format = actualFormat;
|
||||
// Re-set current track to update the UI with actual format
|
||||
setCurrentTrack(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user