Rust/librespot Backend
Relevant source files
The following files were used as context for generating this wiki page:
The Rust/librespot backend is a contained playback leaf that manages Spotify sessions, Connect functionality, audio streaming, and decoding. It serves as the sole production playback implementation for the Spotty macOS music client. The backend provides high-quality 320 kbps audio via local PCM decoding and bridges these streams to the Swift-based AVFoundation renderer.
The module operates as an unofficial, experimental Spotify Premium client leaf. It maintains process-wide ownership where the macOS application creates a single playback engine for one authenticated account. The architecture enforces a narrow C-ABI boundary to separate Rust-based protocol logic from native macOS UI and audio output components.
Sources: README.md:16-20, Backend/spotty-playback/src/lib.rs:1-6, AGENTS.md:46-50
Architecture and Core Modules
The backend organizes responsibilities into specialized modules that handle synchronization, FFI, lifecycle, and transport. It uses a pinned revision of the librespot library to ensure stability across protocol changes.
Module Structure
| Module | Responsibility |
|---|---|
session_lifecycle | Manages Spotify session creation, authentication, and destruction. |
connect | Implements Spotify Connect device discovery and remote playback mirroring. |
player_control | Handles playback commands like play, pause, seek, and track transitions. |
player_event_pump | Dispatches internal player events to the system and UI. |
proxy_sink | Bridges decoded PCM data from Rust to the AVFoundation adapter. |
ffi | Provides the panic-protected C-ABI surface for Swift interaction. |
lifecycle_serialization | Ensures thread-safe mutations of global engine resources. |
Sources: Backend/spotty-playback/src/lib.rs:9-21, Backend/spotty-playback/AGENTS.md:3-8
System Data Flow
The diagram below illustrates the flow of audio data and control commands between the Rust backend and the Swift application.
This diagram shows how control commands flow from Swift to Rust via the ABI, while decoded audio travels from the internal Rust sink to the native macOS audio system.
Sources: AGENTS.md:31-33, AGENTS.md:46-50, Sources/Spotty/Spotify/AGENTS.md:63-65
FFI and C-ABI Surface
The backend exposes a narrow C-ABI through extern "C" functions. These functions are declared in include/spotty_playback.h and must match the signatures in ffi.rs exactly. All exports enter through panic-barrier helpers like block_on_export to prevent Rust panics from aborting the host process.
Key Exported Functions
spotty_playback_init_player: Initializes the playback engine with a configured device name.spotty_playback_load: Loads a specific Spotify URI at a given position.spotty_playback_pause/spotty_playback_resume: Controls the active playback state.spotty_playback_get_position_ms: Returns the current playback progress in milliseconds.spotty_playback_register_audio_data_callback: Sets the function that receives decoded PCM buffers.
Sources: Backend/spotty-playback/src/tests.rs:643-770, Sources/SpottyPlaybackCore/AGENTS.md:7-10, Backend/spotty-playback/AGENTS.md:17-21
FFI Security and Type Stability
The backend validates C layouts and enum encodings against a checked-in fixture (abi-signatures.txt) during testing. It uses stamped_snapshot objects to pass observation state across the FFI boundary as typed C snapshots rather than JSON strings.
Sources: Backend/spotty-playback/src/tests.rs:815-820, Backend/spotty-playback/AGENTS.md:25-28
Lifecycle and Session Management
Lifecycle operations are serialized through a single async lifecycle mutex to maintain correctness. The engine tracks SESSION_GENERATION and LOGOUT_GENERATION to reject stale callbacks or superseded requests.
Recovery and Reconnection
The backend handles transport failures and session invalidation automatically.
- Reconnect triggers capture the current
SESSION_GENERATION. - The system revalidates the generation after acquiring the lifecycle mutex.
- If a session is dead, the
health_check_should_recoverlogic initiates a rebuild. - During teardown or shutdown, recovery is explicitly disabled to avoid conflicts.
Sources: Backend/spotty-playback/src/tests.rs:27-32, Backend/spotty-playback/src/tests.rs:326-340, Backend/spotty-playback/AGENTS.md:9-16
Rehydration and Resuming
Rehydration loads allow playback to resume after a connection loss.
- Only local playback is resumed; the engine ignores remote playback to avoid stealing sessions.
open_rehydration_windowcreates a timed interval where aload_at_positioncommand is accepted for a specific generation.- Paused local players are not resumed automatically.
Sources: Backend/spotty-playback/src/tests.rs:109-125, Backend/spotty-playback/src/tests.rs:160-185
Authentication and Credentials
The engine manages Spotify credentials independently of the Swift UI.
- It stores OAuth credentials in the macOS Keychain.
- Streaming credentials may be cached in a private, app-scoped directory (
Spotty/credentials) with0o700permissions. spotty_playback_authorize_streaminghandles the one-time browser-based grant.spotty_playback_clear_streaming_credentialsremoves all local session data upon logout.
Sources: Backend/spotty-playback/src/tests.rs:408-420, Backend/spotty-playback/src/tests.rs:445-455, PRIVACY.md:15-22
Audio Rendering Flow
The backend uses proxy_sink as the exclusive destination for decoded PCM data. It supports 320 kbps bitrate and enforces gapless transitions.
The audio path is non-blocking. The Rust thread must never be stalled by Swift-side rendering logic.
Sources: Backend/spotty-playback/AGENTS.md:29-32, Sources/Spotty/Spotify/AGENTS.md:63-65, Backend/spotty-playback/src/tests.rs:728-735
Summary
The Rust/librespot backend provides the critical infrastructure for audio streaming and Spotify protocol compliance in Spotty. It operates as a strictly isolated leaf with a narrow ABI, ensuring that complex session management and audio decoding remain decoupled from the macOS application's UI and rendering layers.
Sources: AGENTS.md:46-50, Backend/spotty-playback/src/lib.rs:1-6