diff --git a/cmd/mxl-player/config.go b/cmd/mxl-player/config.go new file mode 100644 index 0000000..56592eb --- /dev/null +++ b/cmd/mxl-player/config.go @@ -0,0 +1,39 @@ +package main + +import ( + "mxl-player/internal/playback" + "time" +) + +const ( + defaultInitialRetryDelay = 500 * time.Millisecond + defaultMaxRetryDelay = 10 * time.Second +) + +func resolveDomain(shared, override string) string { + if override != "" { + return override + } + return shared +} + +func (a appArgs) playbackConfig() playback.SessionConfig { + return playback.SessionConfig{ + Video: playback.FeedConfig{ + Domain: resolveDomain(a.Domain, a.VideoDomain), + UUID: a.VideoFlowId, + Active: a.VideoFlowId != "", + }, + Audio: playback.FeedConfig{ + Domain: resolveDomain(a.Domain, a.AudioDomain), + UUID: a.AudioFlowId, + Active: a.AudioFlowId != "", + }, + SyncRequested: a.SyncRequested, + Retry: playback.RetryPolicy{ + MaxAttempts: a.MaxAttempts, + InitialDelay: defaultInitialRetryDelay, + MaxDelay: defaultMaxRetryDelay, + }, + } +} diff --git a/cmd/mxl-player/config_test.go b/cmd/mxl-player/config_test.go new file mode 100644 index 0000000..06b0f8c --- /dev/null +++ b/cmd/mxl-player/config_test.go @@ -0,0 +1,141 @@ +package main + +import "testing" + +func TestAppArgsPlaybackConfig(t *testing.T) { + tests := []struct { + name string + args appArgs + wantVideoDomain string + wantAudioDomain string + wantVideoActive bool + wantAudioActive bool + wantSyncRequested bool + wantMaxAttempts int + }{ + { + name: "shared domain applies to both feeds", + args: appArgs{ + Domain: "/dev/shm/mxl", + VideoFlowId: "video-uuid", + AudioFlowId: "audio-uuid", + }, + wantVideoDomain: "/dev/shm/mxl", + wantAudioDomain: "/dev/shm/mxl", + wantVideoActive: true, + wantAudioActive: true, + }, + { + name: "video domain overrides shared domain", + args: appArgs{ + Domain: "/dev/shm/default", + VideoDomain: "/dev/shm/video", + VideoFlowId: "video-uuid", + AudioFlowId: "audio-uuid", + }, + wantVideoDomain: "/dev/shm/video", + wantAudioDomain: "/dev/shm/default", + wantVideoActive: true, + wantAudioActive: true, + }, + { + name: "audio domain overrides shared domain", + args: appArgs{ + Domain: "/dev/shm/default", + AudioDomain: "/dev/shm/audio", + VideoFlowId: "video-uuid", + AudioFlowId: "audio-uuid", + }, + wantVideoDomain: "/dev/shm/default", + wantAudioDomain: "/dev/shm/audio", + wantVideoActive: true, + wantAudioActive: true, + }, + { + name: "audio and video use different domain overrides", + args: appArgs{ + Domain: "/dev/shm/default", + VideoDomain: "/dev/shm/video", + AudioDomain: "/dev/shm/audio", + VideoFlowId: "video-uuid", + AudioFlowId: "audio-uuid", + SyncRequested: true, + MaxAttempts: 5, + }, + wantVideoDomain: "/dev/shm/video", + wantAudioDomain: "/dev/shm/audio", + wantVideoActive: true, + wantAudioActive: true, + wantSyncRequested: true, + wantMaxAttempts: 5, + }, + { + name: "no UUIDs produce inactive slots", + args: appArgs{ + Domain: "/dev/shm/mxl", + }, + wantVideoDomain: "/dev/shm/mxl", + wantAudioDomain: "/dev/shm/mxl", + }, + { + name: "video UUID activates only video", + args: appArgs{ + Domain: "/dev/shm/mxl", + VideoFlowId: "video-uuid", + }, + wantVideoDomain: "/dev/shm/mxl", + wantAudioDomain: "/dev/shm/mxl", + wantVideoActive: true, + }, + { + name: "audio UUID activates only audio", + args: appArgs{ + Domain: "/dev/shm/mxl", + AudioFlowId: "audio-uuid", + }, + wantVideoDomain: "/dev/shm/mxl", + wantAudioDomain: "/dev/shm/mxl", + wantAudioActive: true, + }, + { + name: "unlimited attempts and disabled sync are preserved", + args: appArgs{ + Domain: "/dev/shm/mxl", + VideoFlowId: "video-uuid", + SyncRequested: false, + MaxAttempts: 0, + }, + wantVideoDomain: "/dev/shm/mxl", + wantAudioDomain: "/dev/shm/mxl", + wantVideoActive: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.args.playbackConfig() + + if got.Video.Domain != tt.wantVideoDomain { + t.Errorf("video domain = %q, want %q", got.Video.Domain, tt.wantVideoDomain) + } + if got.Audio.Domain != tt.wantAudioDomain { + t.Errorf("audio domain = %q, want %q", got.Audio.Domain, tt.wantAudioDomain) + } + if got.Video.Active != tt.wantVideoActive { + t.Errorf("video active = %t, want %t", got.Video.Active, tt.wantVideoActive) + } + if got.Audio.Active != tt.wantAudioActive { + t.Errorf("audio active = %t, want %t", got.Audio.Active, tt.wantAudioActive) + } + if got.SyncRequested != tt.wantSyncRequested { + t.Errorf("sync requested = %t, want %t", got.SyncRequested, tt.wantSyncRequested) + } + if got.Retry.MaxAttempts != tt.wantMaxAttempts { + t.Errorf("max attempts = %d, want %d", got.Retry.MaxAttempts, tt.wantMaxAttempts) + } + if err := got.Validate(); err != nil { + t.Fatalf("playbackConfig().Validate() returned error: %v", err) + } + }) + } +} diff --git a/cmd/mxl-player/main.go b/cmd/mxl-player/main.go index 013bd7d..6e5af7a 100644 --- a/cmd/mxl-player/main.go +++ b/cmd/mxl-player/main.go @@ -28,16 +28,20 @@ const ( ) type appArgs struct { - ShowHelp bool - Domain string - VideoFlowId string - AudioFlowId string - IsFullscreen bool - PlaybackId uint32 - GpuId uint32 - IsVerbose bool - ListAudio bool - ListGPU bool + ShowHelp bool + Domain string + VideoDomain string + AudioDomain string + VideoFlowId string + AudioFlowId string + IsFullscreen bool + PlaybackId uint32 + GpuId uint32 + IsVerbose bool + ListAudio bool + ListGPU bool + SyncRequested bool + MaxAttempts int } func printCliHelp(fs *pflag.FlagSet) { diff --git a/mxl-player b/mxl-player deleted file mode 100755 index 54440f8..0000000 Binary files a/mxl-player and /dev/null differ