Resolve audio race condition

This commit is contained in:
Trevor Slocum 2020-01-09 15:51:37 -08:00
parent c188b01860
commit 93203a318a
6 changed files with 94 additions and 65 deletions

View file

@ -87,9 +87,11 @@ func play(audioFile *AudioFile) {
audioLock.Lock()
defer audioLock.Unlock()
speaker.Lock()
if playingStreamer != nil {
playingStreamer.Close()
}
speaker.Unlock()
thisFileID := time.Now().UnixNano()
@ -108,11 +110,13 @@ func play(audioFile *AudioFile) {
}
if audioFile.Format.SampleRate != playingSampleRate {
speaker.Clear()
err := speaker.Init(audioFile.Format.SampleRate, audioFile.Format.SampleRate.N(time.Second/2))
if err != nil {
log.Fatalf("failed to initialize audio device: %s", err)
}
playingSampleRate = audioFile.Format.SampleRate
} else {
speaker.Clear()
}
var (
@ -144,9 +148,8 @@ func play(audioFile *AudioFile) {
Paused: false,
}
speaker.Clear()
speaker.Play(ctrl)
app.QueueUpdateDraw(func() {
go app.QueueUpdateDraw(func() {
updateMain()
updateQueue()
updateStatus()
@ -164,7 +167,7 @@ func nextTrack() {
}
play(audioFile)
app.QueueUpdateDraw(updateMain)
go app.QueueUpdateDraw(updateMain)
}
}
@ -201,3 +204,16 @@ func fileFormat(fileName string) string {
return "?"
}
}
func closeAudio() {
audioLock.Lock()
defer audioLock.Unlock()
speaker.Lock()
if playingStreamer != nil {
playingStreamer.Close()
}
speaker.Unlock()
speaker.Close()
}

45
gui.go
View file

@ -5,20 +5,16 @@ import (
"fmt"
"math"
"os"
"path"
"path/filepath"
"strings"
"sync"
"time"
"github.com/mattn/go-runewidth"
"github.com/gdamore/tcell"
"github.com/faiface/beep"
"git.sr.ht/~tslocum/cview"
"github.com/faiface/beep"
"github.com/faiface/beep/speaker"
"github.com/gdamore/tcell"
"github.com/mattn/go-runewidth"
)
var (
@ -98,9 +94,10 @@ func browseFolder(browse string) {
} else {
mainBufferCursor = 0
}
mainBufferOrigin = 0
mainBufferDirectory = browse
app.QueueUpdateDraw(updateMain)
go app.QueueUpdateDraw(updateMain)
}
func updateMain() {
@ -204,6 +201,7 @@ func updateStatus() {
var paused bool
var silent bool
if playingStreamer != nil && volume != nil && ctrl != nil {
audioLock.Lock()
speaker.Lock()
silent = volume.Silent
paused = ctrl.Paused
@ -212,6 +210,7 @@ func updateStatus() {
l = playingFormat.SampleRate.D(playingStreamer.Len()).Truncate(time.Second)
v = volume.Volume
speaker.Unlock()
audioLock.Unlock()
statusBuffer.Reset()
@ -322,33 +321,3 @@ func handleResize(screen tcell.Screen) {
updateQueue()
updateStatus()
}
func selectTrack() {
if mainBufferCursor == 0 {
browseFolder(path.Join(mainBufferDirectory, ".."))
return
}
nextStreamer = nil
nextFormat = beep.Format{}
entry := selectedEntry()
if entry.File.IsDir() {
browseFolder(path.Join(mainBufferDirectory, path.Base(entry.File.Name())))
return
}
audioFile, err := openFile(path.Join(mainBufferDirectory, entry.File.Name()), entry.Metadata)
if err != nil {
statusText = err.Error()
go func() {
time.Sleep(5 * time.Second)
statusText = ""
app.QueueUpdateDraw(updateMain)
}()
app.QueueUpdateDraw(updateMain)
return
}
go play(audioFile)
app.QueueUpdateDraw(updateStatus)
}

View file

@ -23,7 +23,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
}
speaker.Unlock()
updateStatus()
go app.QueueUpdateDraw(updateStatus)
return nil
case '+':
audioLock.Lock()
@ -41,7 +41,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
volume.Silent = false
speaker.Unlock()
updateStatus()
go app.QueueUpdateDraw(updateStatus)
return nil
case ' ':
audioLock.Lock()
@ -55,7 +55,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
ctrl.Paused = !ctrl.Paused
speaker.Unlock()
updateStatus()
go app.QueueUpdateDraw(updateStatus)
return nil
case 'j':
listNext()
@ -70,7 +70,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
}
listPrevious()
go selectTrack()
go listSelect()
}
return nil
case 'n':
@ -80,7 +80,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
}
listNext()
go selectTrack()
go listSelect()
}
return nil
case 'q':
@ -96,7 +96,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
done <- true
return nil
case tcell.KeyEnter:
go selectTrack()
go listSelect()
return nil
case tcell.KeyDown:
listNext()
@ -110,7 +110,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
if mainBufferOrigin >= numEntries-(mainBufHeight-1) {
mainBufferCursor = numEntries
updateMain()
go app.QueueUpdateDraw(updateMain)
return nil
}
@ -120,13 +120,13 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
}
mainBufferCursor = mainBufferOrigin
updateMain()
go app.QueueUpdateDraw(updateMain)
return nil
case tcell.KeyPgUp:
if mainBufferOrigin == 0 {
mainBufferCursor = 0
updateMain()
go app.QueueUpdateDraw(updateMain)
return nil
}
@ -136,7 +136,7 @@ func handleKeyPress(event *tcell.EventKey) *tcell.EventKey {
}
mainBufferCursor = mainBufferOrigin
updateMain()
go app.QueueUpdateDraw(updateMain)
return nil
}
return event

View file

@ -1,5 +1,12 @@
package main
import (
"path"
"time"
"github.com/faiface/beep"
)
func listPrevious() {
if mainBufferOrigin > 0 && mainBufferCursor == mainBufferOrigin {
mainBufferOrigin--
@ -7,7 +14,8 @@ func listPrevious() {
if mainBufferCursor > 0 {
mainBufferCursor--
}
app.QueueUpdateDraw(updateMain)
go app.QueueUpdateDraw(updateMain)
}
func listNext() {
@ -17,7 +25,38 @@ func listNext() {
mainBufferOrigin++
}
}
app.QueueUpdateDraw(updateMain)
go app.QueueUpdateDraw(updateMain)
}
func listSelect() {
if mainBufferCursor == 0 {
browseFolder(path.Join(mainBufferDirectory, ".."))
return
}
nextStreamer = nil
nextFormat = beep.Format{}
entry := selectedEntry()
if entry.File.IsDir() {
browseFolder(path.Join(mainBufferDirectory, path.Base(entry.File.Name())))
return
}
audioFile, err := openFile(path.Join(mainBufferDirectory, entry.File.Name()), entry.Metadata)
if err != nil {
statusText = err.Error()
go func() {
time.Sleep(5 * time.Second)
statusText = ""
go app.QueueUpdateDraw(updateMain)
}()
go app.QueueUpdateDraw(updateMain)
return
}
go play(audioFile)
go app.QueueUpdateDraw(updateStatus)
}
func selectedEntry() *LibraryEntry {

View file

@ -17,8 +17,8 @@ func handleMouse(event *cview.EventMouse) *cview.EventMouse {
// TODO Delay playing while cursor is moved
if mouseY-1 < len(mainBufferFiles)+1 {
mainBufferCursor = mainBufferOrigin + (mouseY - 1)
app.QueueUpdateDraw(updateMain)
go selectTrack()
go app.QueueUpdateDraw(updateMain)
go listSelect()
}
return nil
} else if mouseY == screenHeight-1 {
@ -28,19 +28,21 @@ func handleMouse(event *cview.EventMouse) *cview.EventMouse {
go func() {
time.Sleep(5 * time.Second)
statusText = ""
app.QueueUpdateDraw(updateMain)
go app.QueueUpdateDraw(updateMain)
}()
app.QueueUpdateDraw(updateMain)
go app.QueueUpdateDraw(updateMain)
return nil
}
audioLock.Lock()
speaker.Lock()
seekTo := int(float64(playingStreamer.Len()) * (float64(mouseX-seekStart) / float64(seekEnd-seekStart)))
_ = playingStreamer.Seek(seekTo) // Ignore seek errors
speaker.Unlock()
audioLock.Unlock()
app.QueueUpdateDraw(updateStatus)
go app.QueueUpdateDraw(updateStatus)
return nil
} else if mouseX >= volumeStart && mouseX <= volumeEnd+1 {
if mouseX > volumeEnd {
@ -48,12 +50,15 @@ func handleMouse(event *cview.EventMouse) *cview.EventMouse {
}
if mouseX-volumeStart <= 3 {
audioLock.Lock()
speaker.Lock()
volume.Silent = !volume.Silent
speaker.Unlock()
audioLock.Unlock()
app.QueueUpdateDraw(updateStatus)
go app.QueueUpdateDraw(updateStatus)
} else {
audioLock.Lock()
speaker.Lock()
setVolume := -7.5 + float64(7.5)*(float64(mouseX-volumeStart-3)/float64(volumeEnd-volumeStart-3))
if setVolume < -7.0 {
@ -67,8 +72,9 @@ func handleMouse(event *cview.EventMouse) *cview.EventMouse {
volume.Silent = setVolume <= -7.5
speaker.Unlock()
audioLock.Unlock()
app.QueueUpdateDraw(updateStatus)
go app.QueueUpdateDraw(updateStatus)
}
return nil
}

View file

@ -103,7 +103,7 @@ func main() {
}
}
if startPath == "" {
log.Fatal("supply a folder to browse initially")
log.Fatal("supply a path to browse")
}
fileInfo, err := os.Stat(startPath)
if err != nil {
@ -125,9 +125,8 @@ func main() {
}
defer func() {
if playingStreamer != nil {
playingStreamer.Close()
}
closeAudio()
if app != nil {
app.Stop()
}