-
-
Notifications
You must be signed in to change notification settings - Fork 60
Backgroundog Service
Sucrose.Backgroundog.exe is the headless, long-running background service behind Sucrose's audio-reactive and system-status APIs. It continuously collects machine telemetry (CPU, GPU, RAM, network, storage, battery, BIOS, motherboard, date) plus the now-playing audio metadata and a live FFT audio spectrum, then pushes that data to the running wallpaper over one of three interchangeable transports (Pipe, Signal, or Transmission). It also acts as the engine that enforces Sucrose's performance/pause rules — deciding when to pause, suspend, or close the wallpaper based on conditions like screen lock, full-screen apps, battery level, and CPU/GPU/RAM thresholds. This page is for developers and power users who want to understand exactly what Backgroundog does, what data it emits, and how its timing and settings work.
- Role and lifecycle
- Timers and timing constants
- Sensor collection
- Audio visualizer (FFT)
- Now-playing metadata
- Output channels and the JSON payload
- The data contract (field reference)
- Settings
- Performance / pause enforcement
- Windows session listener
- See also
Backgroundog is a console (hidden) process with a long-running loop. It is not started directly; it is launched on demand through the command bus when a wallpaper needs it:
✔Backgroundog✖<path-to-Sucrose.Backgroundog.exe>
The Launcher/engine spawns it (via Commandog) when PerformanceCounter is enabled, before the engine itself starts.
Startup sequence (App.Main):
-
SSDHG.Configure()(high-performance GPU) +SSDHR.Configure()(private runtime), UTF-8 console encoding, set thread culture from theCulturesetting. - Single-instance guard:
Instance.Basic(Mutex.Backgroundog, App.Backgroundog)— the global mutex{Sucrose-Wallpaper-Engine-Backgroundog}plus aWorkCount <= 1check (see Single-Instance & Mutexes). -
Security.Apply(). -
Initialize.Start(), then the loop:do { Initialize.Dispose(); await Task.Delay(AppTime = 1000 ms); } while (Exit). - On stop:
Initialize.Stop().
Internal.Exit defaults to true. When there is no live wallpaper after a retry sequence, Attempt.Start() sets Exit = false and the service terminates itself — Backgroundog never lingers without a wallpaper to feed.
flowchart TD
Cmd["Commandog: ✔Backgroundog✖<path>"] --> Gate{"Instance.Basic<br/>single-instance gate"}
Gate -->|already running| Stop1["exit"]
Gate -->|first instance| Init["Initialize.Start()"]
Init --> Loop["Loop: AppTime = 1000 ms<br/>InitializeTimer tick = 100 ms"]
Loop --> Spec["Specification.Start()<br/>collect all sensors"]
Spec --> Pick{"live wallpaper?"}
Pick -->|"running, not paused"| Perf["Performance.Start()<br/>should a rule trip?"]
Pick -->|"paused / closed"| Cond["Condition.Start()<br/>should it resume?"]
Pick -->|none| Attempt["Attempt.Start()<br/>retry Run() up to 5x"]
Attempt -->|nothing starts| Exit["Exit = false<br/>service self-terminates"]
Perf --> Loop
Cond --> Loop
All timing constants live in Manage/Internal.cs (milliseconds):
| Constant | Value | Meaning |
|---|---|---|
AppTime |
1000 |
Outer loop delay. |
InitializeTime |
100 |
Base tick unit; the InitializeTimer fires every 100 ms. |
InitializeDueTime |
3000 (100 × 30) |
Delay before the first tick. |
SpecificationLessTime |
1000 |
Cadence for light sensors. |
SpecificationTime |
2000 |
Cadence for standard sensors. |
SpecificationMaxTime |
3000 |
Re-entrancy cool-down for the heavy pass. |
SpecificationPeakTime |
10000 |
Cadence for expensive sensors (e.g. storage WMI). |
Each tick (Initialize.InitializeTimer_Callback):
-
Specification.Start()— collect all sensors as fire-and-forget tasks. - If a
Processingre-entrancy flag allows it, run exactly one of:-
Performance.Start()— when a live wallpaper is running and not already paused (checks whether a rule should trip). -
Condition.Start()— when already paused/closed (checks whether to resume). -
Attempt.Start()— when there is no live wallpaper.
-
A Processing flag ensures only one heavy pass runs at a time, then waits SpecificationMaxTime.
Specification.Start() launches each sensor in its own Task.Run, guarded by a per-sensor boolean flag (e.g. BiosManagement, PingManagement, AudioManagement, ProcessorManagement2, GraphicManagement2, NetworkManagement2, StorageManagement2, etc.) so a slow sensor never blocks the rest.
| Sensor | Source | Notes |
|---|---|---|
| BIOS | WMI Win32_BIOS
|
Name, Caption, Version, Description, ReleaseDate, Manufacturer, SerialNumber, CurrentLanguage. One-shot. |
| Date | DateTime.Now |
Refreshed every tick. |
| Ping | Skylark.Standard.Extension.Ping |
Host chosen by the PingType setting (default "Bing"); 1000 ms timeout. Only when online (Network.GetHostEntryAsync). |
| Audio | NPSMLib + WASAPI | Only when AudioRequired is on. See the two sections below. |
| Memory |
GlobalMemoryStatusEx (Skylark.Wing) |
Physical + virtual (page file) in GB; MemoryLoad %. |
| Battery | WMI Win32_Battery + Skylark.Wing.Utility.Power
|
AC status, energy saver, life %, power plan. |
| Graphic |
VorticeAdapterEnumerator (DXGI) + "GPU Engine" perf counters |
Adapter list persisted to the GraphicInterfaces system setting; first adapter auto-selected; usage read by LUID and clamped to 0–100. |
| Network |
Network.InstanceNetworkInterfaces() + "Network Interface" perf counters |
Interface list persisted to NetworkInterfaces; first auto-selected; "Bytes Sent/sec" & "Bytes Received/sec" → Upload/Download/Total. |
| Storage | WMI Win32_LogicalDisk + "LogicalDisk"/"PhysicalDisk" perf counters |
Collected on the slow (SpecificationPeakTime, 10 s) cadence. |
| CPU | WMI Win32_Processor + "Processor / % Processor Time" perf counters |
_Total and per-core (0..ProcessorCount-1); builds the Cores array with min/max flags. |
| Motherboard | WMI Win32_BaseBoard
|
Product, Version, Manufacturer; Name = "<Manufacturer> <Product>". |
| Remote / Virtual / FullScreen / Focus | Skylark.Wing helpers | Collected only when the matching performance rule is non-Resume (or already active). |
Perfomance-counter collection is gated by the PerformanceCounter setting (default true).
The audio spectrum is produced by Extension/AudioVisualizer.cs and only runs when AudioRequired is on.
-
Capture:
NAudio.Wave.WasapiLoopbackCapturerecords the system output ("what you hear"). The class implementsIMMNotificationClientand recreates the capture when the default render device changes (OnDefaultDeviceChangedforDataFlow.Render). -
Pipeline per
DataAvailablebuffer:- Wrap in a
WaveBuffer, taking lengthFloatBuffer.Length / 8. - Build a
Complex[]and run an FFT viaMathNet.Numerics.IntegralTransforms.Fourier.Forward(FourierOptions.Default). - Keep the last
VerticalSmoothness = 2FFT frames; produceMaxSample = 128output bins. - Smooth with
HorizontalSmoothness = 1plus a multi-frame average → adouble[128]magnitude array. - Fire
AudioDataAvailable, storing the array intoAudioData.Data.
- Wrap in a
The result is the 128-sample spectrum exposed to web wallpapers as Audio.Data — Data[0] is approximately the bass band, and an all-zero array means silence. Libraries: NAudio, MathNet.Numerics. See Audio API for the JavaScript side.
Extension/AudioSession.cs uses NPSMLib (NowPlayingSessionManager / MediaPlaybackDataSource). On SessionListChanged it reads:
-
MediaObjectInfo— Title, Artist, Subtitle, AlbumTitle, AlbumArtist, TrackNumber, AlbumTrackCount, MediaType. -
MediaPlaybackInfo— RepeatMode, PlaybackRate/Mode/State, ShuffleEnabled, PropsValid, LastPlayingFileTime, SourceAppId. -
MediaTimelineProperties— EndTime, Position, StartTime, Min/MaxSeekTime, PositionSetFileTime (times reported in TotalMilliseconds). - A thumbnail stream, Base64-encoded into
AudioData.ThumbnailString.
AudioData.State indicates whether a media session currently exists.
After collection, Specification.Start() builds a single payload of 10 JObject fields and pushes it over whichever channel(s) are enabled. All channels are gated on !Condition (data is not sent while the wallpaper is paused/closed).
| Channel | Enabled when | Target |
|---|---|---|
| Pipe | PipeRequired |
BackgroundogManager.StartClient(json) → pipe "Sucrose.Wallpaper.Engine.Backgroundog.Pipe". |
| Signal | SignalRequired |
BackgroundogManager.FileSave<…>(…) → writes Backgroundog-<guid>.sgnl under %AppData%\Sucrose\Cache\SignalT. |
| Transmission | TransmissionRequired |
TCP to Loopback:TransmissionPort. Default transport. |
The active transport is selected by the CommunicationType setting (default Transmission) on the engine side; the producer reads the *Required/TransmissionPort flags the engine sets. The payload is JSON-serialized with Newtonsoft (Formatting.None, TypeNameHandling.None). Only the WebView and CefSharp engines consume this channel (#if LIVE_WEBVIEW || LIVE_CEFSHARP). See IPC for the full transport mechanics.
flowchart LR
Spec["Specification.Start()<br/>builds 10-JObject payload<br/>Bios/Date/Audio/Memory/Battery/<br/>Graphic/Network/Storage/Processor/Motherboard"]
Spec -->|PipeRequired| Pipe["StartClient(json)<br/>Backgroundog.Pipe"]
Spec -->|SignalRequired| Signal["FileSave<br/>Backgroundog-<guid>.sgnl"]
Spec -->|TransmissionRequired| Trans["TCP loopback<br/>: TransmissionPort"]
Pipe --> Web["WebView / CefSharp<br/>Web.cs server"]
Signal --> Web
Trans --> Web
Web --> Exec["Compatible hooks<br/>ExecuteScriptAsync"]
Exec --> JS["Wallpaper JS<br/>SucroseAudioData / Sucrose<X>Data"]
The 10 JObjects (Pipe.Interface.Backgroundog) are: Bios, Date, Audio, Memory, Battery, Graphic, Network, Storage, Processor, Motherboard. Their inner field names (from Extension/Data.cs) are the public data contract for wallpaper authors:
| Object | Fields |
|---|---|
| Bios | Name, State, Caption, Version, Description, ReleaseDate, Manufacturer, SerialNumber, CurrentLanguage |
| Date | Day, Hour, Year, Month, State, Minute, Second, Kind, DayOfYear, Millisecond, DayOfWeek |
| Audio | State, Title, Artist, Subtitle, AlbumTitle, Data, AlbumArtist, SourceAppId, TrackNumber, MediaType, PlaybackRate, PropsValid, RepeatMode, ShuffleEnabled, PlaybackMode, AlbumTrackCount, ThumbnailString, PlaybackState, EndTime, Position, StartTime, LastPlayingFileTime, PositionSetFileTime, MaxSeekTime, MinSeekTime |
| Memory | Name, State, MemoryLoad, MemoryUsed, VirtualName, MemoryAvailable, VirtualMemoryLoad, VirtualMemoryUsed, VirtualMemoryAvailable |
| Battery | Name, State, Status, Chemistry, SavingMode, BatteryFlag, Description, LifePercent, SaverStatus, FullLifetime, ACPowerStatus, DesignVoltage, LifeRemaining, ChargeStatus, BatteryLifeTime, PowerPlanType, EstimatedRunTime, EnergySaverType, PowerLineStatus, BatteryLifePercent, BatteryFullLifeTime, EstimatedChargeRemaining |
| Graphic | Max, Min, Now, Name, State, Manufacturer |
| Network | Host, Name, Ping, State, Total, Online, Upload, Download, PingData, TotalData, UploadData, PingAddress, DownloadData, FormatTotalData, FormatUploadData, FormatDownloadData |
| Storage |
State, Drivers, LogicalDrivers, PhysicalDrivers (each a JArray of disks) |
| Processor | Max, Min, Now, Core, Name, Type, Cores, State, Thread, CoresMax, CoresMin, CoresNow, ProcessorCount |
| Motherboard | Name, State, Product, Version, Manufacturer |
Every object carries a State boolean indicating whether its data is valid for the current tick. The Audio.Data field is the 128-sample FFT spectrum described above. For the JavaScript-side shape of these objects, see System API and Audio API.
Backgroundog reads its configuration from the Backgroundog settings store. Keys, defaults, and clamp ranges:
| Setting | Default | Range / Type | Effect |
|---|---|---|---|
AudioRequired |
false |
bool | Enable audio capture + FFT visualizer. |
PipeRequired |
false |
bool | Enable Pipe output. |
SignalRequired |
false |
bool | Enable Signal output. |
TransmissionRequired |
false |
bool | Enable TCP (Transmission) output. |
TransmissionPort |
0 |
0–65535 | Loopback port (set dynamically at engine start). |
CommunicationType |
Transmission |
Pipe / Signal / Transmission |
Active live-data transport. |
PerformanceCounter |
true |
bool | Enable perf-counter sensors + start Backgroundog with the wallpaper. |
PingType |
"Bing" |
string (host key) | Host used for the network ping. |
PingValue |
100 |
0–1000 (ms) | Ping threshold for the Network performance rule. |
UploadValue |
800 |
0–99999999 | Upload threshold. |
UploadType |
Kilobyte |
Skylark.Enum.StorageType |
Upload threshold unit. |
DownloadValue |
10 |
0–99999999 | Download threshold. |
DownloadType |
Megabyte |
StorageType | Download threshold unit. |
ProcessorUsage |
70 |
0–100 (%) | CPU pause threshold. |
GraphicUsage |
70 |
0–100 (%) | GPU pause threshold. |
MemoryUsage |
80 |
0–100 (%) | RAM pause threshold. |
BatteryUsage |
50 |
0–100 (%) | Battery pause threshold. |
NetworkAdapter |
"" |
string | Selected network adapter (auto-selected). |
GraphicAdapter |
"" |
string | Selected GPU adapter (auto-selected). |
PausePerformance / ClosePerformance
|
false |
bool | Transient state flags written by the service. |
The per-trigger performance modes (LockPerformance, SleepPerformance, BatteryPerformance, etc.) and PausePerformanceType are surfaced on the Settings → Performance page. See Performance Rules for what each rule does.
Backgroundog owns the auto-pause logic. Performance.Start() evaluates rules in this fixed order:
Lock → Focus → Sleep → Memory → Remote → Battery → Console →
Graphic → Network → Session → Virtual → Processor → FullScreen →
ScreenSaver → BatterySaver
Each rule is skipped if its mode is Resume. Otherwise the service polls the condition for a rule-specific MaxCount (instant 0 for Lock/Sleep/Console/Session/ScreenSaver; 5 for most others; threshold-based for Memory/Graphic/CPU/Battery/Network). On a trip it sets the CategoryPerformance, sets Condition = true, and calls Lifecycle():
- Mode
Close→ setClosePerformance, callLive.Helper.Kill.Stop()(close the wallpaper). - Mode
Pause→ setPausePerformance. IfPausePerformanceType.Heavy, the live process is suspended (viaSpace.Extension.Lifecycle.Suspend), including WebView2/CefSharp child processes whose command line contains"Sucrose"and the Aurora application process.Lightpauses without suspending threads.
In both cases the Launcher tray icon is notified over Signal (Icon = true).
Condition.Start() is the mirror: while in a category it polls until the condition clears, then resumes — Close restarts the wallpaper (Run.Start()), Pause/Heavy resumes the process (Lifecycle.Resume(...)), and Condition is cleared. Tray icon Signal Icon = false.
Attempt.Start() runs when there is no live wallpaper: it retries Space.Helper.Live.Run() up to 5 times (1 s apart, 3 s settle on success). If nothing starts, it sets Exit = false, clears the two transient pause flags, and the service stops.
The enum values behind these rules (src/Shared/Sucrose.Shared.Dependency/Enum/PerformanceType.cs):
-
PerformanceType:Close, Pause, Resume. -
PausePerformanceType:Heavy, Light. -
NetworkPerformanceType:Not, Ping, Upload, Download. -
CategoryPerformanceType:Not, Lock, Focus, Sleep, Memory, Remote, Battery, Console, Graphic, Network, Session, Virtual, Processor, FullScreen, ScreenSaver, BatterySaver. -
HighPerformanceType:Default, PowerSaving, HighPerformance.
Extension/WindowsListener.cs implements Skylark.Wing.Interface.IEventListener and feeds session events into the performance engine:
-
OnLogon/OnLogoff→WindowsSession. -
OnDisplayLock/OnDisplayUnlock→WindowsLock. -
OnStartScreenSaver/OnStopScreenSaver→WindowsScreenSaver.
It is started/stopped by Extension/Windows.cs (Start() / Stop()).
- IPC — the three live-data transports and the command bus that carry Backgroundog's data.
- Performance Rules — user-facing explanation of every auto-pause/close condition.
- Create Audio API — how a web wallpaper subscribes to the audio spectrum and now-playing data.
- Create System API — the JavaScript shape of the system-status objects.
- Architecture Overview — where Backgroundog sits in the process roster.
Getting Started
- Installation
- System Requirements
- Quick Start
- Portal Interface Tour
- Updating Sucrose
- Uninstalling Sucrose
Wallpaper Types
Using Sucrose
- Managing Library
- Using Store
- Customizing Wallpaper
- Multi-Monitor
- Wallpaper Cycling
- Choosing Engines
- Performance Rules
- Theme, Tray & Startup
- Discord Rich Presence
Settings Reference
- Settings Overview
- Settings: General
- Settings: Personal
- Settings: Performance
- Settings: Wallpaper
- Settings: System
- Settings: Other
- Settings: All Keys
Creating Wallpapers
- Create Overview
- Create: Step By Step
- Create: Package Format
- Create: Customization Controls
- Create: JS Bridge
- Create: Audio API
- Create: System API
- Create: Property Listener & Filters
- Create: Web Architecture
- Create: Compatibility
- Create: Example Wallpapers
- Create: Sharing & Publishing
Engine Reference
- Engines Overview
- Engine: MpvPlayer
- Engine: VlcPlayer
- Engine: WebView
- Engine: CefSharp
- Engine: Nebula
- Engine: Vexana
- Engine: Xavier
- Engine: Aurora
- Engine Comparison
Automation & Command Line
Architecture & Internals
- Architecture Overview
- Lifecycle
- Commandog Dispatcher
- Single-Instance Mutexes
- IPC
- Backgroundog Service
- Crash Reporting
- Update Internals
- Property Service
- Undo Internals
Data, Files & Diagnostics
Building & Contributing
- Building From Source
- Repository Layout
- Shared Item Projects
- Code Conventions
- Preprocessor Symbols
- Publish Pipeline
- Bundle Installer Internals
- Extending Sucrose
- Contributing
- Translating with Localizer
- Localization Coverage
- Security Policy
- Privacy & Telemetry
Help & Support