MAJOR ARCHITECTURAL IMPROVEMENT:
Instead of using arbitrary timeouts that don't solve the real problem,
implement proper idle mode and explicit end-of-stream signaling.
Changes:
1. **Remove block_id timeout completely**
- No more BLOCK_ID_TIMEOUT_SECS
- Source enters idle mode when queue is empty
- Waits indefinitely for new block_ids (poll every 100ms)
- Only exits on cancellation or END_OF_BLOCKS_SIGNAL
2. **Introduce END_OF_BLOCKS_SIGNAL (EventId::MAX)**
- Special block_id value to signal "no more blocks"
- Source terminates cleanly after processing current block
- Allows proper shutdown without cancellation
- Exported from pmoparadise crate for public use
3. **Update HTTP timeout to 24 hours**
- Effectively infinite timeout for block downloads
- HTTP stream stays open as long as needed
- Closed by pipeline termination, not arbitrary timeout
4. **Update stream_block example**
- Push END_OF_BLOCKS_SIGNAL after the single block
- Demonstrates clean termination after one block
- Documents pattern for continuous vs. bounded streaming
Benefits:
- No arbitrary timeouts that might truncate valid streams
- Clean separation: cancellation (external) vs. completion (internal)
- Supports both continuous radio and bounded playlists
- Proper idle mode for on-demand streaming applications
Usage pattern:
```rust
// Single block then stop
source.push_block_id(block_id);
source.push_block_id(END_OF_BLOCKS_SIGNAL);
// Continuous streaming
source.push_block_id(block1);
source.push_block_id(block2);
// ... keep pushing or wait in idle mode
// Graceful shutdown
source.push_block_id(END_OF_BLOCKS_SIGNAL);
```
ROOT CAUSE IDENTIFIED:
The previous "wait for playback duration" workaround was masking the real
issue. Radio Paradise blocks last ~20 minutes (1200s), but the HTTP timeout
was only 180 seconds, causing premature stream termination.
With backpressure from the audio pipeline, HTTP download proceeds at real-time
pace. A 20-minute block takes ~20 minutes to download. The 180s timeout
was killing the connection after 3 minutes, resulting in incomplete blocks.
Changes:
1. **Increase HTTP block_timeout: 180s → 7200s (2 hours)**
- Allows complete download of even the longest blocks
- Comment explains why such a long timeout is needed
2. **Increase MPSC channel sizes: 16 → 60 chunks**
- Matches TimerNode max_lead_time (3.0s / 0.05s = 60 chunks)
- Prevents stop-and-go backpressure pattern
- Allows smooth buffering as intended
3. **Replace workaround with proper channel drainage**
- Use tx.closed().await instead of sleep()
- Guarantees all buffered chunks are processed
- More architecturally sound solution
4. **Add comprehensive diagnostic traces**
- Log expected vs actual block duration
- Detect premature EOF (< 95% of expected duration)
- Track bytes decoded and HTTP Content-Length
- Monitor backpressure blocking with timing
This fixes the streaming completely. The block will now:
- Download for the full ~20 minutes (real-time with backpressure)
- Decode all audio data without truncation
- Process all chunks before pipeline shutdown
VLC cannot decode FLAC streams with embedded ICY metadata because
the ICY blocks break the FLAC decoder. Split into two endpoints:
- /test/stream: Pure FLAC (for VLC and standard FLAC players)
- /test/stream-icy: FLAC + ICY metadata (for ICY-aware clients)
This allows:
- VLC to play audio correctly using pure FLAC
- ICY-aware clients to receive metadata updates
- Metadata endpoint remains available for JSON queries
Fixes the "no audio" issue where VLC would connect, receive the
FLAC header with ICY metadata blocks, fail to decode, and disconnect.
Changed stream_handler to always serve ICY-wrapped FLAC instead of
checking for the Icy-MetaData header. This ensures all clients
(including VLC) receive metadata updates.
Changes:
- Removed conditional ICY/pure FLAC logic
- Always use subscribe_icy() for all connections
- Added standard ICY headers (icy-genre, icy-pub)
- Updated documentation to reflect default ICY mode
This allows clients to see "Now Playing" information without needing
to send specific HTTP headers.
Removed references to non-existent VLC options:
- --icy-metadata (doesn't exist)
- --http-continuous (not needed)
VLC automatically sends the "Icy-MetaData: 1" HTTP header when
connecting to HTTP audio streams, and the server responds with
ICY metadata blocks. No special VLC flags are needed.
Also fixed the stream URL in help text (/stream → /test/stream).
The streaming FLAC implementation was experiencing severe lag warnings
(clients skipping 700-2200 messages) because:
1. The broadcast channel capacity (512) was too small for network backpressure
2. The pipeline had no rate limiting, sending data faster than real-time
Changes:
- Increased BROADCAST_CAPACITY from 512 to 4096 (~5min buffer)
- Added TimerNode (3s lead time) to stream_block example pipeline
- Pipeline now: RadioParadiseStreamSource → TimerNode → StreamingFlacSink
This ensures data flows at real-time playback speed with sufficient
buffering for network jitter, eliminating client lag warnings.
- Fix import paths to use public pmoaudio API instead of private modules
- Change AudioError::ConfigurationError to ProcessingError
- Use Node::new_with_input() instead of non-existent Node::new()
- Fix borrow checker issues in IcyClientStream::poll_read()
- Use flatten() on metadata getters to unwrap Result<Option<T>>
- Fix chunk.get_sample_rate() to chunk.sample_rate()
- Remove get_album_artist() call (not in TrackMetadata trait)
- Update pmoparadise Cargo.toml to enable pmoserver feature for axum
- Simplify example init_logging() call to match new pmoserver API
Creates a new example demonstrating StreamingFlacSink usage with pmoserver
for real-world HTTP streaming testing with media players like VLC.
Features:
- Uses pmoserver instead of raw Axum for realistic testing
- Streams a single Radio Paradise block over HTTP
- Supports both pure FLAC and ICY metadata modes
- Provides /test/stream endpoint for streaming
- Provides /test/metadata endpoint for JSON metadata queries
- Includes health check endpoint
Usage:
cargo run --example stream_block --features full -- <channel_id>
Testing with VLC:
# Pure FLAC mode
vlc http://localhost:8080/test/stream
# ICY metadata mode (Now Playing)
vlc --http-continuous --icy-metadata http://localhost:8080/test/stream
Dependencies:
- Requires pmoserver for HTTP server
- Requires StreamingFlacSink from pmoaudio-ext (http-stream feature)
- Integrated with full feature set (pmoaudio + pmoaudio-ext + pmoserver)
The old streaming API has been completely replaced by RadioParadiseStreamSource
which integrates directly with the pmoaudio pipeline.
Removed:
- src/stream.rs (179 lines) - BlockStream, stream_block(), download_block()
- src/track.rs - Per-track extraction functionality
- examples/stream_block.rs - Obsolete streaming example
- examples/extract_track.rs - Per-track extraction example
- Feature "per-track" and dependencies (hound, tempfile)
Updated:
- Cargo.toml: Removed per-track feature and obsolete examples
- lib.rs: Removed module declarations and re-exports
The new RadioParadiseStreamSource provides:
- Direct integration with pmoaudio pipeline
- FLAC decoding via pmoflac
- Automatic TrackBoundary insertion
- Better performance and lower latency