Commit Graph

17 Commits

Author SHA1 Message Date
Claude
8eafff0f0c Add node statistics tracking + reduce MPSC buffer to 8 chunks 2025-11-12 11:56:58 +00:00
Claude
dbb809261a Replace HTTP timeout with idle mode + END_OF_BLOCKS_SIGNAL
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);
```
2025-11-12 11:32:40 +00:00
Claude
e44bef2021 Fix StreamingFlacSink parameter confusion 2025-11-12 10:38:58 +00:00
Claude
ac2d5c9501 Fix REAL bug: HTTP timeout was truncating Radio Paradise blocks
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
2025-11-12 10:32:47 +00:00
Claude
d4508e603f Implement complete OGG-FLAC streaming with proper container wrapping
This commit implements full OGG container support for FLAC streaming,
wrapping FLAC frames in proper OGG pages with CRC32 validation.

## Changes

### pmoaudio-ext/src/sinks/streaming_ogg_flac_sink.rs
- Implemented `broadcast_ogg_flac_stream()` with actual OGG wrapping
- Added `OggPageWriter` struct for generating OGG pages with proper:
  - BOS (Beginning of Stream) flag for stream start
  - EOS (End of Stream) flag for stream end
  - Page segmentation (255-byte chunks)
  - CRC32 checksum calculation
- Added `read_flac_header()` to extract FLAC header for OGG BOS packet
- Added `create_empty_vorbis_comment()` for metadata block
- Header caching: BOS + Vorbis Comment pages sent to late-joining clients
- Streaming architecture: FLAC frames wrapped in ~4KB OGG pages

### pmoparadise/examples/stream_block.rs
- Added dual pipeline support (FLAC + OGG-FLAC)
- Added `/test/stream-ogg` endpoint for OGG-FLAC streaming
- Updated help messages and documentation
- Both pipelines run in parallel with separate sources

### pmoaudio-ext/Cargo.toml
- Added `rand = "0.8"` dependency for OGG stream serial generation

## Architecture

```
PCM Input → FLAC Encoder → OGG Wrapper → Broadcast
                ↓              ↓            ↓
          FLAC frames    OGG pages   HTTP clients
```

## OGG-FLAC Format

1. BOS page: Contains FLAC identification ("fLaC" + STREAMINFO)
2. Comment page: Contains Vorbis Comment block (metadata)
3. Data pages: Contain FLAC audio frames (~4KB per page)
4. EOS page: Marks end of logical bitstream

## Testing

Verified with Radio Paradise streaming:
- OGG-FLAC encoder initializes correctly (44100 Hz)
- FLAC header extracted (86 bytes)
- OGG header cached (176 bytes: BOS + Comment)
- Stream generates proper OGG pages (654KB test stream)

## Endpoints

- `/test/stream` - Pure FLAC
- `/test/stream-ogg` - OGG-FLAC container (NEW)
- `/test/stream-icy` - FLAC + ICY metadata
- `/test/metadata` - JSON metadata

## TODO (Deferred)

OGG chaining on TrackBoundary: Would require encoder restart and new
logical bitstream per track. Currently metadata is served via
`/test/metadata` endpoint for real-time updates.
2025-11-12 00:26:00 +00:00
Claude
d9bc1cfc03 Add separate endpoints for pure FLAC and ICY streams
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.
2025-11-11 23:44:09 +00:00
Claude
1f5884627c Enable ICY metadata by default for all clients
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.
2025-11-11 23:32:33 +00:00
Claude
5c29f55942 Fix incorrect VLC ICY metadata documentation
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).
2025-11-11 23:28:24 +00:00
Claude
2b47f851b6 Fix HTTP streaming lag warnings by adding TimerNode and increasing buffer
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.
2025-11-11 23:15:11 +00:00
Claude
55c66f0462 Fix stream_block example: add server.wait() to block until Ctrl+C 2025-11-11 20:03:49 +00:00
Claude
9043e54076 Fix StreamingFlacSink compilation errors
- 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
2025-11-11 19:57:03 +00:00
Claude
4884fddf0e Add stream_block example for testing HTTP streaming with VLC
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)
2025-11-11 19:33:25 +00:00
Claude
69831a17df refactor: Remove obsolete streaming API (stream.rs, track.rs, per-track feature)
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
2025-11-05 09:15:11 +00:00
fc093743c1 Refactoring du cache pour une meilleur gestion des metadonnées 2025-10-29 22:35:10 +01:00
df138565af meulleur gestion des routes de streaming 2025-10-26 09:18:22 +01:00
776c535862 amélioration de la webapp 2025-10-20 16:18:21 +02:00
ffecc219b5 implemente pmoparadise 2025-10-12 21:34:59 +02:00