C ABI Interface (FFI)
Relevant source files
The following files were used as context for generating this wiki page:
The C ABI Interface provides a narrow Foreign Function Interface (FFI) between the Swift application and the Rust playback engine. This interface allows the Swift-based UI to control Spotify sessions, manage playback, and receive audio data from the underlying librespot implementation.
The surface is defined in Sources/SpottyPlaybackCore/include/spotty_playback.h and must match the exported symbols from the spotty-playback Rust crate exactly. The engine uses a static library format contained within an XCFramework for consumption by Swift.
Sources: Sources/SpottyPlaybackCore/AGENTS.md:1-10, AGENTS.md:38-41
Interface Architecture
The FFI architecture follows a strict boundary between Swift and Rust. PlaybackCore.swift acts as the sole importer of the C module, while RustPlaybackEngine.swift is the only caller. The Rust engine decoded PCM data crosses this adapter to Apple's AVFoundation for final output.
The diagram shows the narrow path data takes from the Rust engine through the C ABI to the Swift application and audio system.
Sources: Sources/SpottyPlaybackCore/AGENTS.md:6-8, AGENTS.md:38-45
Memory and Ownership Rules
The FFI requires explicit ownership management for every pointer, buffer, and callback.
- Every Rust allocation must have a documented release path to prevent memory leaks.
- The system includes specific release functions like
spotty_playback_free_stringandspotty_playback_free_queue_snapshot. - Panic barriers are implemented in Rust to prevent crashes from crossing the ABI; however, they do not validate foreign pointers or extend callback lifetimes.
Sources: Sources/SpottyPlaybackCore/AGENTS.md:9-11, Backend/spotty-playback/src/tests.rs:555-560
Exported Function Signatures
The C ABI exports a stable set of functions for controlling the playback lifecycle and state. These are validated against a signature fixture (abi-signatures.txt) to ensure binary compatibility.
Playback Control Functions
| Function Name | Return Type | Description |
|---|---|---|
spotty_playback_init_player | SpottyPlaybackResult | Initializes the player with a configuration string. |
spotty_playback_load | SpottyPlaybackResult | Loads a URI at a specific position. |
spotty_playback_play_uri | SpottyPlaybackResult | Plays a single Spotify URI. |
spotty_playback_pause | SpottyPlaybackResult | Pauses current playback. |
spotty_playback_resume | SpottyPlaybackResult | Resumes paused playback. |
spotty_playback_next | SpottyPlaybackResult | Skips to the next track. |
spotty_playback_seek | SpottyPlaybackResult | Seeks to a specific millisecond position. |
Sources: Backend/spotty-playback/src/tests.rs:608-660
State and Callback Registration
The interface uses callbacks to push state updates from Rust to Swift.
| Function Name | Callback Type | Purpose |
|---|---|---|
spotty_playback_register_audio_data_callback | AudioDataCallback | Streams raw PCM float data. |
spotty_playback_register_playback_state_callback | PlaybackStateCallback | Reports changes in play/pause, position, and track. |
spotty_playback_register_connection_state_callback | ConnectionStateCallback | Reports session connectivity and errors. |
spotty_playback_register_queue_callback | QueueCallback | Synchronizes the play queue state. |
Sources: Backend/spotty-playback/src/tests.rs:661-680
Validation and Integrity
The project employs several scripts to maintain ABI integrity.
- Symbol Verification:
Scripts/check.shusesnmto compare the actual exports of the static library with the declarations in the C headers. - Signature Matching:
Scripts/generate-c-header.shusescbindgenandClangAST dumps to ensure the generated C header matches theabi-signatures.txtfixture. - Dead Export Detection: The build system checks if every header export is actually called by
PlaybackCore.swift. Any unused exports cause a validation failure. - Layout Consistency: Rust tests in
Backend/spotty-playback/src/tests.rscompile a temporary C probe to verify thatrepr(C)struct layouts in Rust match the expectations of a C compiler.
The sequence diagram illustrates the automated validation steps that occur during the build process to ensure the C ABI remains stable.
Sources: Scripts/check.sh:78-125, Scripts/generate-c-header.sh:65-85, Backend/spotty-playback/src/tests.rs:770-800
Data Structures (repr(C))
Data is passed across the FFI using C-compatible structures. Common snapshots include:
- SpottyPlaybackSnapshot: Contains
position_ms,duration_ms,is_playing, and URIs for track/context. - SpottyConnectionSnapshot: Tracks
session_connected,resume_pending, andcredentials_rejected. - SpottyQueueSnapshot: Manages track lists for
next_tracksandprev_tracks.
Sources: Backend/spotty-playback/src/tests.rs:735-765
Error Handling
FFI functions return a SpottyPlaybackResult, which is an int32_t mapping to specific error states:
SpottyPlaybackResultOk(0)SpottyPlaybackResultErrorSpottyPlaybackResultSessionDisconnectedSpottyPlaybackResultSessionNotConnectedSpottyPlaybackResultCredentialsRejected