Resolve audio race condition
This commit is contained in:
parent
c188b01860
commit
93203a318a
6 changed files with 94 additions and 65 deletions
24
audio.go
24
audio.go
|
@ -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
45
gui.go
|
@ -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)
|
||||
}
|
||||
|
|
20
gui_key.go
20
gui_key.go
|
@ -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
|
||||
|
|
43
gui_list.go
43
gui_list.go
|
@ -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 {
|
||||
|
|
20
gui_mouse.go
20
gui_mouse.go
|
@ -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
|
||||
}
|
||||
|
|
7
main.go
7
main.go
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue