comfort-noise/player/player.go

128 lines
2.1 KiB
Go
Raw Normal View History

2023-08-19 10:35:09 +02:00
package player
2023-08-05 15:17:24 +02:00
import (
2023-08-19 12:07:31 +02:00
"fmt"
2023-08-19 10:35:09 +02:00
"net/http"
2023-08-05 15:17:24 +02:00
"time"
"github.com/faiface/beep"
2023-08-19 10:35:09 +02:00
"github.com/faiface/beep/mp3"
2023-08-05 15:17:24 +02:00
"github.com/faiface/beep/speaker"
)
2023-08-19 10:35:09 +02:00
type Station struct {
Name string
URL string
}
2023-08-19 12:07:31 +02:00
type Status struct {
Playing bool
Station string
Channels []string
}
2023-08-05 15:17:24 +02:00
type Player struct {
2023-08-19 12:07:31 +02:00
stations []Station
current int
2023-08-05 15:17:24 +02:00
oldStreamer beep.StreamCloser
oldCtrl *beep.Ctrl
mixer *beep.Mixer
sr beep.SampleRate
2023-08-05 15:17:24 +02:00
}
2023-08-19 12:07:31 +02:00
func NewPlayer(stations []Station) *Player {
2023-08-05 15:17:24 +02:00
return &Player{
2023-08-19 12:07:31 +02:00
stations: stations,
current: -1,
mixer: &beep.Mixer{},
sr: beep.SampleRate(48000),
2023-08-05 15:17:24 +02:00
}
}
func (p *Player) Init() error {
if err := speaker.Init(p.sr, p.sr.N(time.Second/10)); err != nil {
2023-08-05 15:17:24 +02:00
return err
}
speaker.Play(p.mixer)
return nil
}
2023-08-19 12:07:31 +02:00
func (p *Player) Select(channel int) error {
if channel < 0 || channel >= len(p.stations) {
return fmt.Errorf("unknown channel: %d", channel)
}
res, err := http.Get(p.stations[channel].URL)
2023-08-19 10:35:09 +02:00
if err != nil {
return err
}
streamer, format, err := mp3.Decode(res.Body)
2023-08-19 10:35:09 +02:00
if err != nil {
return err
}
resampled := Resample(4, format.SampleRate, p.sr, streamer)
p.PlayStream(resampled)
2023-08-19 12:07:31 +02:00
p.current = channel
2023-08-19 10:35:09 +02:00
return nil
}
func (p *Player) PlayStream(streamer beep.StreamCloser) {
2023-08-05 15:17:24 +02:00
ctrl := &beep.Ctrl{
Streamer: streamer,
}
p.mixer.Add(ctrl)
speaker.Lock()
if p.oldCtrl != nil {
p.oldCtrl.Paused = true
p.oldCtrl.Streamer = nil
p.oldStreamer.Close()
}
ctrl.Paused = true
ctrl.Streamer = streamer
ctrl.Paused = false
speaker.Unlock()
p.oldCtrl = ctrl
p.oldStreamer = streamer
}
2023-08-19 12:07:31 +02:00
func (p *Player) Stop() {
speaker.Lock()
if p.oldCtrl != nil {
p.oldCtrl.Paused = true
p.oldCtrl.Streamer = nil
p.oldStreamer.Close()
}
speaker.Unlock()
p.current = -1
}
func (p *Player) Status() Status {
channels := make([]string, len(p.stations))
for i, stat := range p.stations {
channels[i] = stat.Name
}
if p.current < 0 || p.current >= len(p.stations) {
return Status{Channels: channels}
}
return Status{
Playing: true,
Station: p.stations[p.current].Name,
Channels: channels,
}
}