feat(35): scenes remember the room — BRB mutes the mic on entry
591 green, 0 warnings.
- `Scene.SceneMutesMic` / `SceneMutesDesktop` are **nullable booleans**: null = leave the mix alone, so
a scene is passive until the creator says otherwise. Schema columns added, NULL for every existing
layout except one deliberate default.
- **Applied once when the scene takes the PROGRAM output** (`TransitionToScene`, only when live or
recording). Staging a scene offline is auditioning, not a stream edit — the test asserts that.
- **The creator is boss:** a manual mute survives any transition into a scene with no opinion; a scene
that does have one wins on its next entry. `SetMicMuted`/`SetGameMuted` are idempotent so a repeated
"mute" cannot clobber the level that unmute would restore.
- **BRB ships muted** (creator spec) for new layouts *and* via a one-time migration for existing rows
where the creator has never expressed an opinion.
- UI: two three-state checkboxes under the layers list ("When this scene goes live"), styled with
`PropertyPillCheck` so the theme test holds.
`SceneAudioTests` covers the whole rule in one integration test: default state, offline staging does
nothing, live entry mutes, manual unmute survives a passive scene, an opinionated scene wins, desktop
untouched, and all three states roundtrip through save/reload.
Needs the creator's eye: the checkboxes are new chrome in the left panel (indeterminate = passive).
This commit is contained in:
@@ -294,6 +294,38 @@ public partial class MainViewModel
|
||||
/// lip-sync is right", so it deserves one click, not a drag.</summary>
|
||||
internal void SetSyncOffset(int milliseconds) => AudioSyncOffsetMs = milliseconds;
|
||||
|
||||
/// <summary>TASK 35: mute/unmute from a scene entry. Idempotent — a scene that says "mute" while
|
||||
/// the mic is already muted must not overwrite the level it would restore.</summary>
|
||||
internal void SetMicMuted(bool muted)
|
||||
{
|
||||
if (muted == MicMuted) return;
|
||||
if (muted)
|
||||
{
|
||||
_volumeBeforeMute = MicVolume;
|
||||
MicVolume = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MicVolume = _volumeBeforeMute ?? 0.8;
|
||||
BeginVolumeFlash();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>TASK 35: as <see cref="SetMicMuted"/>, for desktop/game audio.</summary>
|
||||
internal void SetGameMuted(bool muted)
|
||||
{
|
||||
if (muted == GameMuted) return;
|
||||
if (muted)
|
||||
{
|
||||
_gameVolumeBeforeMute = GameAudioVolume;
|
||||
GameAudioVolume = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameAudioVolume = _gameVolumeBeforeMute ?? 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleMicMute()
|
||||
{
|
||||
if (MicMuted)
|
||||
|
||||
Reference in New Issue
Block a user