chore: refactor the radio player to its own file

This commit is contained in:
José Carlos Cuevas 2023-12-11 10:57:23 +01:00
parent f99baee6e0
commit d5a7bb9a0b
3 changed files with 174 additions and 167 deletions

View file

@ -7,8 +7,8 @@ GO_OPTIONS=-buildmode=default
all: radiospiral
radiospiral: main.go bundle.go
$(GO) -o radiospiral $(GO_OPTIONS) main.go bundle.go
radiospiral: main.go radioplayer.go bundle.go
$(GO) -o radiospiral $(GO_OPTIONS) main.go radioplayer.go bundle.go
# It's a phony so we can always call it and regenerate the file
.PHONY: generate

168
main.go
View file

@ -44,13 +44,11 @@ import (
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/ebitengine/oto/v3"
"github.com/muesli/cancelreader"
"fyne.io/fyne/v2"
@ -69,7 +67,6 @@ const RADIOSPIRAL_JSON_ENDPOINT = "https://radiospiral.net/wp-json/radio/broadca
const (
Loading int = iota
Playing
Paused
Stopped
)
@ -122,165 +119,6 @@ type HostsData struct {
Name string `json:"name"`
}
// Radio player interface
type RadioPlayer interface {
Load(stream_url string)
IsPlaying() bool
Play()
Mute()
Pause()
IncVolume()
DecVolume()
Close()
}
// StreamPlayer
type StreamPlayer struct {
player_name string
stream_url string
command *exec.Cmd
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 {
if player.otoPlayer == nil {
log.Println("Player not loaded!")
return false
}
return player.otoPlayer.IsPlaying()
}
func (player *StreamPlayer) Load(stream_url string) {
if (player.otoPlayer == nil) || (!player.otoPlayer.IsPlaying()) {
var err error
is_playlist := strings.HasSuffix(stream_url, ".m3u") || strings.HasSuffix(stream_url, ".pls")
if is_playlist {
// TODO: Check ffmpeg's ability to deal with playlists
// player.command = exec.Command(player.player_name, "-quiet", "-playlist", stream_url)
player.command = exec.Command(player.player_name, "-nodisp", "-loglevel", "verbose", "-playlist", stream_url)
} else {
player.command = exec.Command(player.player_name, "-loglevel", "verbose", "-i", stream_url, "-f", "wav", "-")
}
// In to send things over stdin to ffmpeg
player.in, err = player.command.StdinPipe()
check(err)
// Out will be the wave data we will read and play
player.audio, err = player.command.StdoutPipe()
check(err)
// Err is the output of ffmpeg, used to get stream title
player.out, err = player.command.StderrPipe()
check(err)
log.Println("Starting ffmpeg")
err = player.command.Start()
check(err)
player.stream_url = stream_url
op := &oto.NewContextOptions{
SampleRate: 44100,
ChannelCount: 2,
Format: oto.FormatSignedInt16LE,
}
if player.otoContext == nil {
otoContext, readyChan, err := oto.NewContext(op)
player.otoContext = otoContext
if err != nil {
log.Fatal(err)
}
<-readyChan
}
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
}()
}
}
func (player *StreamPlayer) Play() {
if player.otoPlayer == nil {
log.Println("Stream not loaded")
return
}
if !player.otoPlayer.IsPlaying() {
if player.command == nil {
player.Load(player.stream_url)
}
player.otoPlayer.Play()
}
}
func (player *StreamPlayer) Close() {
if player.IsPlaying() {
err := player.otoPlayer.Close()
if err != nil {
log.Println(err)
}
player.in.Close()
player.out.Close()
player.audio.Close()
player.stream_url = ""
}
}
func (player *StreamPlayer) Mute() {
if player.IsPlaying() {
if player.otoPlayer.Volume() > 0 {
player.currentVolume = player.otoPlayer.Volume()
player.otoPlayer.SetVolume(0.0)
} else {
player.otoPlayer.SetVolume(player.currentVolume)
}
}
}
func (player *StreamPlayer) Pause() {
if player.IsPlaying() {
if !player.paused {
player.paused = true
player.otoPlayer.Pause()
}
}
}
func (player *StreamPlayer) IncVolume() {
if player.IsPlaying() {
player.currentVolume += 0.05
if player.currentVolume >= 1.0 {
player.currentVolume = 1.0
}
player.otoPlayer.SetVolume(player.currentVolume)
}
}
func (player *StreamPlayer) DecVolume() {
if player.IsPlaying() {
player.currentVolume -= 0.05
if player.currentVolume <= 0.0 {
player.currentVolume = 0.0
}
player.otoPlayer.SetVolume(player.currentVolume)
}
}
// Load images from URLs
func loadImageURL(url string) image.Image {
parts := strings.Split(url, "?")
@ -380,21 +218,21 @@ func main() {
// appearance anytime it is clicked. We make the player start playing
// or pause.
if !streamPlayer.IsPlaying() && !streamPlayer.paused {
playButton.SetIcon(theme.MediaPauseIcon())
playButton.SetIcon(theme.MediaStopIcon())
playButton.SetText("(Buffering)")
streamPlayer.Load(RADIOSPIRAL_STREAM)
streamPlayer.Play()
playStatus = Loading
} else {
if playStatus == Playing {
playStatus = Paused
playStatus = Stopped
playButton.SetIcon(theme.MediaPlayIcon())
streamPlayer.Pause()
} else {
reader.Cancel()
playStatus = Loading
playButton.SetText("(Buffering)")
playButton.SetIcon(theme.MediaPauseIcon())
playButton.SetIcon(theme.MediaStopIcon())
streamPlayer.Load(RADIOSPIRAL_STREAM)
streamPlayer.Play()
}

169
radioplayer.go Normal file
View file

@ -0,0 +1,169 @@
package main
import (
"io"
"log"
"os/exec"
"strings"
"github.com/ebitengine/oto/v3"
)
// Radio player interface
type RadioPlayer interface {
Load(stream_url string)
IsPlaying() bool
Play()
Mute()
Pause()
IncVolume()
DecVolume()
Close()
}
// StreamPlayer
type StreamPlayer struct {
player_name string
stream_url string
command *exec.Cmd
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 {
if player.otoPlayer == nil {
log.Println("Player not loaded!")
return false
}
return player.otoPlayer.IsPlaying()
}
func (player *StreamPlayer) Load(stream_url string) {
if (player.otoPlayer == nil) || (!player.otoPlayer.IsPlaying()) {
var err error
is_playlist := strings.HasSuffix(stream_url, ".m3u") || strings.HasSuffix(stream_url, ".pls")
if is_playlist {
// TODO: Check ffmpeg's ability to deal with playlists
// player.command = exec.Command(player.player_name, "-quiet", "-playlist", stream_url)
player.command = exec.Command(player.player_name, "-nodisp", "-loglevel", "verbose", "-playlist", stream_url)
} else {
player.command = exec.Command(player.player_name, "-loglevel", "verbose", "-i", stream_url, "-f", "wav", "-")
}
// In to send things over stdin to ffmpeg
player.in, err = player.command.StdinPipe()
check(err)
// Out will be the wave data we will read and play
player.audio, err = player.command.StdoutPipe()
check(err)
// Err is the output of ffmpeg, used to get stream title
player.out, err = player.command.StderrPipe()
check(err)
log.Println("Starting ffmpeg")
err = player.command.Start()
check(err)
player.stream_url = stream_url
op := &oto.NewContextOptions{
SampleRate: 44100,
ChannelCount: 2,
Format: oto.FormatSignedInt16LE,
}
if player.otoContext == nil {
otoContext, readyChan, err := oto.NewContext(op)
player.otoContext = otoContext
if err != nil {
log.Fatal(err)
}
<-readyChan
}
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
}()
}
}
func (player *StreamPlayer) Play() {
if player.otoPlayer == nil {
log.Println("Stream not loaded")
return
}
if !player.otoPlayer.IsPlaying() {
if player.command == nil {
player.Load(player.stream_url)
}
player.otoPlayer.Play()
}
}
func (player *StreamPlayer) Close() {
if player.IsPlaying() {
err := player.otoPlayer.Close()
if err != nil {
log.Println(err)
}
player.in.Close()
player.out.Close()
player.audio.Close()
player.stream_url = ""
}
}
func (player *StreamPlayer) Mute() {
if player.IsPlaying() {
if player.otoPlayer.Volume() > 0 {
player.currentVolume = player.otoPlayer.Volume()
player.otoPlayer.SetVolume(0.0)
} else {
player.otoPlayer.SetVolume(player.currentVolume)
}
}
}
func (player *StreamPlayer) Pause() {
if player.IsPlaying() {
if !player.paused {
player.paused = true
player.otoPlayer.Pause()
}
}
}
func (player *StreamPlayer) IncVolume() {
if player.IsPlaying() {
player.currentVolume += 0.05
if player.currentVolume >= 1.0 {
player.currentVolume = 1.0
}
player.otoPlayer.SetVolume(player.currentVolume)
}
}
func (player *StreamPlayer) DecVolume() {
if player.IsPlaying() {
player.currentVolume -= 0.05
if player.currentVolume <= 0.0 {
player.currentVolume = 0.0
}
player.otoPlayer.SetVolume(player.currentVolume)
}
}