<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to Backgroundog Service</title><link>https://sourceforge.net/p/sucrose/wiki/Backgroundog%2520Service/</link><description>Recent changes to Backgroundog Service</description><atom:link href="https://sourceforge.net/p/sucrose/wiki/Backgroundog%20Service/feed" rel="self"/><language>en</language><lastBuildDate>Sat, 04 Jul 2026 04:15:52 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/sucrose/wiki/Backgroundog%20Service/feed" rel="self" type="application/rss+xml"/><item><title>Backgroundog Service modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Backgroundog%2520Service/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v4
+++ v5
@@ -82,7 +82,7 @@
 | **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. |
+| **Audio** | Playhead + 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. |
@@ -110,7 +110,7 @@

 ## Now-playing metadata

-`Extension/AudioSession.cs` uses **NPSMLib** (`NowPlayingSessionManager` / `MediaPlaybackDataSource`). On `SessionListChanged` it reads:
+`Extension/AudioSession.cs` uses **Playhead** (`NowPlayingSessionManager` / `MediaPlaybackDataSource`). On `SessionListChanged` it reads:


 - `MediaObjectInfo` — Title, Artist, Subtitle, AlbumTitle, AlbumArtist, TrackNumber, AlbumTrackCount, MediaType.
 - `MediaPlaybackInfo` — RepeatMode, PlaybackRate/Mode/State, ShuffleEnabled, PropsValid, LastPlayingFileTime. (SourceAppId is read from the NowPlayingSession, not from MediaPlaybackInfo.)
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:52 -0000</pubDate><guid>https://sourceforge.net920f4955658bb4c63c9d08d1d08014244b49381b</guid></item><item><title>Backgroundog Service modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Backgroundog%2520Service/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v3
+++ v4
@@ -99,14 +99,14 @@
 The audio spectrum is produced by `Extension/AudioVisualizer.cs` and only runs when `AudioRequired` is on.


 - **Capture:** `NAudio.Wave.WasapiLoopbackCapture` records the system output ("what you hear"). The class implements `IMMNotificationClient` and recreates the capture when the default render device changes (`OnDefaultDeviceChanged` for `DataFlow.Render`).
-- **Pipeline** per `DataAvailable` buffer:
-  1. Wrap in a `WaveBuffer`, taking length `FloatBuffer.Length / 8`.
-  2. Build a `Complex[]` and run an **FFT** via `MathNet.Numerics.IntegralTransforms.Fourier.Forward` (`FourierOptions.Default`).
-  3. Keep the last `VerticalSmoothness = 2` FFT frames; produce `MaxSample = 128` output bins.
-  4. Smooth with `HorizontalSmoothness = 1` plus a multi-frame average → a `double[128]` magnitude array.
-  5. Fire `AudioDataAvailable`, storing the array into `AudioData.Data`.
-
-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](Create-Audio-API) for the JavaScript side.
+- **Pipeline** (the ring buffer is fed on every `DataAvailable` callback; the FFT + emit are throttled to ~60 Hz, i.e. once every `EmitIntervalMs = 16` ms):
+  1. De-interleave the captured samples into per-channel **left/right ring buffers** of fixed size `FftSize = 4096`, decoupled from the WASAPI callback buffer size so the bin→frequency mapping stays deterministic. Sample reads are format-robust (float32 / PCM16 / PCM32).
+  2. Apply a **Hann window** and run **two FFTs** (left and right) via `MathNet.Numerics.IntegralTransforms.Fourier.Forward` with `FourierOptions.NoScaling` (keeps the magnitude scale deterministic for the full-scale reference).
+  3. Collapse each FFT into **`MaxSample = 128` logarithmic frequency bands** spanning **20 Hz – 16 kHz** (peak magnitude per band), computed for mono, left, and right. Mono = `|(L + R) / 2|`.
+  4. In `Finalize`: normalise each band to **`[0, 1]`** (linear magnitude × high-frequency tilt ÷ full-scale reference × `LinearGain = 2.5`, minus `NoiseFloor = 0.01`, then clamped), apply **asymmetric attack/decay smoothing** (`AttackSpeed = 0.35` fast rise, `ReleaseSpeed = 0.06` slow fall) per bin, then **neighbour-bin smoothing** (`HorizontalSmoothness = 1`) → a `double[128]` array per channel.
+  5. Fire `AudioDataAvailable`, storing the three arrays into `AudioData.Data` (mono), `AudioData.DataLeft`, and `AudioData.DataRight`.
+
+The result is the 128-sample mono spectrum exposed to web wallpapers as `Audio.Data`, with the per-channel `Audio.DataLeft` / `Audio.DataRight` alongside it. All three are 128 bins logarithmically mapped across 20 Hz – 16 kHz, each normalised to `[0, 1]`; `Data[0]` is the lowest (bass) band and an all-zero array means silence. A high-frequency tilt (+2 dB/octave) keeps treble content visible against music's natural roll-off. Libraries: **NAudio**, **MathNet.Numerics**. See [Audio API](Create-Audio-API) for the JavaScript side.

 ## Now-playing metadata

@@ -151,7 +151,7 @@
 |---|---|
 | **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` |
+| **Audio** | `State, Title, Artist, Subtitle, AlbumTitle, Data, DataLeft, DataRight, 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` |
@@ -160,7 +160,7 @@
 | **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](Create-System-API) and [Audio API](Create-Audio-API).
+Every object carries a `State` boolean indicating whether its data is valid for the current tick. The `Audio.Data` field is the 128-sample mono FFT spectrum described above; `Audio.DataLeft` / `Audio.DataRight` are the per-channel spectra (same 128-value `[0, 1]` shape). For the JavaScript-side shape of these objects, see [System API](Create-System-API) and [Audio API](Create-Audio-API).

 ## Settings

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:50 -0000</pubDate><guid>https://sourceforge.net7dff3c2037f920f3ed4e2d17d77cbf87af6b7af9</guid></item><item><title>Backgroundog Service modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Backgroundog%2520Service/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v2
+++ v3
@@ -113,8 +113,8 @@
 `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**).
+- `MediaPlaybackInfo` — RepeatMode, PlaybackRate/Mode/State, ShuffleEnabled, PropsValid, LastPlayingFileTime. (SourceAppId is read from the NowPlayingSession, not from MediaPlaybackInfo.)
+- `MediaTimelineProperties` — EndTime, Position, StartTime, Min/MaxSeekTime (reported in **TotalMilliseconds**), plus PositionSetFileTime (a DateTime, serialized as-is — not a millisecond value).
 - A thumbnail stream, Base64-encoded into `AudioData.ThumbnailString`.

 `AudioData.State` indicates whether a media session currently exists.
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:45 -0000</pubDate><guid>https://sourceforge.netbb42c2fd8e5a3445b929e124c6b3de9cd060642b</guid></item><item><title>Backgroundog Service modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Backgroundog%2520Service/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v1
+++ v2
@@ -34,7 +34,20 @@

 `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.

-&amp;gt; 🖼️ **Diagram needed:** Backgroundog lifecycle — on-demand launch via Commandog → single-instance gate → Initialize loop (Specification + Performance/Condition/Attempt) → self-exit when no live wallpaper.

+    :::mermaid
+    flowchart TD
+        Cmd["Commandog: ✔Backgroundog✖&amp;lt;path&amp;gt;"] --&amp;gt; Gate{"Instance.Basic&lt;br/&gt;single-instance gate"}
+        Gate --&amp;gt;|already running| Stop1["exit"]
+        Gate --&amp;gt;|first instance| Init["Initialize.Start()"]
+        Init --&amp;gt; Loop["Loop: AppTime = 1000 ms&lt;br/&gt;InitializeTimer tick = 100 ms"]
+        Loop --&amp;gt; Spec["Specification.Start()&lt;br/&gt;collect all sensors"]
+        Spec --&amp;gt; Pick{"live wallpaper?"}
+        Pick --&amp;gt;|"running, not paused"| Perf["Performance.Start()&lt;br/&gt;should a rule trip?"]
+        Pick --&amp;gt;|"paused / closed"| Cond["Condition.Start()&lt;br/&gt;should it resume?"]
+        Pick --&amp;gt;|none| Attempt["Attempt.Start()&lt;br/&gt;retry Run() up to 5x"]
+        Attempt --&amp;gt;|nothing starts| Exit["Exit = false&lt;br/&gt;service self-terminates"]
+        Perf --&amp;gt; Loop
+        Cond --&amp;gt; Loop

 ## Timers and timing constants

@@ -118,7 +131,17 @@

 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](IPC) for the full transport mechanics.

-&amp;gt; 🖼️ **Diagram needed:** Backgroundog data pump — Specification.Start() builds the 10-JObject payload → branches on PipeRequired/SignalRequired/TransmissionRequired → WebView/CefSharp Web.cs server → JS bridge ExecuteScriptAsync.

+    :::mermaid
+    flowchart LR
+        Spec["Specification.Start()&lt;br/&gt;builds 10-JObject payload&lt;br/&gt;Bios/Date/Audio/Memory/Battery/&lt;br/&gt;Graphic/Network/Storage/Processor/Motherboard"]
+        Spec --&amp;gt;|PipeRequired| Pipe["StartClient(json)&lt;br/&gt;Backgroundog.Pipe"]
+        Spec --&amp;gt;|SignalRequired| Signal["FileSave&lt;br/&gt;Backgroundog-&amp;lt;guid&amp;gt;.sgnl"]
+        Spec --&amp;gt;|TransmissionRequired| Trans["TCP loopback&lt;br/&gt;: TransmissionPort"]
+        Pipe --&amp;gt; Web["WebView / CefSharp&lt;br/&gt;Web.cs server"]
+        Signal --&amp;gt; Web
+        Trans --&amp;gt; Web
+        Web --&amp;gt; Exec["Compatible hooks&lt;br/&gt;ExecuteScriptAsync"]
+        Exec --&amp;gt; JS["Wallpaper JS&lt;br/&gt;SucroseAudioData / Sucrose&amp;lt;X&amp;gt;Data"]

 ## The data contract (field reference)

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:43 -0000</pubDate><guid>https://sourceforge.netce06be071190eedd81d7ab91928e544f6d7a45bd</guid></item><item><title>Backgroundog Service modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Backgroundog%2520Service/</link><description>&lt;div class="markdown_content"&gt;&lt;h1 id="h-backgroundog-service"&gt;Backgroundog Service&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;Sucrose.Backgroundog.exe&lt;/code&gt; is the headless, long-running background service behind Sucrose's &lt;strong&gt;audio-reactive&lt;/strong&gt; and &lt;strong&gt;system-status&lt;/strong&gt; 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 &lt;strong&gt;pushes that data to the running wallpaper&lt;/strong&gt; 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.&lt;/p&gt;
&lt;h2 id="h-contents"&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#role-and-lifecycle"&gt;Role and lifecycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#timers-and-timing-constants"&gt;Timers and timing constants&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#sensor-collection"&gt;Sensor collection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#audio-visualizer-fft"&gt;Audio visualizer (FFT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#now-playing-metadata"&gt;Now-playing metadata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#output-channels-and-the-json-payload"&gt;Output channels and the JSON payload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-data-contract-field-reference"&gt;The data contract (field reference)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#settings"&gt;Settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#performance--pause-enforcement"&gt;Performance / pause enforcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#windows-session-listener"&gt;Windows session listener&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#see-also"&gt;See also&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h-role-and-lifecycle"&gt;Role and lifecycle&lt;/h2&gt;
&lt;p&gt;Backgroundog is a &lt;strong&gt;console (hidden) process&lt;/strong&gt; with a long-running loop. It is not started directly; it is launched on demand through the command bus when a wallpaper needs it:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;✔Backgroundog✖&amp;lt;path-to-Sucrose.Backgroundog.exe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Launcher/engine spawns it (via &lt;a href="./Commandog-Dispatcher"&gt;Commandog&lt;/a&gt;) when &lt;code&gt;PerformanceCounter&lt;/code&gt; is enabled, before the engine itself starts.&lt;/p&gt;
&lt;p&gt;Startup sequence (&lt;code&gt;App.Main&lt;/code&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;SSDHG.Configure()&lt;/code&gt; (high-performance GPU) + &lt;code&gt;SSDHR.Configure()&lt;/code&gt; (private runtime), UTF-8 console encoding, set thread culture from the &lt;code&gt;Culture&lt;/code&gt; setting.&lt;/li&gt;
&lt;li&gt;Single-instance guard: &lt;code&gt;Instance.Basic(Mutex.Backgroundog, App.Backgroundog)&lt;/code&gt; — the global mutex &lt;code&gt;{Sucrose-Wallpaper-Engine-Backgroundog}&lt;/code&gt; plus a &lt;code&gt;WorkCount &amp;lt;= 1&lt;/code&gt; check (see &lt;a href="./Single-Instance-Mutexes"&gt;Single-Instance &amp;amp; Mutexes&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Security.Apply()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Initialize.Start()&lt;/code&gt;, then the loop: &lt;code&gt;do { Initialize.Dispose(); await Task.Delay(AppTime = 1000 ms); } while (Exit)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On stop: &lt;code&gt;Initialize.Stop()&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Internal.Exit&lt;/code&gt; defaults to &lt;code&gt;true&lt;/code&gt;. When there is &lt;strong&gt;no live wallpaper&lt;/strong&gt; after a retry sequence, &lt;code&gt;Attempt.Start()&lt;/code&gt; sets &lt;code&gt;Exit = false&lt;/code&gt; and the service terminates itself — Backgroundog never lingers without a wallpaper to feed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🖼️ &lt;strong&gt;Diagram needed:&lt;/strong&gt; Backgroundog lifecycle — on-demand launch via Commandog → single-instance gate → Initialize loop (Specification + Performance/Condition/Attempt) → self-exit when no live wallpaper.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="h-timers-and-timing-constants"&gt;Timers and timing constants&lt;/h2&gt;
&lt;p&gt;All timing constants live in &lt;code&gt;Manage/Internal.cs&lt;/code&gt; (milliseconds):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Constant&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AppTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Outer loop delay.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InitializeTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base tick unit; the &lt;code&gt;InitializeTimer&lt;/code&gt; fires every 100 ms.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InitializeDueTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3000&lt;/code&gt; (&lt;code&gt;100 × 30&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Delay before the first tick.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SpecificationLessTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cadence for light sensors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SpecificationTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cadence for standard sensors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SpecificationMaxTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Re-entrancy cool-down for the heavy pass.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SpecificationPeakTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cadence for expensive sensors (e.g. storage WMI).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each tick (&lt;code&gt;Initialize.InitializeTimer_Callback&lt;/code&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Specification.Start()&lt;/code&gt; — collect all sensors as fire-and-forget tasks.&lt;/li&gt;
&lt;li&gt;If a &lt;code&gt;Processing&lt;/code&gt; re-entrancy flag allows it, run exactly one of:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Performance.Start()&lt;/code&gt; — when a live wallpaper is running and not already paused (checks whether a rule should trip).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Condition.Start()&lt;/code&gt; — when already paused/closed (checks whether to resume).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Attempt.Start()&lt;/code&gt; — when there is no live wallpaper.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A &lt;code&gt;Processing&lt;/code&gt; flag ensures only one heavy pass runs at a time, then waits &lt;code&gt;SpecificationMaxTime&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="h-sensor-collection"&gt;Sensor collection&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Specification.Start()&lt;/code&gt; launches each sensor in its own &lt;code&gt;Task.Run&lt;/code&gt;, guarded by a per-sensor boolean flag (e.g. &lt;code&gt;BiosManagement&lt;/code&gt;, &lt;code&gt;PingManagement&lt;/code&gt;, &lt;code&gt;AudioManagement&lt;/code&gt;, &lt;code&gt;ProcessorManagement2&lt;/code&gt;, &lt;code&gt;GraphicManagement2&lt;/code&gt;, &lt;code&gt;NetworkManagement2&lt;/code&gt;, &lt;code&gt;StorageManagement2&lt;/code&gt;, etc.) so a slow sensor never blocks the rest.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sensor&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BIOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WMI &lt;code&gt;Win32_BIOS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name, Caption, Version, Description, ReleaseDate, Manufacturer, SerialNumber, CurrentLanguage. One-shot.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DateTime.Now&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Refreshed every tick.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Skylark.Standard.Extension.Ping&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Host chosen by the &lt;code&gt;PingType&lt;/code&gt; setting (default &lt;code&gt;"Bing"&lt;/code&gt;); 1000 ms timeout. Only when online (&lt;code&gt;Network.GetHostEntryAsync&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NPSMLib + WASAPI&lt;/td&gt;
&lt;td&gt;Only when &lt;code&gt;AudioRequired&lt;/code&gt; is on. See the two sections below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GlobalMemoryStatusEx&lt;/code&gt; (Skylark.Wing)&lt;/td&gt;
&lt;td&gt;Physical + virtual (page file) in GB; &lt;code&gt;MemoryLoad&lt;/code&gt; %.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Battery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WMI &lt;code&gt;Win32_Battery&lt;/code&gt; + &lt;code&gt;Skylark.Wing.Utility.Power&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AC status, energy saver, life %, power plan.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graphic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VorticeAdapterEnumerator&lt;/code&gt; (DXGI) + "GPU Engine" perf counters&lt;/td&gt;
&lt;td&gt;Adapter list persisted to the &lt;code&gt;GraphicInterfaces&lt;/code&gt; system setting; first adapter auto-selected; usage read by LUID and clamped to 0–100.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Network.InstanceNetworkInterfaces()&lt;/code&gt; + "Network Interface" perf counters&lt;/td&gt;
&lt;td&gt;Interface list persisted to &lt;code&gt;NetworkInterfaces&lt;/code&gt;; first auto-selected; "Bytes Sent/sec" &amp;amp; "Bytes Received/sec" → Upload/Download/Total.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WMI &lt;code&gt;Win32_LogicalDisk&lt;/code&gt; + "LogicalDisk"/"PhysicalDisk" perf counters&lt;/td&gt;
&lt;td&gt;Collected on the slow (&lt;code&gt;SpecificationPeakTime&lt;/code&gt;, 10 s) cadence.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WMI &lt;code&gt;Win32_Processor&lt;/code&gt; + "Processor / % Processor Time" perf counters&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_Total&lt;/code&gt; and per-core (&lt;code&gt;0..ProcessorCount-1&lt;/code&gt;); builds the &lt;code&gt;Cores&lt;/code&gt; array with min/max flags.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Motherboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WMI &lt;code&gt;Win32_BaseBoard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Product, Version, Manufacturer; &lt;code&gt;Name = "&amp;lt;Manufacturer&amp;gt; &amp;lt;Product&amp;gt;"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Remote / Virtual / FullScreen / Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Skylark.Wing helpers&lt;/td&gt;
&lt;td&gt;Collected only when the matching performance rule is non-&lt;code&gt;Resume&lt;/code&gt; (or already active).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Perfomance-counter collection is gated by the &lt;code&gt;PerformanceCounter&lt;/code&gt; setting (default &lt;code&gt;true&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="h-audio-visualizer-fft"&gt;Audio visualizer (FFT)&lt;/h2&gt;
&lt;p&gt;The audio spectrum is produced by &lt;code&gt;Extension/AudioVisualizer.cs&lt;/code&gt; and only runs when &lt;code&gt;AudioRequired&lt;/code&gt; is on.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Capture:&lt;/strong&gt; &lt;code&gt;NAudio.Wave.WasapiLoopbackCapture&lt;/code&gt; records the system output ("what you hear"). The class implements &lt;code&gt;IMMNotificationClient&lt;/code&gt; and recreates the capture when the default render device changes (&lt;code&gt;OnDefaultDeviceChanged&lt;/code&gt; for &lt;code&gt;DataFlow.Render&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipeline&lt;/strong&gt; per &lt;code&gt;DataAvailable&lt;/code&gt; buffer:&lt;/li&gt;
&lt;li&gt;Wrap in a &lt;code&gt;WaveBuffer&lt;/code&gt;, taking length &lt;code&gt;FloatBuffer.Length / 8&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Build a &lt;code&gt;Complex[]&lt;/code&gt; and run an &lt;strong&gt;FFT&lt;/strong&gt; via &lt;code&gt;MathNet.Numerics.IntegralTransforms.Fourier.Forward&lt;/code&gt; (&lt;code&gt;FourierOptions.Default&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Keep the last &lt;code&gt;VerticalSmoothness = 2&lt;/code&gt; FFT frames; produce &lt;code&gt;MaxSample = 128&lt;/code&gt; output bins.&lt;/li&gt;
&lt;li&gt;Smooth with &lt;code&gt;HorizontalSmoothness = 1&lt;/code&gt; plus a multi-frame average → a &lt;code&gt;double[128]&lt;/code&gt; magnitude array.&lt;/li&gt;
&lt;li&gt;Fire &lt;code&gt;AudioDataAvailable&lt;/code&gt;, storing the array into &lt;code&gt;AudioData.Data&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is the 128-sample spectrum exposed to web wallpapers as &lt;code&gt;Audio.Data&lt;/code&gt; — &lt;code&gt;Data[0]&lt;/code&gt; is approximately the bass band, and an all-zero array means silence. Libraries: &lt;strong&gt;NAudio&lt;/strong&gt;, &lt;strong&gt;MathNet.Numerics&lt;/strong&gt;. See &lt;a href="./Create-Audio-API"&gt;Audio API&lt;/a&gt; for the JavaScript side.&lt;/p&gt;
&lt;h2 id="h-now-playing-metadata"&gt;Now-playing metadata&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Extension/AudioSession.cs&lt;/code&gt; uses &lt;strong&gt;NPSMLib&lt;/strong&gt; (&lt;code&gt;NowPlayingSessionManager&lt;/code&gt; / &lt;code&gt;MediaPlaybackDataSource&lt;/code&gt;). On &lt;code&gt;SessionListChanged&lt;/code&gt; it reads:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MediaObjectInfo&lt;/code&gt; — Title, Artist, Subtitle, AlbumTitle, AlbumArtist, TrackNumber, AlbumTrackCount, MediaType.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MediaPlaybackInfo&lt;/code&gt; — RepeatMode, PlaybackRate/Mode/State, ShuffleEnabled, PropsValid, LastPlayingFileTime, SourceAppId.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MediaTimelineProperties&lt;/code&gt; — EndTime, Position, StartTime, Min/MaxSeekTime, PositionSetFileTime (times reported in &lt;strong&gt;TotalMilliseconds&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;A thumbnail stream, Base64-encoded into &lt;code&gt;AudioData.ThumbnailString&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;AudioData.State&lt;/code&gt; indicates whether a media session currently exists.&lt;/p&gt;
&lt;h2 id="h-output-channels-and-the-json-payload"&gt;Output channels and the JSON payload&lt;/h2&gt;
&lt;p&gt;After collection, &lt;code&gt;Specification.Start()&lt;/code&gt; builds a single payload of &lt;strong&gt;10 &lt;code&gt;JObject&lt;/code&gt; fields&lt;/strong&gt; and pushes it over whichever channel(s) are enabled. All channels are gated on &lt;code&gt;!Condition&lt;/code&gt; (data is not sent while the wallpaper is paused/closed).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Channel&lt;/th&gt;
&lt;th&gt;Enabled when&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pipe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PipeRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BackgroundogManager.StartClient(json)&lt;/code&gt; → pipe &lt;code&gt;"Sucrose.Wallpaper.Engine.Backgroundog.Pipe"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Signal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SignalRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BackgroundogManager.FileSave&amp;lt;…&amp;gt;(…)&lt;/code&gt; → writes &lt;code&gt;Backgroundog-&amp;lt;guid&amp;gt;.sgnl&lt;/code&gt; under &lt;code&gt;%AppData%\Sucrose\Cache\SignalT&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transmission&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TransmissionRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TCP to &lt;code&gt;Loopback:TransmissionPort&lt;/code&gt;. &lt;strong&gt;Default&lt;/strong&gt; transport.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The active transport is selected by the &lt;code&gt;CommunicationType&lt;/code&gt; setting (default &lt;code&gt;Transmission&lt;/code&gt;) on the engine side; the producer reads the &lt;code&gt;*Required&lt;/code&gt;/&lt;code&gt;TransmissionPort&lt;/code&gt; flags the engine sets. The payload is JSON-serialized with Newtonsoft (&lt;code&gt;Formatting.None&lt;/code&gt;, &lt;code&gt;TypeNameHandling.None&lt;/code&gt;). Only the &lt;strong&gt;WebView&lt;/strong&gt; and &lt;strong&gt;CefSharp&lt;/strong&gt; engines consume this channel (&lt;code&gt;#if LIVE_WEBVIEW || LIVE_CEFSHARP&lt;/code&gt;). See &lt;a href="./IPC"&gt;IPC&lt;/a&gt; for the full transport mechanics.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🖼️ &lt;strong&gt;Diagram needed:&lt;/strong&gt; Backgroundog data pump — Specification.Start() builds the 10-JObject payload → branches on PipeRequired/SignalRequired/TransmissionRequired → WebView/CefSharp Web.cs server → JS bridge ExecuteScriptAsync.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="h-the-data-contract-field-reference"&gt;The data contract (field reference)&lt;/h2&gt;
&lt;p&gt;The 10 JObjects (&lt;code&gt;Pipe.Interface.Backgroundog&lt;/code&gt;) are: &lt;code&gt;Bios, Date, Audio, Memory, Battery, Graphic, Network, Storage, Processor, Motherboard&lt;/code&gt;. Their inner field names (from &lt;code&gt;Extension/Data.cs&lt;/code&gt;) are the &lt;strong&gt;public data contract for wallpaper authors&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Object&lt;/th&gt;
&lt;th&gt;Fields&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bios&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Name, State, Caption, Version, Description, ReleaseDate, Manufacturer, SerialNumber, CurrentLanguage&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Day, Hour, Year, Month, State, Minute, Second, Kind, DayOfYear, Millisecond, DayOfWeek&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;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&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Name, State, MemoryLoad, MemoryUsed, VirtualName, MemoryAvailable, VirtualMemoryLoad, VirtualMemoryUsed, VirtualMemoryAvailable&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Battery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Name, State, Status, Chemistry, SavingMode, BatteryFlag, Description, LifePercent, SaverStatus, FullLifetime, ACPowerStatus, DesignVoltage, LifeRemaining, ChargeStatus, BatteryLifeTime, PowerPlanType, EstimatedRunTime, EnergySaverType, PowerLineStatus, BatteryLifePercent, BatteryFullLifeTime, EstimatedChargeRemaining&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graphic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Max, Min, Now, Name, State, Manufacturer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Host, Name, Ping, State, Total, Online, Upload, Download, PingData, TotalData, UploadData, PingAddress, DownloadData, FormatTotalData, FormatUploadData, FormatDownloadData&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;State, Drivers, LogicalDrivers, PhysicalDrivers&lt;/code&gt; (each a JArray of disks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Processor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Max, Min, Now, Core, Name, Type, Cores, State, Thread, CoresMax, CoresMin, CoresNow, ProcessorCount&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Motherboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Name, State, Product, Version, Manufacturer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Every object carries a &lt;code&gt;State&lt;/code&gt; boolean indicating whether its data is valid for the current tick. The &lt;code&gt;Audio.Data&lt;/code&gt; field is the 128-sample FFT spectrum described above. For the JavaScript-side shape of these objects, see &lt;a href="./Create-System-API"&gt;System API&lt;/a&gt; and &lt;a href="./Create-Audio-API"&gt;Audio API&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="h-settings"&gt;Settings&lt;/h2&gt;
&lt;p&gt;Backgroundog reads its configuration from the Backgroundog settings store. Keys, defaults, and clamp ranges:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Range / Type&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AudioRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Enable audio capture + FFT visualizer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PipeRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Enable Pipe output.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SignalRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Enable Signal output.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TransmissionRequired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Enable TCP (Transmission) output.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TransmissionPort&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–65535&lt;/td&gt;
&lt;td&gt;Loopback port (set dynamically at engine start).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CommunicationType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Transmission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pipe / Signal / Transmission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Active live-data transport.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PerformanceCounter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Enable perf-counter sensors + start Backgroundog with the wallpaper.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PingType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"Bing"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string (host key)&lt;/td&gt;
&lt;td&gt;Host used for the network ping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PingValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–1000 (ms)&lt;/td&gt;
&lt;td&gt;Ping threshold for the Network performance rule.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UploadValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;800&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–99999999&lt;/td&gt;
&lt;td&gt;Upload threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UploadType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Kilobyte&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Skylark.Enum.StorageType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upload threshold unit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DownloadValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–99999999&lt;/td&gt;
&lt;td&gt;Download threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DownloadType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Megabyte&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;StorageType&lt;/td&gt;
&lt;td&gt;Download threshold unit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ProcessorUsage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;70&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–100 (%)&lt;/td&gt;
&lt;td&gt;CPU pause threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GraphicUsage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;70&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–100 (%)&lt;/td&gt;
&lt;td&gt;GPU pause threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MemoryUsage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–100 (%)&lt;/td&gt;
&lt;td&gt;RAM pause threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BatteryUsage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0–100 (%)&lt;/td&gt;
&lt;td&gt;Battery pause threshold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NetworkAdapter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Selected network adapter (auto-selected).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GraphicAdapter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Selected GPU adapter (auto-selected).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PausePerformance&lt;/code&gt; / &lt;code&gt;ClosePerformance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;Transient state flags written by the service.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The per-trigger performance modes (&lt;code&gt;LockPerformance&lt;/code&gt;, &lt;code&gt;SleepPerformance&lt;/code&gt;, &lt;code&gt;BatteryPerformance&lt;/code&gt;, etc.) and &lt;code&gt;PausePerformanceType&lt;/code&gt; are surfaced on the &lt;a href="./Settings-Performance"&gt;Settings → Performance&lt;/a&gt; page. See &lt;a href="./Performance-Rules"&gt;Performance Rules&lt;/a&gt; for what each rule does.&lt;/p&gt;
&lt;h2 id="h-performance-pause-enforcement"&gt;Performance / pause enforcement&lt;/h2&gt;
&lt;p&gt;Backgroundog owns the auto-pause logic. &lt;code&gt;Performance.Start()&lt;/code&gt; evaluates rules &lt;strong&gt;in this fixed order&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Lock → Focus → Sleep → Memory → Remote → Battery → Console →
Graphic → Network → Session → Virtual → Processor → FullScreen →
ScreenSaver → BatterySaver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Each rule is skipped if its mode is &lt;code&gt;Resume&lt;/code&gt;. Otherwise the service polls the condition for a rule-specific &lt;code&gt;MaxCount&lt;/code&gt; (instant &lt;code&gt;0&lt;/code&gt; for Lock/Sleep/Console/Session/ScreenSaver; &lt;code&gt;5&lt;/code&gt; for most others; threshold-based for Memory/Graphic/CPU/Battery/Network). On a trip it sets the &lt;code&gt;CategoryPerformance&lt;/code&gt;, sets &lt;code&gt;Condition = true&lt;/code&gt;, and calls &lt;code&gt;Lifecycle()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mode &lt;code&gt;Close&lt;/code&gt; → set &lt;code&gt;ClosePerformance&lt;/code&gt;, call &lt;code&gt;Live.Helper.Kill.Stop()&lt;/code&gt; (close the wallpaper).&lt;/li&gt;
&lt;li&gt;Mode &lt;code&gt;Pause&lt;/code&gt; → set &lt;code&gt;PausePerformance&lt;/code&gt;. If &lt;code&gt;PausePerformanceType.Heavy&lt;/code&gt;, the live process is &lt;strong&gt;suspended&lt;/strong&gt; (via &lt;code&gt;Space.Extension.Lifecycle.Suspend&lt;/code&gt;), including WebView2/CefSharp child processes whose command line contains &lt;code&gt;"Sucrose"&lt;/code&gt; and the Aurora application process. &lt;code&gt;Light&lt;/code&gt; pauses without suspending threads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases the Launcher tray icon is notified over Signal (&lt;code&gt;Icon = true&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Condition.Start()&lt;/code&gt; is the mirror: while in a category it polls until the condition clears, then resumes — &lt;code&gt;Close&lt;/code&gt; restarts the wallpaper (&lt;code&gt;Run.Start()&lt;/code&gt;), &lt;code&gt;Pause/Heavy&lt;/code&gt; resumes the process (&lt;code&gt;Lifecycle.Resume(...)&lt;/code&gt;), and &lt;code&gt;Condition&lt;/code&gt; is cleared. Tray icon Signal &lt;code&gt;Icon = false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Attempt.Start()&lt;/code&gt; runs when there is no live wallpaper: it retries &lt;code&gt;Space.Helper.Live.Run()&lt;/code&gt; up to 5 times (1 s apart, 3 s settle on success). If nothing starts, it sets &lt;code&gt;Exit = false&lt;/code&gt;, clears the two transient pause flags, and the service stops.&lt;/p&gt;
&lt;p&gt;The enum values behind these rules (&lt;code&gt;src/Shared/Sucrose.Shared.Dependency/Enum/PerformanceType.cs&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PerformanceType&lt;/code&gt;: &lt;code&gt;Close, Pause, Resume&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PausePerformanceType&lt;/code&gt;: &lt;code&gt;Heavy, Light&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NetworkPerformanceType&lt;/code&gt;: &lt;code&gt;Not, Ping, Upload, Download&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CategoryPerformanceType&lt;/code&gt;: &lt;code&gt;Not, Lock, Focus, Sleep, Memory, Remote, Battery, Console, Graphic, Network, Session, Virtual, Processor, FullScreen, ScreenSaver, BatterySaver&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HighPerformanceType&lt;/code&gt;: &lt;code&gt;Default, PowerSaving, HighPerformance&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="h-windows-session-listener"&gt;Windows session listener&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Extension/WindowsListener.cs&lt;/code&gt; implements &lt;code&gt;Skylark.Wing.Interface.IEventListener&lt;/code&gt; and feeds session events into the performance engine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OnLogon&lt;/code&gt; / &lt;code&gt;OnLogoff&lt;/code&gt; → &lt;code&gt;WindowsSession&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnDisplayLock&lt;/code&gt; / &lt;code&gt;OnDisplayUnlock&lt;/code&gt; → &lt;code&gt;WindowsLock&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnStartScreenSaver&lt;/code&gt; / &lt;code&gt;OnStopScreenSaver&lt;/code&gt; → &lt;code&gt;WindowsScreenSaver&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is started/stopped by &lt;code&gt;Extension/Windows.cs&lt;/code&gt; (&lt;code&gt;Start()&lt;/code&gt; / &lt;code&gt;Stop()&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="h-see-also"&gt;See also&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="./IPC"&gt;IPC&lt;/a&gt; — the three live-data transports and the command bus that carry Backgroundog's data.&lt;/li&gt;
&lt;li&gt;&lt;a href="./Performance-Rules"&gt;Performance Rules&lt;/a&gt; — user-facing explanation of every auto-pause/close condition.&lt;/li&gt;
&lt;li&gt;&lt;a href="./Create-Audio-API"&gt;Create Audio API&lt;/a&gt; — how a web wallpaper subscribes to the audio spectrum and now-playing data.&lt;/li&gt;
&lt;li&gt;&lt;a href="./Create-System-API"&gt;Create System API&lt;/a&gt; — the JavaScript shape of the system-status objects.&lt;/li&gt;
&lt;li&gt;&lt;a href="./Architecture-Overview"&gt;Architecture Overview&lt;/a&gt; — where Backgroundog sits in the process roster.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:17 -0000</pubDate><guid>https://sourceforge.net5a42f4417a43d3ab2b8cf7c9de61a12983277e6e</guid></item></channel></rss>