From aa07ad9f084c6c7377985b09bca9817ba3bfe30b Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Sun, 10 May 2026 21:10:30 -0400 Subject: [PATCH] Auto-record when Teams joins a meeting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/TeamsISO.App/MainWindow.xaml | 5 ++++ src/TeamsISO.App/Services/UIPreferences.cs | 7 ++++- .../ViewModels/GlobalSettingsViewModel.cs | 20 ++++++++++++- src/TeamsISO.App/ViewModels/MainViewModel.cs | 29 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/TeamsISO.App/MainWindow.xaml b/src/TeamsISO.App/MainWindow.xaml index aa16a8a..5ab756a 100644 --- a/src/TeamsISO.App/MainWindow.xaml +++ b/src/TeamsISO.App/MainWindow.xaml @@ -1338,6 +1338,11 @@ 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."/> + + /// Auto-launch the Microsoft Teams desktop client when TeamsISO starts. @@ -289,6 +292,21 @@ public sealed class GlobalSettingsViewModel : ObservableObject } } + /// + /// 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. + /// + public bool AutoRecordOnCall + { + get => _autoRecordOnCall; + set + { + if (SetField(ref _autoRecordOnCall, value)) PersistUiPrefs(); + } + } + /// /// Record each newly-enabled ISO's normalized output to disk under /// . Already-running ISOs are not retroactively diff --git a/src/TeamsISO.App/ViewModels/MainViewModel.cs b/src/TeamsISO.App/ViewModels/MainViewModel.cs index fff6b22..5b7b3bc 100644 --- a/src/TeamsISO.App/ViewModels/MainViewModel.cs +++ b/src/TeamsISO.App/ViewModels/MainViewModel.cs @@ -693,10 +693,39 @@ public sealed class MainViewModel : ObservableObject, IDisposable var title = inCall ? ExtractMeetingTitle(TeamsLauncher.GetActiveWindowTitle()) : null; _dispatcher.InvokeAsync(() => { + var previousInCall = IsTeamsInCall; IsTeamsInCall = inCall; TeamsMeetingState = inCall ? (string.IsNullOrEmpty(title) ? "IN CALL" : $"IN CALL · {title}") : "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 */ }