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"); } }
/* * [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 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); } } }); }