Every music app needs a player. Making one that feels great — and doesn't break — is the hard part. In this post we walk through the audio engine that powers Phonq.
The core is a single HTML5 audio element owned by a global React context. That context holds the queue, shuffle and repeat state, and survives navigation across the app. When you press play on a track card, we build the queue from the section you're in, so 'next' and 'previous' always make sense.
The waveform is the fun part. We route the audio element through an AnalyserNode in the Web Audio API and read frequency data every animation frame, drawing bars onto a canvas. There's a catch though: the Web Audio API only lets you analyse media that was loaded with CORS approval.
Before connecting the graph, we probe the stream with a ranged CORS request. If the stream allows it, we wire up the analyser. If not — which happens with some CDNs — we swap to a deterministic, decorative visualizer. The key decision was to make playback completely independent of the visualizer. No analyser, no problem: the music always plays.
The same defensive thinking applies to the queue. Shuffle uses a Fisher-Yates-safe 'don't repeat yourself' index picker, repeat modes are handled at the 'ended' event, and everything degrades gracefully on mobile and slow connections.
You can read the whole implementation in the open-source repository. Building it taught us a lot about Web Audio, and we're happy to share.