diff --git a/cmd/mxl-player/main.go b/cmd/mxl-player/main.go index 27b8c01..08b82ac 100644 --- a/cmd/mxl-player/main.go +++ b/cmd/mxl-player/main.go @@ -15,6 +15,7 @@ import ( "mxl-player/internal/source" "os" "runtime" + "sync" "time" "unsafe" @@ -109,6 +110,12 @@ func main() { flagSet.StringVarP(&args.Domain, "domain", "d", "", "MXL domain directory") flagSet.StringVarP(&args.VideoFlowId, "video", "v", "", "Video flow UUID") flagSet.StringVarP(&args.AudioFlowId, "audio", "a", "", "Audio flow UUID") + flagSet.BoolVarP( + &args.SyncRequested, + "sync", "s", + false, + "Start configured audio and video as a synchronized group", + ) flagSet.IntVar( &args.MaxAttempts, "max-attempts", @@ -149,8 +156,10 @@ func main() { checkMXLargs(args) } // path selection - useVideoSlot := args.AudioFlowId == "" - useAudioSlot := args.AudioFlowId != "" && args.VideoFlowId == "" + useLegacySync := args.SyncRequested && + args.VideoFlowId != "" && + args.AudioFlowId != "" + useIndependentSlots := !useLegacySync runtime.LockOSThread() if err := sdl.Load(); err != nil { @@ -281,8 +290,12 @@ func main() { } switch { - case args.VideoFlowId != "" && args.AudioFlowId != "": - syncSrc, err = source.OpenSameDomainSync(args.Domain, args.VideoFlowId, args.AudioFlowId) + case useLegacySync: + syncSrc, err = source.OpenSameDomainSync( + args.Domain, + args.VideoFlowId, + args.AudioFlowId, + ) if err != nil { log.Fatalf("sync source: %v", err) } @@ -302,12 +315,9 @@ func main() { sdl.ResumeAudioStreamDevice(audioStream) fmt.Printf("sync: video %dx%d audio %dch batch=%d\n", syncSrc.Width(), syncSrc.Height(), aChans, audioBatch) - case args.VideoFlowId != "": - // VideoSlot owns opening and closing the video reader. - case args.AudioFlowId != "": - // AudioSlot owns opening and closing the audio reader. default: - // No configured feeds. Renderer and GUI use the placeholder. + // Independent slots own their readers. + // Empty startup opens nothing. } defer func() { @@ -374,7 +384,7 @@ func main() { showStats bool = true ) videoActive := args.VideoFlowId != "" - audioActive := useAudioSlot + audioActive := args.AudioFlowId != "" ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -535,34 +545,30 @@ func main() { } doReconnect := func() { - if useVideoSlot { + if useIndependentSlots { videoActive = videoStr != "" + audioActive = audioStr != "" - config := playback.FeedConfig{} + videoConfig := playback.FeedConfig{} if videoStr != "" { - config = playback.FeedConfig{ + videoConfig = playback.FeedConfig{ Domain: domainStr, UUID: videoStr, Active: true, } } - enqueueVideoConfig(config) - return - } - if useAudioSlot { - audioActive = audioStr != "" - - config := playback.FeedConfig{} + audioConfig := playback.FeedConfig{} if audioStr != "" { - config = playback.FeedConfig{ + audioConfig = playback.FeedConfig{ Domain: domainStr, UUID: audioStr, Active: true, } } - enqueueAudioConfig(config) + enqueueVideoConfig(videoConfig) + enqueueAudioConfig(audioConfig) return } // legacy @@ -577,34 +583,46 @@ func main() { go func() { defer close(playbackDone) - if useVideoSlot { - err := videoSlot.Run( - ctx, - playback.FeedConfig{ - Domain: args.Domain, - UUID: args.VideoFlowId, - Active: args.VideoFlowId != "", - }, - videoCommands, - ) - if err != nil && !errors.Is(err, context.Canceled) { - log.Printf("video slot: %v", err) - } - return - } - if useAudioSlot { - err := audioSlot.Run( - ctx, - playback.FeedConfig{ - Domain: args.Domain, - UUID: args.AudioFlowId, - Active: args.AudioFlowId != "", - }, - audioCommands, - ) - if err != nil && !errors.Is(err, context.Canceled) { - log.Printf("audio slot: %v", err) - } + if useIndependentSlots { + var slots sync.WaitGroup + slots.Add(2) + + go func() { + defer slots.Done() + + err := videoSlot.Run( + ctx, + playback.FeedConfig{ + Domain: args.Domain, + UUID: args.VideoFlowId, + Active: args.VideoFlowId != "", + }, + videoCommands, + ) + if err != nil && !errors.Is(err, context.Canceled) { + log.Printf("video slot: %v", err) + } + }() + + go func() { + defer slots.Done() + + err := audioSlot.Run( + ctx, + playback.FeedConfig{ + Domain: args.Domain, + UUID: args.AudioFlowId, + Active: args.AudioFlowId != "", + }, + audioCommands, + ) + if err != nil && !errors.Is(err, context.Canceled) { + log.Printf("audio slot: %v", err) + } + }() + + <-ctx.Done() + slots.Wait() return } @@ -930,7 +948,7 @@ func main() { if cimgui.Button("Connect") { doReconnect() } - if useVideoSlot && videoActive { + if useIndependentSlots && videoActive { cimgui.SameLine() if cimgui.Button("Stop video") { videoActive = false @@ -942,7 +960,7 @@ func main() { }) } } - if useVideoSlot && !videoActive && videoStr != "" { + if useIndependentSlots && !videoActive && videoStr != "" { cimgui.SameLine() if cimgui.Button("Resume video") { videoActive = true @@ -953,14 +971,14 @@ func main() { }) } } - if useVideoSlot && videoStr != "" { + if useIndependentSlots && videoStr != "" { if cimgui.Button("Remove video") { videoActive = false videoStr = "" enqueueVideoConfig(playback.FeedConfig{}) } } - if useVideoSlot { + if useIndependentSlots { if videoActive { cimgui.Text("Video desired: active") } else if videoStr != "" { @@ -994,7 +1012,7 @@ func main() { cimgui.Text("Video actual: not started") } } - if useAudioSlot && audioActive { + if useIndependentSlots && audioActive { if cimgui.Button("Stop audio") { audioActive = false enqueueAudioConfig(playback.FeedConfig{ @@ -1005,7 +1023,7 @@ func main() { } } - if useAudioSlot && !audioActive && audioStr != "" { + if useIndependentSlots && !audioActive && audioStr != "" { if cimgui.Button("Resume audio") { audioActive = true enqueueAudioConfig(playback.FeedConfig{ @@ -1016,7 +1034,7 @@ func main() { } } - if useAudioSlot && audioStr != "" { + if useIndependentSlots && audioStr != "" { if cimgui.Button("Remove audio") { audioActive = false audioStr = "" @@ -1024,7 +1042,7 @@ func main() { } } - if useAudioSlot { + if useIndependentSlots { if audioActive { cimgui.Text("Audio desired: active") } else if audioStr != "" { diff --git a/imgui.ini b/imgui.ini index 97d736a..b45ea7c 100644 --- a/imgui.ini +++ b/imgui.ini @@ -14,7 +14,7 @@ Size=200,200 Collapsed=0 [Window][Connection] -Pos=174,363 -Size=986,237 +Pos=366,563 +Size=430,227 Collapsed=0