CP's Nice Player
Stream audio files inside VS Code with chunked, low-latency playback powered by FFmpeg and Web Audio.
Instead of transcoding an entire file before play starts, CP's Nice Player scans the source, builds a time-indexed manifest, and fetches ~1 second segments on demand. Playback begins quickly, seeking jumps to the right chunk, and memory stays bounded to a small sliding buffer.
Features
- Chunked streaming — Audio starts after the first segment is ready, not after a full-file transcode.
- Responsive seeking — Scrub to any position; only the chunks you need are fetched and decoded.
- Seamless chunk joins — WSOLA-aligned linear crossfade blends overlap tails at chunk boundaries (configurable via
playback.crossfadeMs).
- Bounded memory — The webview keeps a configurable window of decoded PCM, not the whole track.
- Broad format support — MP3, WAV, OGG, Opus, FLAC, M4A, AAC, WebM, MP4, and MKV containers open in the custom editor (audio tracks only).
- Remote development — Playback works over Remote SSH, Dev Containers, WSL, and Codespaces via VS Code port forwarding.
- Configurable output — Stream as Ogg Vorbis (default) or FLAC, with tunable chunk size and buffer depth.
Installation
Install from your editor's marketplace:
Or download the .vsix from GitHub Releases and install it with Extensions: Install from VSIX….
Getting started
Open a file
Supported files open in CP's Nice Player by default. You can also:
- Run CP's Nice Player: Open in CP's Nice Player from the Command Palette.
- Right-click a file and choose Open With… → CP's Nice Player.
To use a different editor for a file type, use Reopen Editor With… or set workbench.editorAssociations in Settings.
Requirements
- VS Code 1.90.0 or newer (or a compatible editor such as VSCodium on Open VSX).
- FFmpeg must be installed and available on your
PATH, or set cp-nice-player.ffmpegPath in user settings to the executable on the machine where playback runs. FFmpeg is used to probe the source and transcode playback chunks on the host.
If FFmpeg is missing, the extension shows a one-time notification with setup guidance.
How it works
When you open a track:
- The extension starts a playback server on
127.0.0.1 in the environment where FFmpeg runs.
- It resolves the server address with
vscode.env.asExternalUri, which triggers VS Code port forwarding when the UI and server are not on the same host (Remote SSH, Dev Containers, WSL, Codespaces, etc.). The webview receives that external URI and fetches chunks through the forwarded port.
- The server scans audio frames and builds an index of ~1 s, frame-aligned chunks.
- The player fetches the index, then requests chunks around the playhead.
- Each chunk is decoded to PCM in the webview and written into an AudioWorklet ring buffer for continuous playback.
- At chunk seams, a WSOLA-aligned linear crossfade blends the overlap tail of one chunk with the head of the next.
- On seek, in-flight fetches are cancelled and buffering reprioritizes around the new position.
Extension settings
| Setting |
Default |
Description |
cp-nice-player.ffmpegPath |
(empty) |
Path to the ffmpeg executable on the playback machine. Machine-scoped (user settings only). Leave empty to use ffmpeg from PATH. |
cp-nice-player.playback.format |
ogg |
Preferred output format for streamed chunks: ogg (smaller, faster) or flac (lossless). If the preferred FFmpeg encoder is unavailable, the extension falls back to mp3 (when ogg is set) or wav (when flac is set). See Encode format resolution. |
cp-nice-player.playback.oggQuality |
6 |
libvorbis quality (0–10) when effective format is ogg. Also maps to libmp3lame quality when fallback is mp3. Higher is better quality and larger chunks. |
cp-nice-player.playback.chunkDurationSec |
1 |
Target duration of each streamed chunk in seconds (0.5–10). |
cp-nice-player.playback.crossfadeMs |
20 |
Per-chunk overlap tail length in milliseconds (0–500). Non-final chunks encode a short tail past the body boundary; the player crossfades it with the next chunk. Set to 0 to disable crossfade. |
cp-nice-player.playback.chunkBufferCount |
5 |
Number of chunks to buffer ahead of the playhead, including the current chunk. At 1 s chunks, 5 ≈ 5 s of buffered audio. |
cp-nice-player.playback.maxIndexEntries |
64 |
Maximum stream index manifests kept in memory for the playback server session (1–256). |
cp-nice-player.playback.maxEncodedChunks |
64 |
Maximum encoded audio chunks kept in the webview LRU cache (1–256). |
cp-nice-player.playback.debugLogging |
false |
Log playback settings and transcode template at startup, plus per-request server activity, to the extension host console. |
Known limitations
- Audio only — Video tracks are not played; only the audio stream is handled.
- VS Code only — Streaming is served through VS Code's port forwarding to the extension's localhost server, not for external media players or standalone network deployment.
Development
Running tests
npm test runs the full suite:
| Command |
What it runs |
npm test |
Vitest media tests, then Mocha extension-host tests |
npm run test:media |
Vitest + jsdom — engine modules, StreamingAudioEngine, WorkletScheduler, player UI |
npm run test:extension |
Mocha + @vscode/test-cli — playback backend and playerPanel bridge |
FFmpeg on PATH is required for integration tests in the extension suite; suites skip automatically when FFmpeg is missing.
Release notes
0.2.1
WSOLA alignment at chunk joins now searches ±overlapFrames (signed shift support). Encode-format fallback (mp3/wav) and streaming architecture docs updated.
0.2.0
In-memory streaming only — no disk cache under globalStorage/stream/. Pin-aware LRU for encoded chunks in the webview. FFmpeg encoder fallback to mp3/wav when ogg/flac encoders are unavailable. Full backend and frontend test suites (npm test).
0.1.7
Accurate playhead from consumed PCM frames (with WSOLA drop compensation), so the UI stays in sync during buffering and at chunk joins. Worklet ring stats at 20 Hz, decode limited to one chunk ahead, and seek UI held steady while dragging. Debug panel adds frame-consumption and WSOLA diagnostics.
0.1.6
Leaner webview debug UI and event log (fetch/decode completion only, with size and timing). Default crossfade is 20 ms. When playback.debugLogging is on, the extension logs effective settings at startup and one FFmpeg transcode template per server start.
0.1.5
Chunk-boundary crossfade: configurable playback.crossfadeMs, backend frame-aligned overlap tails, and frontend WSOLA-aligned linear blending. Playback now uses an AudioWorklet PCM scheduler. npm test runs headless (no Electron). WebCodecs decode path removed; chunks decode via decodeAudioData only.
0.1.4
Lowers the minimum VS Code version to 1.90.0 and adds automated publishing to Open VSX, the Visual Studio Marketplace, and GitHub Releases.
0.1.3
Security hardening: ffmpegPath restricted to machine scope, XSS fixes in the debug panel, and strict CORS on the playback server.
0.1.2
Fixes playback in remote and containerized setups by resolving the server URL through vscode.env.asExternalUri, which triggers VS Code port forwarding. Stream request URLs are built with the URL API for safe path joining.
0.1.0
Streaming engine overhaul: independent fetch and decode loops, suspend/resume pause without discarding scheduled audio, configurable fetch concurrency, and more reliable seek/buffer behavior.
0.0.1
Initial release with chunked streaming playback: frame-indexed segments, on-demand FFmpeg transcode, and Web Audio scheduling in the editor webview.