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.
39 lines
1.1 KiB
TOML
39 lines
1.1 KiB
TOML
[package]
|
|
name = "pmoaudio-ext"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
|
|
[dependencies]
|
|
# Core audio types
|
|
pmoaudio = { path = "../pmoaudio" }
|
|
pmocovers = { path = "../pmocovers"}
|
|
|
|
# Optional dependencies for cache-sink feature
|
|
pmoaudiocache = { path = "../pmoaudiocache", optional = true }
|
|
pmoflac = { path = "../pmoflac", optional = true }
|
|
pmometadata = { path = "../pmometadata", optional = true }
|
|
|
|
# Optional dependencies for playlist integration
|
|
pmoplaylist = { path = "../pmoplaylist", optional = true }
|
|
pmocache = { path = "../pmocache", optional = true }
|
|
|
|
# Async runtime
|
|
tokio = { version = "1.0", features = ["full"] }
|
|
tokio-util = { version = "0.7" }
|
|
async-trait = "0.1"
|
|
|
|
# Utilities
|
|
tracing = "0.1"
|
|
rand = "0.8"
|
|
|
|
# HTTP streaming dependencies
|
|
bytes = { version = "1.0", optional = true }
|
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
|
|
|
[features]
|
|
default = []
|
|
cache-sink = ["dep:pmoaudiocache", "dep:pmoflac", "dep:pmometadata"]
|
|
playlist = ["cache-sink", "dep:pmoplaylist", "dep:pmocache"]
|
|
http-stream = ["dep:pmoflac", "dep:pmometadata", "dep:bytes", "dep:serde"]
|
|
all = ["cache-sink", "playlist", "http-stream"]
|