mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-13 20:42:07 +01:00
audio: Bug fix: Seek might cause dead lock after Close
This commit is contained in:
parent
db77658935
commit
04739a7249
@ -36,6 +36,7 @@ package audio
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
@ -331,7 +332,8 @@ type Player struct {
|
|||||||
volume float64
|
volume float64
|
||||||
|
|
||||||
closeCh chan struct{}
|
closeCh chan struct{}
|
||||||
closedCh chan error
|
closedCh chan struct{}
|
||||||
|
readLoopEndedCh chan struct{}
|
||||||
seekCh chan seekArgs
|
seekCh chan seekArgs
|
||||||
seekedCh chan error
|
seekedCh chan error
|
||||||
proceedCh chan []int16
|
proceedCh chan []int16
|
||||||
@ -371,7 +373,8 @@ func NewPlayer(context *Context, src ReadSeekCloser) (*Player, error) {
|
|||||||
buf: []byte{},
|
buf: []byte{},
|
||||||
volume: 1,
|
volume: 1,
|
||||||
closeCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
closedCh: make(chan error),
|
closedCh: make(chan struct{}),
|
||||||
|
readLoopEndedCh: make(chan struct{}),
|
||||||
seekCh: make(chan seekArgs),
|
seekCh: make(chan seekArgs),
|
||||||
seekedCh: make(chan error),
|
seekedCh: make(chan error),
|
||||||
proceedCh: make(chan []int16),
|
proceedCh: make(chan []int16),
|
||||||
@ -419,14 +422,23 @@ func (p *Player) Close() error {
|
|||||||
runtime.SetFinalizer(p, nil)
|
runtime.SetFinalizer(p, nil)
|
||||||
p.players.removePlayer(p)
|
p.players.removePlayer(p)
|
||||||
|
|
||||||
p.closeCh <- struct{}{}
|
select {
|
||||||
return <-p.closedCh
|
case p.closeCh <- struct{}{}:
|
||||||
|
<-p.closedCh
|
||||||
|
return nil
|
||||||
|
case <-p.readLoopEndedCh:
|
||||||
|
return fmt.Errorf("audio: the player is already closed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) bufferToInt16(lengthInBytes int) ([]int16, error) {
|
func (p *Player) bufferToInt16(lengthInBytes int) ([]int16, error) {
|
||||||
p.proceedCh <- make([]int16, lengthInBytes/2)
|
select {
|
||||||
|
case p.proceedCh <- make([]int16, lengthInBytes/2):
|
||||||
r := <-p.proceededCh
|
r := <-p.proceededCh
|
||||||
return r.buf, r.err
|
return r.buf, r.err
|
||||||
|
case <-p.readLoopEndedCh:
|
||||||
|
return nil, fmt.Errorf("audio: the player is already closed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play plays the stream.
|
// Play plays the stream.
|
||||||
@ -438,12 +450,18 @@ func (p *Player) Play() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) readLoop() {
|
func (p *Player) readLoop() {
|
||||||
|
defer func() {
|
||||||
|
// Note: the error is ignored
|
||||||
|
p.src.Close()
|
||||||
|
close(p.readLoopEndedCh)
|
||||||
|
}()
|
||||||
|
|
||||||
t := time.After(0)
|
t := time.After(0)
|
||||||
var readErr error
|
var readErr error
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-p.closeCh:
|
case <-p.closeCh:
|
||||||
p.closedCh <- p.src.Close()
|
p.closedCh <- struct{}{}
|
||||||
return
|
return
|
||||||
|
|
||||||
case s := <-p.seekCh:
|
case s := <-p.seekCh:
|
||||||
@ -549,8 +567,12 @@ func (p *Player) Rewind() error {
|
|||||||
func (p *Player) Seek(offset time.Duration) error {
|
func (p *Player) Seek(offset time.Duration) error {
|
||||||
o := int64(offset) * bytesPerSample * channelNum * int64(p.sampleRate) / int64(time.Second)
|
o := int64(offset) * bytesPerSample * channelNum * int64(p.sampleRate) / int64(time.Second)
|
||||||
o &= mask
|
o &= mask
|
||||||
p.seekCh <- seekArgs{o, io.SeekStart}
|
select {
|
||||||
|
case p.seekCh <- seekArgs{o, io.SeekStart}:
|
||||||
return <-p.seekedCh
|
return <-p.seekedCh
|
||||||
|
case <-p.readLoopEndedCh:
|
||||||
|
return fmt.Errorf("audio: the player is already closed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause pauses the playing.
|
// Pause pauses the playing.
|
||||||
|
Loading…
Reference in New Issue
Block a user