audio/internal/readdriver: Bug fix: Potential busy loop on Android

This is basically the same fix as 91d3d6b4e7
but for Android.

Updates #1650
This commit is contained in:
Hajime Hoshi 2021-05-26 12:46:37 +09:00
parent 8692ba5f06
commit 46ed239632

View File

@ -72,6 +72,7 @@ type player struct {
cond *sync.Cond cond *sync.Cond
closed bool closed bool
volume float64 volume float64
eof bool
} }
func (p *player) Pause() { func (p *player) Pause() {
@ -158,7 +159,10 @@ func (p *player) IsPlaying() bool {
func (p *player) Reset() { func (p *player) Reset() {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
p.resetImpl()
}
func (p *player) resetImpl() {
if p.err != nil { if p.err != nil {
return return
} }
@ -173,6 +177,7 @@ func (p *player) Reset() {
return return
} }
p.p = nil p.p = nil
p.eof = false
p.cond.Signal() p.cond.Signal()
} }
@ -195,6 +200,10 @@ func (p *player) SetVolume(volume float64) {
func (p *player) UnplayedBufferSize() int { func (p *player) UnplayedBufferSize() int {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
return p.unplayedBufferSizeImpl()
}
func (p *player) unplayedBufferSizeImpl() int {
if p.p == nil { if p.p == nil {
return 0 return 0
} }
@ -248,10 +257,18 @@ func (p *player) shouldWait() bool {
if p.p == nil { if p.p == nil {
return false return false
} }
if p.p.IsPlaying() {
return p.p.UnplayedBufferSize() >= p.context.maxBufferSize() // Wait when the player is paused.
if !p.p.IsPlaying() {
return true
} }
return true
// When the source reaches EOF, wait until all the data is consumed.
if p.eof {
return p.p.UnplayedBufferSize() > 0
}
return p.p.UnplayedBufferSize() >= p.context.maxBufferSize()
} }
func (p *player) wait() bool { func (p *player) wait() bool {
@ -291,13 +308,21 @@ func (p *player) loop() {
} }
p.write(buf[:n]) p.write(buf[:n])
// Now p.p.Reset() doesn't close the stream gracefully. Then buffer size check is necessary here. p.cond.L.Lock()
if err == io.EOF && p.UnplayedBufferSize() == 0 { if err == io.EOF {
// Even when the unplayed buffer size is 0, the audio data in the hardware might not be played yet (#1632). p.eof = true
}
// Now p.resetImpl() doesn't close the stream gracefully. Then buffer size check is necessary here.
if p.eof && p.unplayedBufferSizeImpl() == 0 {
// Even when the unplayed buffer size is 0,
// the audio data in the hardware might not be played yet (#1632).
// Just wait for a while. // Just wait for a while.
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
p.Reset() p.resetImpl()
p.cond.L.Unlock()
return return
} }
p.cond.L.Unlock()
} }
} }