mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
audio: Skip the player in the state of starting, seeking or EOF
This is basically reland of
2fee7a6fe5
.
Before this change, if a player's buffer was not enough for
reading, 0 value were used and this caused noises. The reading
size should be aligned with all the players.
However, there are some cases that the player should be skippped.
For example, just after a player just starts playing or seeking,
the buffer is empty. In this case, other players should not wait
for the player since decoding might take some time. Another case
is that the player reached EOF.
This change aligns the read buffer sizes but use zero values only
when the player just starts or seeks, or reaches EOF.
This commit is contained in:
parent
facf184548
commit
273093b237
@ -74,6 +74,25 @@ func (p *players) Read(b []byte) (int, error) {
|
||||
l := len(b)
|
||||
l &= mask
|
||||
|
||||
for player := range p.players {
|
||||
if player.shouldSkip() {
|
||||
continue
|
||||
}
|
||||
s := player.bufferSizeInBytes()
|
||||
if l > s {
|
||||
l = s
|
||||
l &= mask
|
||||
}
|
||||
}
|
||||
|
||||
if l == 0 {
|
||||
// If l is 0, all the players might reach EOF at the next update.
|
||||
// However, this Read might block forever and never causes context switch
|
||||
// on single-thread environment (e.g. browser).
|
||||
// Call Gosched to cause context switch on purpose.
|
||||
runtime.Gosched()
|
||||
}
|
||||
|
||||
b16s := [][]int16{}
|
||||
for player := range p.players {
|
||||
buf, err := player.bufferToInt16(l)
|
||||
@ -82,6 +101,7 @@ func (p *players) Read(b []byte) (int, error) {
|
||||
}
|
||||
b16s = append(b16s, buf)
|
||||
}
|
||||
|
||||
for i := 0; i < l/2; i++ {
|
||||
x := 0
|
||||
for _, b16 := range b16s {
|
||||
@ -349,7 +369,7 @@ func NewPlayer(context *Context, src io.ReadCloser) (*Player, error) {
|
||||
players: context.players,
|
||||
src: src,
|
||||
sampleRate: context.sampleRate,
|
||||
buf: []byte{},
|
||||
buf: nil,
|
||||
volume: 1,
|
||||
closeCh: make(chan struct{}),
|
||||
closedCh: make(chan struct{}),
|
||||
@ -526,13 +546,15 @@ func (p *Player) readLoop() {
|
||||
return
|
||||
}
|
||||
|
||||
lengthInBytes := len(buf) * 2
|
||||
l := lengthInBytes
|
||||
|
||||
if len(p.buf) < lengthInBytes && !p.srcEOF {
|
||||
if p.shouldSkipImpl() {
|
||||
// Return zero values.
|
||||
p.proceededCh <- proceededValues{buf, nil}
|
||||
break
|
||||
}
|
||||
|
||||
lengthInBytes := len(buf) * 2
|
||||
l := lengthInBytes
|
||||
|
||||
if l > len(p.buf) {
|
||||
l = len(p.buf)
|
||||
}
|
||||
@ -543,7 +565,7 @@ func (p *Player) readLoop() {
|
||||
p.pos += int64(l)
|
||||
p.buf = p.buf[l:]
|
||||
|
||||
p.proceededCh <- proceededValues{buf, nil}
|
||||
p.proceededCh <- proceededValues{buf[:l/2], nil}
|
||||
|
||||
case f := <-p.syncCh:
|
||||
f()
|
||||
@ -566,14 +588,46 @@ func (p *Player) sync(f func()) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) shouldSkip() bool {
|
||||
r := false
|
||||
p.sync(func() {
|
||||
r = p.shouldSkipImpl()
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *Player) shouldSkipImpl() bool {
|
||||
// When p.buf is nil, the player just starts playing or seeking.
|
||||
// Note that this is different from len(p.buf) == 0 && p.buf != nil.
|
||||
if p.buf == nil {
|
||||
return true
|
||||
}
|
||||
if p.eofImpl() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Player) bufferSizeInBytes() int {
|
||||
s := 0
|
||||
p.sync(func() {
|
||||
s = len(p.buf)
|
||||
})
|
||||
return s
|
||||
}
|
||||
|
||||
func (p *Player) eof() bool {
|
||||
r := false
|
||||
p.sync(func() {
|
||||
r = p.srcEOF && len(p.buf) == 0
|
||||
r = p.eofImpl()
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *Player) eofImpl() bool {
|
||||
return p.srcEOF && len(p.buf) == 0
|
||||
}
|
||||
|
||||
// IsPlaying returns boolean indicating whether the player is playing.
|
||||
func (p *Player) IsPlaying() bool {
|
||||
return p.players.hasPlayer(p)
|
||||
|
Loading…
Reference in New Issue
Block a user