Files
LlamaCasty/ytLive.Tests/GameMeterHonestyTests.cs
gramps 7f2bda8ed3 fix(audio): game meter scales by GameAudioVolume — meter/stream/headphones all follow the one knob
Creator report 2026-09-01: with the desktop slider dragged to 20%, the game bar's
meter stayed pegged yellow/red. Root cause: the mic meter's formula (level x volume)
was cloned to the game bar WITHOUT the x-volume factor, and the clone inherited a
false premise — that WASAPI loopback capture tracks the endpoint volume. Tonight's
observation disproves it (the tap is pre-endpoint-volume), so both the meter (display)
and the mix (AudioGainProvider.LoopbackGain, fixed in 5ead064) must scale it themselves.
ai.md's two 'loopback scales with the slider' sentences corrected in the same pass.

Test seam: VolumePushOverride (internal static, mirrors LayoutPathOverride pattern) so
the test never hijacks the machine's real volume. GameMeterHonestyTests (RealApp +
temp DB): unity -> hot/red, 20% -> ~1/5 width/green, push observed.
2026-09-01 21:22:57 -07:00

73 lines
2.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Data.Sqlite;
using Xunit;
using ytLive.Services;
using ytLive.ViewModels;
namespace ytLive.Tests;
/// <summary>
/// Game-bar meter honesty (creator bug 2026-09-01): the WASAPI loopback tap is
/// PRE-endpoint-volume, so lowering the desktop slider left the meter pegged
/// yellow/red at 20% — the mic formula scales level × volume, the game clone
/// dropped the factor. The meter, the stream gain, and the headphones must all
/// follow the one knob.
/// </summary>
[Collection("RealApp")]
public sealed class GameMeterHonestyTests
{
private readonly RealAppHost _app;
public GameMeterHonestyTests(RealAppHost app) => _app = app;
[Fact]
public void Game_Meter_Scales_By_Volume()
{
_app.Run(Run);
}
private void Run()
{
var tempDb = Path.Combine(Path.GetTempPath(), $"ytLlive-gamemeter-{Guid.NewGuid():N}.db");
MainViewModel.LayoutPathOverride = tempDb;
var pushed = new List<double>();
MainViewModel.VolumePushOverride = v => pushed.Add(v);
var window = default(MainWindow);
try
{
using (var schema = new LayoutStore(tempDb)) { }
SqliteConnection.ClearAllPools();
window = new MainWindow();
var vm = (MainViewModel)window.DataContext;
window.Show();
// Hot desktop bed pegged at full linear level (ToDisplay ~= 1.0).
vm.GameAudioVolume = 1.0;
vm.GameAudioLevel = 1.0;
Assert.True(vm.GameMeterFillWidth > 230, "unity volume must keep the meter hot");
Assert.Equal("#ef4444", vm.GameMeterBrush);
// Drop the knob to 20% — the captured level does NOT change (the OS
// tap is pre-endpoint-volume); the meter must scale it anyway.
vm.GameAudioVolume = 0.2;
vm.GameAudioLevel = 1.0;
Assert.InRange(vm.GameMeterFillWidth, 40, 80);
Assert.Equal("#22c55e", vm.GameMeterBrush);
// And the push really reached the (faked) endpoint — one knob, honest.
Assert.Contains(0.2, pushed);
}
finally
{
MainViewModel.VolumePushOverride = null;
if (window != null) window.Close();
MainViewModel.LayoutPathOverride = null;
SqliteConnection.ClearAllPools();
try { File.Delete(tempDb); } catch { /* best-effort */ }
}
}
}