func runCurrentProgram(s *datastore.Schedule) error { cp, err := s.CurrentProgram() if err != nil { log.Println("Error fetching current program:", s.Id, err) return err } // Rewrite the start_at parameter to resume position from playback counter params := cp.Parameters pc := cp.PlaybackCounter(s.Id) startAt, _ := params["start_at"] startParam, parseErr := strconv.ParseInt(startAt, 10, 64) if parseErr != nil { startParam = 0 } newStart := startParam + pc params["start_at"] = fmt.Sprintf("%d", newStart) // now we run the function pipeline := RunPipe(cp.FunctionId, cp.UUID, params) checkTicker := time.Tick(100 * time.Millisecond) pipeline.Close() cancelStillPlaying := make(chan int, 3) go func() { timeout := time.Tick(1 * time.Second) s.StillPlaying() // lock schedule playback for { select { case <-cancelStillPlaying: return case <-timeout: s.StillPlaying() } } }() cancelPlayingMarker := func() { cancelStillPlaying <- 0 } defer cancelPlayingMarker() startDiscontinuityWritten := false // always write discontinuity when starting segmentTimer := time.After(1 * time.Nanosecond) for pipeout := pipeline.MediaChannel(); true; { select { case <-segmentTimer: // if it's time to send the next segment v, more := <-pipeout segment := v.Segment segmentDuration := time.Duration(segment.TargetDuration * 1000000) segmentTimer = time.After(segmentDuration * time.Microsecond) cp.IncrementPlaybackCounter(s.Id) if !more { cp.ResetPlaybackCounter(s.Id) return nil } if !startDiscontinuityWritten { segment.Discontinuity = true startDiscontinuityWritten = true } if err := AddSegmentToSchedule(s, segment); err != nil { log.Println("Error adding new segment to schedule:", err) } case <-checkTicker: // if it's time to check for the next program nextProgramStart, err := s.NextProgramStart() if err == nil && time.Now().After(nextProgramStart) { s.PopCurrentProgram() cp.ResetPlaybackCounter(s.Id) return nil } } } return nil }