audio/internal/go2cpp: Recreate the underlying audio player when resetting

This commit is contained in:
Hajime Hoshi 2021-01-12 11:29:23 +09:00
parent a66097df19
commit 2f8172f819

View File

@ -38,16 +38,14 @@ func (c *Context) NewPlayer(r io.Reader) *Player {
cond.Signal() cond.Signal()
return nil return nil
}) })
v := c.v.Call("createPlayer", onwritten)
p := &Player{ p := &Player{
context: c,
src: r, src: r,
v: v, volume: 1,
cond: cond, cond: cond,
onWritten: onwritten, onWritten: onwritten,
} }
runtime.SetFinalizer(p, (*Player).Close) runtime.SetFinalizer(p, (*Player).Close)
go p.loop()
return p return p
} }
@ -61,15 +59,16 @@ const (
playerStatePaused playerState = iota playerStatePaused playerState = iota
playerStatePlaying playerStatePlaying
playerStateClosed playerStateClosed
playerStateError
) )
type Player struct { type Player struct {
src io.Reader context *Context
v js.Value src io.Reader
state playerState v js.Value
cond *sync.Cond state playerState
err error volume float64
cond *sync.Cond
err error
onWritten js.Func onWritten js.Func
} }
@ -81,6 +80,10 @@ func (p *Player) Pause() {
if p.state == playerStateClosed { if p.state == playerStateClosed {
return return
} }
if !p.v.Truthy() {
return
}
p.v.Call("pause") p.v.Call("pause")
p.state = playerStatePaused p.state = playerStatePaused
p.cond.Signal() p.cond.Signal()
@ -93,6 +96,12 @@ func (p *Player) Play() {
if p.state == playerStateClosed { if p.state == playerStateClosed {
return return
} }
if !p.v.Truthy() {
p.v = p.context.v.Call("createPlayer", p.onWritten)
p.v.Set("volume", p.volume)
go p.loop()
}
p.v.Call("play") p.v.Call("play")
p.state = playerStatePlaying p.state = playerStatePlaying
p.cond.Signal() p.cond.Signal()
@ -105,45 +114,63 @@ func (p *Player) Reset() {
if p.state == playerStateClosed { if p.state == playerStateClosed {
return return
} }
if !p.v.Truthy() {
return
}
p.v.Call("reset") p.v.Call("close", true)
p.v = js.Undefined()
p.cond.Signal() p.cond.Signal()
} }
func (p *Player) Volume() float64 { func (p *Player) Volume() float64 {
if !p.v.Truthy() {
return p.volume
}
return p.v.Get("volume").Float() return p.v.Get("volume").Float()
} }
func (p *Player) SetVolume(volume float64) { func (p *Player) SetVolume(volume float64) {
if !p.v.Truthy() {
return
}
p.v.Set("volume", volume) p.v.Set("volume", volume)
p.volume = volume
} }
func (p *Player) Close() error { func (p *Player) Close() error {
runtime.SetFinalizer(p, nil) runtime.SetFinalizer(p, nil)
return p.close(true)
}
func (p *Player) close(remove bool) error {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
if p.state == playerStateError { if p.state == playerStateClosed {
return p.err return p.err
} }
p.v.Call("close") p.v.Call("close", false)
p.state = playerStateClosed p.v = js.Undefined()
if remove {
p.state = playerStateClosed
p.onWritten.Release()
} else {
p.state = playerStatePaused
}
p.cond.Signal() p.cond.Signal()
p.onWritten.Release() return p.err
return nil
} }
func (p *Player) setError(err error) { func (p *Player) setError(err error) {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
if p.state == playerStateError { if p.state != playerStateClosed && p.v.Truthy() {
return p.v.Call("close", true)
p.v = js.Undefined()
} }
p.v.Call("close")
p.err = err p.err = err
p.state = playerStateClosed p.state = playerStateClosed
p.cond.Signal() p.cond.Signal()
@ -153,10 +180,10 @@ func (p *Player) waitUntilUnpaused() bool {
p.cond.L.Lock() p.cond.L.Lock()
defer p.cond.L.Unlock() defer p.cond.L.Unlock()
for p.state == playerStatePaused || (p.state == playerStatePlaying && !p.v.Call("isWritable").Bool()) { for p.v.Truthy() && (p.state == playerStatePaused || (p.state == playerStatePlaying && !p.v.Call("isWritable").Bool())) {
p.cond.Wait() p.cond.Wait()
} }
return p.state == playerStatePlaying return p.v.Truthy() && p.state == playerStatePlaying
} }
func (p *Player) loop() { func (p *Player) loop() {
@ -181,8 +208,7 @@ func (p *Player) loop() {
} }
if err == io.EOF { if err == io.EOF {
// TODO: This should be Pause instead of Close for Rewind p.close(false)
p.Close()
return return
} }
} }