Skip to main content

Design a Music Streaming App

Concepts Utilized: Audio Streaming (AVPlayer/ExoPlayer), Background Playback, Offline Downloads, DRM Protection, Lock Screen Controls, Now Playing Info Center, Gapless Playback, Audio Session Management, Download Manager

This document covers the mobile architecture for a music streaming application with audio playback, offline downloads, and background audio support.

Requirements

Functional Requirements

FeatureDescription
Browse and searchNavigate and search the music library
StreamingOn-demand audio streaming
DownloadsOffline playback of downloaded content
PlaylistsCreate and manage playlists
Background playbackAudio continues with lock screen controls
Queue managementView and modify the playback queue
Audio qualityConfigurable streaming and download quality

Non-Functional Requirements

RequirementTarget
Playback startUnder 1 second
Gapless playbackSeamless transitions between tracks
Battery usageMinimal consumption during background playback
Storage efficiencySmart caching with configurable limits

Architecture Overview

Loading diagram...

Core Components

1. Audio Player Engine

Platform Audio APIs

PlatformAPI
iOSAVFoundation (AVPlayer, AVAudioEngine)
AndroidExoPlayer, MediaPlayer
Cross-platformPlatform-specific implementations behind shared interface

Player State Machine

Loading diagram...

2. Streaming Architecture

Adaptive Bitrate Options

QualityBitrateFile Size (3 min song)
Low24 kbps~0.5 MB
Normal96 kbps~2 MB
High160 kbps~3.5 MB
Very High320 kbps~7 MB
Lossless~1000 kbps~20 MB

Streaming Quality Selection

Auto quality selection: When quality is set to auto, select based on network conditions: WiFi uses very high quality, 4G uses high, 3G uses normal, and slow connections use low. Manual quality overrides this selection.

Buffer management: Monitor buffer status by comparing current playback position with buffer end. Trigger additional buffering when remaining buffer drops below a target threshold (such as 30 seconds) and more content is available.

3. Queue Management

Data structure: Maintain both original and shuffled queue arrays. Track current index and shuffle state. Select the active queue based on shuffle state.

Current track and up next: Return track at current index from the active queue. Up next returns remaining tracks after current index.

Set queue: Store tracks in original queue. If shuffled, remove current track from list, shuffle remaining, prepend current track, and reset index to 0.

Toggle shuffle: When enabling shuffle, keep current track at position 0 and shuffle remaining tracks. When disabling, find current track's position in the original queue and restore that index.

Skip: Adjust current index by the delta (positive for forward, negative for backward), clamping to valid queue bounds.

4. Offline Downloads

Download Manager

Download function:

  1. Check if already downloaded; return early if so
  2. Verify sufficient storage; notify delegate of error if insufficient
  3. Create download task with appropriate URL for quality
  4. Queue task; start immediately if under concurrent download limit

Local path lookup: Construct path in documents directory using track ID. Check file existence and return path if found, nil otherwise.

Storage management: Calculate total downloaded size by summing file sizes in the downloads folder. Remove downloads by deleting the file and updating database status.

Storage Priority

PriorityEviction Policy
User downloadsNever auto-delete
Recently playedCache for 7 days
Playlists marked offlineKeep synced
Auto-cached songsLRU eviction when space needed

5. Background Playback

iOS Audio Session Configuration

Audio session setup: Configure AVAudioSession with playback category to enable background audio. Enable options for AirPlay and Bluetooth output. Activate the session to claim audio resources.

Remote command center: Register handlers for lock screen and headphone controls. Handle play, pause, next track, previous track, and seek commands. Return success or failure status from each handler.

Now playing info: Update the MPNowPlayingInfoCenter with current track metadata (title, artist, duration, elapsed time, and album artwork). This information displays on the lock screen and in Control Center.

6. Gapless Playback

Gapless playback eliminates audible gaps between consecutive tracks by pre-loading the next track before the current track ends.

Implementation approach:

  1. Maintain references to current player and pre-loaded next player
  2. When preparing next track, create an asset and player item, then preroll the player
  3. Observe the current player's end notification
  4. When current track ends, immediately swap to the pre-loaded player and start playback
  5. Begin preparing the subsequent track to maintain the preload chain

Data Layer

Local Database Schema

Tracks table: Stores cached track metadata including ID, title, artist and album references, duration, download status, local file path, last played timestamp, and play count.

Playlists table: Stores playlist metadata including ID, name, offline sync flag, track count, total duration, owner reference, and timestamps.

Playlist tracks table: Join table linking playlists to tracks with position ordering and added timestamp. Composite primary key prevents duplicates.

Listening history table: Records play history with track reference, timestamp, duration listened, and context (what triggered playback, such as album, playlist, or search).

Caching Strategy

Get cached audio: Check if file exists at cache path. If found, update access time for LRU tracking and return the path. Return nil if not cached.

Cache audio: Before writing, check if cache would exceed size limit. If so, evict least recently used entries until space is available. Write data to the cache path.

LRU eviction: Query database for the cached track with oldest access time. Delete that file from the cache to free space.

Performance Optimizations

1. Pre-buffering

Implementation approach: Get the next few tracks from the queue (such as 3). For each track, prefetch album art and pre-buffer the first portion of audio (such as 10 seconds) if not already cached. This ensures smooth playback transitions.

2. Album Art Loading

Two-tier caching with resizing:

  1. Create cache key from URL and size
  2. Check memory cache; return if found
  3. Check disk cache; promote to memory and return if found
  4. Download image, resize to requested dimensions
  5. Store in both memory and disk caches
  6. Return the resized image

3. List Rendering

Cell configuration: Set text labels immediately. Cancel any existing image load task. Show placeholder image. Start a new async task to load album art. When loaded, update the image view on the main thread.

Cell reuse: Cancel the image load task and reset to placeholder image. This prevents images from previous rows appearing in recycled cells.

Summary

DecisionOptionsRecommendation
Audio frameworkAVPlayer, AVAudioEngine, ExoPlayerPlatform-native (AVPlayer/ExoPlayer)
Streaming formatProgressive, HLS/DASHProgressive for music
Offline storageApp sandbox, shared storageApp documents directory
Queue stateIn-memory, PersistedPersisted to survive app termination
CachingFixed size, LRU, User-controlledLRU with user downloads protected