-
Notifications
You must be signed in to change notification settings - Fork 0
System Architecture
Relevant source files
The following files were used as context for generating this wiki page:
Aurora utilizes a daemon/client architecture to decouple audio engine management from the graphical user interface. This split ensures that music playback remains uninterrupted even if the GUI is closed or restarted. The two components communicate over a local Unix domain socket using a custom, length-prefixed JSON protocol defined in the shared aurora-protocol crate.
The system is divided into three primary crates:
-
aurora-daemon: The background service responsible for the audio pipeline (rodio), library indexing (SQLite), and system integrations like MPRIS2. -
aurora-player: The Slint-based frontend that provides the user interface and sends commands to the daemon. -
aurora-protocol: The "Source of Truth" containing shared data structures and the IPC message schema.
The following diagram illustrates the lifecycle of a request, from a user interaction in the GUI to audio output in the daemon.
Diagram: Request-Response Lifecycle
sequenceDiagram
participant UI as "aurora-player (Slint UI)"
participant Client as "aurora-player (interface.rs)"
participant Protocol as "aurora-protocol"
participant Daemon as "aurora-daemon (handlers.rs)"
participant Audio as "rodio Sink"
UI->>Client: User clicks "Play Song"
Client->>Protocol: Construct Request::Play(Uuid)
Protocol-->>Client: Serialize to JSON
Client->>Daemon: Send length-prefixed JSON over Unix Socket
Daemon->>Protocol: Deserialize JSON to Request enum
Daemon->>Daemon: handle_client() dispatches to Play handler
Daemon->>Audio: sink.play() / append()
Daemon->>Protocol: Construct Response::Status
Daemon->>Client: Broadcast Status to all connected clients
Client->>UI: Update Slint Properties (position, is_playing)
Sources: README.md:12-18, protocol/src/interface.rs:5-35, daemon/src/main.rs:115-142
Aurora relies on Unix domain sockets for low-latency local communication. The daemon acts as a UnixListener, while the player acts as a UnixStream client.
The daemon manages its lifecycle using specific files located in /tmp:
| Constant | Path | Purpose |
|---|---|---|
PIDFILE |
/tmp/aurora-daemon.pid |
Ensures only one instance of the daemon runs. |
SOCKFILE |
/tmp/aurora-daemon.sock |
The Unix socket address for IPC. |
OUTFILE |
/tmp/aurora-daemon.out |
Redirected stdout for the daemonized process. |
Sources: daemon/src/main.rs:24-26
Upon startup, the daemon binds to SOCKFILE daemon/src/main.rs:108-112. When a client connects, the daemon splits the socket into a reader and writer daemon/src/main.rs:117.
- The Writer is stored in the global
StateStruct.clientslist to allow for asynchronous broadcasts (e.g., status updates or theme changes) daemon/src/main.rs:121. - The Reader is passed to
handlers::handle_clientto process incomingRequestvariants daemon/src/main.rs:128.
To ensure reliable message framing over the stream-oriented Unix socket, Aurora uses a length-prefixed strategy.
- Length Header: Every message is preceded by a 4-byte big-endian integer representing the length of the following JSON payload.
-
JSON Payload: The actual data is a serialized
RequestorResponseenum variant.
The aurora-protocol crate defines the exact shape of every message. This ensures that both the daemon and the player are always in sync regarding data types.
Key Structures:
-
Request: Commands sent from Player to Daemon (e.g.,Play,Pause,SetVolume,PlaylistCreate) protocol/src/interface.rs:6-35. -
Response: Data or updates sent from Daemon to Player (e.g.,Status,SearchResults,Theme) protocol/src/interface.rs:38-50. -
Status: A heartbeat-style struct containing the current playback state protocol/src/lib.rs:13-20.
Diagram: Protocol Entity Mapping
classDiagram
class Request {
<<enumeration>>
+Play(Uuid)
+Pause()
+Enqueue(Uuid)
+SetVolume(f32)
+Search(SearchType)
}
class Response {
<<enumeration>>
+Status(Status)
+Queue(Vec~Song~)
+Theme(Theme)
+Error(u8, String)
}
class Status {
+Option~Song~ current_song
+bool is_paused
+Duration position
+f32 volume
}
class Theme {
+String bgd0
+String acct
+String txt1
}
Request ..> Response : Triggers
Response o-- Status : Contains
Response o-- Theme : Contains
Sources: protocol/src/interface.rs:1-51, protocol/src/lib.rs:12-40
When the system initializes, the daemon prepares the environment for IPC and audio:
-
Daemonization: If launched without arguments, the process forks into the background and creates the
PIDFILEdaemon/src/main.rs:31-40. -
State Initialization: The
StateStructis initialized, loading the library index from SQLite, recently played history, and liked songs daemon/src/main.rs:71-94. -
Thread Spawning: Several background threads are started to handle asynchronous events:
-
watcher_thread: Monitors therodio::Sinkto advance the queue when a song ends daemon/src/main.rs:97. -
theme_thread: Watches for changes inconfig.tomlto broadcast newThemeresponses daemon/src/main.rs:106. -
mpris_thread: Syncs daemon state with the system D-Bus daemon/src/main.rs:103.
-
-
IPC Loop: The
async_mainfunction enters an infinite loop, accepting new Unix socket connections and spawning atokiotask for each client daemon/src/main.rs:115-142.
The daemon captures TERM_SIGNALS. Upon receiving a termination signal, it performs a cleanup by deleting the SOCKFILE and PIDFILE before exiting daemon/src/main.rs:52-63.
Sources: daemon/src/main.rs:51-143
Overview
aurora-daemon
- Background Service
- Startup & State Init
- Request Handlers & Dispatch
- Playback Engine & Audio
- Library Indexing & Watching
- Playlists, Liked & History
- Background Threads
aurora-protocol
aurora-player
Reference