From cd3a909e616c32895a3b8366bcd19de078604c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Cuevas?= Date: Sun, 17 Dec 2023 16:05:49 +0100 Subject: [PATCH] fix: Better management of stop and play behavior Removed the need of cancelreader that didn't work on Windows as expected, so we did away with the silly pipe to return a ReadCloser of the output, and used the object directly from the RadioPlayer object itself. Now when we stop, we close the stream and the ffmpeg instance. --- go.mod | 3 +-- go.sum | 4 --- main.go | 71 +++++++++++++++++++++++--------------------------- radioplayer.go | 18 +++---------- 4 files changed, 37 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index cbd9f47..d15a6d7 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,7 @@ go 1.16 require ( fyne.io/fyne/v2 v2.4.2 - github.com/ebitengine/oto/v3 v3.1.0 // indirect + github.com/ebitengine/oto/v3 v3.1.0 github.com/ebitengine/purego v0.5.1 // indirect - github.com/muesli/cancelreader v0.2.2 // indirect golang.org/x/sys v0.15.0 // indirect ) diff --git a/go.sum b/go.sum index b4ce960..b0f85a3 100644 --- a/go.sum +++ b/go.sum @@ -243,8 +243,6 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= @@ -504,7 +502,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -514,7 +511,6 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go index 3ba6a6b..f2e8d49 100644 --- a/main.go +++ b/main.go @@ -49,8 +49,6 @@ import ( "strings" "time" - "github.com/muesli/cancelreader" - "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/canvas" @@ -70,10 +68,6 @@ const ( Stopped ) -// Cancel Reader - -var reader cancelreader.CancelReader - // helper func check(err error) { if err != nil { @@ -159,10 +153,10 @@ func main() { log.Println("Starting the app") // Create the status channel, to read from StreamPlayer and the pipe to send commands to it - pipe_chan := make(chan io.ReadCloser) + // pipe_chan := make(chan io.ReadCloser) // Create our StreamPlayer instance - streamPlayer := StreamPlayer{player_name: PLAYER_CMD, pipe_chan: pipe_chan} + streamPlayer := StreamPlayer{player_name: PLAYER_CMD} // Create our app and window app := app.New() @@ -217,7 +211,7 @@ func main() { // Here we control each time the button is pressed and update its // appearance anytime it is clicked. We make the player start playing // or pause. - if !streamPlayer.IsPlaying() && !streamPlayer.paused { + if !streamPlayer.IsPlaying() { playButton.SetIcon(theme.MediaStopIcon()) playButton.SetText("(Buffering)") streamPlayer.Load(RADIOSPIRAL_STREAM) @@ -227,9 +221,8 @@ func main() { if playStatus == Playing { playStatus = Stopped playButton.SetIcon(theme.MediaPlayIcon()) - streamPlayer.Pause() + streamPlayer.Stop() } else { - reader.Cancel() playStatus = Loading playButton.SetText("(Buffering)") playButton.SetIcon(theme.MediaStopIcon()) @@ -242,37 +235,37 @@ func main() { // Process the output of ffmpeg here in a separate goroutine go func() { for { - out_pipe := <-pipe_chan - var err error - reader, err = cancelreader.NewReader(out_pipe) - if err != nil { - log.Println("Error opening reader") - } - for { - var data [255]byte - _, err := reader.Read(data[:]) - if err != nil { - log.Println(err) - break - } - lines := strings.Split(string(data[:]), "\n") - for _, line := range lines { - // Log, if enabled, the output of StreamPlayer - if *loggingToFilePtr { - log.Print("[" + streamPlayer.player_name + "] " + line) + if streamPlayer.out != nil { + for { + var data [255]byte + _, err := streamPlayer.out.Read(data[:]) + if err != nil { + log.Println(err) + break } - if strings.Contains(line, "Output #0") { - playStatus = Playing - playButton.SetText("") - } - // Check if there's an updated title and reflect it on the - // GUI - if strings.Contains(line, "StreamTitle: ") { - log.Println("Found new stream title, updating GUI") - newTitleParts := strings.Split(line, "StreamTitle: ") - nowPlayingLabel.SetText(newTitleParts[1]) + lines := strings.Split(string(data[:]), "\n") + for _, line := range lines { + // Log, if enabled, the output of StreamPlayer + if *loggingToFilePtr { + log.Print("[" + streamPlayer.player_name + "] " + line) + } + if strings.Contains(line, "Output #0") { + playStatus = Playing + playButton.SetText("") + } + // Check if there's an updated title and reflect it on the + // GUI + if strings.Contains(line, "StreamTitle: ") { + log.Println("Found new stream title, updating GUI") + newTitleParts := strings.Split(line, "StreamTitle: ") + nowPlayingLabel.SetText(newTitleParts[1]) + } } } + } else { + // To avoid high CPU usage, we wait some milliseconds before testing + // again for the change in streamPlayer.out from nil to ReadCloser + time.Sleep(200 * time.Millisecond) } } }() diff --git a/radioplayer.go b/radioplayer.go index c8672db..0b9c769 100644 --- a/radioplayer.go +++ b/radioplayer.go @@ -38,7 +38,7 @@ type RadioPlayer interface { IsPlaying() bool Play() Mute() - Pause() + Stop() IncVolume() DecVolume() Close() @@ -52,11 +52,9 @@ type StreamPlayer struct { in io.WriteCloser out io.ReadCloser audio io.ReadCloser - pipe_chan chan io.ReadCloser otoContext *oto.Context otoPlayer *oto.Player currentVolume float64 - paused bool } func (player *StreamPlayer) IsPlaying() bool { @@ -114,12 +112,6 @@ func (player *StreamPlayer) Load(stream_url string) { player.otoPlayer = player.otoContext.NewPlayer(player.audio) // Save current volume for the mute function player.currentVolume = player.otoPlayer.Volume() - - player.paused = false - - go func() { - player.pipe_chan <- player.out - }() } } @@ -146,6 +138,7 @@ func (player *StreamPlayer) Close() { player.in.Close() player.out.Close() player.audio.Close() + player.out = nil player.stream_url = "" } @@ -162,12 +155,9 @@ func (player *StreamPlayer) Mute() { } } -func (player *StreamPlayer) Pause() { +func (player *StreamPlayer) Stop() { if player.IsPlaying() { - if !player.paused { - player.paused = true - player.otoPlayer.Pause() - } + player.Close() } }