Example #1
0
        private void LibAtemReceive(object sender, IReadOnlyList <byte[]> commands)
        {
            lock (_libAtemStateLock)
            {
                foreach (byte[] cmdBytes in commands)
                {
                    // It should be safe to assume exactly one per
                    ParsedCommand.ReadNextCommand(cmdBytes, 0, out ParsedCommandSpec? cmd);
                    if (cmd == null)
                    {
                        throw new Exception("Failed to parse command");
                    }

                    ICommand cmd2 = CommandParser.Parse(_mockServer.CurrentVersion, cmd.Value);
                    if (cmd2 == null)
                    {
                        throw new Exception("Failed to parse command2");
                    }

                    OnLibAtemCommand?.Invoke(this, cmd2);

                    // TODO - handle result?
                    IUpdateResult result = AtemStateBuilder.Update(_libAtemState, cmd2, StateSettings);
                    foreach (string change in result.ChangedPaths)
                    {
                        OnLibAtemStateChange?.Invoke(this, change);
                    }
                }
            }
        }
        private void TestSingle(Type t)
        {
            ICommand raw   = (ICommand)Activator.CreateInstance(t);
            var      state = new AtemState();

            DoUpdate(state, new TopologyV8Command()
            {
                MediaPlayers     = 2,
                MixEffectBlocks  = 2,
                DownstreamKeyers = 2,
                Auxiliaries      = 2,
                SuperSource      = 2,
                HyperDecks       = 2,
                MixMinusOutputs  = 24,
            });
            DoUpdate(state, new SuperSourceConfigV8Command
            {
                SSrcId = 0,
                Boxes  = 4
            });
            DoUpdate(state, new MixEffectBlockConfigCommand
            {
                Index    = 0,
                KeyCount = 2,
            });
            DoUpdate(state, new MediaPoolConfigCommand
            {
                ClipCount  = 2,
                StillCount = 10
            });
            DoUpdate(state, new AudioMixerConfigCommand
            {
                Monitors = 1,
                Inputs   = 10
            });
            DoUpdate(state, new MultiviewerConfigV8Command
            {
                Count       = 1,
                WindowCount = 10
            });
            DoUpdate(state, new MacroPoolConfigCommand
            {
                MacroCount = 10
            });

            // TODO - this should be done to provide a strict test that everything gets applied to the state correctly
            DoUpdate(state, raw);
            AtemStateBuilder.Update(state, raw);
        }
        private void DoUpdate(AtemState state, ICommand cmd)
        {
            var res = AtemStateBuilder.Update(state, cmd);

            if (res.Errors.Count > 0)
            {
                _output.WriteLine("Failed: {0} {1}\n", cmd.GetType().FullName, string.Join('\n', res.Errors));
            }
            Assert.Equal(0, res.Errors.Count);

            if (!res.Success)
            {
                throw new Exception("State update was not successful");
            }
        }
Example #4
0
        /*
         * [Fact]
         * public void TestStateReal()
         * {
         *  var stateSettings = new AtemStateBuilderSettings();
         *  using var helper = new AtemSdkClientWrapper("10.42.13.95", stateSettings);
         *
         *  var libAtemState = GetLibAtemState(stateSettings, "10.42.13.95");
         *
         *  List<string> before = AtemStateComparer.AreEqual(helper.State, libAtemState);
         *  if (before.Count != 0 && _output != null)
         *  {
         *      _output.WriteLine("state mismatch:");
         *      before.ForEach(_output.WriteLine);
         *  }
         *  Assert.Empty(before);
         * }
         */

        private AtemState GetLibAtemState(AtemStateBuilderSettings stateSettings, string address)
        {
            using var client = new AtemClient(address, false);
            var state = new AtemState();

            AutoResetEvent handshakeEvent    = new AutoResetEvent(false);
            bool           handshakeFinished = false;

            client.OnReceive += (o, cmds) =>
            {
                cmds.ForEach(cmd => AtemStateBuilder.Update(state, cmd, stateSettings));

                if (!handshakeFinished && cmds.Any(c => c is InitializationCompleteCommand))
                {
                    handshakeEvent.Set();
                    handshakeFinished = true;
                }
            };
            client.Connect();
            Assert.True(handshakeEvent.WaitOne(5000));

            return(state);
        }
        public void TestStateUpdaterProperties()
        {
            Assert.True(AtemStateBuilder.IsDebug(), "State lib needs to be debug to have the check compiled");

            var failures = new List <string>();

            Assembly           assembly = typeof(ICommand).GetTypeInfo().Assembly;
            IEnumerable <Type> types    = assembly.GetTypes().Where(t => typeof(SerializableCommandBase).GetTypeInfo().IsAssignableFrom(t));

            foreach (Type type in types)
            {
                if (type == typeof(SerializableCommandBase))
                {
                    continue;
                }

                var attr = type.GetCustomAttribute <CommandNameAttribute>();
                if (attr == null || attr.Direction == CommandDirection.ToServer)
                {
                    continue;
                }

                try
                {
                    // output.WriteLine("Testing: {0}", type.Name);
                    TestSingle(type);
                }
                catch (Exception e)
                {
                    failures.Add($"{type.Name}: {e.Message} {e.StackTrace}");
                }
            }

            _output.WriteLine(string.Join("\n\n", failures));
            Assert.Empty(failures);
        }
Example #6
0
        public AtemClientExt(string deviceId, AtemClient client, IHubContext <DevicesHub> context, TransferJobMonitor transfers, HashSet <string> subscriptions)
        {
            _deviceId      = deviceId;
            _profile       = new DeviceProfileHandler();
            _subscriptions = subscriptions;
            _state         = new AtemState();
            _context       = context;
            _mediaCache    = new AtemMediaCache(transfers);

            Client               = client;
            Client.OnReceive    += _profile.HandleCommands;
            Client.OnConnection += sender =>
            {
                Connected = true;
                OnChange?.Invoke(this);
                SendState(GetState());
            };
            Client.OnDisconnect += sender =>
            {
                Connected = false;
                OnChange?.Invoke(this);
                SendState(null);
            };

            Client.OnReceive += (sender, commands) =>
            {
                var changedPaths = new HashSet <string>();
                var errors       = new List <string>();
                lock (_state)
                {
                    foreach (var command in commands)
                    {
                        var res = AtemStateBuilder.Update(_state, command);
                        changedPaths.AddRange(res.ChangedPaths);

                        if (!res.Success)
                        {
                            if (res.Errors.Count > 0)
                            {
                                errors.AddRange(res.Errors);
                            }
                            else
                            {
                                errors.Add($"Failed to update state for {command.GetType().Name}");
                            }
                        }
                    }
                }

                AtemState newState = GetState();

                /*
                 * var diffs = new Dictionary<string, object>();
                 * foreach (string path in changedPaths)
                 * {
                 *  diffs.Add(path, new object()); // TODO
                 * }*/

                SendStateDiff(GetState(), changedPaths);

                _mediaCache.EnsureMediaIsDownloaded(Client, newState);
            };


            Client.DataTransfer.OnJobStarted += (sender, job) => transfers.JobStarted(deviceId, job);
            Client.DataTransfer.OnJobQueued  += (sender, job) => transfers.JobQueued(deviceId, job);
        }
        public void TestCurrentTimelineTime()
        {
            AtemMockServerWrapper.Each(_output, _pool, null, DeviceTestCases.HyperDecks, helper =>
            {
                ImmutableList <ICommand> allCommands = helper.Server.GetParsedDataDump();
                List <HyperDeckSettingsGetCommand> settingsCommands = allCommands.OfType <HyperDeckSettingsGetCommand>().ToList();
                List <HyperDeckPlayerGetCommand> playerCommands     = allCommands.OfType <HyperDeckPlayerGetCommand>().ToList();

                foreach (IBMDSwitcherHyperDeck deck in GetHyperDecks(helper))
                {
                    deck.GetId(out long id);

                    HyperDeckSettingsGetCommand cmd   = settingsCommands.Single(c => c.Id == id);
                    HyperDeckPlayerGetCommand playCmd = playerCommands.Single(c => c.Id == id);

                    // Force it to be connected
                    AtemState stateBefore = helper.Helper.BuildLibState();
                    cmd.Status            = HyperDeckConnectionStatus.Connected;
                    stateBefore.Hyperdecks[(int)id].Settings.Status = HyperDeckConnectionStatus.Connected;
                    stateBefore.Hyperdecks[(int)id].Player.State    = HyperDeckPlayerState.Idle;
                    helper.SendFromServerAndWaitForChange(stateBefore, cmd);

                    // Define a clip
                    stateBefore.Hyperdecks[(int)id].Clips =
                        UpdaterUtil.CreateList(1, i => new HyperdeckState.ClipState());
                    helper.SendFromServerAndWaitForChange(stateBefore, new HyperDeckClipCountCommand
                    {
                        Id        = (uint)id,
                        ClipCount = 1,
                    });
                    var clipCmd = new HyperDeckClipInfoCommand
                    {
                        HyperdeckId = (uint)id,
                        ClipId      = 0,
                        Name        = "something 123",
                        Duration    = new HyperDeckTime {
                            Hour = 24
                        },
                        TimelineStart = new HyperDeckTime(),
                        TimelineEnd   = new HyperDeckTime {
                            Hour = 24
                        },
                    };
                    AtemStateBuilder.Update(stateBefore, clipCmd);
                    helper.SendFromServerAndWaitForChange(stateBefore, clipCmd);
                    stateBefore = helper.Helper.BuildLibState();

                    // Set the clip to be playing
                    HyperDeckStorageGetCommand srcCmd = new HyperDeckStorageGetCommand
                    {
                        Id = (uint)id,
                        ActiveStorageMedia  = 0,
                        CurrentClipId       = 0,
                        FrameRate           = 50000,
                        TimeScale           = 1000,
                        RemainingRecordTime = new HyperDeckTime(),
                    };
                    AtemStateBuilder.Update(stateBefore, srcCmd);
                    helper.SendFromServerAndWaitForChange(stateBefore, srcCmd);
                    stateBefore = helper.Helper.BuildLibState();

                    HyperdeckState deckState = stateBefore.Hyperdecks[(int)id];

                    // Now try the stuff
                    for (int i = 0; i < 5; i++)
                    {
                        uint hours   = (uint)Randomiser.RangeInt(1, 20);
                        uint minutes = (uint)Randomiser.RangeInt(1, 59);
                        uint seconds = (uint)Randomiser.RangeInt(1, 59);
                        uint frames  = (uint)Randomiser.RangeInt(1, 20);
                        deckState.Player.ClipTime = new HyperDeckTime();
                        playCmd.TimelineTime      = deckState.Player.TimelineTime = new HyperDeckTime
                        {
                            Hour = hours, Minute = minutes, Second = seconds, Frame = frames
                        };

                        helper.SendFromServerAndWaitForChange(stateBefore, playCmd);
                    }
                }
            });
        }