- Remplacer les Arc+Box::pin manuels par la macro action_handler!(captures(...))
- Supprimer helpers locaux dupliqués dans renderer.rs (add_var, add_action)
- Extraire handlers génériques pour GET requests
- Factoriser extraction metadata dans set_uri_handler /set_next_uriHandler
- Simplifier build_renderingcontrol en retirant pipeline inutile
- Mettre à jour edition Rust de 2021 vers 2024 dans tous les Cargo.toml
- Corriger pattern matching inutile `ref` sur déréférencement dans pmoaudio et pmoflac
- Introduce `Streamtype` enum (Continuous vs Finite) to distinguish radio streams from finite tracks
- Enrich `TrackBoundary` sync marker with stream type for proper pause behavior per mode (silence vs backpressure)
- Update all sources and sinks to pass `StreamType` when creating track boundaries
- Radio Paradise, HTTP source → Continuous (infinite)
- Improve UPnP control architecture: pause sends silence for radio, blocks pipeline via backpressure for tracks
- Prepare groundwork for multi-client DSP architecture with shared source and per-DSP pipelines
- Ajout d'un BaseUrl layer dans pmoserver pour gérer les URLs absolues (LAN/WAN)
- Renommage de `covers_absolute_url_for` → ` covers_relative_route`, stocker les routes relatives
- Mise à jour des appels UPnP vers `covers_absolute_url_for_upnp` (fallback PMO_SERVER_URL)
- Correction des tâches de fond pour stocker les routes, pas l'URL complète
- Suppression du feature gate `simd` inutilisé dans pmoaudio/src/lib.rs
Replace hardcoded relative URLs and manual base_url concatenation with a unified absolute URL API via pmocache::covers_absolute_url_for() and CacheTrait::absolute_url_for().
- Add pmocache as a required dependency to pmoparadise
- Introduce absolute_url_for() and covers_absolute_url_for() helpers using PMO_SERVER_URL env var (default: http://localhost:8080)
- Update all callers to use absolute URLs for covers and audio in streaming, playlists, Qobuz, Radio France, UPnP, and server startup
- Remove redundant route_for() usage in URL construction
- Add pmocache to Cargo.lock
Cette mise à jour refactorise les nœuds audio pour utiliser la méthode `boxed()` lors de l'enregistrement des enfants, améliorant ainsi la cohérence et la lisibilité du code. Les méthodes `make()` sont ajoutées pour faciliter la création d'instances boxées des nœuds, et les exemples sont mis à jour en conséquence.
This commit refactors the album art URL normalization logic in Rust to use match expressions for cleaner and more concise code. It also simplifies the image display logic in Vue by removing the redundant cacheBustedUrl check, ensuring the image is displayed based solely on load and error states.
Update version from 0.3.18 to 0.3.19 in Cargo.toml, package-lock.json, and version.txt.
Also update the API endpoint in pmoparadise/src/client.rs from `/get_block` to `/play` and remove the `peer` property from several dependencies in package-lock.json.
Additionally, update the ARCHITECTURE.md documentation to reflect the change in API endpoint.
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
Investigation revealed the root cause of premature streaming termination:
1. MPSC Channel Size Issue:
- DEFAULT_CHANNEL_SIZE = 16 chunks × 50ms = 800ms capacity
- TimerNode max_lead_time = 3.0 seconds
- The channel fills up in 0.8s while TimerNode wants 3s buffer
- This creates stop-and-go pattern instead of smooth backpressure
2. Channel Closure Issue:
- When RadioParadiseStreamSource::process() returns, the Node
automatically closes output channels
- TimerNode receives EOF and terminates immediately
- Remaining chunks in MPSC buffer (up to 16) are never sent to sink
Added comprehensive tracing:
- RadioParadiseStreamSource: Track backpressure blocking, chunk counts,
decode timing
- TimerNode: Log all pacing decisions, sleep durations, lead time
- Both use trace! for high-frequency events, debug! for blocking
Next steps:
- Option A: Increase channel size to match max_lead_time
(60 chunks for 3s @ 50ms)
- Option B: Wait for channels to drain before closing
(use tx.closed().await)
- Option C: Both A and B for optimal behavior
The previous "wait for playback duration" fix is a valid workaround
but doesn't address the architectural issue.