mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +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 {
|
for _, player := range closed {
|
||||||
|
if player.isFinalized() {
|
||||||
|
player.closeImpl()
|
||||||
|
}
|
||||||
delete(p.players, player)
|
delete(p.players, player)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,6 +356,8 @@ type playerImpl struct {
|
|||||||
proceedCh chan []int16
|
proceedCh chan []int16
|
||||||
proceededCh chan proceededValues
|
proceededCh chan proceededValues
|
||||||
syncCh chan func()
|
syncCh chan func()
|
||||||
|
|
||||||
|
finalized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type seekArgs struct {
|
type seekArgs struct {
|
||||||
@ -407,7 +412,7 @@ func NewPlayer(context *Context, src io.ReadCloser) (*Player, error) {
|
|||||||
}
|
}
|
||||||
p.p.pos = pos
|
p.p.pos = pos
|
||||||
}
|
}
|
||||||
runtime.SetFinalizer(p, (*Player).Close)
|
runtime.SetFinalizer(p, (*Player).finalize)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
p.p.readLoop()
|
p.p.readLoop()
|
||||||
@ -433,6 +438,30 @@ func NewPlayerFromBytes(context *Context, src []byte) (*Player, error) {
|
|||||||
return p, nil
|
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.
|
// Close closes the stream.
|
||||||
//
|
//
|
||||||
// When closing, the stream owned by the player will also be closed by calling its Close.
|
// 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 {
|
func (p *playerImpl) Close() error {
|
||||||
p.players.removePlayer(p)
|
p.players.removePlayer(p)
|
||||||
|
return p.closeImpl()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *playerImpl) closeImpl() error {
|
||||||
select {
|
select {
|
||||||
case p.closeCh <- struct{}{}:
|
case p.closeCh <- struct{}{}:
|
||||||
<-p.closedCh
|
<-p.closedCh
|
||||||
|
@ -15,12 +15,34 @@
|
|||||||
package audio_test
|
package audio_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten"
|
||||||
. "github.com/hajimehoshi/ebiten/audio"
|
. "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
|
var context *Context
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -48,6 +70,9 @@ func TestGC(t *testing.T) {
|
|||||||
runtime.KeepAlive(p)
|
runtime.KeepAlive(p)
|
||||||
p = nil
|
p = nil
|
||||||
runtime.GC()
|
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()
|
got = PlayersNumForTesting()
|
||||||
if want := 0; got != want {
|
if want := 0; got != want {
|
||||||
t.Errorf("PlayersNum() after GC: got: %d, want: %d", got, want)
|
t.Errorf("PlayersNum() after GC: got: %d, want: %d", got, want)
|
||||||
|
Loading…
Reference in New Issue
Block a user