### EarTrumpetActionsAddon.Import / .Export Source: https://context7.com/file-new-project/eartrumpet/llms.txt Serialise action configurations to XML for backup or sharing, and import them back into EarTrumpet. Imported actions are assigned new GUIDs and merged with existing ones. ```APIDOC ## EarTrumpetActionsAddon.Import / .Export — Serialise action configurations ### Description Export the current action list as an XML string (for backup or sharing), and import from a file. Imported actions are assigned new GUIDs and merged with existing ones. ### Method `Export()`: Returns a string containing the XML representation of the current actions. `Import(string filePath)`: Imports actions from the specified XML file path. ### Usage Example (C#) ```csharp using EarTrumpet.Actions; using System.IO; EarTrumpetActionsAddon addon = EarTrumpetActionsAddon.Current; // Export current actions to an XML string string xml = addon.Export(); File.WriteAllText(@"C:\Temp\eartrumpet-actions-backup.xml", xml); // Import actions from a file (merges with existing; new GUIDs assigned to imports) try { addon.Import(@"C:\Temp\eartrumpet-actions-backup.xml"); Console.WriteLine($"Now have {addon.Actions.Length} actions"); } catch (Exception ex) { Console.WriteLine($"Import failed: {ex.Message}"); } // Manually trigger any action programmatically (bypasses triggers/conditions) var targetAction = addon.Actions.FirstOrDefault(a => a.DisplayName == "Reduce Chrome volume"); if (targetAction != null) addon.TriggerAction(targetAction); ``` ### Related Operations - `TriggerAction(EarTrumpetAction action)`: Manually triggers a specified action. ``` -------------------------------- ### Define Automation Rules with EarTrumpetAction Source: https://context7.com/file-new-project/eartrumpet/llms.txt Create custom automation rules by defining triggers, conditions, and actions using EarTrumpetAction. This example demonstrates setting a specific app volume and toggling mute based on a hotkey and a variable condition. ```csharp using EarTrumpet.Actions.DataModel.Serialization; using EarTrumpet.Actions.DataModel.Enum; using EarTrumpet.Interop.Helpers; using System.Windows.Input; // Build an action that sets Chrome to 50% volume when a hotkey is pressed, // but only if a specific variable is True. var action = new EarTrumpetAction { DisplayName = "Reduce Chrome volume", Triggers = { new HotkeyTrigger { Option = new HotkeyData { Key = Key.F9, ModifiersEnum = ModifierKeys.Control | ModifierKeys.Alt } } }, Conditions = { new VariableCondition { Text = "ChromeAudioActive", Value = BoolValue.True } }, Actions = { new SetAppVolumeAction { App = new AppRef { /* AppId = "chrome" or EveryApp */ }, Device = new Device { /* DeviceId or DefaultDevice */ }, Option = SetVolumeKind.Exact, Volume = 50.0 }, new SetAppMuteAction { App = new AppRef { }, Device = new Device { }, Option = MuteKind.ToggleMute } } }; // Register via EarTrumpetActionsAddon (requires add-on to be loaded) // EarTrumpetActionsAddon.Current.Actions = // EarTrumpetActionsAddon.Current.Actions.Append(action).ToArray(); ``` -------------------------------- ### Obtain and Use Shared Audio Device Manager Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use WindowsAudioFactory.Create to get a singleton IAudioDeviceManager for playback or recording. The manager populates asynchronously; subscribe to the Loaded event before accessing devices. This manager allows for system-wide changes to default devices. ```csharp using EarTrumpet.DataModel.Audio; using EarTrumpet.DataModel.WindowsAudio; // Obtain the shared playback device manager (singleton; safe to call multiple times) IAudioDeviceManager playback = WindowsAudioFactory.Create(AudioDeviceKind.Playback); IAudioDeviceManager recording = WindowsAudioFactory.Create(AudioDeviceKind.Recording); // Wait until devices are enumerated before reading Devices playback.Loaded += (sender, _) => { Console.WriteLine($"Default playback device: {playback.Default?.DisplayName ?? "none"}"); foreach (IAudioDevice device in playback.Devices) { Console.WriteLine($"Device: {device.DisplayName} Volume: {device.Volume * 100:0}% Muted: {device.IsMuted}"); foreach (IAudioDeviceSession session in device.Groups) { Console.WriteLine($" App: {session.DisplayName} PID: {session.ProcessId} State: {session.State}"); } } }; // Change the default playback device playback.DefaultChanged += (sender, newDefault) => Console.WriteLine($"Default changed to: {newDefault?.DisplayName}"); // Set a different device as default (applies system-wide via IPolicyConfig) if (playback.Devices.Count > 1) { playback.Default = playback.Devices[1]; } // Create a non-shared, independent manager instance (for isolated consumers) IAudioDeviceManager isolated = WindowsAudioFactory.CreateNonSharedDeviceManager(AudioDeviceKind.Playback); ``` -------------------------------- ### Resolve App Metadata from Process ID Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use AppInformationFactory.CreateForProcess to get IAppInfo for a running process. Set trackProcess=true to receive a Stopped event when the process exits. PID 0 returns SystemSoundsAppInfo. ```csharp using EarTrumpet.DataModel.AppInformation; using System.Diagnostics; int pid = Process.GetProcessesByName("spotify").FirstOrDefault()?.Id ?? 0; // trackProcess=true: fires IAppInfo.Stopped when the process exits IAppInfo info = AppInformationFactory.CreateForProcess(pid, trackProcess: true); Console.WriteLine($"Display name: {info.DisplayName}"); Console.WriteLine($"Executable name: {info.ExeName}"); Console.WriteLine($"Install path: {info.PackageInstallPath}"); Console.WriteLine($"Logo path: {info.SmallLogoPath}"); Console.WriteLine($"Is desktop app: {info.IsDesktopApp}"); // Expected output for Spotify (MSIX): // Display name: Spotify Music // Executable name: C:\Program Files\WindowsApps\SpotifyAB.SpotifyMusic_...\Spotify.exe // Is desktop app: False info.Stopped += (appInfo) => Console.WriteLine($"{appInfo.DisplayName} has exited."); // For PID 0 (system sounds): IAppInfo systemSounds = AppInformationFactory.CreateForProcess(0); Console.WriteLine(systemSounds.IsDesktopApp); // False ``` -------------------------------- ### Import/Export EarTrumpet Actions Source: https://context7.com/file-new-project/eartrumpet/llms.txt Export current actions to an XML string for backup or sharing, and import actions from an XML file. Imported actions are assigned new GUIDs and merged with existing ones. Manually trigger actions programmatically. ```csharp using EarTrumpet.Actions; using System.IO; EarTrumpetActionsAddon addon = EarTrumpetActionsAddon.Current; // Export current actions to an XML string string xml = addon.Export(); File.WriteAllText(@"C:\\Temp\\eartrumpet-actions-backup.xml", xml); // // // Reduce Chrome volume... // Import actions from a file (merges with existing; new GUIDs assigned to imports) try { addon.Import(@"C:\\Temp\\eartrumpet-actions-backup.xml"); Console.WriteLine($"Now have {addon.Actions.Length} actions"); } catch (Exception ex) { Console.WriteLine($"Import failed: {ex.Message}"); } // Manually trigger any action programmatically (bypasses triggers/conditions) var targetAction = addon.Actions.FirstOrDefault(a => a.DisplayName == "Reduce Chrome volume"); if (targetAction != null) addon.TriggerAction(targetAction); ``` -------------------------------- ### Load and Unload EarTrumpet Add-on Host Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use `AddonManager.Load` at app startup to discover and initialize add-ons, and `AddonManager.Shutdown` at app shutdown to broadcast lifecycle events. `AddonManager.Host` provides access to loaded add-ons and their contributions. ```csharp using EarTrumpet.Extensibility.Hosting; using EarTrumpet.Extensibility; // At app startup (after the audio device manager has loaded) AddonManager.Load(shouldLoadInternalAddons: true); // true = also load EarTrumpet.Actions built-in addon // Access loaded add-ons by interface foreach (var addon in AddonManager.Host.Addons) Console.WriteLine($"Loaded: {addon.Manifest?.Id} v{addon.Manifest?.Version}"); // Tray context menu contributions from all addons var menuItems = AddonManager.Host.TrayContextMenuItems .SelectMany(a => a.NotificationAreaContextMenuItems); // Settings page contributions var settingsCategories = AddonManager.Host.SettingsItems .Select(a => a.GetSettingsCategory()); // Diagnostic info (space-separated list of loaded addon IDs) string diag = AddonManager.GetDiagnosticInfo(); Console.WriteLine($"Loaded addon IDs: {diag}"); // At app shutdown AddonManager.Shutdown(); // broadcasts AddonEventKind.AppShuttingDown to all addons ``` -------------------------------- ### Create a Loadable EarTrumpet Add-on Assembly Source: https://context7.com/file-new-project/eartrumpet/llms.txt Implement the `EarTrumpetAddon` class and one or more add-on interfaces to extend EarTrumpet. Ensure an `AddonManifest.json` file is placed next to your DLL. Add-ons are discovered in the `\Addons\\\EarTrumpet*.dll. ```json // AddonManifest.json (place next to your DLL) // { // "Id": "MyCompany.MyAddon", // "PublisherName": "My Company", // "HelpLink": "https://example.com/help", // "Version": "1.0.0" // } ``` ```csharp using EarTrumpet.Extensibility; using EarTrumpet.UI.ViewModels; using System.Collections.Generic; using System.ComponentModel.Composition; [Export(typeof(EarTrumpetAddon))] public class MyAddon : EarTrumpetAddon, IEarTrumpetAddonEvents, IEarTrumpetAddonSettingsPage, IEarTrumpetAddonNotificationAreaContextMenu, IEarTrumpetAddonAppContent, IEarTrumpetAddonDeviceContent { public MyAddon() { DisplayName = "My Addon"; } // --- IEarTrumpetAddonEvents --- public void OnAddonEvent(AddonEventKind evt) { switch (evt) { case AddonEventKind.InitializeAddon: // Called first; other addons may not be ready yet break; case AddonEventKind.AddonsInitialized: // All addons loaded; safe to use ServiceBus or cross-addon APIs LoadAddonResources(); // loads AddonResources.xaml into app resources bool mySetting = Settings.Get("IsEnabled", true); break; case AddonEventKind.AppShuttingDown: // Cleanup break; } } // --- IEarTrumpetAddonSettingsPage --- public SettingsCategoryViewModel GetSettingsCategory() { // Return your settings category; EarTrumpet appends an "About" page automatically return new SettingsCategoryViewModel( "My Addon", "\xE713", "Configure My Addon", null, new[] { new MyAddonSettingsPageViewModel(Settings) }); } // --- IEarTrumpetAddonNotificationAreaContextMenu --- public IEnumerable NotificationAreaContextMenuItems => new[] { new ContextMenuItem { DisplayName = "My Addon Action", Glyph = "\xE1CE", Command = new EarTrumpet.UI.Helpers.RelayCommand(() => System.Diagnostics.Trace.WriteLine("My Addon Action triggered")) } }; // --- IEarTrumpetAddonAppContent --- // Return a WPF UIElement or null; shown in the app row popup panel public object GetContentForApp(string deviceId, string appId, System.Action requestClose) => null; public IEnumerable GetContextMenuItemsForApp(string deviceId, string appId) => System.Array.Empty(); // --- IEarTrumpetAddonDeviceContent --- public object GetContentForDevice(string deviceId, System.Action requestClose) => null; public IEnumerable GetContextMenuItemsForDevice(string deviceId) => System.Array.Empty(); } ``` -------------------------------- ### StorageFactory.GetSettings Source: https://context7.com/file-new-project/eartrumpet/llms.txt Provides access to a settings bag, backed by Windows Storage or the Registry, with optional namespacing for add-ons. ```APIDOC ## StorageFactory.GetSettings ### Description Read and write persisted key/value settings. Returns an `ISettingsBag` backed by Windows Storage (`ApplicationData.Current.LocalSettings`) when running as a packaged app, or the Windows Registry (`HKCU`) otherwise. Pass a namespace string to scope settings to an add-on. ### Usage ```csharp using EarTrumpet.DataModel.Storage; // Global settings bag (no namespace) ISettingsBag settings = StorageFactory.GetSettings(); // Read with a default value bool useLegacyIcon = settings.Get("UseLegacyIcon", false); int someCount = settings.Get("LaunchCount", 0); // Write settings.Set("UseLegacyIcon", true); settings.Set("LaunchCount", someCount + 1); // Check existence if (!settings.HasKey("hasShownFirstRun")) { settings.Set("hasShownFirstRun", true); Console.WriteLine("First run!"); } // React to changes settings.SettingChanged += (sender, key) => Console.WriteLine($"Setting changed: {key}"); // Namespaced bag for an add-on ISettingsBag addonSettings = StorageFactory.GetSettings("MyAddon.v1"); addonSettings.Set("Enabled", true); bool enabled = addonSettings.Get("Enabled", false); // true Console.WriteLine($"Namespace: {addonSettings.Namespace}"); // MyAddon.v1 ``` ``` -------------------------------- ### WindowsAudioFactory.Create Source: https://context7.com/file-new-project/eartrumpet/llms.txt Obtain a shared audio device manager for playback or recording devices. The manager self-populates in the background and fires a 'Loaded' event when ready. ```APIDOC ## WindowsAudioFactory.Create — Obtain a shared audio device manager ### Description Returns a singleton `IAudioDeviceManager` for the given `AudioDeviceKind`. The manager self-populates via a background thread using `IMMDeviceEnumerator` and fires `Loaded` when ready. ### Method Signature ```csharp public static IAudioDeviceManager Create(AudioDeviceKind kind) ``` ### Parameters #### Path Parameters - **kind** (AudioDeviceKind) - Required - Specifies whether to create a manager for playback or recording devices. ### Request Example ```csharp using EarTrumpet.DataModel.Audio; using EarTrumpet.DataModel.WindowsAudio; // Obtain the shared playback device manager (singleton; safe to call multiple times) IAudioDeviceManager playback = WindowsAudioFactory.Create(AudioDeviceKind.Playback); IAudioDeviceManager recording = WindowsAudioFactory.Create(AudioDeviceKind.Recording); // Wait until devices are enumerated before reading Devices playback.Loaded += (sender, _) => { Console.WriteLine($"Default playback device: {playback.Default?.DisplayName ?? "none"}"); foreach (IAudioDevice device in playback.Devices) { Console.WriteLine($"Device: {device.DisplayName} Volume: {device.Volume * 100:0}% Muted: {device.IsMuted}"); foreach (IAudioDeviceSession session in device.Groups) { Console.WriteLine($" App: {session.DisplayName} PID: {session.ProcessId} State: {session.State}"); } } }; // Change the default playback device playback.DefaultChanged += (sender, newDefault) => Console.WriteLine($"Default changed to: {newDefault?.DisplayName}"); // Set a different device as default (applies system-wide via IPolicyConfig) if (playback.Devices.Count > 1) { playback.Default = playback.Devices[1]; } // Create a non-shared, independent manager instance (for isolated consumers) IAudioDeviceManager isolated = WindowsAudioFactory.CreateNonSharedDeviceManager(AudioDeviceKind.Playback); ``` ### Response #### Success Response Returns an `IAudioDeviceManager` instance. #### Response Example ```csharp // Example of IAudioDeviceManager usage within the Loaded event handler // (See Request Example for full context) ``` ``` -------------------------------- ### XAML Theme Options Source Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Set the theme configuration source at the top-level window to either 'App' or 'System'. 'System' is used for taskbar and flyout UI, while 'App' is for other windows. ```xml ``` -------------------------------- ### Register and Retrieve Services with ServiceBus Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use ServiceBus to share service objects between add-ons. Register services during InitializeAddon and retrieve them during AddonsInitialized or later. GetMany returns an empty list if no services are registered for a key. ```csharp using EarTrumpet.Extensibility.Shared; using System.Collections.Generic; // In Addon A — register a service during InitializeAddon public interface IMyService { void DoSomething(); } public class MyServiceImpl : IMyService { public void DoSomething() => System.Console.WriteLine("MyService.DoSomething()"); } // Registration (key is a stable contract string) ServiceBus.RegisterMany("MyCompany.IMyService", new MyServiceImpl()); // In Addon B — retrieve during AddonsInitialized List services = ServiceBus.GetMany("MyCompany.IMyService"); foreach (var svc in services) { ((IMyService)svc).DoSomething(); // MyService.DoSomething() } // If no services registered under a key, GetMany returns an empty list (never null) List empty = ServiceBus.GetMany("NonExistent.Key"); Console.WriteLine(empty.Count); // 0 ``` -------------------------------- ### EarTrumpetAddon Interfaces Source: https://context7.com/file-new-project/eartrumpet/llms.txt Implement these interfaces within a class inheriting from EarTrumpetAddon to extend EarTrumpet's functionality. Add-ons are discovered from a specific directory and require a manifest file. ```APIDOC ## EarTrumpetAddon + Add-on interfaces ### Description Implement one or more add-on interfaces to extend specific surfaces of EarTrumpet. Add-ons are MEF-exported classes that inherit `EarTrumpetAddon` and are discovered from `\Addons\\\EarTrumpet*.dll`, accompanied by an `AddonManifest.json`. ### Interfaces - **IEarTrumpetAddonEvents**: Handles lifecycle events such as initialization and shutdown. - **IEarTrumpetAddonSettingsPage**: Provides custom settings pages for the add-on. - **IEarTrumpetAddonNotificationAreaContextMenu**: Contributes items to the system tray notification area context menu. - **IEarTrumpetAddonAppContent**: Provides custom UI content for specific applications within EarTrumpet. - **IEarTrumpetAddonDeviceContent**: Provides custom UI content for specific audio devices within EarTrumpet. ### Example AddonManifest.json ```json { "Id": "MyCompany.MyAddon", "PublisherName": "My Company", "HelpLink": "https://example.com/help", "Version": "1.0.0" } ``` ### Example C# Implementation ```csharp using EarTrumpet.Extensibility; using EarTrumpet.UI.ViewModels; using System.Collections.Generic; using System.ComponentModel.Composition; [Export(typeof(EarTrumpetAddon))] public class MyAddon : EarTrumpetAddon, IEarTrumpetAddonEvents, IEarTrumpetAddonSettingsPage, IEarTrumpetAddonNotificationAreaContextMenu, IEarTrumpetAddonAppContent, IEarTrumpetAddonDeviceContent { public MyAddon() { DisplayName = "My Addon"; } // --- IEarTrumpetAddonEvents --- public void OnAddonEvent(AddonEventKind evt) { // Handle events like InitializeAddon, AddonsInitialized, AppShuttingDown } // --- IEarTrumpetAddonSettingsPage --- public SettingsCategoryViewModel GetSettingsCategory() { // Return a SettingsCategoryViewModel for your add-on's settings page return new SettingsCategoryViewModel("My Addon", "\xE713", "Configure My Addon", null, new[] { new MyAddonSettingsPageViewModel(Settings) }); } // --- IEarTrumpetAddonNotificationAreaContextMenu --- public IEnumerable NotificationAreaContextMenuItems => new[] { new ContextMenuItem { DisplayName = "My Addon Action", Glyph = "\xE1CE", Command = new EarTrumpet.UI.Helpers.RelayCommand(() => System.Diagnostics.Trace.WriteLine("My Addon Action triggered")) } }; // --- IEarTrumpetAddonAppContent --- public object GetContentForApp(string deviceId, string appId, System.Action requestClose) => null; public IEnumerable GetContextMenuItemsForApp(string deviceId, string appId) => System.Array.Empty(); // --- IEarTrumpetAddonDeviceContent --- public object GetContentForDevice(string deviceId, System.Action requestClose) => null; public IEnumerable GetContextMenuItemsForDevice(string deviceId) => System.Array.Empty(); } ``` ``` -------------------------------- ### Read and Write Persisted Settings with StorageFactory Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use ISettingsBag for reading and writing key/value settings. Supports default values for reads and provides an event for reacting to changes. Pass a namespace string to scope settings. ```csharp using EarTrumpet.DataModel.Storage; // Global settings bag (no namespace) ISettingsBag settings = StorageFactory.GetSettings(); // Read with a default value (generic; supports bool, int, string, structs) bool useLegacyIcon = settings.Get("UseLegacyIcon", false); int someCount = settings.Get("LaunchCount", 0); // Write settings.Set("UseLegacyIcon", true); settings.Set("LaunchCount", someCount + 1); // Check existence if (!settings.HasKey("hasShownFirstRun")) { settings.Set("hasShownFirstRun", true); Console.WriteLine("First run!"); } // React to changes (e.g., settings changed from another code path) settings.SettingChanged += (sender, key) => Console.WriteLine($"Setting changed: {key}"); // Namespaced bag for an add-on (keys are prefixed internally) ISettingsBag addonSettings = StorageFactory.GetSettings("MyAddon.v1"); addonSettings.Set("Enabled", true); bool enabled = addonSettings.Get("Enabled", false); // true Console.WriteLine($"Namespace: {addonSettings.Namespace}"); // MyAddon.v1 ``` -------------------------------- ### Subscribe to Audio Events with PlaybackDataModelHost Source: https://context7.com/file-new-project/eartrumpet/llms.txt PlaybackDataModelHost provides a unified event source for audio changes. Subscribe to AppAdded, AppRemoved, AppPropertyChanged, DeviceAdded, DeviceRemoved, and DevicePropertyChanged events to react to audio system events without managing complex subscriptions. ```csharp using EarTrumpet.Extensibility.Shared; using EarTrumpet.DataModel.Audio; PlaybackDataModelHost host = PlaybackDataModelHost.Current; // React to a new audio session (app) starting on any device host.AppAdded += (IAudioDeviceSession session) => Console.WriteLine($"App started: {session.DisplayName} on {session.Parent.DisplayName}"); // React to an audio session ending host.AppRemoved += (session) => Console.WriteLine($"App stopped: {session.DisplayName}"); // React to any property change on a session (volume, mute, peak, state…) host.AppPropertyChanged += (session, propertyName) => { if (propertyName == nameof(IAudioDeviceSession.Volume)) Console.WriteLine($"{session.DisplayName} volume → {session.Volume:P0}"); }; // React to device plug/unplug host.DeviceAdded += (device) => Console.WriteLine($"Device added: {device.DisplayName}"); host.DeviceRemoved += (device) => Console.WriteLine($"Device removed: {device.DisplayName}"); host.DevicePropertyChanged += (device, prop) => { if (prop == nameof(IAudioDevice.IsMuted)) Console.WriteLine($"Device {device.DisplayName} muted: {device.IsMuted}"); }; ``` -------------------------------- ### AppInformationFactory.CreateForProcess - Resolve app metadata from a process ID Source: https://context7.com/file-new-project/eartrumpet/llms.txt Retrieve application metadata for a running process using its process ID. This method dispatches to either a Modern-app (MSIX/UWP) or Desktop-app implementation based on whether the process is packaged. PID 0 returns the SystemSoundsAppInfo. ```APIDOC ## AppInformationFactory.CreateForProcess — Resolve app metadata from a process ID ### Description Returns an `IAppInfo` object describing a running process. It determines whether the process is a packaged Modern-app (MSIX/UWP) or a Desktop-app and dispatches accordingly. Providing PID 0 returns the `SystemSoundsAppInfo`. ### Method C# Method Calls ### Endpoint N/A (SDK Usage) ### Parameters N/A (SDK Usage) ### Request Example ```csharp using EarTrumpet.DataModel.AppInformation; using System.Diagnostics; int pid = Process.GetProcessesByName("spotify").FirstOrDefault()?.Id ?? 0; // trackProcess=true: fires IAppInfo.Stopped when the process exits IAppInfo info = AppInformationFactory.CreateForProcess(pid, trackProcess: true); Console.WriteLine($"Display name: {info.DisplayName}"); Console.WriteLine($"Executable name: {info.ExeName}"); Console.WriteLine($"Install path: {info.PackageInstallPath}"); Console.WriteLine($"Logo path: {info.SmallLogoPath}"); Console.WriteLine($"Is desktop app: {info.IsDesktopApp}"); // Expected output for Spotify (MSIX): // Display name: Spotify Music // Executable name: C:\Program Files\WindowsApps\SpotifyAB.SpotifyMusic_...\Spotify.exe // Is desktop app: False info.Stopped += (appInfo) => Console.WriteLine($"{appInfo.DisplayName} has exited."); // For PID 0 (system sounds): IAppInfo systemSounds = AppInformationFactory.CreateForProcess(0); Console.WriteLine(systemSounds.IsDesktopApp); // False ``` ### Response N/A (SDK Usage) ``` -------------------------------- ### XAML Theme Brush with Configuration Values Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Specify theme brush values for different configurations like Light, Dark, and HighContrast. Values can be combined with transparency settings. ```xml Light=LightChromeWhite, Dark=DarkChromeWhite, HighContrast=Highlight ``` -------------------------------- ### XAML Theme Options Scope Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Specify different colors for the flyout and other surfaces using scopes. Requires defining tokens for both scopes, even if they are identical. ```xml Flyout:Theme=Red, Flyout:HighContrast=HotTrack, :Theme=Blue, :HighContrast=HotTrack ``` -------------------------------- ### Serializer.ToString / Serializer.FromString Source: https://context7.com/file-new-project/eartrumpet/llms.txt Utility methods for XML-serializing and deserializing complex objects to be stored within an ISettingsBag. ```APIDOC ## Serializer.ToString / Serializer.FromString ### Description Converts strongly-typed objects to an XML string for storage inside `ISettingsBag`, and back. Used internally by EarTrumpet.Actions to persist `EarTrumpetAction[]`. ### Usage ```csharp using EarTrumpet.DataModel.Storage; using System.Collections.Generic; [System.Xml.Serialization.XmlRoot("HotkeyConfig")] public class HotkeyConfig { public string Key { get; set; } public bool Ctrl { get; set; } public bool Alt { get; set; } } // Serialise to XML string var config = new HotkeyConfig { Key = "F1", Ctrl = true, Alt = false }; string xml = Serializer.ToString("HotkeyConfig", config); // F1truefalse // Persist in settings ISettingsBag bag = StorageFactory.GetSettings("MyAddon"); bag.Set("HotkeyConfig", xml); // Deserialise back string stored = bag.Get("HotkeyConfig", ""); if (!string.IsNullOrEmpty(stored)) { HotkeyConfig restored = Serializer.FromString(stored); Console.WriteLine($"Key: {restored.Key}, Ctrl: {restored.Ctrl}"); // Key: F1, Ctrl: True } ``` ``` -------------------------------- ### XAML Theme Brush with Variable and Transparency Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Use the {Theme} variable for Light/Dark configurations and optionally modify the color alpha channel using a value between 0.0-1.0. ```xml Theme={Theme}ChromeWhite, HighContrast=Highlight ``` ```xml Light=LightChromeWhite/0.8 ``` ```xml Light=LightChromeWhite/0.8/1 ``` -------------------------------- ### XML Serialize Complex Settings with Serializer Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use Serializer.ToString and Serializer.FromString to convert strongly-typed objects to and from XML strings for storage. This is used internally for persisting complex data structures like EarTrumpetAction arrays. ```csharp using EarTrumpet.DataModel.Storage; using System.Collections.Generic; [System.Xml.Serialization.XmlRoot("HotkeyConfig")] public class HotkeyConfig { public string Key { get; set; } public bool Ctrl { get; set; } public bool Alt { get; set; } } // Serialise to XML string var config = new HotkeyConfig { Key = "F1", Ctrl = true, Alt = false }; string xml = Serializer.ToString("HotkeyConfig", config); // F1truefalse // Persist in settings ISettingsBag bag = StorageFactory.GetSettings("MyAddon"); bag.Set("HotkeyConfig", xml); // Deserialise back string stored = bag.Get("HotkeyConfig", ""); if (!string.IsNullOrEmpty(stored)) { HotkeyConfig restored = Serializer.FromString(stored); Console.WriteLine($"Key: {restored.Key}, Ctrl: {restored.Ctrl}"); // Key: F1, Ctrl: True } ``` -------------------------------- ### AddonManager Load and Shutdown Source: https://context7.com/file-new-project/eartrumpet/llms.txt Manage the lifecycle of add-ons within EarTrumpet. The AddonManager discovers, loads, and unloads add-on assemblies, and provides access to loaded add-ons. ```APIDOC ## AddonManager.Load / AddonManager.Shutdown ### Description Load and unload the add-on host. Called by `App` at startup and shutdown, respectively. Discovers add-on assemblies, initializes each, and broadcasts lifecycle events. `AddonManager.Host` provides typed lists of each add-on interface. ### Loading Add-ons At application startup, typically after the audio device manager has loaded: ```csharp using EarTrumpet.Extensibility.Hosting; using EarTrumpet.Extensibility; // Load add-ons, including internal ones if specified AddonManager.Load(shouldLoadInternalAddons: true); // Access loaded add-ons through AddonManager.Host // Example: Iterate through all loaded add-ons foreach (var addon in AddonManager.Host.Addons) Console.WriteLine($"Loaded: {addon.Manifest?.Id} v{addon.Manifest?.Version}"); // Example: Get tray context menu contributions from all addons var menuItems = AddonManager.Host.TrayContextMenuItems .SelectMany(a => a.NotificationAreaContextMenuItems); // Example: Get settings page contributions var settingsCategories = AddonManager.Host.SettingsItems .Select(a => a.GetSettingsCategory()); // Get diagnostic information about loaded add-ons string diag = AddonManager.GetDiagnosticInfo(); Console.WriteLine($"Loaded addon IDs: {diag}"); ``` ### Unloading Add-ons At application shutdown: ```csharp // Broadcasts AddonEventKind.AppShuttingDown to all addons AddonManager.Shutdown(); ``` ``` -------------------------------- ### Resolve Theme Colors Programmatically Source: https://context7.com/file-new-project/eartrumpet/llms.txt Programmatically resolve theme color references and subscribe to theme change events. Useful for custom drawing or dynamic UI updates. ```csharp // Resolve a theme color reference programmatically (e.g., for drawing) using EarTrumpet.UI.Themes; using System.Windows.Media; Color accent = Manager.Current.ResolveRef(myControl, "SystemAccent"); bool isDark = Manager.Current.IsLightTheme == false; bool isHC = Manager.Current.IsHighContrast; // Subscribe to theme changes Manager.Current.ThemeChanged += () => { Console.WriteLine($"Theme changed — Light: {Manager.Current.IsLightTheme}, HC: {Manager.Current.IsHighContrast}"); }; ``` -------------------------------- ### IAudioDevice / IAudioDeviceSession - Control volume and mute Source: https://context7.com/file-new-project/eartrumpet/llms.txt Control volume and mute status for audio devices and application sessions. IAudioDevice represents a physical or virtual audio endpoint, while IAudioDeviceSession represents a single application audio stream. Both implement IStreamWithVolumeControl, which exposes Volume (0.0–1.0), IsMuted, and stereo peak values. ```APIDOC ## IAudioDevice / IAudioDeviceSession — Control volume and mute ### Description Represents a physical or virtual audio endpoint (`IAudioDevice`) or a single application audio stream (`IAudioDeviceSession`). Both implement `IStreamWithVolumeControl`, providing access to volume, mute status, and peak values. ### Method C# Method Calls ### Endpoint N/A (SDK Usage) ### Parameters N/A (SDK Usage) ### Request Example ```csharp using EarTrumpet.DataModel.Audio; using EarTrumpet.DataModel.WindowsAudio; using System.Collections.Specialized; IAudioDeviceManager mgr = WindowsAudioFactory.Create(AudioDeviceKind.Playback); mgr.Loaded += (_, __) => { IAudioDevice defaultDevice = mgr.Default; if (defaultDevice == null) return; // Read and write device-level volume (0.0 = silent, 1.0 = full) Console.WriteLine($"Current volume: {defaultDevice.Volume:P0}"); defaultDevice.Volume = 0.5f; // Set to 50% defaultDevice.IsMuted = false; // Unmute // Listen to peak meter updates (call UpdatePeakValues() on a timer to refresh) defaultDevice.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(IAudioDevice.PeakValue1)) Console.WriteLine($"Peak L/R: {defaultDevice.PeakValue1:F2} / {defaultDevice.PeakValue2:F2}"); }; // React to apps appearing or disappearing defaultDevice.Groups.CollectionChanged += (s, e) => { if (e.Action == NotifyCollectionChangedAction.Add) { var session = (IAudioDeviceSession)e.NewItems[0]; Console.WriteLine($"App started: {session.DisplayName} ({session.ExeName}) PID={session.ProcessId}"); } }; // Mute a specific app by name foreach (IAudioDeviceSession session in defaultDevice.Groups) { if (session.ExeName?.Equals("chrome", StringComparison.OrdinalIgnoreCase) == true) { session.IsMuted = true; Console.WriteLine($"Muted Chrome. AppId: {session.AppId}"); } } // Periodically sample peak values from a background/UI timer mgr.UpdatePeakValues(); }; ``` ### Response N/A (SDK Usage) ``` -------------------------------- ### Control Audio Device Volume and Mute Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use IAudioDevice and IAudioDeviceSession to manage volume and mute states. Listen for peak meter updates and react to application changes. ```csharp using EarTrumpet.DataModel.Audio; using EarTrumpet.DataModel.WindowsAudio; using System.Collections.Specialized; IAudioDeviceManager mgr = WindowsAudioFactory.Create(AudioDeviceKind.Playback); mgr.Loaded += (_, __) => { IAudioDevice defaultDevice = mgr.Default; if (defaultDevice == null) return; // Read and write device-level volume (0.0 = silent, 1.0 = full) Console.WriteLine($"Current volume: {defaultDevice.Volume:P0}"); defaultDevice.Volume = 0.5f; // Set to 50% defaultDevice.IsMuted = false; // Unmute // Listen to peak meter updates (call UpdatePeakValues() on a timer to refresh) defaultDevice.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(IAudioDevice.PeakValue1)) Console.WriteLine($"Peak L/R: {defaultDevice.PeakValue1:F2} / {defaultDevice.PeakValue2:F2}"); }; // React to apps appearing or disappearing defaultDevice.Groups.CollectionChanged += (s, e) => { if (e.Action == NotifyCollectionChangedAction.Add) { var session = (IAudioDeviceSession)e.NewItems[0]; Console.WriteLine($"App started: {session.DisplayName} ({session.ExeName}) PID={session.ProcessId}"); } }; // Mute a specific app by name foreach (IAudioDeviceSession session in defaultDevice.Groups) { if (session.ExeName?.Equals("chrome", StringComparison.OrdinalIgnoreCase) == true) { session.IsMuted = true; Console.WriteLine($"Muted Chrome. AppId: {session.AppId}"); } } // Periodically sample peak values from a background/UI timer mgr.UpdatePeakValues(); }; ``` -------------------------------- ### XAML Theme OS Dependency Property Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Use OS-specific dependency properties for theming across different Windows versions. Currently includes 'IsWindows11' for Windows 11 specific theming. ```xml ``` -------------------------------- ### Theme:Brush Attached Properties Source: https://context7.com/file-new-project/eartrumpet/llms.txt Declare theme-aware colors in XAML using attached dependency properties that re-evaluate at runtime when the Windows theme changes. ```APIDOC ## UI Themes — Dynamic Brush System ### `Theme:Brush` attached properties — Declare theme-aware colors in XAML ### Description The `Theme:Brush` class provides attached dependency properties (`Foreground`, `Background`, `BorderBrush`, `Fill`, `Stroke`, `SelectionBrush`, `CaretBrush`) that re-evaluate at runtime whenever the Windows theme changes, supporting light, dark, high-contrast, and accent-color configurations. ### Usage Example (XAML) ```xml ``` ### Usage Example (C#) ```csharp // Resolve a theme color reference programmatically (e.g., for drawing) using EarTrumpet.UI.Themes; using System.Windows.Media; Color accent = Manager.Current.ResolveRef(myControl, "SystemAccent"); bool isDark = Manager.Current.IsLightTheme == false; bool isHC = Manager.Current.IsHighContrast; // Subscribe to theme changes Manager.Current.ThemeChanged += () => { Console.WriteLine($"Theme changed — Light: {Manager.Current.IsLightTheme}, HC: {Manager.Current.IsHighContrast}"); }; ``` ### Related Properties - `Theme:Options.Scope`: Specifies whether theme settings apply to flyouts or the main application window. - `Theme:Options.Source`: Determines whether to use the application's theme or the system's theme (taskbar/flyout). ``` -------------------------------- ### Filter Audio Device and Session Collections Source: https://context7.com/file-new-project/eartrumpet/llms.txt Apply filters to IAudioDeviceManager or IAudioDevice to create derived views of collections. Filters are chained for multiple independent views. ```csharp using EarTrumpet.DataModel.Audio; using EarTrumpet.DataModel.WindowsAudio; using System.Collections.ObjectModel; using System.Linq; IAudioDeviceManager mgr = WindowsAudioFactory.Create(AudioDeviceKind.Playback); // Exclude devices whose display name contains "Virtual" mgr.AddFilter(devices => { var filtered = new ObservableCollection( devices.Where(d => !d.DisplayName.Contains("Virtual")) ); return filtered; }); mgr.Loaded += (_, __) => { // mgr.Devices now reflects the filtered view foreach (var d in mgr.Devices) Console.WriteLine(d.DisplayName); // Per-device: hide system sounds session from UI mgr.Default?.AddFilter(sessions => new ObservableCollection( sessions.Where(s => !s.IsSystemSoundsSession) ) ); }; ``` -------------------------------- ### XAML Theme Brush Reference Rules Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Define complex brush values using nested and reference them like static colors. Rules are evaluated sequentially based on 'On' conditions. ```xml ``` -------------------------------- ### Declare Theme-Aware Colors in XAML Source: https://context7.com/file-new-project/eartrumpet/llms.txt Use `Theme:Brush` attached properties to define colors in XAML that re-evaluate at runtime when the Windows theme changes. Supports static colors, named system colors, light/dark adaptive colors, and transparency. ```xml ``` -------------------------------- ### IAudioDeviceManager.AddFilter / IAudioDevice.AddFilter - Filter the device or session collection Source: https://context7.com/file-new-project/eartrumpet/llms.txt Apply filters to device or session collections to create derived views. Both IAudioDeviceManager and IAudioDevice accept a filter delegate that transforms the underlying ObservableCollection. ```APIDOC ## IAudioDeviceManager.AddFilter / IAudioDevice.AddFilter — Filter the device or session collection ### Description Allows filtering of device or session collections by accepting a filter delegate. This transforms the underlying `ObservableCollection` into a derived view, enabling chained filtering for independent consumer views. ### Method C# Method Calls ### Endpoint N/A (SDK Usage) ### Parameters N/A (SDK Usage) ### Request Example ```csharp using EarTrumpet.DataModel.Audio; using EarTrumpet.DataModel.WindowsAudio; using System.Collections.ObjectModel; using System.Linq; IAudioDeviceManager mgr = WindowsAudioFactory.Create(AudioDeviceKind.Playback); // Exclude devices whose display name contains "Virtual" mgr.AddFilter(devices => { var filtered = new ObservableCollection( devices.Where(d => !d.DisplayName.Contains("Virtual")) ); return filtered; }); mgr.Loaded += (_, __) => { // mgr.Devices now reflects the filtered view foreach (var d in mgr.Devices) Console.WriteLine(d.DisplayName); // Per-device: hide system sounds session from UI mgr.Default?.AddFilter(sessions => new ObservableCollection( sessions.Where(s => !s.IsSystemSoundsSession) ) ); }; ``` ### Response N/A (SDK Usage) ``` -------------------------------- ### XAML Theme Brush Declaration Source: https://github.com/file-new-project/eartrumpet/blob/master/EarTrumpet/README.md Declare theme brush values on elements in XAML. Supports static colors, system accents, and theme-specific values for Light, Dark, and HighContrast configurations. ```xml ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.