Design a mobile video-streaming client — buffering strategy, adaptive bitrate, offline downloads
The ABR decision loop that blends throughput and buffer occupancy, the player's state machine, and the separate path a download manager needs for offline playback.
LEARN BY DOINGPut your intuition to work3 steps
Design a mobile video-streaming client — buffering strategy, adaptive bitrate, offline downloads
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.#Clarify the requirements
Video streaming design questions cover a lot of ground, so I'd scope it first: video-on-demand or live (live adds a latency budget and a moving "live edge" that VOD doesn't have), DRM-protected content or open, offline downloads for licensed content, the network conditions we're designing for (a market with strong WiFi everywhere is a very different problem than a market where 3G on a crowded cell tower is the common case), and whether multiple audio/subtitle tracks and ad insertion are in scope. For the rest of this answer I'll assume: VOD with optional DRM, offline downloads required, and a wide range of network conditions — which is the version of this question that actually stresses the interesting parts of the design.
#The pipeline, top to bottom
A streaming client is built around a manifest — HLS's .m3u8 or DASH's .mpd — that lists the available renditions (a ladder of resolution/bitrate pairs) and the segments (typically 2-10 second chunks) that make up each rendition. The player downloads segments ahead of the playhead into a buffer, decodes them (always via hardware acceleration — software decode burns battery and thermal budget fast), and renders frames on schedule. The two decisions that define the feel of the player are how big a buffer to maintain, and which rendition to fetch next — that second one is the adaptive bitrate algorithm.
#Buffer states and the player's state machine
The buffer isn't just "more is better" — too little risks stalling on any network hiccup, too much wastes bandwidth on video that might never play (the user could abandon the video) and delays how quickly a bitrate upgrade takes effect. A typical design targets a buffer window (say, 30 seconds) with low and high watermarks that drive how aggressively the player prefetches, and the player itself is a state machine layered on top of that buffer:
#The ABR decision loop
Pure throughput-based estimation — take a harmonic mean of the last few segment download speeds and pick the highest rendition whose bitrate that throughput can sustain — reacts fast but is noisy, especially on cellular, where a single slow segment can trigger an unnecessary downgrade. Pure buffer-based estimation — use how much buffer you're sitting on as your confidence signal, since buffer occupancy is a much more stable, low-noise number that already reflects the network's recent behavior — is more robust in steady state but reacts too slowly at startup, when there's no buffer yet to read a signal from. Production players (ExoPlayer, AVPlayer) approximate a hybrid: throughput-based for the cold-start decision (there's no buffer signal yet, so estimate from the first segment fetches), and buffer-based once the player is in steady state. Bitrate switches only happen at segment boundaries — you can't change encoding mid-segment — and a cooldown/hysteresis window prevents the algorithm from flapping between two adjacent renditions when throughput is borderline, because oscillating quality is more visually jarring to a viewer than holding a slightly lower bitrate steady.
#Startup latency deserves its own policy
Cold start and steady-state playback have different goals, so they should use different logic rather than forcing one ABR policy to serve both. At startup there's no buffer to read a confidence signal from, so the player should fetch the lowest bitrate for the first segment or two to get pixels on screen as fast as possible, then ramp up once real throughput data exists — optimizing for time-to-first-frame rather than for picking the "correct" steady-state bitrate immediately. Pre-fetching the manifest as early as the user's intent is known (e.g., on thumbnail tap, before the player screen even finishes transitioning in) shaves real, user-perceptible milliseconds off this path.
#Offline downloads are a different code path, not a special case of ABR
Once content is fully downloaded, there is no adaptive bitrate — the user picked a fixed rendition (or the app picked one based on available storage) at download time, and the download manager's job is completely different: resumable range requests so a download can pause and continue across app restarts and network changes, a storage quota policy, and — for DRM content — acquiring an offline license up front and renewing it before it expires, or previously downloaded content silently stops playing with no obvious cause to the user. This is worth calling out explicitly in an interview: candidates who describe the downloader as "ABR but writing to disk instead of a buffer" are missing that the two systems solve genuinely different problems and share almost no logic.
#Resilience and the metrics that actually define quality
Real networks fail in pieces, not all at once, so segment fetches need their own retry-with-backoff independent of the ABR decision, and sustained failure on one CDN should trigger multi-CDN failover rather than surfacing an error immediately. Under sustained poor conditions, dropping to the lowest video rendition — or even audio-only — is a better user experience than repeated hard stalls. Finally, none of this can be tuned without telemetry: startup time, rebuffer ratio, average bitrate, and bitrate-switch count are the QoE (quality of experience) metrics that the large streaming players actually optimize against, and a senior candidate should name them, because "does it feel smooth" isn't answerable without deciding, in advance, what "smooth" is measured by.