Add sample rate extraction and debug logs for OGG-FLAC (still failing)

- Added extract_sample_rate_from_streaminfo() to parse STREAMINFO block
- Added debug logs to track frame boundary detection
- Granule position tracking with add_samples()

Problem persists: No OGG pages are broadcast after headers. The condition
'boundary >= 4096 && samples_in_frames > 0' is never satisfied, meaning
frame detection is failing.

Root cause unclear - need deeper investigation of:
1. Why find_complete_frames_with_samples() returns (0, 0)
2. Whether FLAC sync codes are being detected at all
3. If there's an issue with how FLAC encoder outputs data
This commit is contained in:
Claude
2025-11-13 09:57:19 +00:00
parent 3219a8beda
commit 0129fd49cc

View File

@@ -859,13 +859,15 @@ async fn broadcast_ogg_flac_stream(
// Also calculate total samples for granule position // Also calculate total samples for granule position
let (boundary, samples_in_frames) = find_complete_frames_with_samples(&flac_accumulator); let (boundary, samples_in_frames) = find_complete_frames_with_samples(&flac_accumulator);
trace!( if flac_accumulator.len() > 1000 {
"Buffer state: accumulator={} bytes, boundary={} bytes, samples={}, will_send={}", debug!(
flac_accumulator.len(), "OGG Frame detection: accumulator={} bytes, boundary={} bytes, samples={}, will_send={}",
boundary, flac_accumulator.len(),
samples_in_frames, boundary,
boundary >= 4096 samples_in_frames,
); boundary >= 4096 && samples_in_frames > 0
);
}
// Only broadcast if we have at least one complete frame (4KB minimum for efficiency) // Only broadcast if we have at least one complete frame (4KB minimum for efficiency)
// OGG pages can be larger than pure FLAC broadcasts since they include page overhead // OGG pages can be larger than pure FLAC broadcasts since they include page overhead
@@ -926,6 +928,46 @@ async fn broadcast_ogg_flac_stream(
Ok(()) Ok(())
} }
/// Extract sample rate from STREAMINFO block in FLAC header
fn extract_sample_rate_from_streaminfo(flac_header: &[u8]) -> Result<u32, AudioError> {
// Verify we have at least "fLaC" magic + STREAMINFO block header
if flac_header.len() < 8 {
return Err(AudioError::ProcessingError("FLAC header too short".into()));
}
if &flac_header[0..4] != b"fLaC" {
return Err(AudioError::ProcessingError("Invalid FLAC magic".into()));
}
// First metadata block should be STREAMINFO (type 0)
let block_type = flac_header[4] & 0x7F;
if block_type != 0 {
return Err(AudioError::ProcessingError("First block is not STREAMINFO".into()));
}
// STREAMINFO data starts at offset 8 (after magic + block header)
// Sample rate is at offset 10-12 of STREAMINFO data (bytes 18-20 of header)
if flac_header.len() < 21 {
return Err(AudioError::ProcessingError("STREAMINFO block truncated".into()));
}
// Sample rate: 20 bits starting at byte 10 of STREAMINFO
// Format: [byte10: SSSSSSSS] [byte11: SSSSSSSS] [byte12: SSSSCCCC]
// S = sample rate bits, C = channels bits
let byte10 = flac_header[18] as u32;
let byte11 = flac_header[19] as u32;
let byte12 = flac_header[20] as u32;
// Extract 20 bits for sample rate (top 20 bits of 3 bytes)
let sample_rate = (byte10 << 12) | (byte11 << 4) | (byte12 >> 4);
if sample_rate == 0 {
return Err(AudioError::ProcessingError("Invalid sample rate (0)".into()));
}
Ok(sample_rate)
}
/// Read FLAC header (fLaC + all metadata blocks until first frame) /// Read FLAC header (fLaC + all metadata blocks until first frame)
async fn read_flac_header(stream: &mut FlacEncodedStream) -> Result<Vec<u8>, AudioError> { async fn read_flac_header(stream: &mut FlacEncodedStream) -> Result<Vec<u8>, AudioError> {
let mut header = Vec::new(); let mut header = Vec::new();