From 743e1680c13f34287a46219db5a2bd93eee620ea Mon Sep 17 00:00:00 2001 From: Dmitry Sergeev Date: Thu, 27 Aug 2026 23:33:04 +0300 Subject: [PATCH] display video worker status --- cmd/mxl-player/main.go | 33 +++++++++++++++++++++++++--- imgui.ini | 4 ++-- internal/playback/state.go | 37 ++++++++++++++++++++++++++++++- internal/playback/state_test.go | 39 +++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/cmd/mxl-player/main.go b/cmd/mxl-player/main.go index ca405ed..b17e103 100644 --- a/cmd/mxl-player/main.go +++ b/cmd/mxl-player/main.go @@ -397,6 +397,7 @@ func main() { // Reconnect requests from GUI or automatic retry control := make(chan reconnectParams, 1) videoBridge := playback.NewVideoBridge() + statusStore := playback.NewStatusStore() videoWorker, err := playback.NewVideoWorker( mxladapter.VideoFactory{}, @@ -404,6 +405,7 @@ func main() { retryPolicy, mxladapter.ShouldRetry, func(status playback.Status) { + statusStore.Observe(status) if status.Err != nil { log.Printf( "video: state=%v attempt=%d failed=%d: %v", @@ -891,11 +893,36 @@ func main() { } if useVideoSlot { if videoActive { - cimgui.Text("Video state: active") + cimgui.Text("Video desired: active") } else if videoStr != "" { - cimgui.Text("Video state: stopped") + cimgui.Text("Video desired: stopped") } else { - cimgui.Text("Video state: not configured") + cimgui.Text("Video desired: not configured") + } + + if status, ok := statusStore.Snapshot(playback.UnitVideo); ok { + cimgui.Text(fmt.Sprintf( + "Video actual: %s", + status.State, + )) + cimgui.Text(fmt.Sprintf( + "Attempt: %d, failed: %d", + status.Attempt, + status.FailedAttempts, + )) + + if status.RetryIn > 0 { + cimgui.Text(fmt.Sprintf( + "Retry in: %s", + status.RetryIn.Round(time.Millisecond), + )) + } + + if status.Err != nil { + cimgui.TextWrapped(status.Err.Error()) + } + } else { + cimgui.Text("Video actual: not started") } } cimgui.End() diff --git a/imgui.ini b/imgui.ini index 1219662..6eddbff 100644 --- a/imgui.ini +++ b/imgui.ini @@ -14,7 +14,7 @@ Size=200,200 Collapsed=0 [Window][Connection] -Pos=285,503 -Size=681,205 +Pos=202,343 +Size=799,226 Collapsed=0 diff --git a/internal/playback/state.go b/internal/playback/state.go index 4fea8aa..1d07333 100644 --- a/internal/playback/state.go +++ b/internal/playback/state.go @@ -1,6 +1,9 @@ package playback -import "time" +import ( + "fmt" + "time" +) type Unit uint8 @@ -31,3 +34,35 @@ type Status struct { } type StatusObserver func(Status) + +func (u Unit) String() string { + switch u { + case UnitVideo: + return "video" + case UnitAudio: + return "audio" + case UnitSync: + return "sync" + default: + return fmt.Sprintf("Unit(%d)", uint8(u)) + } +} + +func (s State) String() string { + switch s { + case StateIdle: + return "idle" + case StateConnecting: + return "connecting" + case StatePlaying: + return "playing" + case StateReconnecting: + return "reconnecting" + case StateFailed: + return "failed" + case StateStopping: + return "stopping" + default: + return fmt.Sprintf("State(%d)", uint8(s)) + } +} diff --git a/internal/playback/state_test.go b/internal/playback/state_test.go index 7b3f43c..98892fa 100644 --- a/internal/playback/state_test.go +++ b/internal/playback/state_test.go @@ -38,3 +38,42 @@ func TestStatusPreservesValues(t *testing.T) { t.Errorf("RetryIn = %s, want %s", status.RetryIn, time.Second) } } + +func TestUnitString(t *testing.T) { + tests := []struct { + unit Unit + want string + }{ + {unit: UnitVideo, want: "video"}, + {unit: UnitAudio, want: "audio"}, + {unit: UnitSync, want: "sync"}, + {unit: Unit(255), want: "Unit(255)"}, + } + + for _, tt := range tests { + if got := tt.unit.String(); got != tt.want { + t.Errorf("Unit(%d).String() = %q, want %q", tt.unit, got, tt.want) + } + } +} + +func TestStateString(t *testing.T) { + tests := []struct { + state State + want string + }{ + {state: StateIdle, want: "idle"}, + {state: StateConnecting, want: "connecting"}, + {state: StatePlaying, want: "playing"}, + {state: StateReconnecting, want: "reconnecting"}, + {state: StateFailed, want: "failed"}, + {state: StateStopping, want: "stopping"}, + {state: State(255), want: "State(255)"}, + } + + for _, tt := range tests { + if got := tt.state.String(); got != tt.want { + t.Errorf("State(%d).String() = %q, want %q", tt.state, got, tt.want) + } + } +}