TASK 4 ship step 6: health stats land in the bottom bar — FramePump.HealthUpdated is now wired to the VM (OnFramePumpHealthUpdated marshals onto the UI thread — the encoder's stderr loop raises on a background thread — and copies the parsed bitrate/FPS/dropped/duration into CurrentHealth, the bottom bar's existing binding); ResetHealth zeroes dropped frames + elapsed duration on go-live and on End so stats never linger from a previous session (bitrate/FPS stay on the tier's targets); the bar shows real encoder values once TASK 5 fills _rtmpUrlProvider (until then the pump skips the encoder) — 169 tests passing, 0 warnings
This commit is contained in:
@@ -1078,6 +1078,7 @@ public class MainViewModel : ViewModelBase
|
||||
log: message => AppLog.Write(message),
|
||||
socialBar: () => (_socialBarFrame, _socials?.BarPosition ?? SocialBarPosition.Bottom));
|
||||
_framePump.Failed += OnFramePumpFailed;
|
||||
_framePump.HealthUpdated += OnFramePumpHealthUpdated;
|
||||
|
||||
LoadLayout();
|
||||
_ = LoadSavedSessionAsync();
|
||||
@@ -1965,6 +1966,7 @@ public class MainViewModel : ViewModelBase
|
||||
? "ytLlive"
|
||||
: $"{dialog.StreamTitle} — ytLlive";
|
||||
StreamStatus = StreamStatus.Streaming;
|
||||
ResetHealth(StreamStatus.Streaming);
|
||||
_ = _framePump.StartAsync(); // never throws; failures log + surface via Failed
|
||||
}
|
||||
}
|
||||
@@ -1973,6 +1975,7 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
StreamStatus = StreamStatus.Offline;
|
||||
WindowTitle = "ytLlive";
|
||||
ResetHealth(StreamStatus.Offline);
|
||||
// Audio capture is always-on (preview monitoring); only the frame pump
|
||||
// and the session stop here.
|
||||
_ = _framePump.StopAsync();
|
||||
@@ -2114,6 +2117,42 @@ public class MainViewModel : ViewModelBase
|
||||
if (IsLive) StreamStatus = StreamStatus.Error;
|
||||
}
|
||||
|
||||
// TASK 4 ship step 6: the encoder's parsed health (bitrate/FPS/dropped/
|
||||
// duration) lands in the bottom bar. The stderr loop raises on a background
|
||||
// thread — marshal to the UI thread like the audio level handlers.
|
||||
private void OnFramePumpHealthUpdated(object? sender, StreamHealth health)
|
||||
{
|
||||
var dispatcher = System.Windows.Application.Current?.Dispatcher;
|
||||
if (dispatcher != null && !dispatcher.CheckAccess())
|
||||
dispatcher.BeginInvoke(() => ApplyHealth(health));
|
||||
else
|
||||
ApplyHealth(health);
|
||||
}
|
||||
|
||||
private void ApplyHealth(StreamHealth health)
|
||||
{
|
||||
CurrentHealth.Status = health.Status;
|
||||
CurrentHealth.CurrentBitrate = health.CurrentBitrate;
|
||||
CurrentHealth.FPS = health.FPS;
|
||||
CurrentHealth.DroppedFrames = health.DroppedFrames;
|
||||
CurrentHealth.StreamDuration = health.StreamDuration;
|
||||
CurrentHealth.LastError = health.LastError;
|
||||
CurrentHealth.HealthMessage = health.HealthMessage;
|
||||
OnPropertyChanged(nameof(CurrentHealth));
|
||||
}
|
||||
|
||||
// Keeps the bottom-bar stats honest across sessions: dropped frames and the
|
||||
// elapsed duration must not linger from a previous go-live (bitrate/FPS stay
|
||||
// on the tier's targets — ApplyStreamQuality sets them on pick).
|
||||
private void ResetHealth(StreamStatus status)
|
||||
{
|
||||
CurrentHealth.Status = status;
|
||||
CurrentHealth.DroppedFrames = 0;
|
||||
CurrentHealth.StreamDuration = TimeSpan.Zero;
|
||||
CurrentHealth.LastError = null;
|
||||
OnPropertyChanged(nameof(CurrentHealth));
|
||||
}
|
||||
|
||||
private void UpdateLiveVisuals()
|
||||
{
|
||||
var live = IsLive;
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user