Skip to content

Background Threads

Joseph Chacko edited this page Jul 22, 2026 · 2 revisions

Background Threads: MPRIS2, Theme & Watcher

Relevant source files

The following files were used as context for generating this wiki page:

The aurora-daemon relies on three specialized background threads to manage system integration, configuration persistence, and playback continuity. These threads operate independently of the primary IPC request-handling loop, ensuring that the daemon remains responsive to external D-Bus signals, filesystem changes, and audio hardware events.

MPRIS2 Integration (mpris_thread)

The mpris_thread provides integration with the Linux D-Bus MPRIS2 (Media Player Remote Interfacing Specification) protocol. This allows Aurora to be controlled via system media widgets (e.g., GNOME/KDE shells), hardware media keys, and CLI tools like playerctl.

Implementation Details

The implementation is split into two primary components:

  1. The Controller: Manages the mpris-server instance and maps D-Bus method calls (Play, Pause, Seek, etc.) to PlayerCommand variants sent through an internal channel daemon/src/mpris_thread.rs:90-148.
  2. The Command Loop: Listens for PlayerCommand variants and applies them to the global State daemon/src/mpris_thread.rs:31-85.

Metadata Synchronization

A synchronization loop runs every 500ms to reconcile the daemon's internal State with the MPRIS2 bus daemon/src/mpris_thread.rs:156-157. It detects changes in the current_song, playback position, and volume, then updates the D-Bus properties accordingly daemon/src/mpris_thread.rs:183-206.

MPRIS2 Command Mapping

PlayerCommand Action on State IPC Response Triggered
PlayPause state.pause() daemon/src/mpris_thread.rs:34 Status Update
Next state.next(1) daemon/src/mpris_thread.rs:53 Response::Queue daemon/src/mpris_thread.rs:57
Prev state.prev(1) daemon/src/mpris_thread.rs:61 Response::Queue daemon/src/mpris_thread.rs:65
SeekOffset audio.seek(current + offset) daemon/src/mpris_thread.rs:72 Status Update
SetVolume sink.set_volume(vol) daemon/src/mpris_thread.rs:82 Status Update

Data Flow: D-Bus to Daemon State

graph TD
    subgraph "D-Bus Ecosystem"
        A["External Controller (playerctl)"] -- "DBus Method" --> B["mpris_server::Player"]
    end

    subgraph "mpris_thread.rs"
        B -- "Callback" --> C["UnboundedSender<PlayerCommand>"]
        C -- "rx.recv()" --> D["Command Loop"]
    end

    subgraph "State Management"
        D -- "lock().await" --> E["StateStruct"]
        E -- "audio.seek()" --> F["Rodio/Symphonia"]
        E -- "next()" --> G["Queue Management"]
    end
    
    G -- "send_to_all" --> H["Connected Clients"]
Loading

Sources: daemon/src/mpris_thread.rs:8-18, daemon/src/mpris_thread.rs:31-85, daemon/src/mpris_thread.rs:90-148.


Theme & Config Watcher (theme_thread)

The theme_thread manages the hot-reloading of the application's visual style. It monitors the config.toml file located in the user's configuration directory.

Hot-Reload Logic

  1. Initialization: On startup, get_config() reads ~/.config/aurora-player/config.toml. If the file is missing or malformed, it returns a default "Gruvbox-inspired" palette daemon/src/theme_thread.rs:6-30.
  2. File Watching: Uses the notify crate to watch the configuration directory daemon/src/theme_thread.rs:38-39.
  3. Broadcast: When a Modify, Create, or Remove event is detected, the thread re-parses the TOML file, updates the StateStruct, and broadcasts a Response::Theme to all connected clients daemon/src/theme_thread.rs:43-47.

Theme Configuration Structure

The Theme struct (and config.toml) defines 10 color keys, primarily focusing on background depths (bgd0-bgd4), text contrasts (txt1-txt2), and an accent color (acct) themes/mavenblack.toml:1-11.

Theme Update Sequence

sequenceDiagram
    participant FS as Filesystem (config.toml)
    participant TW as theme_thread::init
    participant S as StateStruct
    participant C as Connected Clients

    TW->>FS: watch(RecursiveMode::Recursive)
    Note over FS: User saves config.toml
    FS-->>TW: EventKind::Modify
    TW->>TW: get_config()
    TW->>S: lock() & update theme
    TW->>C: send_to_all(Response::Theme)
Loading

Sources: daemon/src/theme_thread.rs:6-30, daemon/src/theme_thread.rs:32-54, themes/.


Auto-Advance Watcher (watcher_thread)

The watcher_thread is a lightweight loop responsible for maintaining playback continuity. While rodio handles the actual audio buffer feeding, this thread monitors the status of the Rodio::Sink to determine when a track has finished.

Logic Flow

The thread polls the state every 100ms daemon/src/watcher_thread.rs:9:

  1. Check Sink: It queries state_locked.sink.empty() daemon/src/watcher_thread.rs:11.
  2. Check Queue: It ensures the queue is not empty daemon/src/watcher_thread.rs:11.
  3. Advance: If the sink is empty and a queue exists, it calls state_locked.next(1) to increment the index and state_locked.add() to decode the next file into the sink daemon/src/watcher_thread.rs:12-13.
  4. Notify: It broadcasts the updated queue state to all clients so the UI can update the "Now Playing" indicators daemon/src/watcher_thread.rs:15-17.

Entity Mapping: Watcher to Audio Engine

graph LR
    subgraph "watcher_thread.rs"
        W["init() loop"]
    end

    subgraph "StateStruct (types.rs)"
        S["sink: rodio::Sink"]
        Q["queue: VecDeque<SongMeta>"]
        A["audio: Option<SeekableAudio>"]
    end

    W -- "sink.empty()" --> S
    W -- "next(1)" --> Q
    W -- "add()" --> A
    A -- "decode" --> S
Loading

Sources: daemon/src/watcher_thread.rs:6-21, daemon/src/handlers/replace_queue.rs:35-37.

Clone this wiki locally