func screenRenderLoop(evtLoop *spectrum.EventLoop, screenChannel <-chan *spectrum.DisplayData, renderer screen_renderer_t) { terminating := false shutdown.Add(1) for { select { case <-evtLoop.Pause: terminating = true evtLoop.Pause <- 0 case <-evtLoop.Terminate: // Terminate this Go routine if evtLoop.App().Verbose { evtLoop.App().PrintfMsg("screen render loop: exit") } evtLoop.Terminate <- 0 shutdown.Done() return case screen := <-screenChannel: if screen != nil { if !terminating { renderer.render(screen) } } else { done := evtLoop.Delete() go func() { <-done }() } } } }
// Forward 'AudioData' objects from 'audio.data' to 'audio.playback' func forwarderLoop(evtLoop *spectrum.EventLoop, audio *SDLAudio) { audioDataChannel := audio.data playback_closed := false shutdown.Add(1) for { select { case <-evtLoop.Pause: // Remove all enqueued AudioData objects loop: for { select { case <-audio.playback: default: break loop } } audio.mutex.Lock() { if !audio.sdlAudioUnpaused { // Unpause SDL Audio. This is needed in order to avoid // a potential deadlock on 'sdl_audio.SendAudio_int16()'. // (If audio is paused, 'sdl_audio.SendAudio_int16()' waits indefinitely.) sdl_audio.PauseAudio(false) audio.sdlAudioUnpaused = true } } audio.mutex.Unlock() close(audio.playback) playback_closed = true <-audio.playbackLoopFinished sdl_audio.CloseAudio() audio.mutex.Lock() forwarderLoopFinished := audio.forwarderLoopFinished audio.mutex.Unlock() if forwarderLoopFinished != nil { forwarderLoopFinished <- 0 } evtLoop.Pause <- 0 case <-evtLoop.Terminate: // Terminate this Go routine if evtLoop.App().Verbose { evtLoop.App().PrintfMsg("audio forwarder loop: exit") } evtLoop.Terminate <- 0 shutdown.Done() return case audioData := <-audioDataChannel: if audioData != nil { if !playback_closed { audio.bufferAdd() audio.playback <- audioData } } else { // Prevent any future sends via the 'audio.data' channel close(audio.data) // Replace 'audioDataChannel' with nil, // so that future executions of the 'select' statement ignore the "<-audioDataChannel" case audioDataChannel = nil // Go to the '<-evtLoop.Pause' case done := evtLoop.Delete() go func() { <-done }() } } } }