switch back to using HTTP server to stream file to MPV - it doesn't idle after playing FIFO

This commit is contained in:
Drew Weymouth
2025-07-27 17:39:48 -07:00
parent 9844bbf6cb
commit 333b96dd3b
3 changed files with 14 additions and 81 deletions
-1
View File
@@ -119,7 +119,6 @@ func (p *PlaybackManager) addOnTrackChangeHook() {
case <-ctx.Done():
return
default:
log.Println("updating waveform img, job step", job.step)
img := job.Get()
for _, cb := range p.onWaveformImgUpdate {
cb(img)
+2 -8
View File
@@ -51,7 +51,6 @@ func (fs *FileStreamerServer) Serve() error {
_ = fs.server.Serve(fs.listener)
}()
log.Println("Serving and WAITING for done")
<-fs.done // wait for the handler to finish
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
@@ -61,13 +60,9 @@ func (fs *FileStreamerServer) Serve() error {
}
// Handler that streams the file using chunked transfer encoding.
func (fs *FileStreamerServer) streamHandler(w http.ResponseWriter, r *http.Request) {
log.Println("FILE STREAMER REQUEST")
func (fs *FileStreamerServer) streamHandler(w http.ResponseWriter, _ *http.Request) {
defer close(fs.done) // signal Serve() to shut down after this request
totalWrote := 0
defer log.Println("File streamer wrote", totalWrote, "bytes")
file, err := os.Open(fs.Path)
if err != nil {
log.Println("File streamer failed to open source file")
@@ -92,7 +87,7 @@ func (fs *FileStreamerServer) streamHandler(w http.ResponseWriter, r *http.Reque
}
if n > 0 {
written, err := w.Write(buf[:n])
_, err := w.Write(buf[:n])
if err != nil {
log.Printf("client write error: %v", err)
break
@@ -100,7 +95,6 @@ func (fs *FileStreamerServer) streamHandler(w http.ResponseWriter, r *http.Reque
if canFlush {
flusher.Flush()
}
totalWrote += written
}
if n == 0 && complete {
+12 -72
View File
@@ -15,10 +15,10 @@ import (
"time"
"github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/backend/util"
"github.com/go-audio/audio"
"github.com/go-audio/wav"
"github.com/supersonic-app/go-mpv"
"golang.org/x/sys/unix"
)
type WaveformImageGenerator struct {
@@ -135,9 +135,17 @@ func (w *WaveformImageGenerator) StartWaveformGeneration(item *mediaprovider.Tra
// stream it to MPV via fifo so it doesn't possibly
// terminate the conversion to WAV early encountering EOF
if !fileDone() {
fifoPath := filepath.Join(filepath.Dir(path), filepath.Base(path)+"_fifo")
copyFileToFifo(ctx, job, path, fifoPath, fileDone)
path = fifoPath // MPV will read from the FIFO
srv, err := util.NewFileStreamerServer(path, fileDone)
if err != nil {
job.setError(err)
return
}
path = srv.Addr()
log.Println("streaming file to MPV at ", path)
go srv.Serve()
time.Sleep(10 * time.Millisecond) // make sure server has time to come up
}
// Start converting the file to WAV for analysis
@@ -237,71 +245,6 @@ func generateWaveformImage(ctx context.Context, data *waveformData, job *Wavefor
}
}
func copyFileToFifo(ctx context.Context, job *WaveformImageJob, filePath, fifoPath string, fileDone func() bool) {
if err := unix.Mkfifo(fifoPath, 0600); err != nil {
job.setError(err)
return
}
go func() {
fifo, err := os.OpenFile(fifoPath, os.O_WRONLY, os.ModeNamedPipe)
if err != nil {
job.setError(err)
return
}
file, err := os.Open(filePath)
if err != nil {
job.setError(err)
return
}
defer file.Close()
defer fifo.Close()
buf := make([]byte, 4096)
offset := int64(0)
for {
if e := ctx.Err(); e != nil {
job.setError(e)
return
}
done := fileDone()
info, err := os.Stat(filePath)
if err != nil {
job.setError(err)
return
}
currentSize := info.Size()
// If we've read everything available so far
if offset >= currentSize {
if done {
return // done
}
// wait a bit for more data to be written to file
time.Sleep(50 * time.Millisecond)
continue
}
// Calculate how much is safe to read
toRead := currentSize - offset - 1
if toRead > int64(cap(buf)) {
toRead = int64(cap(buf))
}
n, err := file.ReadAt(buf[:toRead], offset)
if n > 0 {
if _, werr := fifo.Write(buf[:n]); werr != nil {
job.setError(werr)
return
}
offset += int64(n)
}
}
}()
}
// assumes mono, 16 bit
func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformData, millisecs int64, fileDone func() bool) error {
f, err := os.Open(transcodeFile)
@@ -379,8 +322,6 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
if err == io.EOF && !fileDone() {
return errors.New("WAV read got premature EOF")
}
} else if fileIsDone {
log.Println("read samples on done file")
}
if err != nil {
return err
@@ -401,7 +342,6 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
data.progress = curChunk
chunkSamples = chunkSamples[:0]
if curChunk >= 1024 {
doneReading = true
break
}
}