Game audio bar is now ALWAYS visible (TASK 4 gating removed, 2026-08-15): the show/hide machinery kept hiding the desktop/game meter whenever no full-screen game with sound was up or no TRAX music played, which the creator read as the meter being lost. Deleted IGameAudioDetector/GameAudioDetector/GameAudioHysteresis (Services/), the VM's 250ms DispatcherTimer poll + OnGameAudioActiveChanged/OnGameAudioPollTick + IsGameAudioBarVisible + _gameAudioBarActive/_gameAudioTimer/_gameAudioDetector, and the two detector test files (GameAudioDetectorTests, GameAudioHysteresisTests); MainWindow.xaml drops the Visibility binding so the bar renders unconditionally. Desktop audio is just automatic WASAPI loopback now. Docs in the same commit: ai.md (audio section + Services inventory), Services/index.md, ViewModels/index.md, TASKS.md TASK 9 item 7 follow-up, HANDOFF.md shipped state + stale poll-timer landmine removed. Build 0 warnings, 189 tests passing (8 detector tests removed)
This commit is contained in:
@@ -28,7 +28,6 @@ public class MainViewModel : ViewModelBase
|
||||
private readonly DispatcherTimer _liveTimer;
|
||||
private readonly DispatcherTimer _volumeFlashTimer;
|
||||
private readonly DispatcherTimer _gameVolumeFlashTimer;
|
||||
private readonly DispatcherTimer _gameAudioTimer;
|
||||
|
||||
private Scene? _activeScene;
|
||||
private SceneElement? _selectedElement;
|
||||
@@ -50,7 +49,6 @@ public class MainViewModel : ViewModelBase
|
||||
private double _gameVolume = 1.0;
|
||||
private bool _gameMuted;
|
||||
private double? _gameVolumeBeforeMute;
|
||||
private bool _gameAudioBarActive;
|
||||
|
||||
// TRAX (TASK 9): free background music at a fixed quiet volume, playing to
|
||||
// the default device so it rides the loopback into the stream. The dot is
|
||||
@@ -122,7 +120,6 @@ public class MainViewModel : ViewModelBase
|
||||
private readonly IFullScreenDetector _fullScreenDetector;
|
||||
private readonly ScreenCaptureManager _screenCaptureManager;
|
||||
private readonly ScreenCaptureSourceFactory _screenCaptureFactory;
|
||||
private readonly IGameAudioDetector _gameAudioDetector;
|
||||
private int? _lastForegroundFullScreenMonitor;
|
||||
private CancellationTokenSource? _deactivateCts;
|
||||
private ImageSource? _backdropImage;
|
||||
@@ -491,14 +488,8 @@ public class MainViewModel : ViewModelBase
|
||||
_ => "No mic connected — click to choose a microphone",
|
||||
};
|
||||
|
||||
// ─── Game audio bar (desktop/game): visible only while a full-screen game
|
||||
// ─── is producing sound (IGameAudioDetector). Meter + mute + volume mirror
|
||||
// ─── the mic bar. ───
|
||||
|
||||
/// <summary>True while the game audio bar should be shown: a full-screen game
|
||||
/// producing sound (IGameAudioDetector) OR background music playing (TASK 9)
|
||||
/// — the meter bounces during scene setup even with no game up.</summary>
|
||||
public bool IsGameAudioBarVisible => _gameAudioBarActive || IsMusicPlaying;
|
||||
// ─── Game audio bar (desktop/game): always visible — a mirror of the mic bar
|
||||
// ─── (meter + mute + volume). Desktop/game audio is automatic (WASAPI loopback). ───
|
||||
|
||||
/// <summary>True while the TRAX background track is playing.</summary>
|
||||
public bool IsMusicPlaying
|
||||
@@ -510,7 +501,6 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
OnPropertyChanged(nameof(TraxDotBrush));
|
||||
OnPropertyChanged(nameof(TraxToolTip));
|
||||
OnPropertyChanged(nameof(IsGameAudioBarVisible));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1202,13 +1192,6 @@ public class MainViewModel : ViewModelBase
|
||||
foreach (var display in _fullScreenDetector.GetDisplays())
|
||||
Displays.Add(display);
|
||||
|
||||
_gameAudioDetector = new GameAudioDetector(
|
||||
() => _fullScreenDetector.GetForegroundFullScreenMonitorIndex(),
|
||||
() => (float)GameAudioLevel);
|
||||
_gameAudioDetector.IsGameAudioActiveChanged += OnGameAudioActiveChanged;
|
||||
_gameAudioTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
|
||||
_gameAudioTimer.Tick += OnGameAudioPollTick;
|
||||
_gameAudioTimer.Start();
|
||||
_screenCaptureFactory = new ScreenCaptureSourceFactory(
|
||||
() => new WindowInteropHelper(System.Windows.Application.Current?.MainWindow).Handle);
|
||||
_screenCaptureManager = new ScreenCaptureManager(
|
||||
@@ -1546,7 +1529,6 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
_saveDebounce?.Stop();
|
||||
SaveLayoutNow();
|
||||
_gameAudioTimer.Stop();
|
||||
_audioMixer.Dispose();
|
||||
_framePump.Dispose();
|
||||
_cameraManager.Dispose();
|
||||
@@ -2261,24 +2243,6 @@ public class MainViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGameAudioActiveChanged(bool active)
|
||||
{
|
||||
_gameAudioBarActive = active;
|
||||
OnPropertyChanged(nameof(IsGameAudioBarVisible));
|
||||
}
|
||||
|
||||
private void OnGameAudioPollTick(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_gameAudioDetector.Poll();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLog.Write($"Game audio detection failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Scene-element → latest frame, for the live compositor. The map mirrors the
|
||||
// preview: webcam by DeviceId, live captures (the backdrop) by CaptureKey,
|
||||
// images/background by AssetId. A null frame leaves the element transparent.
|
||||
|
||||
Reference in New Issue
Block a user