docs: record Phase 1.2 Wave 2 progress; update PLAN.md and DeepDrftPublic.Client CLAUDE.md
This commit is contained in:
@@ -76,11 +76,12 @@ Both are configured with JSON serializer settings (case-insensitive property mat
|
||||
### Format decoders (TypeScript)
|
||||
New modules in `DeepDrftPublic/Interop/audio/`:
|
||||
|
||||
- `IFormatDecoder.ts`: Interface. Defines contract for format-specific decoders: `parseHeader(chunk, offset)` → header metadata; `decodeChunk(chunk, offset)` → `AudioBuffer`.
|
||||
- `WavFormatDecoder.ts`: Concrete WAV implementation. Parses RIFF/WAVE structure, fmt and data chunks. All WAV-specific byte-parsing logic lives here. Exported as the default WAV decoder.
|
||||
- Future decoders: MP3, FLAC, etc. (TBD).
|
||||
- `IFormatDecoder.ts`: Interface. Defines contract for format-specific decoders: `parseHeader(chunk, offset)` → header metadata; `decodeChunk(chunk, offset)` → `AudioBuffer`; `getAlignedSegmentSize(chunk, offset, rawData?)` → frame-aligned segment boundary (optional `rawData` parameter for format-specific frame-boundary scanning).
|
||||
- `WavFormatDecoder.ts`: Concrete WAV implementation (active). Parses RIFF/WAVE structure, fmt and data chunks. All WAV-specific byte-parsing logic lives here. Exported as the default WAV decoder.
|
||||
- `Mp3FormatDecoder.ts`: Concrete MP3 implementation (implemented, not yet wired). Implements `IFormatDecoder` for MP3: ID3v2 skip, MPEG Layer III frame-sync + header decode (MPEG1/2/2.5), Xing/Info/VBRI VBR-header detection (frame count + 100-entry TOC for seek), CBR frame-aligned segment sizing, VBR TOC-interpolation seek (`calculateByteOffset`), zero-copy `wrapSegment` (raw MP3 frames are self-contained). CBR sub-frame tail guard prevents over-read.
|
||||
- `FlacFormatDecoder.ts`: Concrete FLAC implementation (implemented, not yet wired). Implements `IFormatDecoder` for FLAC: scans all metadata blocks (STREAMINFO mandatory, SEEKTABLE optional), extracts 20-bit sample rate / 3-bit channels / 5-bit bitsPerSample / 36-bit total-samples from bit-packed STREAMINFO, builds 38-byte synthetic STREAMINFO block for per-segment wrapping, binary-search SEEKTABLE for seek. `wrapSegment` prepends `fLaC + STREAMINFO` to each audio segment so `decodeAudioData` sees a valid FLAC stream. `getAlignedSegmentSize` scans backward through peek bytes for the `0xFF/(0xF8|0xF9)` FLAC frame sync so each segment ends on a real frame boundary.
|
||||
|
||||
`StreamDecoder.ts` remains the orchestrator — it accepts the first chunk, selects the right format decoder via factory (based on `contentType`), delegates all format-specific work to it, and chains subsequent chunks through the same decoder instance.
|
||||
`StreamDecoder.ts` remains the orchestrator — it accepts the first chunk, selects the right format decoder via factory (based on `contentType`), peeks candidate bytes before calling `getAlignedSegmentSize` (non-destructive read), passes them as `rawData`, and uses zero-copy `subarray` for the actual segment. It delegates all format-specific work to the decoder and chains subsequent chunks through the same decoder instance. `Mp3FormatDecoder` and `FlacFormatDecoder` are implemented modules but not yet wired into `AudioPlayer.createFormatDecoder` factory (Wave 3 pending).
|
||||
|
||||
### Component integration
|
||||
- `AudioPlayerProvider.razor` is the cascading host. It injects `IStreamingPlayerService` (resolved to `StreamingAudioPlayerService` in DI), stores it in a cascade with `IsFixed="true"`, and keeps it alive across navigation.
|
||||
|
||||
@@ -32,7 +32,7 @@ These were flagged during the audit but classified as feature work, not defect f
|
||||
- Client side: the JS decoder is currently a WAV byte-walker. For non-WAV, the simplest path is `decodeAudioData` over the full payload (loses streaming-start). The richer path is per-format chunked decoders. Worth a design pass before committing.
|
||||
- **Prerequisite:** None functionally, but consider settling **Phase 4 (HTTP Range)** first — native range/cache is much more important for large MP3s than for WAVs.
|
||||
- **Constraint:** Spectrum FFT tap currently relies on raw `AudioBuffer`s through `decodeAudioData`. If a future path uses `MediaElementAudioSourceNode` (see 4.1), the FFT tap still works but the early-playback story changes.
|
||||
- **Progress:** Wave 1 (foundation) landed on `dev` (2026-06-10). Format router (`Mp3AudioProcessor`, `FlacAudioProcessor`, `AudioProcessorRouter`) and client-side `IFormatDecoder` interface + `WavFormatDecoder` implementation are in place. `TrackContentService.AddTrackAsync` is the new format-agnostic primary method; `AddTrackFromWavAsync` is a shim. Client `StreamDecoder` is now format-agnostic; WAV-specific logic moved to `WavFormatDecoder`. Wave 2 (per-format chunked decoders) and Wave 3 (full wiring) pending.
|
||||
- **Progress:** Wave 1 (foundation) landed on `dev` (2026-06-10). Format router (`Mp3AudioProcessor`, `FlacAudioProcessor`, `AudioProcessorRouter`) and client-side `IFormatDecoder` interface + `WavFormatDecoder` implementation are in place. `TrackContentService.AddTrackAsync` is the new format-agnostic primary method; `AddTrackFromWavAsync` is a shim. Client `StreamDecoder` is now format-agnostic; WAV-specific logic moved to `WavFormatDecoder`. Wave 2 (per-format chunked decoders) landed on `dev` (2026-06-11): `Mp3FormatDecoder` and `FlacFormatDecoder` are implemented modules at `DeepDrftPublic/Interop/audio/`; `IFormatDecoder.getAlignedSegmentSize` extended with optional `rawData` parameter for format-specific frame-boundary scanning; `StreamDecoder.tryDecodeNextSegment` updated to peek candidate bytes and pass them via `rawData`, using zero-copy `subarray` for segments. Wave 3 (wiring decoders into `AudioPlayer.createFormatDecoder` factory; end-to-end integration) pending.
|
||||
|
||||
### 1.3 Preload / prefetch of the next track
|
||||
|
||||
|
||||
Reference in New Issue
Block a user