public void TestWindowSupportsSafeAreaEnabled()
        {
            AtemMockServerWrapper.Each(_output, _pool, null, DeviceTestCases.MultiviewToggleSafeArea, helper =>
            {
                var cmds = helper.Server.GetParsedDataDump().OfType <MultiviewWindowInputGetCommand>().ToList();
                foreach (Tuple <uint, IBMDSwitcherMultiView> mv in GetMultiviewers(helper))
                {
                    mv.Item2.CanToggleSafeAreaEnabled(out int supported);
                    Assert.Equal(1, supported);

                    mv.Item2.SupportsQuadrantLayout(out int supportsQuadrant);
                    int[] windows = Randomiser
                                    .SelectionOfGroup(Enumerable.Range(0, supportsQuadrant == 0 ? 10 : 16).ToList()).ToArray();

                    foreach (int window in windows)
                    {
                        AtemState stateBefore = helper.Helper.BuildLibState();
                        MultiViewerState.WindowState windowState = stateBefore.Settings.MultiViewers[(int)mv.Item1].Windows[window];

                        MultiviewWindowInputGetCommand cmd = cmds.Single(c => c.WindowIndex == window && c.MultiviewIndex == mv.Item1);

                        for (int i = 0; i < 5; i++)
                        {
                            windowState.SupportsSafeArea = cmd.SupportsSafeArea = !windowState.SupportsSafeArea;

                            helper.SendFromServerAndWaitForChange(stateBefore, cmd);
                        }
                    }
                }
            });
        }
        public void TestSource()
        {
            AtemMockServerWrapper.Each(_output, _pool, SourceCommandHandler, DeviceTestCases.MultiviewRouteInputs, helper =>
            {
                VideoSource[] validSources = helper.Helper.BuildLibState().Settings.Inputs
                                             .Where(i => i.Value.Properties.SourceAvailability.HasFlag(SourceAvailability.Multiviewer))
                                             .Select(i => i.Key).ToArray();

                foreach (Tuple <uint, IBMDSwitcherMultiView> mv in GetMultiviewers(helper))
                {
                    mv.Item2.CanRouteInputs(out int supported);
                    Assert.Equal(1, supported);

                    mv.Item2.SupportsQuadrantLayout(out int supportsQuadrant);
                    int[] windows = Randomiser
                                    .SelectionOfGroup(Enumerable.Range(supportsQuadrant == 0 ? 2 : 0, supportsQuadrant == 0 ? 8 : 16).ToList()).ToArray();

                    foreach (int window in windows)
                    {
                        AtemState stateBefore = helper.Helper.BuildLibState();
                        MultiViewerState.WindowState windowState = stateBefore.Settings.MultiViewers[(int)mv.Item1].Windows[window];

                        //var sampleSources = VideoSourceUtil.TakeSelection(validSources);
                        var sampleSources = Randomiser.SelectionOfGroup(validSources.ToList(), 5);
                        foreach (VideoSource src in sampleSources)
                        {
                            windowState.Source = src;

                            helper.SendAndWaitForChange(stateBefore, () =>
                            {
                                mv.Item2.SetWindowInput((uint)window, (long)src);
                            });
                        }
                    }
                }
            });
        }
        private static Tuple <InfoState.MultiViewInfoState, MultiViewerState> BuildOne(IBMDSwitcherMultiView props)
        {
            var state = new MultiViewerState();
            var info  = new InfoState.MultiViewInfoState();

            props.SupportsVuMeters(out int supportsVu);
            info.SupportsVuMeters = supportsVu != 0;
            props.SupportsProgramPreviewSwap(out int supportsSwap);
            info.SupportsProgramPreviewSwapped = supportsSwap != 0;
            props.SupportsQuadrantLayout(out int supportsQuadrants);
            info.SupportsQuadrantLayout = supportsQuadrants != 0;
            props.CanToggleSafeAreaEnabled(out int supportsToggleSafeArea);
            info.SupportsToggleSafeArea = supportsToggleSafeArea != 0;
            props.CanRouteInputs(out int canRoute);
            info.CanRouteInputs = canRoute != 0;
#if !ATEM_v8_1
            props.CanChangeLayout(out int canChangeLayout);
            info.CanChangeLayout = canChangeLayout != 0;
            props.CanAdjustVuMeterOpacity(out int canChangeVuOpacity);
            info.CanChangeVuMeterOpacity = canChangeVuOpacity != 0;
#endif

            props.GetLayout(out _BMDSwitcherMultiViewLayout layout);
            state.Properties.Layout = (MultiViewLayoutV8)layout;
            props.GetProgramPreviewSwapped(out int swapped);
            state.Properties.ProgramPreviewSwapped = swapped != 0;

            if (info.SupportsVuMeters)
            {
                props.GetVuMeterOpacity(out double opacity);
                state.VuMeterOpacity = opacity * 100;
            }

            props.GetWindowCount(out uint count);
            state.Windows = Enumerable.Range(0, (int)count).Select(window =>
            {
                props.GetWindowInput((uint)window, out long input);
                props.GetSafeAreaEnabled((uint)window, out int enabled);

                var st = new MultiViewerState.WindowState
                {
                    Source          = (VideoSource)input,
                    SafeAreaEnabled = enabled != 0,
                };

                if (info.SupportsToggleSafeArea)
                {
                    props.CurrentInputSupportsSafeArea((uint)window, out int supportsSafeArea);
                    st.SupportsSafeArea = supportsSafeArea != 0;
                }

                if (info.SupportsVuMeters)
                {
                    props.CurrentInputSupportsVuMeter((uint)window, out int windowSupportsVu);
                    st.SupportsVuMeter = windowSupportsVu != 0;
                    props.GetVuMeterEnabled((uint)window, out int vuEnabled);
                    st.VuMeterEnabled = vuEnabled != 0;
                }

                return(st);
            }).ToList();

            return(Tuple.Create(info, state));
        }