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
This commit is contained in:
Hajime Hoshi 2021-04-20 00:57:27 +09:00
parent 5b96439fed
commit e650e71d8c
2 changed files with 31 additions and 11 deletions

View File

@ -96,6 +96,7 @@ type playerImpl struct {
state playerState state playerState
gain js.Value gain js.Value
err error err error
buf []byte
nextPos float64 nextPos float64
bufferSourceNodes []js.Value 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 p.nextPos = c + 1.0/60.0
} }
bs := make([]byte, p.context.oneBufferSize()) tmp := make([]byte, 4096)
n, err := io.ReadFull(p.src, bs) need := p.context.oneBufferSize()
if err != nil { bs := make([]byte, 0, need)
if err != io.EOF && err != io.ErrUnexpectedEOF { 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.err = err
p.Pause() p.Pause()
return nil return nil
} }
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 p.eof = true
break
} }
if n == 0 {
return nil
} }
bs = bs[:n]
l, r := toLR(bs) l, r := toLR(bs)
tl, tr := float32SliceToTypedArray(l), float32SliceToTypedArray(r) tl, tr := float32SliceToTypedArray(l), float32SliceToTypedArray(r)
@ -234,6 +253,7 @@ func (p *playerImpl) Reset() {
p.Pause() p.Pause()
p.eof = false p.eof = false
p.buf = p.buf[:0]
} }
func (p *playerImpl) Volume() float64 { func (p *playerImpl) Volume() float64 {

View File

@ -15,7 +15,6 @@
package audio package audio
import ( import (
"fmt"
"io" "io"
"runtime" "runtime"
"sync" "sync"
@ -243,7 +242,8 @@ func newTimeStream(r io.Reader, sampleRate int, maxBufferSize int) (*timeStream,
func (s *timeStream) Unread(n int) { func (s *timeStream) Unread(n int) {
if s.unread+n > len(s.buf) { 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.unread += n
s.pos -= int64(n) s.pos -= int64(n)