package playback import "fmt" type SessionTopology uint8 const ( TopologyIdle SessionTopology = iota TopologyIndependent 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 { Topology SessionTopology // Desired states for independent slots. Video FeedConfig Audio FeedConfig // Desired state for the synchronized slot. Sync SyncPairConfig } func BuildSessionPlan( desired SessionConfig, canSync SyncPredicate, ) (SessionPlan, error) { if err := desired.Validate(); err != nil { return SessionPlan{}, fmt.Errorf("validate desired session: %w", err) } if desired.SyncRequested && desired.Video.Active && desired.Audio.Active && canSync != nil && canSync(desired.Video, desired.Audio) { return SessionPlan{ Topology: TopologySynchronized, Video: stoppedFeed(desired.Video), Audio: stoppedFeed(desired.Audio), Sync: SyncPairConfig{ Video: desired.Video, Audio: desired.Audio, }, }, nil } if desired.Video.Active || desired.Audio.Active { return SessionPlan{ Topology: TopologyIndependent, Video: desired.Video, Audio: desired.Audio, Sync: SyncPairConfig{ Video: stoppedFeed(desired.Video), Audio: stoppedFeed(desired.Audio), }, }, nil } return SessionPlan{ Topology: TopologyIdle, Video: stoppedFeed(desired.Video), Audio: stoppedFeed(desired.Audio), Sync: SyncPairConfig{ Video: stoppedFeed(desired.Video), Audio: stoppedFeed(desired.Audio), }, }, nil } func stoppedFeed(config FeedConfig) FeedConfig { config.Active = false return config }