mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
audio: Close audio after its playing finishes
Fixes #746 This is a temporal fix and we will need further re-designing of audio package.
This commit is contained in:
parent
732b036343
commit
b0cb216f5f
@ -124,6 +124,9 @@ func (p *players) Read(b []byte) (int, error) {
|
||||
}
|
||||
}
|
||||
for _, player := range closed {
|
||||
if player.isFinalized() {
|
||||
player.closeImpl()
|
||||
}
|
||||
delete(p.players, player)
|
||||
}
|
||||
|
||||
@ -353,6 +356,8 @@ type playerImpl struct {
|
||||
proceedCh chan []int16
|
||||
proceededCh chan proceededValues
|
||||
syncCh chan func()
|
||||
|
||||
finalized bool
|
||||
}
|
||||
|
||||
type seekArgs struct {
|
||||
@ -407,7 +412,7 @@ func NewPlayer(context *Context, src io.ReadCloser) (*Player, error) {
|
||||
}
|
||||
p.p.pos = pos
|
||||
}
|
||||
runtime.SetFinalizer(p, (*Player).Close)
|
||||
runtime.SetFinalizer(p, (*Player).finalize)
|
||||
|
||||
go func() {
|
||||
p.p.readLoop()
|
||||
@ -433,6 +438,30 @@ func NewPlayerFromBytes(context *Context, src []byte) (*Player, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *Player) finalize() {
|
||||
runtime.SetFinalizer(p, nil)
|
||||
p.p.setFinalized(true)
|
||||
// TODO: It is really hard to say concurrent safety.
|
||||
// Refactor this package to reduce goroutines.
|
||||
if !p.IsPlaying() {
|
||||
p.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *playerImpl) setFinalized(finalized bool) {
|
||||
p.sync(func() {
|
||||
p.finalized = finalized
|
||||
})
|
||||
}
|
||||
|
||||
func (p *playerImpl) isFinalized() bool {
|
||||
b := false
|
||||
p.sync(func() {
|
||||
b = p.finalized
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Close closes the stream.
|
||||
//
|
||||
// When closing, the stream owned by the player will also be closed by calling its Close.
|
||||
@ -446,7 +475,10 @@ func (p *Player) Close() error {
|
||||
|
||||
func (p *playerImpl) Close() error {
|
||||
p.players.removePlayer(p)
|
||||
return p.closeImpl()
|
||||
}
|
||||
|
||||
func (p *playerImpl) closeImpl() error {
|
||||
select {
|
||||
case p.closeCh <- struct{}{}:
|
||||
<-p.closedCh
|
||||
|
@ -15,12 +15,34 @@
|
||||
package audio_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
. "github.com/hajimehoshi/ebiten/audio"
|
||||
"github.com/hajimehoshi/ebiten/internal/testflock"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testflock.Lock()
|
||||
defer testflock.Unlock()
|
||||
|
||||
code := 0
|
||||
// Run an Ebiten process so that audio is available.
|
||||
regularTermination := errors.New("regular termination")
|
||||
f := func(screen *ebiten.Image) error {
|
||||
code = m.Run()
|
||||
return regularTermination
|
||||
}
|
||||
if err := ebiten.Run(f, 320, 240, 1, "Test"); err != nil && err != regularTermination {
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
var context *Context
|
||||
|
||||
func init() {
|
||||
@ -48,6 +70,9 @@ func TestGC(t *testing.T) {
|
||||
runtime.KeepAlive(p)
|
||||
p = nil
|
||||
runtime.GC()
|
||||
// 100[ms] should be enough all the bytes are consumed.
|
||||
// TODO: This is a darty hack. Would it be possible to use virtual time?
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
got = PlayersNumForTesting()
|
||||
if want := 0; got != want {
|
||||
t.Errorf("PlayersNum() after GC: got: %d, want: %d", got, want)
|
||||
|
Loading…
Reference in New Issue
Block a user