feat: buffering indicator implemented, solved bug reading when paused
This commit is contained in:
parent
43f40b7e6d
commit
8c48b48371
3 changed files with 70 additions and 52 deletions
1
go.mod
1
go.mod
|
@ -6,5 +6,6 @@ require (
|
|||
fyne.io/fyne/v2 v2.4.2
|
||||
github.com/ebitengine/oto/v3 v3.1.0 // indirect
|
||||
github.com/ebitengine/purego v0.5.1 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
)
|
||||
|
|
3
go.sum
3
go.sum
|
@ -243,6 +243,8 @@ 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=
|
||||
|
@ -502,6 +504,7 @@ 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=
|
||||
|
|
118
main.go
118
main.go
|
@ -36,7 +36,6 @@ package main
|
|||
*/
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"image"
|
||||
|
@ -51,6 +50,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ebitengine/oto/v3"
|
||||
"github.com/muesli/cancelreader"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/app"
|
||||
|
@ -61,6 +61,21 @@ import (
|
|||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// Enums and constants
|
||||
const RADIOSPIRAL_STREAM = "https://radiospiral.radio/stream.mp3"
|
||||
const RADIOSPIRAL_JSON_ENDPOINT = "https://radiospiral.net/wp-json/radio/broadcast"
|
||||
|
||||
const (
|
||||
Loading int = iota
|
||||
Playing
|
||||
Paused
|
||||
Stopped
|
||||
)
|
||||
|
||||
// Cancel Reader
|
||||
|
||||
var reader cancelreader.CancelReader
|
||||
|
||||
// helper
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
|
@ -220,7 +235,6 @@ func (player *StreamPlayer) Close() {
|
|||
player.in.Close()
|
||||
player.out.Close()
|
||||
player.audio.Close()
|
||||
// player.command.Cancel()
|
||||
|
||||
player.stream_url = ""
|
||||
}
|
||||
|
@ -240,13 +254,8 @@ func (player *StreamPlayer) Mute() {
|
|||
func (player *StreamPlayer) Pause() {
|
||||
if player.IsPlaying() {
|
||||
if !player.paused {
|
||||
log.Println("[oto] Pausing")
|
||||
player.paused = true
|
||||
player.otoPlayer.Pause()
|
||||
} else {
|
||||
log.Println("[oto] Playing")
|
||||
player.paused = false
|
||||
player.otoPlayer.Play()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -284,8 +293,6 @@ func loadImageURL(url string) image.Image {
|
|||
}
|
||||
|
||||
func main() {
|
||||
const RADIOSPIRAL_STREAM = "https://radiospiral.radio/stream.mp3"
|
||||
const RADIOSPIRAL_JSON_ENDPOINT = "https://radiospiral.net/wp-json/radio/broadcast"
|
||||
PLAYER_CMD := "ffmpeg"
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
|
@ -313,9 +320,6 @@ func main() {
|
|||
// Create our StreamPlayer instance
|
||||
streamPlayer := StreamPlayer{player_name: PLAYER_CMD, pipe_chan: pipe_chan}
|
||||
|
||||
// Make sure that StreamPlayer closes when the program ends
|
||||
defer streamPlayer.Close()
|
||||
|
||||
// Create our app and window
|
||||
app := app.New()
|
||||
window := app.NewWindow("RadioSpiral Player")
|
||||
|
@ -324,7 +328,7 @@ func main() {
|
|||
window.SetIcon(resourceIconPng)
|
||||
|
||||
// Keep the status of the player
|
||||
playStatus := false
|
||||
playStatus := Stopped
|
||||
|
||||
// Placeholder avatar
|
||||
radioSpiralAvatar := loadImageURL("https://radiospiral.net/wp-content/uploads/2018/03/Radio-Spiral-Logo-1.png")
|
||||
|
@ -343,7 +347,6 @@ func main() {
|
|||
// Player section
|
||||
nowPlayingLabelHeader := widget.NewLabel("Now playing:")
|
||||
nowPlayingLabel := widget.NewLabel("")
|
||||
var playButton *widget.Button
|
||||
volumeDown := widget.NewButtonWithIcon("", theme.VolumeDownIcon(), func() {
|
||||
streamPlayer.DecVolume()
|
||||
})
|
||||
|
@ -364,34 +367,65 @@ func main() {
|
|||
nowPlayingLabel.Alignment = fyne.TextAlignCenter
|
||||
nowPlayingLabel.Wrapping = fyne.TextWrapWord
|
||||
|
||||
// Process the output of Mplayer here in a separate goroutine
|
||||
var playButton *widget.Button
|
||||
|
||||
playButton = widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {
|
||||
// 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 {
|
||||
playButton.SetIcon(theme.MediaPauseIcon())
|
||||
playButton.SetText("(Buffering)")
|
||||
streamPlayer.Load(RADIOSPIRAL_STREAM)
|
||||
streamPlayer.Play()
|
||||
playStatus = Loading
|
||||
} else {
|
||||
if playStatus == Playing {
|
||||
playStatus = Paused
|
||||
playButton.SetIcon(theme.MediaPlayIcon())
|
||||
streamPlayer.Pause()
|
||||
} else {
|
||||
reader.Cancel()
|
||||
playStatus = Loading
|
||||
playButton.SetText("(Buffering)")
|
||||
playButton.SetIcon(theme.MediaPauseIcon())
|
||||
streamPlayer.Load(RADIOSPIRAL_STREAM)
|
||||
streamPlayer.Play()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Process the output of ffmpeg here in a separate goroutine
|
||||
go func() {
|
||||
for {
|
||||
out_pipe := <-pipe_chan
|
||||
reader := bufio.NewReader(out_pipe)
|
||||
var err error
|
||||
reader, err = cancelreader.NewReader(out_pipe)
|
||||
if err != nil {
|
||||
log.Println("Error opening reader")
|
||||
}
|
||||
for {
|
||||
data, err := reader.ReadString('\n')
|
||||
var data [255]byte
|
||||
_, err := reader.Read(data[:])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Println("Reloading player")
|
||||
streamPlayer.Close()
|
||||
pipe_chan = make(chan io.ReadCloser)
|
||||
streamPlayer = StreamPlayer{player_name: PLAYER_CMD, pipe_chan: pipe_chan}
|
||||
streamPlayer.Load(RADIOSPIRAL_STREAM)
|
||||
streamPlayer.Play()
|
||||
playStatus = true
|
||||
playButton.SetIcon(theme.MediaPlayIcon())
|
||||
defer streamPlayer.Close()
|
||||
} else {
|
||||
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 + "] " + data)
|
||||
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(data, "StreamTitle: ") {
|
||||
if strings.Contains(line, "StreamTitle: ") {
|
||||
log.Println("Found new stream title, updating GUI")
|
||||
newTitleParts := strings.Split(data, "StreamTitle: ")
|
||||
newTitleParts := strings.Split(line, "StreamTitle: ")
|
||||
nowPlayingLabel.SetText(newTitleParts[1])
|
||||
}
|
||||
}
|
||||
|
@ -399,27 +433,6 @@ func main() {
|
|||
}
|
||||
}()
|
||||
|
||||
playButton = widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {
|
||||
// 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() {
|
||||
playButton.SetIcon(theme.MediaPauseIcon())
|
||||
streamPlayer.Load(RADIOSPIRAL_STREAM)
|
||||
streamPlayer.Play()
|
||||
playStatus = true
|
||||
} else {
|
||||
if playStatus {
|
||||
playStatus = false
|
||||
playButton.SetIcon(theme.MediaPlayIcon())
|
||||
} else {
|
||||
playStatus = true
|
||||
playButton.SetIcon(theme.MediaPauseIcon())
|
||||
}
|
||||
streamPlayer.Pause()
|
||||
}
|
||||
})
|
||||
|
||||
rsUrl, err := url.Parse("https://radiospiral.net")
|
||||
|
||||
if err != nil {
|
||||
|
@ -477,4 +490,5 @@ func main() {
|
|||
|
||||
// Showtime!
|
||||
window.ShowAndRun()
|
||||
streamPlayer.Close()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue