From 3bd2a334978a7fc0af127badd5108be678186595 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 7 Nov 2025 06:23:35 +0000 Subject: [PATCH] Fix FLAC pk collision by skipping header for pk calculation Problem: All FLAC files with the same format (44.1kHz, stereo, 16-bit) had identical headers and thus the same pk (071c5713d5cf485ca688832207bef0f9). This caused the cache to think all tracks were the same file, regardless of channel selection or actual content. Solution: Skip the FLAC header (first 512 bytes) and calculate the pk from bytes 512-1024 (actual audio content) instead. This ensures each track gets a unique pk based on its actual audio data, not just its format header. Changes: - Modified add_from_reader_with_pk() to read 1024 bytes instead of 512 - Use bytes 512-1024 for pk calculation when explicit_pk is None - This works even with poor metadata (empty artist/title) - Maintains backward compatibility with explicit_pk parameter Fixes the issue where changing radio channel played the same song. --- pmoaudio-ext/src/sinks/flac_cache_sink.rs | 2 ++ pmocache/src/cache.rs | 40 ++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/pmoaudio-ext/src/sinks/flac_cache_sink.rs b/pmoaudio-ext/src/sinks/flac_cache_sink.rs index 54ca97b9..3a6d948f 100755 --- a/pmoaudio-ext/src/sinks/flac_cache_sink.rs +++ b/pmoaudio-ext/src/sinks/flac_cache_sink.rs @@ -135,6 +135,8 @@ impl NodeLogic for FlacCacheSinkLogic { // Ingérer le FLAC progressivement dans le cache // add_from_reader lance l'ingestion en arrière-plan et retourne dès que // le prebuffer (512 KB) est atteint, permettant un streaming progressif + // Le cache skip automatiquement le header FLAC (512 octets) pour calculer le pk + // à partir du contenu audio, évitant les collisions entre morceaux au même format let collection_ref = self.collection.as_deref(); let cache_future = self.cache.add_from_reader( None, diff --git a/pmocache/src/cache.rs b/pmocache/src/cache.rs index 095d5ed5..4aae6c2a 100755 --- a/pmocache/src/cache.rs +++ b/pmocache/src/cache.rs @@ -368,13 +368,45 @@ impl Cache { where R: AsyncRead + Send + Unpin + 'static, { - // 1. Lire les 512 premiers octets pour calculer le pk - let header = crate::download::peek_reader_header(&mut reader, 512) + self.add_from_reader_with_pk(source_uri, reader, length, collection, None).await + } + + /// Ajoute un fichier à partir d'un flux avec un pk explicite optionnel. + /// + /// Si `explicit_pk` est fourni, utilise ce pk au lieu de le calculer à partir du contenu. + /// Ceci est utile quand plusieurs fichiers ont le même header mais doivent être cachés séparément + /// (par exemple, des fichiers FLAC avec le même format mais du contenu différent). + pub async fn add_from_reader_with_pk( + &self, + source_uri: Option<&str>, + mut reader: R, + length: Option, + collection: Option<&str>, + explicit_pk: Option, + ) -> Result + where + R: AsyncRead + Send + Unpin + 'static, + { + // 1. Lire les premiers octets pour calculer le pk + // Pour éviter les collisions entre fichiers FLAC au même format, on skip le header (512 octets) + // et on utilise les octets 512-1024 (début du contenu audio) pour calculer le pk + let buffer_size = if explicit_pk.is_none() { 1024 } else { 512 }; + let header = crate::download::peek_reader_header(&mut reader, buffer_size) .await .map_err(|e| anyhow!("Failed to peek reader header: {}", e))?; - // 2. Calculer le pk basé sur le contenu - let pk = crate::cache_trait::pk_from_content_header(&header); + // 2. Calculer le pk: si pas de pk explicite, utiliser octets 512-1024 au lieu de 0-512 + let pk = if let Some(explicit) = explicit_pk { + explicit + } else { + // Skip les 512 premiers octets (header FLAC) et utiliser les 512 suivants + let pk_bytes = if header.len() > 512 { + &header[512..] + } else { + &header[..] + }; + crate::cache_trait::pk_from_content_header(pk_bytes) + }; if let Some(uri) = source_uri { tracing::debug!("Computed pk {} for source_uri {}", pk, uri); } else {