From e650e71d8c1e130f628734da82c5a43abfe633ce Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Tue, 20 Apr 2021 00:57:27 +0900 Subject: [PATCH] audio/internal/readerdriver: Bug fix: ReadFull could get stuck If the source io.Reader's implementation is not good (e.g., Read returns 0 if the buffer size is not multiples of 4), io.ReadFull gets stuck forever. Instead, use reguler Read with a decent amount of bytes buffer. Closes #1599 --- audio/internal/readerdriver/driver_js.go | 38 ++++++++++++++++++------ audio/readerplayer.go | 4 +-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/audio/internal/readerdriver/driver_js.go b/audio/internal/readerdriver/driver_js.go index e3cea5c5e..adc4d48f9 100644 --- a/audio/internal/readerdriver/driver_js.go +++ b/audio/internal/readerdriver/driver_js.go @@ -96,6 +96,7 @@ type playerImpl struct { state playerState gain js.Value err error + buf []byte nextPos float64 bufferSourceNodes []js.Value @@ -176,20 +177,38 @@ func (p *playerImpl) appendBuffer(this js.Value, args []js.Value) interface{} { p.nextPos = c + 1.0/60.0 } - bs := make([]byte, p.context.oneBufferSize()) - n, err := io.ReadFull(p.src, bs) - if err != nil { - if err != io.EOF && err != io.ErrUnexpectedEOF { + tmp := make([]byte, 4096) + need := p.context.oneBufferSize() + bs := make([]byte, 0, need) + for need > 0 { + if len(p.buf) > 0 { + n := len(p.buf) + if n > need { + n = need + } + bs = append(bs, p.buf[:n]...) + p.buf = p.buf[n:] + need -= n + continue + } + n, err := p.src.Read(tmp) + if err != nil && err != io.EOF { p.err = err p.Pause() return nil } - p.eof = true + if n > need { + p.buf = append(p.buf, tmp[need:]...) + n = need + } + bs = append(bs, tmp[:n]...) + need -= n + if err == io.EOF { + p.eof = true + break + } } - if n == 0 { - return nil - } - bs = bs[:n] + l, r := toLR(bs) tl, tr := float32SliceToTypedArray(l), float32SliceToTypedArray(r) @@ -234,6 +253,7 @@ func (p *playerImpl) Reset() { p.Pause() p.eof = false + p.buf = p.buf[:0] } func (p *playerImpl) Volume() float64 { diff --git a/audio/readerplayer.go b/audio/readerplayer.go index 415dd4029..3b4918235 100644 --- a/audio/readerplayer.go +++ b/audio/readerplayer.go @@ -15,7 +15,6 @@ package audio import ( - "fmt" "io" "runtime" "sync" @@ -243,7 +242,8 @@ func newTimeStream(r io.Reader, sampleRate int, maxBufferSize int) (*timeStream, func (s *timeStream) Unread(n int) { if s.unread+n > len(s.buf) { - panic(fmt.Sprintf("audio: too much unreading: %d, the buffer size: %d, unreading position: %d", n, len(s.buf), s.unread)) + // This should not happen usually, but the player's UnplayedBufferSize can include some errors. + n = len(s.buf) - s.unread } s.unread += n s.pos -= int64(n)