Remove beep and the files where it was imported (#2731)
Beep isn't needed anymore since we rely on MPV instead. The changes to `go.mod` and `go.sum` were done with: ``` go get github.com/faiface/beep@none go mod tidy ``` Signed-off-by: Dany Marcoux <git@dmarcoux.com>
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
//go:build beep
|
||||
|
||||
package beepaudio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/faiface/beep"
|
||||
"github.com/faiface/beep/flac"
|
||||
"github.com/faiface/beep/mp3"
|
||||
"github.com/faiface/beep/wav"
|
||||
"github.com/navidrome/navidrome/core/ffmpeg"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
)
|
||||
|
||||
func DecodeMp3(path string) (s beep.StreamSeekCloser, format beep.Format, err error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, beep.Format{}, err
|
||||
}
|
||||
return mp3.Decode(f)
|
||||
}
|
||||
|
||||
func DecodeWAV(path string) (s beep.StreamSeekCloser, format beep.Format, err error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, beep.Format{}, err
|
||||
}
|
||||
return wav.Decode(f)
|
||||
}
|
||||
|
||||
func DecodeFLAC(path string) (s beep.StreamSeekCloser, format beep.Format, fileToCleanup string, err error) {
|
||||
// TODO: Turn this into a semi-parallel operation: start playing while still transcoding/copying
|
||||
log.Debug("decode to FLAC", "filename", path)
|
||||
fFmpeg := ffmpeg.New()
|
||||
readCloser, err := fFmpeg.ConvertToFLAC(context.TODO(), path)
|
||||
if err != nil {
|
||||
log.Error("error converting file to FLAC", path, err)
|
||||
return nil, beep.Format{}, "", err
|
||||
}
|
||||
|
||||
tempFile, err := os.CreateTemp("", "*.flac")
|
||||
|
||||
if err != nil {
|
||||
log.Error("error creating temp file", err)
|
||||
return nil, beep.Format{}, "", err
|
||||
}
|
||||
log.Debug("created tempfile", "filename", tempFile.Name())
|
||||
|
||||
written, err := io.Copy(tempFile, readCloser)
|
||||
if err != nil {
|
||||
log.Error("error coping file", "dest", tempFile.Name())
|
||||
}
|
||||
log.Debug("copy pipe into tempfile", "bytes written", written, "filename", tempFile.Name())
|
||||
|
||||
f, err := os.Open(tempFile.Name())
|
||||
if err != nil {
|
||||
log.Error("could not re-open tempfile", "filename", tempFile.Name())
|
||||
return nil, beep.Format{}, "", err
|
||||
}
|
||||
|
||||
s, format, err = flac.Decode(f)
|
||||
return s, format, tempFile.Name(), err
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
//go:build beep
|
||||
|
||||
package beepaudio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/faiface/beep"
|
||||
"github.com/faiface/beep/effects"
|
||||
"github.com/faiface/beep/speaker"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
)
|
||||
|
||||
type BeepTrack struct {
|
||||
MediaFile model.MediaFile
|
||||
Ctrl *beep.Ctrl
|
||||
Volume *effects.Volume
|
||||
ActiveStream beep.StreamSeekCloser
|
||||
TempfileToCleanup string
|
||||
SampleRate beep.SampleRate
|
||||
PlaybackDone chan bool
|
||||
}
|
||||
|
||||
func NewTrack(playbackDoneChannel chan bool, mf model.MediaFile) (*BeepTrack, error) {
|
||||
t := BeepTrack{}
|
||||
|
||||
contentType := mf.ContentType()
|
||||
log.Debug("loading track", "trackname", mf.Path, "mediatype", contentType)
|
||||
|
||||
var streamer beep.StreamSeekCloser
|
||||
var format beep.Format
|
||||
var err error
|
||||
var tmpfileToCleanup = ""
|
||||
|
||||
switch contentType {
|
||||
case "audio/mpeg":
|
||||
streamer, format, err = DecodeMp3(mf.Path)
|
||||
case "audio/x-wav":
|
||||
streamer, format, err = DecodeWAV(mf.Path)
|
||||
case "audio/mp4":
|
||||
streamer, format, tmpfileToCleanup, err = DecodeFLAC(mf.Path)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported content type: %s", contentType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// save running stream for closing when switching tracks
|
||||
t.ActiveStream = streamer
|
||||
t.TempfileToCleanup = tmpfileToCleanup
|
||||
|
||||
log.Debug("Setting up audio device")
|
||||
t.Ctrl = &beep.Ctrl{Streamer: streamer, Paused: true}
|
||||
t.Volume = &effects.Volume{Streamer: t.Ctrl, Base: 2}
|
||||
t.SampleRate = format.SampleRate
|
||||
t.PlaybackDone = playbackDoneChannel
|
||||
t.MediaFile = mf
|
||||
|
||||
err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
log.Debug("speaker.Init() finished")
|
||||
|
||||
go func() {
|
||||
speaker.Play(beep.Seq(t.Volume, beep.Callback(func() {
|
||||
log.Info("Hitting end-of-stream, signalling on channel")
|
||||
t.PlaybackDone <- true
|
||||
log.Debug("Signalling finished")
|
||||
})))
|
||||
log.Debug("dropping out of speaker.Play()")
|
||||
}()
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (t *BeepTrack) String() string {
|
||||
return fmt.Sprintf("Name: %s", t.MediaFile.Path)
|
||||
}
|
||||
|
||||
func (t *BeepTrack) SetVolume(value float64) {
|
||||
speaker.Lock()
|
||||
t.Volume.Volume += value
|
||||
speaker.Unlock()
|
||||
}
|
||||
|
||||
func (t *BeepTrack) Unpause() {
|
||||
speaker.Lock()
|
||||
if t.Ctrl.Paused {
|
||||
t.Ctrl.Paused = false
|
||||
} else {
|
||||
log.Debug("tried to unpause while not paused")
|
||||
}
|
||||
speaker.Unlock()
|
||||
}
|
||||
|
||||
func (t *BeepTrack) Pause() {
|
||||
speaker.Lock()
|
||||
if t.Ctrl.Paused {
|
||||
log.Debug("tried to pause while already paused")
|
||||
} else {
|
||||
t.Ctrl.Paused = true
|
||||
}
|
||||
speaker.Unlock()
|
||||
}
|
||||
|
||||
func (t *BeepTrack) Close() {
|
||||
if t.ActiveStream != nil {
|
||||
log.Debug("closing activ stream")
|
||||
t.ActiveStream.Close()
|
||||
t.ActiveStream = nil
|
||||
}
|
||||
|
||||
speaker.Close()
|
||||
|
||||
if t.TempfileToCleanup != "" {
|
||||
log.Debug("Removing tempfile", "tmpfilename", t.TempfileToCleanup)
|
||||
err := os.Remove(t.TempfileToCleanup)
|
||||
if err != nil {
|
||||
log.Error("error cleaning up tempfile: ", t.TempfileToCleanup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Position returns the playback position in seconds
|
||||
func (t *BeepTrack) Position() int {
|
||||
if t.Ctrl.Streamer == nil {
|
||||
log.Debug("streamer is not setup (nil), could not get position")
|
||||
return 0
|
||||
}
|
||||
|
||||
streamer, ok := t.Ctrl.Streamer.(beep.StreamSeeker)
|
||||
if ok {
|
||||
position := t.SampleRate.D(streamer.Position())
|
||||
posSecs := position.Round(time.Second).Seconds()
|
||||
return int(posSecs)
|
||||
} else {
|
||||
log.Debug("streamer is no beep.StreamSeeker, could not get position")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// offset = pd.PlaybackQueue.Offset
|
||||
func (t *BeepTrack) SetPosition(offset int) error {
|
||||
streamer, ok := t.Ctrl.Streamer.(beep.StreamSeeker)
|
||||
if ok {
|
||||
sampleRatePerSecond := t.SampleRate.N(time.Second)
|
||||
nextPosition := sampleRatePerSecond * offset
|
||||
log.Debug("SetPosition", "samplerate", sampleRatePerSecond, "nextPosition", nextPosition)
|
||||
return streamer.Seek(nextPosition)
|
||||
}
|
||||
return fmt.Errorf("streamer is not seekable")
|
||||
}
|
||||
|
||||
func (t *BeepTrack) IsPlaying() bool {
|
||||
return t.Ctrl != nil && !t.Ctrl.Paused
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package playback implements audio playback using PlaybackDevices. It is used to implement the Jukebox mode in turn.
|
||||
// It makes use of the BEEP library to do the playback. Major parts are:
|
||||
// It makes use of the MPV library to do the playback. Major parts are:
|
||||
// - decoder which includes decoding and transcoding of various audio file formats
|
||||
// - device implementing the basic functions to work with audio devices like set, play, stop, skip, ...
|
||||
// - queue a simple playlist
|
||||
|
||||
Reference in New Issue
Block a user