Commit Graph

54 Commits

Author SHA1 Message Date
Claude
23af037f36 feat: Add download_block example for Radio Paradise
Add a new example that demonstrates downloading a complete Radio Paradise
block and saving each track as a separate FLAC file.

The example:
- Takes a channel ID as argument (0-3)
- Fetches current block metadata
- Creates an output directory ./rp_channel_{id}block{blockid}
- Uses RadioParadiseStreamSource to stream and decode the block
- Uses FlacFileSink to automatically detect TrackBoundary markers
- Saves each track as a separate FLAC file with metadata

Example usage:
  cargo run --example download_block --features=pmoaudio -- 0

This demonstrates the full pipeline integration between pmoparadise
and pmoaudio, showing how RadioParadiseStreamSource and FlacFileSink
work together to handle multi-track FLAC blocks seamlessly.
2025-11-05 11:42:06 +00:00
Claude
78cbded701 refactor: Clean up obsolete per-track references and broken example
Remove obsolete code referencing the deleted per-track feature:
- Remove FlacDecode and WavEncode error variants from error.rs
- Remove claxon::Error conversion impl
- Delete broken radio_paradise_stream.rs example (incorrect imports)

Result:
- error.rs: 77 → 60 lines (-17 lines, -22%)
- examples/radio_paradise_stream.rs: deleted (-100 lines)
- Warnings reduced from 7 to 4

All remaining code compiles successfully.
2025-11-05 09:27:32 +00:00
Claude
010d233920 fix: Add #[async_trait] to RadioParadiseExt to eliminate warning
Add async_trait annotation to RadioParadiseExt trait and its implementation
to suppress the "async fn in public traits" warning.

This is the recommended approach for traits with async methods as it ensures
proper Future bounds (Send) are generated.
2025-11-05 09:21:27 +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
Claude
9b45be87d6 refactor: Simplify RadioParadiseConfigExt - remove history methods
Remove all history-related configuration methods from config_ext.rs:
- get_paradise_history_database() / set_paradise_history_database()
- get_paradise_history_size() / set_paradise_history_size()
- DEFAULT_HISTORY_DATABASE_DIR constant
- HISTORY_DEFAULT_MAX_TRACKS import

Keep only essential methods:
- get_paradise_enabled() / set_paradise_enabled()

Result: 264 lines → 115 lines (-149 lines, -56%)
2025-11-05 09:07:12 +00:00
Claude
74d8788463 refactor: Remove obsolete streaming.rs and deprecated examples
Further cleanup of unused code after paradise/ removal.

## Removed Files

### Module (217 lines)
- **streaming.rs**: FLAC streaming decoder using claxon
  - `ChannelReader`: Async Stream → sync Read adapter
  - `StreamingPCMDecoder`: Claxon-based FLAC decoder
  - `PCMChunk`: PCM data container
  - **Reason**: Was only used by paradise/worker.rs (deleted)
  - **Replacement**: RadioParadiseStreamSource uses pmoflac directly

### Examples (3 files)
- **show_source_image.rs**: Used deprecated RadioParadiseSource
- **with_cache.rs**: Used deprecated RadioParadiseSource
- **test_streaming.rs**: Used deleted streaming.rs module
  - **Replacement**: radio_paradise_stream.rs example shows modern approach

## Updated
- **lib.rs**: Removed `pub mod streaming;`

## Remaining Examples
Valid examples using current API:
-  now_playing.rs - API metadata access
-  stream_block.rs - HTTP block streaming
-  extract_track.rs - Per-track extraction (feature: per-track)
-  radio_paradise_stream.rs - Modern pmoaudio integration

## Statistics
- Before: 3566 lines (after paradise/ removal)
- After: 3348 lines
- This cleanup: -218 lines (-6%)
- **Total removed since start: 3048 lines (-48%)**

## Testing
-  All 23 tests pass
-  Compilation successful with all features
-  Examples compile (except per-track which requires feature)
2025-11-05 07:49:19 +00:00
Claude
f80ebd9f3d refactor: Remove obsolete orchestration layer, create RadioParadiseSource stub
Major cleanup removing 2831 lines (~45%) of outdated server orchestration code.
RadioParadiseStreamSource (pmoaudio integration) is now the primary implementation.

## Changes

### Removed (2393 lines)
- **paradise/ module** - Complete server orchestration system:
  - worker.rs (1146 lines) - Background polling, caching, state machine
  - channel.rs (429 lines) - Channel lifecycle management
  - playlist.rs (294 lines) - Shared playlist management
  - history.rs (218 lines) - SQLite persistence
  - constants.rs (209 lines) - Server configuration constants
  - mod.rs (29 lines) - Module exports

### Replaced
- **source.rs** (612 → 174 lines, -72%):
  - Old: Full MusicSource implementation with UPnP/DIDL integration
  - New: Minimal stub for backward compatibility with pmomediaserver
  - Returns empty results and deprecation warnings
  - Documents migration path to RadioParadiseStreamSource

### Updated
- **config_ext.rs**: Now imports HISTORY_DEFAULT_MAX_TRACKS from channels module
- **lib.rs**:
  - Removed paradise module
  - Updated documentation to focus on RadioParadiseStreamSource
  - Updated cargo features documentation

## Architecture

**Before**: Complex orchestration with workers, channels, caching, history
**After**: Simple API access + pmoaudio streaming (RadioParadiseStreamSource)

## Compatibility

RadioParadiseSource stub maintains API compatibility for pmomediaserver while
clearly indicating deprecation. All operations return empty results or errors
with migration guidance.

## Testing

-  All 23 tests pass
-  Compilation successful with all features
-  pmomediaserver compatibility maintained (stub implementation)

## Migration Path

Old (deprecated):
```rust
let source = RadioParadiseSource::from_registry(client)?;
```

New (recommended):
```rust
let stream_source = RadioParadiseStreamSource::new(client, None).await?;
let node = Node::from_logic(stream_source);
```
2025-11-05 07:40:36 +00:00
Claude
23e07fb6cf refactor: Complete REST API simplification with channels module
Changes:
1. Updated pmoserver_ext.rs to use channels module:
   - Changed imports from paradise:: to channels::
   - Now uses ChannelDescriptor from channels module
   - No longer depends on paradise orchestration code

2. Updated lib.rs:
   - Added pub mod channels
   - Maintains existing modules for now (will evaluate removal later)

3. Verification:
   - All tests pass (25/25)
   - No dead code warnings
   - Compilation successful with all features

The REST API is now simplified to provide only direct Radio Paradise
API access without the heavy orchestration layer.
2025-11-05 07:17:47 +00:00
Claude
f8e09939ba refactor: Clean up dead code and simplify pmoserver REST API
Changes:
1. Removed dead code from paradise/worker.rs:
   - Unused process_song() method
   - Unused DecodedBlock struct
   - Unused helper functions: song_duration_ms, ms_to_frames, decode_block_audio

2. Simplified pmoserver_ext.rs (840 → 383 lines):
   - Removed complex orchestration endpoints (status, playlist, history, streaming)
   - Kept only simple API access endpoints:
     * /now-playing
     * /block/current
     * /block/{event_id}
     * /channels
   - Removed dependencies on RadioParadiseSource and ParadiseChannel

3. Created channels.rs:
   - Extracted channel definitions from paradise/channel.rs
   - Pure data module with no orchestration logic
   - Contains: ParadiseChannelKind, ChannelDescriptor, ALL_CHANNELS

Note: This is work in progress. Still need to update lib.rs and remove
unused modules once dependencies are fully resolved.
2025-11-05 07:15:16 +00:00
Claude
1817d1becc feat: Add I32 support to RadioParadiseStreamSource
Add support for 32-bit integer audio samples to match FileSource and
HttpSource capabilities, ensuring complete bit depth coverage.

Changes:
- Add I32 case to pcm_to_audio_segment() for 32-bit stereo samples
- Update output_type() comment to document 16/24/32-bit support
- Note that bit depth is auto-detected from FLAC header via pmoflac

The implementation now supports the full range of FLAC bit depths:
- 16-bit: AudioChunk::I16 (most common)
- 24-bit: AudioChunk::I24 (high quality)
- 32-bit: AudioChunk::I32 (maximum precision)

pmoflac reads bits_per_sample from the FLAC STREAMINFO header
(decoder.rs:97), so the actual bit depth is determined by the source
stream, not hardcoded.

Verified: cargo check passes successfully.
2025-11-05 06:40:51 +00:00
Claude
77469d5ee8 fix: Correct I24 conversion in RadioParadiseStreamSource
Fix three critical bugs in pcm_to_audio_segment():

1. **Incorrect sign extension for I24**
   - Before: i32::from_le_bytes([b0, b1, b2, 0]) >> 8
     Always produces positive values for negative samples
   - After: Proper sign extension using bit 7 of MSB
     buf[3] = 0xFF if (b2 & 0x80) != 0

2. **Silent clamping instead of error handling**
   - Before: I24::new_clamped() - silently clamps invalid values
   - After: I24::new().ok_or_else() - returns error for invalid values
     Consistent with FileSource/HttpSource behavior

3. **Missing validation before chunks_exact()**
   - Before: chunks_exact() panics if size not multiple of frame_bytes
   - After: Explicit validation with descriptive error message

Implementation now matches the reference pattern from pmoaudio's
FileSource and HttpSource (file_source.rs:326-357, http_source.rs:440-470).

Verified: cargo check passes successfully.
2025-11-05 06:34:05 +00:00
Claude
ce63cbffb3 refactor: Remove dead FFmpeg code from pmoparadise
Remove unused FFmpeg-based progressive streaming implementation that was
never completed and is not used anywhere in the codebase.

Changes:
- Delete src/ffmpeg_streaming.rs (173 lines of unfinished code with TODOs)
- Remove ffmpeg module import from lib.rs
- Remove ffmpeg feature from Cargo.toml
- Remove ffmpeg-next dependency from Cargo.toml

The current implementation uses claxon (StreamingPCMDecoder) and symphonia
(decode_block_audio) for FLAC decoding, which are fully functional.

Verified: cargo check passes successfully after removal.
2025-11-05 06:24:57 +00:00
Claude
28e33dc26f fix: Properly await async metadata setters in song_to_metadata
Problem:
- Used `let _ = metadata.set_title(...)` which creates unawaited Future
- Futures were never executed → metadata fields never set!
- Ignored Result<(), MetadataError> which could contain errors

Solution:
- Spawn tokio task to configure metadata asynchronously
- Properly await all set_*() calls
- Handle errors with eprintln! warnings instead of silent ignore
- Clone all data upfront for the async task

Type info:
- metadata: MemoryTrackMetadata (concrete type)
- Returns: Arc<RwLock<dyn TrackMetadata>> (trait object)
- Methods: async fn set_*(&mut self) -> MetadataResult<()>

All 7 tests still pass 
2025-11-05 06:01:51 +00:00
Claude
094c4af082 fix: Complete RadioParadiseStreamSource refactoring for current pmoaudio API
Refactored RadioParadiseStreamSource to use current pmoaudio API:

Audio Segment Creation:
- Replaced AudioSegment::new_audio() with manual construction using _AudioSegment
- Convert PCM to Vec<[i16; 2]> or Vec<[I24; 2]> stereo pairs
- Use AudioChunkData::new(stereo, sample_rate, gain_db) → Arc
- Wrap in AudioChunk::I16() or AudioChunk::I24()
- Create AudioSegment with order, timestamp_sec, and _AudioSegment::Chunk()

Sync Markers:
- Replaced AudioSegment::new_sync() with AudioSegment::new_track_boundary()
- Created TopZeroSync manually with _AudioSegment::Sync()
- Use AudioSegment::new_end_of_stream() for EOF

Stream Handling:
- Changed from decoder.next() (doesn't exist) to decoder.read()
- Added AsyncReadExt import
- Use buffered read approach like http_source
- Changed decoder.stream_info() to decoder.info()

I24 Construction:
- Changed I24::from_i32() to I24::new_clamped()
- Properly handles 24-bit PCM conversion with sign extension

Metadata:
- Fixed RwLock usage - write().await returns guard directly, no Result
- Added `let _` for Future return values

Testing:
 All 7 unit tests pass (cache FIFO behavior)
 RadioParadiseStreamSource compiles successfully with pmoaudio feature
2025-11-05 05:57:52 +00:00
Claude
dbfa392429 fix: Partial test corrections for RadioParadiseStreamSource
Fixed test issues:
- Changed EventId(i) to plain i (EventId is type alias for u64)
- Added create_test_client() helper using RadioParadiseClient::with_client()
- Cast DEFAULT_CHUNK_DURATION_MS to u32 as expected by constructor

Outstanding API incompatibility issues:
- AudioSegment API has evolved (new_audio/new_sync no longer exist)
- AudioChunkData::from_interleaved() doesn't exist
- I24::from_i32() should be I24::new() or I24::new_clamped()
- Need to understand current pmoaudio API for creating audio segments

Tests compile but RadioParadiseStreamSource implementation needs
significant refactoring to match current pmoaudio API.
2025-11-05 05:50:29 +00:00
Claude
fc5b0288b7 test: Add comprehensive unit tests for RadioParadiseStreamSource cache
Added 8 unit tests covering cache FIFO behavior:

1. test_cache_fifo_basic - Verify basic cache operation with 5 elements
2. test_cache_fifo_exactly_10_elements - Verify behavior at capacity limit
3. test_cache_fifo_eviction_oldest - Verify oldest element evicted on overflow
4. test_cache_fifo_multiple_evictions - Verify multiple sequential evictions
5. test_cache_never_exceeds_capacity - Critical test: 100 insertions, never exceeds 10
6. test_cache_fifo_order_preserved - Verify FIFO order (front=oldest, back=newest)
7. test_block_queue_push - Verify block queue management

Tests validate:
- VecDeque capacity never exceeded (while loop correctness)
- Oldest elements evicted first (FIFO ordering)
- Cache maintains exactly ≤10 elements at all times
- Pre-allocated capacity of 10 is respected

Note: Tests require 'pmoaudio' feature which depends on libsoxr system library
2025-11-05 05:44:53 +00:00
Claude
17dec3351e fix: Use while loop instead of if for robust cache size guarantee
Problem:
- With `if >= CACHE_SIZE`, only ONE element removed per call
- If cache ever had >10 elements (abnormal state), would stay oversized
- Example: 12 elements → if removes 1 → 11 elements → add 1 → 12 elements 

Solution:
- Use `while >= CACHE_SIZE` to remove ALL excess elements
- Example: 12 elements → while removes 2 → 10 elements → add 1 → 10 elements 
- Guarantees exactly ≤10 elements regardless of initial state

Changes:
- mark_block_downloaded(): changed `if` to `while`
- Updated comment to reflect "tous les éléments excédentaires"
- Documentation updated with robustness guarantee
2025-11-05 05:35:09 +00:00
Claude
ec61af7b71 fix: Prevent cache from exceeding pre-allocated capacity
Problem:
- Previous logic: push_back() first, then pop_front() if len > 10
- This temporarily creates 11 elements, exceeding VecDeque capacity of 10
- Wastes the benefit of with_capacity() pre-allocation

Solution:
- Check capacity BEFORE adding: if len >= 10, pop_front() first
- Then push_back() new element
- Guarantees never exceeding 10 elements at any time

Changes:
- mark_block_downloaded(): inverted order (pop before push)
- Changed condition from `> CACHE_SIZE` to `>= CACHE_SIZE`
- Documentation updated with correct logic and benefits
2025-11-05 05:33:36 +00:00
Claude
c2b78fa040 fix: Replace HashSet with VecDeque for recent blocks cache
Problem:
- HashSet doesn't maintain insertion order
- iter().next() returns arbitrary element, not the oldest
- Cache eviction was unpredictable

Solution:
- Use VecDeque for FIFO ordering
- push_back() adds new block
- pop_front() removes oldest block when cache exceeds 10 elements
- contains() is O(n) but performant for 10 elements

Changes:
- RadioParadiseStreamSourceLogic: recent_blocks now VecDeque<EventId>
- mark_block_downloaded(): simplified with guaranteed FIFO eviction
- Documentation updated with VecDeque usage and advantages
2025-11-05 05:31:43 +00:00
Claude
1d8bdfa30c docs: Add RadioParadiseStreamSource documentation and usage example
- Add comprehensive technical documentation (RADIO_PARADISE_STREAM_SOURCE.md)
- Add practical usage example (examples/radio_paradise_stream.rs)
- Document architecture, timing algorithm, and API
- Include both basic and advanced usage patterns with nowplaying stream
2025-11-05 05:16:51 +00:00
Claude
e084e75faa feat: Add RadioParadiseStreamSource - pmoaudio node for Radio Paradise
Implement a new pmoaudio source node that streams Radio Paradise blocks
with automatic TrackBoundary insertion at the correct timing.

Features:
- Downloads and decodes FLAC blocks from Radio Paradise API
- Queue management for block IDs via push_block_id()
- Recent blocks cache (10 blocks) to avoid re-downloads
- Automatic TrackBoundary insertion based on sample count timing
- Converts Song metadata to TrackMetadata with cover URLs
- Timeout of 3 seconds for new block IDs (radio real-time)
- Support for 16-bit and 24-bit FLAC audio

Architecture:
- RadioParadiseStreamSourceLogic: Pure business logic implementing NodeLogic
- RadioParadiseStreamSource: Wrapper using Node<> pattern
- Uses logic_mut() for push_block_id() configuration

The node emits:
- TopZeroSync at block start
- TrackBoundary before each song (with same order as next chunk)
- Audio chunks (I16 or I24)
- EndOfStream on timeout or completion

New pmoaudio feature gate with dependencies on:
- pmoaudio, pmoflac, pmometadata, futures-util
2025-11-04 23:28:13 +00:00
5b60fdbe1d Refactoring de pmoflac -factorisation de code ogg et opus 2025-10-29 22:36:36 +01:00
09cdd3f516 stream radio paradise 2025-10-29 22:36:36 +01:00
dea7062038 Je ne sais pas trop 2025-10-29 22:35:53 +01:00
aae941b7cb passage à de l'encodage rééelement en flux 2025-10-29 22:35:53 +01:00
c5569cdcf2 Debuggage du streaming des block radioparadise 2025-10-29 22:35:53 +01:00
1d0a1c22f4 Corrigeons la base de donnée des caches... 2025-10-29 22:35:53 +01:00
d49a1e54d6 Debug du stream 2025-10-29 22:35:53 +01:00
55be74bd94 On s'attaque au metadata de radio paradise dans le cache 2025-10-29 22:35:10 +01:00
d2b9cbf93b encore des problèmes de configuration 2025-10-29 22:35:10 +01:00
e5fbf372c4 On continue le refactoring des sources 2025-10-29 22:35:10 +01: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
4b29d12859 retire le mediaserver de pmoparadise 2025-10-26 07:42:33 +01:00
882b6e2886 retire le support des codec non flac de radio paradise 2025-10-26 07:33:52 +01:00
a64a5f6a6a evite les doubles download de block 2025-10-26 07:22:12 +01:00
2ab526464d Lire le flac en stream et le décoder en PCM avec claxon 2025-10-26 06:46:56 +01:00
6c40b93089 on retravaille les sources et pmoparadise en particulier 2025-10-25 22:01:02 +02:00
1567beee2e Refactoring profond de pmoparadise 2025-10-21 18:37:40 +02:00
f510e59b1a Patch of the web logger 2025-10-20 19:50:58 +02:00
b6e439dcf6 lastest correction on webapp 2025-10-20 16:18:21 +02:00
2632233dbd Correction on cache system 2025-10-20 16:18:21 +02:00
f3e6c59143 Correction de la source radio paradise pour avoir un sous dossier par canal 2025-10-20 16:18:21 +02:00
776c535862 amélioration de la webapp 2025-10-20 16:18:21 +02:00
e9109a8a0c Session de debug radio paradise 2025-10-20 16:18:21 +02:00
7a8562fe8e Ajount d'un viewer radio paradise 2025-10-20 16:18:21 +02:00
032b55a6f1 ebuggage transcodage audio en flac 2025-10-20 16:18:21 +02:00
5c36116092 device multisession 2025-10-20 16:18:21 +02:00
ebc15b0518 nouveau mediarenderer 2025-10-18 14:33:52 +02:00
c1e0151a11 Refactoring des pmosource 2025-10-18 09:38:33 +02:00