internal void ProcessMain(ClientStreamer mainStreamer, IDeviceIndicators kpi, StreamerRebuildContext lastRebuildContext)
        {
            if (mainStreamer == null)
            {
                kpi.CloudOut.State = IndicatorState.Disabled;
                kpi.Encoder.State  = IndicatorState.Disabled;
                _cloudOutAverage   = null;
            }
            else
            {
                if (_cloudOutAverage == null)
                {
                    _cloudOutAverage = new AverageIntValue(3, true);
                }

                var stat     = mainStreamer.ResourceManager.GetStatistics(out var period);
                var overload = mainStreamer.ResourceManager.GetOverload();

                int failedInputs = 0;

                if (_coreData.Root.Settings.SelectedScene != null &&
                    _coreData.Root.Scenes.TryGetValue(_coreData.Root.Settings.SelectedScene, out var scene) &&
                    scene.Owner == _coreData.ThisDeviceId)
                {
                    ProcessInputs(stat, lastRebuildContext.Videos, "V", _prevVideos, scene.VideoIssues, s => scene.VideoIssues = s);
                    ProcessInputs(stat, lastRebuildContext.Audios, "A", _prevAudios, scene.AudioIssues, s => scene.AudioIssues = s);

                    if (scene.VideoIssues != null)
                    {
                        foreach (var vi in scene.VideoIssues)
                        {
                            if (scene.Items.TryGetValue(vi.Id, out var item) && item.Visible)
                            {
                                failedInputs++;
                            }
                        }
                    }
                    if (scene.AudioIssues != null)
                    {
                        foreach (var vi in scene.AudioIssues)
                        {
                            if (scene.Audios.TryGetValue(vi.Id, out var item) && !item.Muted)
                            {
                                failedInputs++;
                            }
                        }
                    }
                }

                ProcessMainKpi(stat, kpi, period, overload, failedInputs);
            }
        }
        internal void ProcessReceivier(ClientStreamer receiverStreamer, IDeviceIndicators kpi)
        {
            if (receiverStreamer == null)
            {
                kpi.CloudIn.State = IndicatorState.Disabled;
                _cloudInAverage   = null;
            }
            else
            {
                if (_cloudInAverage == null)
                {
                    _cloudInAverage = new AverageIntValue(3, true);
                }

                var stat  = receiverStreamer.ResourceManager.GetStatistics(out var period);
                var input = stat.FirstOrDefault(s => s.Name.Name == "I" && s.Name.Trunk == "0" && s.Name.TrunkPrefix == "V");

                if (input == null)
                {
                    kpi.CloudIn.State = IndicatorState.Disabled; // no outgest data yet
                }
                else
                {
                    var data    = (StatisticDataOfInputOutput)input.Data;
                    var bitrate = (int)(data.Bytes * 8 / period.TotalMilliseconds);
                    var ave     = _cloudInAverage.AddValue(bitrate);

                    IndicatorState state = IndicatorState.Ok;
                    if (data.Errors > 0 || bitrate == 0)
                    {
                        state = IndicatorState.Error;
                    }
                    else
                    {
                        var bitratePercent = (ave * 100) / _coreData.Settings.Bitrate;

                        if (bitratePercent < 60)
                        {
                            state = IndicatorState.Warning;
                        }
                    }

                    kpi.CloudIn.Bitrate = ave;
                    kpi.CloudIn.State   = state;
                }
            }
        }
        private void ProcessMainKpi(List <StatisticItem> stat, IDeviceIndicators kpi, TimeSpan period, int overload, int failedInputs)
        {
            //out to cloud
            var item = stat.FirstOrDefault(s => s.Name.Trunk == MainStreamerModel.OutputNameStreamToCloud && s.Name.TrunkPrefix == "X");

            if (item == null)
            {
                kpi.CloudOut.State = IndicatorState.Disabled;
            }
            else
            {
                var data    = (StatisticDataOfInputOutput)item.Data;
                var bitrate = (int)(data.Bytes * 8 / period.TotalMilliseconds);
                var ave     = _cloudOutAverage.AddValue(bitrate);

                IndicatorState state = IndicatorState.Ok;
                if (data.Errors > 0)
                {
                    if (bitrate > 0)
                    {
                        state = IndicatorState.Error;
                    }
                    else
                    {
                        state = IndicatorState.Error2;
                    }
                }
                else
                {
                    var bitratePercent = (ave * 100) / _coreData.Settings.Bitrate;

                    if (bitratePercent < 60)
                    {
                        state = IndicatorState.Warning2;
                    }
                    else if (bitratePercent < 80)
                    {
                        state = IndicatorState.Warning;
                    }
                }

                kpi.CloudOut.Bitrate = ave;
                kpi.CloudOut.State   = state;
            }

            // encoder & inputs
            var encoder = kpi.Encoder;

            var encoderStat = stat.FirstOrDefault(s => s.Name.Name == "E" && s.Name.TrunkPrefix == "VE");

            if (encoderStat == null)
            {
                Log.Warning("Encoder statistics not found");
            }

            if (encoderStat != null)
            {
                var encData       = (StatisticDataOfProcessingNode)encoderStat.Data;
                var fps           = (int)(encData.OutFrames / period.TotalSeconds);
                var configuredFps = _coreData.Settings.Fps;

                var fpsPercent = (fps * 100) / configuredFps;

                var state = IndicatorState.Ok;
                if (failedInputs > 0)
                {
                    state = IndicatorState.Error2;
                }
                else if (overload > 6)
                {
                    state = IndicatorState.Error;
                }
                else if (fpsPercent < 87)
                {
                    state = IndicatorState.Warning;
                }

                encoder.State = state;
                encoder.Data  = new EncoderData
                {
                    Q = overload,
                    O = fps,
                    F = failedInputs
                };
            }
            else
            {
                encoder.State = IndicatorState.Disabled;
            }
        }