Auto-record when Teams joins a meeting
Some checks failed
CI / build-and-test (push) Failing after 26s
Some checks failed
CI / build-and-test (push) Failing after 26s
New AutoRecordOnCall preference (DISPLAY tab). When checked, recording auto-flips ON the moment Teams transitions into a call (UIA Leave button appears in tree), and auto-flips OFF when the call ends. Completes the unattended-show story: with Launch + AutoHide + AutoRecord all ticked, the operator launches TeamsISO and walks away — Teams runs invisibly, recording begins/ends with the meeting, ISOs route, all done. Toast surfaces each transition so they know what's happening if they glance at the screen. Implementation: transition detection lives in the existing UIA-probe code in OnStatsTick. previousInCall != inCall gate prevents the auto-toggle from re-firing on every poll. Direct call to _controller.SetRecording + Settings.RecordIsosToDisk = ... so the existing recording infrastructure handles the rest. Toast for visibility, swallow-on-error so a recording config issue can't break the IN-CALL pill update path.
This commit is contained in:
parent
1d5d055b68
commit
aa07ad9f08
4 changed files with 59 additions and 2 deletions
|
|
@ -1338,6 +1338,11 @@
|
||||||
Margin="0,8,0,0"
|
Margin="0,8,0,0"
|
||||||
ToolTip="When checked, Teams' windows are hidden as soon as they materialize after launch. Use the eye-icon button in the rail to restore them when needed. Drives Teams via the IN-CALL bar (mute / camera / share / leave / marker) and the participants DataGrid for ISO routing."/>
|
ToolTip="When checked, Teams' windows are hidden as soon as they materialize after launch. Use the eye-icon button in the rail to restore them when needed. Drives Teams via the IN-CALL bar (mute / camera / share / leave / marker) and the participants DataGrid for ISO routing."/>
|
||||||
|
|
||||||
|
<CheckBox Content="Auto-record when Teams joins a meeting"
|
||||||
|
IsChecked="{Binding Settings.AutoRecordOnCall}"
|
||||||
|
Margin="0,8,0,0"
|
||||||
|
ToolTip="When checked, recording auto-starts the moment Teams transitions into a call (IN CALL pill goes cyan) and auto-stops when the call ends. Removes the manual Record toggle step from unattended-show workflows."/>
|
||||||
|
|
||||||
<Separator Margin="0,16,0,8"/>
|
<Separator Margin="0,16,0,8"/>
|
||||||
|
|
||||||
<CheckBox Content="Record ISOs to disk"
|
<CheckBox Content="Record ISOs to disk"
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,12 @@ public static class UIPreferences
|
||||||
// background and its windows are auto-hidden as soon as they materialize.
|
// background and its windows are auto-hidden as soon as they materialize.
|
||||||
// All control happens via the IN-CALL bar + participants DataGrid.
|
// All control happens via the IN-CALL bar + participants DataGrid.
|
||||||
bool LaunchTeamsOnStartup = false,
|
bool LaunchTeamsOnStartup = false,
|
||||||
bool AutoHideTeamsWindows = false);
|
bool AutoHideTeamsWindows = false,
|
||||||
|
// Auto-record on meeting start: when Teams transitions into a call
|
||||||
|
// (UIA Leave button appears), TeamsISO flips global recording on;
|
||||||
|
// when the call ends, recording stops. Pairs naturally with the
|
||||||
|
// headless workflow — operator never touches the recording toggle.
|
||||||
|
bool AutoRecordOnCall = false);
|
||||||
|
|
||||||
public static Prefs Load()
|
public static Prefs Load()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ public sealed class GlobalSettingsViewModel : ObservableObject
|
||||||
private bool _controlSurfaceLanReachable;
|
private bool _controlSurfaceLanReachable;
|
||||||
private bool _launchTeamsOnStartup;
|
private bool _launchTeamsOnStartup;
|
||||||
private bool _autoHideTeamsWindows;
|
private bool _autoHideTeamsWindows;
|
||||||
|
private bool _autoRecordOnCall;
|
||||||
|
|
||||||
public GlobalSettingsViewModel(IIsoController controller, ToastViewModel? toast = null)
|
public GlobalSettingsViewModel(IIsoController controller, ToastViewModel? toast = null)
|
||||||
{
|
{
|
||||||
|
|
@ -63,6 +64,7 @@ public sealed class GlobalSettingsViewModel : ObservableObject
|
||||||
_controlSurfaceLanReachable = uiPrefs.ControlSurfaceLanReachable;
|
_controlSurfaceLanReachable = uiPrefs.ControlSurfaceLanReachable;
|
||||||
_launchTeamsOnStartup = uiPrefs.LaunchTeamsOnStartup;
|
_launchTeamsOnStartup = uiPrefs.LaunchTeamsOnStartup;
|
||||||
_autoHideTeamsWindows = uiPrefs.AutoHideTeamsWindows;
|
_autoHideTeamsWindows = uiPrefs.AutoHideTeamsWindows;
|
||||||
|
_autoRecordOnCall = uiPrefs.AutoRecordOnCall;
|
||||||
|
|
||||||
// Bring the auto-apply flag in from the presets store so the checkbox
|
// Bring the auto-apply flag in from the presets store so the checkbox
|
||||||
// reflects the user's prior choice when the settings panel opens.
|
// reflects the user's prior choice when the settings panel opens.
|
||||||
|
|
@ -255,7 +257,8 @@ public sealed class GlobalSettingsViewModel : ObservableObject
|
||||||
MinimizeToTray: _minimizeToTray,
|
MinimizeToTray: _minimizeToTray,
|
||||||
ControlSurfaceLanReachable: _controlSurfaceLanReachable,
|
ControlSurfaceLanReachable: _controlSurfaceLanReachable,
|
||||||
LaunchTeamsOnStartup: _launchTeamsOnStartup,
|
LaunchTeamsOnStartup: _launchTeamsOnStartup,
|
||||||
AutoHideTeamsWindows: _autoHideTeamsWindows));
|
AutoHideTeamsWindows: _autoHideTeamsWindows,
|
||||||
|
AutoRecordOnCall: _autoRecordOnCall));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Auto-launch the Microsoft Teams desktop client when TeamsISO starts.
|
/// Auto-launch the Microsoft Teams desktop client when TeamsISO starts.
|
||||||
|
|
@ -289,6 +292,21 @@ public sealed class GlobalSettingsViewModel : ObservableObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When Teams transitions into a call, automatically enable recording;
|
||||||
|
/// when the call ends, stop. Removes the manual record-toggle step from
|
||||||
|
/// the headless workflow. Recording state changes are surfaced via the
|
||||||
|
/// existing toast + footer badge so the operator knows what's happening.
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoRecordOnCall
|
||||||
|
{
|
||||||
|
get => _autoRecordOnCall;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetField(ref _autoRecordOnCall, value)) PersistUiPrefs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Record each newly-enabled ISO's normalized output to disk under
|
/// Record each newly-enabled ISO's normalized output to disk under
|
||||||
/// <see cref="RecordingDirectory"/>. Already-running ISOs are not retroactively
|
/// <see cref="RecordingDirectory"/>. Already-running ISOs are not retroactively
|
||||||
|
|
|
||||||
|
|
@ -693,10 +693,39 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
||||||
var title = inCall ? ExtractMeetingTitle(TeamsLauncher.GetActiveWindowTitle()) : null;
|
var title = inCall ? ExtractMeetingTitle(TeamsLauncher.GetActiveWindowTitle()) : null;
|
||||||
_dispatcher.InvokeAsync(() =>
|
_dispatcher.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
|
var previousInCall = IsTeamsInCall;
|
||||||
IsTeamsInCall = inCall;
|
IsTeamsInCall = inCall;
|
||||||
TeamsMeetingState = inCall
|
TeamsMeetingState = inCall
|
||||||
? (string.IsNullOrEmpty(title) ? "IN CALL" : $"IN CALL · {title}")
|
? (string.IsNullOrEmpty(title) ? "IN CALL" : $"IN CALL · {title}")
|
||||||
: "READY";
|
: "READY";
|
||||||
|
|
||||||
|
// Auto-record on meeting transitions. False→True
|
||||||
|
// turns recording on; True→False turns it off.
|
||||||
|
// Guarded against repeating on every poll by
|
||||||
|
// gating on the actual transition.
|
||||||
|
if (Settings.AutoRecordOnCall && previousInCall != inCall)
|
||||||
|
{
|
||||||
|
if (inCall && !_controller.RecordingEnabled)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controller.SetRecording(true, Settings.RecordingDirectory);
|
||||||
|
Settings.RecordIsosToDisk = true;
|
||||||
|
Toast.Show("Auto-record: meeting started — recording ON");
|
||||||
|
}
|
||||||
|
catch { /* defensive — recording shouldn't block other state */ }
|
||||||
|
}
|
||||||
|
else if (!inCall && _controller.RecordingEnabled)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controller.SetRecording(false, null);
|
||||||
|
Settings.RecordIsosToDisk = false;
|
||||||
|
Toast.Show("Auto-record: meeting ended — recording OFF");
|
||||||
|
}
|
||||||
|
catch { /* defensive */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch { /* UIA flakiness shouldn't crash the stats tick */ }
|
catch { /* UIA flakiness shouldn't crash the stats tick */ }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue