@@ -82,20 +82,35 @@ func (s *StreamState) stopStream(logger *zap.Logger) {
8282
8383 logger .Info ("Stopping existing stream..." )
8484
85- // Stop FFmpeg process
86- if s .ffmpegCmd != nil && s .ffmpegCmd .Process != nil {
87- logger .Debug ("Terminating FFmpeg process" )
88- if err := s .ffmpegCmd .Process .Kill (); err != nil {
89- logger .Warn ("Failed to kill FFmpeg process" , zap .Error (err ))
90- }
91- }
92-
9385 // Cancel Chrome context
9486 if s .chromeCancel != nil {
9587 logger .Debug ("Cancelling Chrome context" )
9688 s .chromeCancel ()
9789 }
9890
91+ // Ask FFmpeg to terminate gracefully
92+ if s .ffmpegCmd != nil && s .ffmpegCmd .Process != nil {
93+ logger .Debug ("Sending SIGTERM to FFmpeg process" )
94+ _ = s .ffmpegCmd .Process .Signal (syscall .SIGTERM )
95+
96+ done := make (chan struct {})
97+ go func (cmd * exec.Cmd ) {
98+ // Wait will reap the process and free OS resources
99+ _ , _ = cmd .Process .Wait ()
100+ close (done )
101+ }(s .ffmpegCmd )
102+
103+ select {
104+ case <- done :
105+ logger .Debug ("FFmpeg exited gracefully" )
106+ case <- time .After (5 * time .Second ):
107+ logger .Warn ("FFmpeg did not exit in time, killing" )
108+ _ = s .ffmpegCmd .Process .Kill ()
109+ // Ensure we still reap it
110+ go func (cmd * exec.Cmd ) { _ , _ = cmd .Process .Wait () }(s .ffmpegCmd )
111+ }
112+ }
113+
99114 // Cancel main stream context
100115 if s .cancelFunc != nil {
101116 logger .Debug ("Cancelling stream context" )
@@ -202,17 +217,20 @@ func main() {
202217 }()
203218
204219 // Setup stream status checker (will start monitoring after stream begins)
205- setupStreamStatusChecker (ctx , config )
220+ cronScheduler := setupStreamStatusChecker (ctx , config )
206221
207222 // Handle graceful shutdown
208223 c := make (chan os.Signal , 1 )
209224 signal .Notify (c , os .Interrupt , syscall .SIGTERM )
210225 go func () {
211226 <- c
212227 logger .Info ("Received shutdown signal, stopping..." )
213-
228+ signal . Stop ( c )
214229 // Stop current stream if running
215230 StopCurrentStream (ctx )
231+ if cronScheduler != nil {
232+ cronScheduler .Stop ()
233+ }
216234
217235 // Shutdown HTTP server
218236 shutdownCtx , shutdownCancel := context .WithTimeout (context .Background (), 5 * time .Second )
@@ -497,6 +515,28 @@ func startFFmpegStream(ctx context.Context, config *Config, display string, stre
497515 return fmt .Errorf ("failed to start ffmpeg: %v" , err )
498516 }
499517
518+ // Start a goroutine to periodically flush the zapWriter while the command is running
519+ go func () {
520+ ticker := time .NewTicker (2 * time .Second )
521+ defer ticker .Stop ()
522+
523+ for {
524+ select {
525+ case <- ticker .C :
526+ // Check if the process is still running
527+ if cmd .Process != nil && cmd .ProcessState == nil {
528+ // Sync forces any buffered output to be written
529+ zapWriter .Sync ()
530+ } else {
531+ // Process is done or never started
532+ return
533+ }
534+ case <- ctx .Done ():
535+ return
536+ }
537+ }
538+ }()
539+
500540 // Register this stream as running
501541 globalStreamState .setStreamRunning (streamCancel , chromeCancel , cmd )
502542
@@ -526,7 +566,7 @@ func startFFmpegStream(ctx context.Context, config *Config, display string, stre
526566// If the proper enviromental variables are set, setup a cron job to check the status of the stream
527567// If the stream is not live, then restart the stream
528568// This is used because various platforms have maximum stream durations and after that we need to restart
529- func setupStreamStatusChecker (ctx context.Context , config * Config ) {
569+ func setupStreamStatusChecker (ctx context.Context , config * Config ) * cron. Cron {
530570 logger := utils .GetLoggerFromContext (ctx )
531571
532572 logger .Debug ("Setting up stream status checker" )
@@ -568,7 +608,9 @@ func setupStreamStatusChecker(ctx context.Context, config *Config) {
568608 })
569609 c .Start ()
570610 logger .Info ("Stream status checker started" , zap .String ("cronString" , cronString ))
611+ return c
571612 } else {
572613 logger .Debug ("Stream status checker not configured, skipping setup" )
573614 }
615+ return nil
574616}
0 commit comments