Refactoring #3
+102
-40
@@ -368,6 +368,28 @@ func main() {
|
||||
},
|
||||
})
|
||||
}
|
||||
drawUnitStatus := func(label string, unit playback.Unit) {
|
||||
status, ok := statusStore.Snapshot(unit)
|
||||
if !ok {
|
||||
cimgui.Text(fmt.Sprintf("%s: not started", label))
|
||||
return
|
||||
}
|
||||
cimgui.Text(fmt.Sprintf("%s: %s", label, 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())
|
||||
}
|
||||
}
|
||||
|
||||
playbackDone := make(chan error, 1)
|
||||
go func() {
|
||||
@@ -524,20 +546,48 @@ func main() {
|
||||
cimgui.End()
|
||||
}
|
||||
cimgui.Begin("Connection")
|
||||
cimgui.InputTextWithHint("Video domain", "/dev/shm/mxl", &videoDomainStr, 0, nil)
|
||||
cimgui.InputTextWithHint("Audio domain", "/dev/shm/mxl", &audioDomainStr, 0, nil)
|
||||
cimgui.InputTextWithHint("Video UUID", "", &videoStr, 0, nil)
|
||||
cimgui.InputTextWithHint("Audio UUID", "", &audioStr, 0, nil)
|
||||
if snapshot, ok := player.Controller.Snapshot(); ok {
|
||||
|
||||
snapshot, hasSnapshot := player.Controller.Snapshot()
|
||||
videoConfigured := videoStr != ""
|
||||
audioConfigured := audioStr != ""
|
||||
if hasSnapshot {
|
||||
videoActive = snapshot.Desired.Video.Active
|
||||
audioActive = snapshot.Desired.Audio.Active
|
||||
videoConfigured = snapshot.Desired.Video.IsConfigured()
|
||||
audioConfigured = snapshot.Desired.Audio.IsConfigured()
|
||||
syncRequested = snapshot.Desired.SyncRequested
|
||||
cimgui.Text(fmt.Sprintf(
|
||||
"Topology: %s (generation %d)",
|
||||
snapshot.Plan.Topology,
|
||||
snapshot.Generation,
|
||||
))
|
||||
} else {
|
||||
cimgui.Text("Topology: starting")
|
||||
}
|
||||
if cimgui.Button("Connect") {
|
||||
|
||||
cimgui.Separator()
|
||||
cimgui.InputTextWithHint("Video domain", "/dev/shm/mxl", &videoDomainStr, 0, nil)
|
||||
cimgui.InputTextWithHint("Video UUID", "", &videoStr, 0, nil)
|
||||
cimgui.InputTextWithHint("Audio domain", "/dev/shm/mxl", &audioDomainStr, 0, nil)
|
||||
cimgui.InputTextWithHint("Audio UUID", "", &audioStr, 0, nil)
|
||||
if cimgui.Button("Apply feeds") {
|
||||
doReconnect()
|
||||
}
|
||||
cimgui.SameLine()
|
||||
cimgui.Checkbox("Show stats", &showStats)
|
||||
if videoActive || audioActive {
|
||||
if cimgui.Button("Stop all") {
|
||||
enqueueCommand(playback.SessionCommand{Kind: playback.CommandStopAll})
|
||||
}
|
||||
}
|
||||
if (videoConfigured && !videoActive) || (audioConfigured && !audioActive) {
|
||||
if videoActive || audioActive {
|
||||
cimgui.SameLine()
|
||||
}
|
||||
if cimgui.Button("Resume all") {
|
||||
enqueueCommand(playback.SessionCommand{Kind: playback.CommandResumeAll})
|
||||
}
|
||||
}
|
||||
|
||||
if cimgui.Checkbox("Synchronize", &syncRequested) {
|
||||
kind := playback.CommandDisableSync
|
||||
if syncRequested {
|
||||
@@ -545,20 +595,36 @@ func main() {
|
||||
}
|
||||
enqueueCommand(playback.SessionCommand{Kind: kind})
|
||||
}
|
||||
if hasSnapshot && syncRequested && snapshot.Plan.Topology != playback.TopologySynchronized {
|
||||
switch {
|
||||
case !videoConfigured || !audioConfigured:
|
||||
cimgui.TextWrapped("Sync requested: waiting for both feeds to be configured.")
|
||||
case !videoActive || !audioActive:
|
||||
cimgui.TextWrapped("Sync requested: waiting for both feeds to be active.")
|
||||
case snapshot.Desired.Video.Domain != snapshot.Desired.Audio.Domain:
|
||||
cimgui.TextWrapped("Sync requested, but native MXL sync requires matching domains. Playing independently.")
|
||||
default:
|
||||
cimgui.TextWrapped("Sync requested but currently unavailable. Playing independently.")
|
||||
}
|
||||
}
|
||||
|
||||
cimgui.Separator()
|
||||
cimgui.Text("Video")
|
||||
if videoActive {
|
||||
if cimgui.Button("Stop video") {
|
||||
videoActive = false
|
||||
enqueueCommand(playback.SessionCommand{Kind: playback.CommandStopVideo})
|
||||
}
|
||||
}
|
||||
if !videoActive && videoStr != "" {
|
||||
if !videoActive && videoConfigured {
|
||||
cimgui.SameLine()
|
||||
if cimgui.Button("Resume video") {
|
||||
videoActive = true
|
||||
enqueueCommand(playback.SessionCommand{Kind: playback.CommandResumeVideo})
|
||||
}
|
||||
}
|
||||
if videoStr != "" {
|
||||
if videoConfigured {
|
||||
cimgui.SameLine()
|
||||
if cimgui.Button("Remove video") {
|
||||
videoActive = false
|
||||
videoStr = ""
|
||||
@@ -567,24 +633,14 @@ func main() {
|
||||
}
|
||||
if videoActive {
|
||||
cimgui.Text("Video desired: active")
|
||||
} else if videoStr != "" {
|
||||
} else if videoConfigured {
|
||||
cimgui.Text("Video desired: stopped")
|
||||
} else {
|
||||
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.Separator()
|
||||
cimgui.Text("Audio")
|
||||
if audioActive {
|
||||
if cimgui.Button("Stop audio") {
|
||||
audioActive = false
|
||||
@@ -592,14 +648,16 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
if !audioActive && audioStr != "" {
|
||||
if !audioActive && audioConfigured {
|
||||
cimgui.SameLine()
|
||||
if cimgui.Button("Resume audio") {
|
||||
audioActive = true
|
||||
enqueueCommand(playback.SessionCommand{Kind: playback.CommandResumeAudio})
|
||||
}
|
||||
}
|
||||
|
||||
if audioStr != "" {
|
||||
if audioConfigured {
|
||||
cimgui.SameLine()
|
||||
if cimgui.Button("Remove audio") {
|
||||
audioActive = false
|
||||
audioStr = ""
|
||||
@@ -609,31 +667,35 @@ func main() {
|
||||
|
||||
if audioActive {
|
||||
cimgui.Text("Audio desired: active")
|
||||
} else if audioStr != "" {
|
||||
} else if audioConfigured {
|
||||
cimgui.Text("Audio desired: stopped")
|
||||
} else {
|
||||
cimgui.Text("Audio desired: not configured")
|
||||
}
|
||||
|
||||
if status, ok := statusStore.Snapshot(playback.UnitAudio); ok {
|
||||
cimgui.Text(fmt.Sprintf("Audio 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())
|
||||
cimgui.Separator()
|
||||
cimgui.Text("Current playback")
|
||||
if hasSnapshot {
|
||||
switch snapshot.Plan.Topology {
|
||||
case playback.TopologySynchronized:
|
||||
drawUnitStatus("Synchronized group", playback.UnitSync)
|
||||
case playback.TopologyIndependent:
|
||||
if snapshot.Plan.Video.Active {
|
||||
drawUnitStatus("Video", playback.UnitVideo)
|
||||
}
|
||||
if snapshot.Plan.Audio.Active {
|
||||
drawUnitStatus("Audio", playback.UnitAudio)
|
||||
}
|
||||
case playback.TopologyIdle:
|
||||
cimgui.Text("No active feeds")
|
||||
}
|
||||
} else {
|
||||
cimgui.Text("Audio actual: not started")
|
||||
}
|
||||
if status, ok := statusStore.Snapshot(playback.UnitSync); ok {
|
||||
cimgui.Text(fmt.Sprintf("Sync actual: %s", status.State))
|
||||
if status.Err != nil {
|
||||
cimgui.TextWrapped(status.Err.Error())
|
||||
}
|
||||
cimgui.Text("Playback controller is starting")
|
||||
}
|
||||
|
||||
cimgui.Separator()
|
||||
cimgui.Checkbox("Show stats", &showStats)
|
||||
|
||||
cimgui.End()
|
||||
gui.EndFrame()
|
||||
lastFrame = time.Now()
|
||||
|
||||
@@ -10,6 +10,19 @@ const (
|
||||
TopologySynchronized
|
||||
)
|
||||
|
||||
func (t SessionTopology) String() string {
|
||||
switch t {
|
||||
case TopologyIdle:
|
||||
return "idle"
|
||||
case TopologyIndependent:
|
||||
return "independent"
|
||||
case TopologySynchronized:
|
||||
return "synchronized"
|
||||
default:
|
||||
return fmt.Sprintf("SessionTopology(%d)", uint8(t))
|
||||
}
|
||||
}
|
||||
|
||||
type SyncPredicate func(video, audio FeedConfig) bool
|
||||
|
||||
type SessionPlan struct {
|
||||
|
||||
@@ -5,6 +5,23 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSessionTopologyString(t *testing.T) {
|
||||
tests := []struct {
|
||||
topology SessionTopology
|
||||
want string
|
||||
}{
|
||||
{TopologyIdle, "idle"},
|
||||
{TopologyIndependent, "independent"},
|
||||
{TopologySynchronized, "synchronized"},
|
||||
{SessionTopology(99), "SessionTopology(99)"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := tt.topology.String(); got != tt.want {
|
||||
t.Errorf("%d.String() = %q, want %q", tt.topology, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSessionPlan(t *testing.T) {
|
||||
base := validCommandSession()
|
||||
stoppedVideo := stoppedFeed(base.Video)
|
||||
|
||||
Reference in New Issue
Block a user