package app import ( "context" "errors" "fmt" "log" "mxl-pattern-generator/internal/audio" "mxl-pattern-generator/internal/video" "github.com/qvest-digital/go-mxl/mxl" ) const ( Name = "MXL pattern generator" Version = "0.1.0" ) type Config struct { Domain string Video *video.Config Audio *audio.Config } func Run(ctx context.Context, cfg Config) (runErr error) { if err := validateConfig(cfg); err != nil { return err } log.Printf("%s %s", Name, Version) log.Printf("Domain: %s", cfg.Domain) if cfg.Video != nil { log.Printf("Video: %dx%d %d/%d", cfg.Video.Width(), cfg.Video.Height(), cfg.Video.Rate().Num, cfg.Video.Rate().Den) log.Printf("Video ID: %s", cfg.Video.ID()) } if cfg.Audio != nil { log.Printf("Audio: %d channels %d/%d Hz %.0f dBFS", cfg.Audio.Channels(), cfg.Audio.Rate().Num, cfg.Audio.Rate().Den, cfg.Audio.LevelDBFS) log.Printf("Audio ID: %s", cfg.Audio.ID()) } inst, err := mxl.NewInstance(cfg.Domain, "") if err != nil { return fmt.Errorf("initialize MXL domain %q: %w", cfg.Domain, err) } defer func() { if err := inst.Close(); err != nil { runErr = errors.Join(runErr, fmt.Errorf("close MXL instance: %w", err)) } }() runners := make([]Runner, 0, 2) if cfg.Video != nil { runners = append(runners, Runner{ Name: "video", Run: func(ctx context.Context) error { return video.Run(ctx, inst, *cfg.Video) }, }) } if cfg.Audio != nil { runners = append(runners, Runner{ Name: "audio", Run: func(ctx context.Context) error { return audio.Run(ctx, inst, *cfg.Audio) }, }) } return RunConcurrent(ctx, runners...) } func validateConfig(cfg Config) error { if cfg.Video == nil && cfg.Audio == nil { return fmt.Errorf("at least one media flow must be enabled") } return nil }