This article details the system design behind a beat-discovery mobile app requiring immediate, beat-aligned, artifact-free audio switching under mobile constraints. It outlines a custom architecture featuring virtual chunking, byte-range fetching, careful MP3 boundary handling, and a native C++ playback engine. The design addresses limitations of standard players and streaming protocols for real-time, non-linear audio interaction.
Read original on InfoQ ArchitectureThe core challenge was to enable seamless, beat-aligned, and artifact-free switching between audio sections and tracks on mobile devices, despite network latency, jitter, and bandwidth limitations. This interaction model combined a personalized feed navigation with stringent audio playback requirements, where users frequently jumped between sections or tracks, spending only 2-3 seconds per beat.
The final architecture involved a custom transport model and a native playback engine, comprising six stages: upload, server-side processing, descriptor generation, storage, mobile range fetching, and native playback.
Instead of physical segments (like HLS), the system used virtual chunks. This involved storing one MP3 file and generating compact binary descriptors containing byte ranges for each chunk. The mobile client then fetched only the prioritized byte ranges using HTTP Range requests, offering precise control over data retrieval without the overhead of many small files.
Trade-off: Chunk Size
A chunk size of approximately 3.5 seconds was chosen. Smaller chunks improved responsiveness but increased request overhead, while larger chunks reduced requests but wasted bandwidth on potentially skipped audio, delaying critical data on low-bandwidth connections.
MP3 frames are not always independently decodable due to bit-reservoir behavior. To ensure artifact-free playback when starting at arbitrary chunk boundaries, the system prepended nine overlap frames (warm-up context) to every non-initial chunk during server-side planning. These warm-up samples were decoded and then discarded before writing PCM into the playback buffer. The native C++ playback engine, integrated with React Native, scheduled track and section changes within its audio control loop, bypassing the limitations of the RN bridge for critical timing.
f.write(struct.pack("<I", version))
f.write(struct.pack("<I", len(chunks))) # uint32 count
for chunk in chunks:
f.write(struct.pack("<HHII", chunk.start_frame, chunk.frames, chunk.start_byte, chunk.bytes))A compact binary descriptor format was developed for chunk metadata, optimized for fast mobile parsing and low overhead. This custom format, instead of Protobuf or MessagePack, was chosen due to the fixed record shape and trivial parsing logic, ensuring exact control over byte layout under explicit V1 constraints (e.g., max 10-minute track length, 44,100 Hz sample rate).