Fix FLAC pk collision by ensuring full 1024 bytes are read

Problem Analysis:
- All FLAC files had the same pk (071c5713d5cf485ca688832207bef0f9)
- Root cause: read() can return < 1024 bytes on first call
- If read returned only 400 bytes:
  * header.len() = 400
  * 400 > 512 = false
  * Used header[..] (first 400 bytes = FLAC header)
  * All FLAC files have identical headers → same pk!

Solution:
- Added read_exact_or_eof() that loops until 1024 bytes read (or EOF)
- Guarantees we skip FLAC header and use actual audio content
- Works for small files (< 512 bytes) and large files (>= 1024 bytes)

Additional Feature:
- Added AudioSink::with_null_output() for testing without audio device
- Added --null-audio flag to play_and_cache example
- Allows testing in containerized environments

Changes:
1. pmocache/src/download.rs: Added read_exact_or_eof()
2. pmocache/src/cache.rs: Use read_exact_or_eof() for pk calculation
3. pmoaudio/src/nodes/audio_sink.rs: Added null output mode
4. pmoparadise/examples/play_and_cache.rs: Added --null-audio flag

Test Results:
- New pk: 83702c1cbca72074ebf7c123336786ea (was 071c...)
- Null audio output works correctly
- Ready for full testing
This commit is contained in:
Claude
2025-11-07 07:24:19 +00:00
parent 64586721b9
commit 78004b0327
4 changed files with 129 additions and 9 deletions

View File

@@ -387,10 +387,11 @@ impl<C: CacheConfig> Cache<C> {
where
R: AsyncRead + Send + Unpin + 'static,
{
// 1. Lire jusqu'à 1024 octets (ou ce qui est disponible)
let header = crate::download::peek_reader_header(&mut reader, 1024)
// 1. Lire EXACTEMENT 1024 octets (ou EOF si fichier plus petit)
// Utilise read_exact_or_eof qui boucle jusqu'à avoir tous les octets demandés
let header = crate::download::read_exact_or_eof(&mut reader, 1024)
.await
.map_err(|e| anyhow!("Failed to peek reader header: {}", e))?;
.map_err(|e| anyhow!("Failed to read header bytes: {}", e))?;
// 2. Calculer le pk en utilisant au plus les 512 derniers octets
// Ceci évite les collisions pour les fichiers avec headers identiques (ex: FLAC)
@@ -399,7 +400,7 @@ impl<C: CacheConfig> Cache<C> {
explicit
} else {
let pk_bytes = if header.len() > 512 {
// Fichier >= 512 octets: utiliser les octets 512+ (au plus 512 octets)
// Fichier >= 512 octets: utiliser les octets 512-1024 (contenu audio pour FLAC)
&header[512..]
} else {
// Petit fichier < 512 octets: utiliser tout le contenu