audio: Lazy initialization at reader players

This commit is contained in:
Hajime Hoshi 2021-02-28 23:41:30 +09:00
parent dbdfce5fed
commit 4bc0bb607b

View File

@ -39,11 +39,12 @@ type readerDriverPlayer interface {
type readerPlayerFactory struct { type readerPlayerFactory struct {
driver readerDriver driver readerDriver
sampleRate int
} }
func newReaderPlayerFactory(sampleRate int) *readerPlayerFactory { func newReaderPlayerFactory(sampleRate int) *readerPlayerFactory {
return &readerPlayerFactory{ return &readerPlayerFactory{
driver: newReaderDriverImpl(sampleRate), sampleRate: sampleRate,
} }
// TODO: Consider the hooks. // TODO: Consider the hooks.
} }
@ -52,11 +53,11 @@ type readerPlayer struct {
context *Context context *Context
player readerDriverPlayer player readerDriverPlayer
src *timeStream src *timeStream
sampleRate int factory *readerPlayerFactory
m sync.Mutex m sync.Mutex
} }
func (c *readerPlayerFactory) newPlayerImpl(context *Context, src io.Reader) (playerImpl, error) { func (f *readerPlayerFactory) newPlayerImpl(context *Context, src io.Reader) (playerImpl, error) {
sampleRate := context.SampleRate() sampleRate := context.SampleRate()
s, err := newTimeStream(src, sampleRate) s, err := newTimeStream(src, sampleRate)
if err != nil { if err != nil {
@ -65,16 +66,31 @@ func (c *readerPlayerFactory) newPlayerImpl(context *Context, src io.Reader) (pl
p := &readerPlayer{ p := &readerPlayer{
context: context, context: context,
player: c.driver.NewPlayer(s),
src: s, src: s,
sampleRate: sampleRate, factory: f,
} }
return p, nil return p, nil
} }
func (p *readerPlayer) ensurePlayer() {
// Initialize the underlying player lazily to enable calling NewContext in an 'init' function.
// Accessing the underlying player functions requires the environment to be already initialized,
// but if Ebiten is used for a shared library, the timing when init functions are called
// is unexpectable.
// e.g. a variable for JVM on Android might not be set.
if p.factory.driver == nil {
p.factory.driver = newReaderDriverImpl(p.factory.sampleRate)
}
if p.player == nil {
p.player = p.factory.driver.NewPlayer(p.src)
}
// TODO: If some error happens, call p.context.setError().
}
func (p *readerPlayer) Play() { func (p *readerPlayer) Play() {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
p.player.Play() p.player.Play()
p.context.addPlayer(p) p.context.addPlayer(p)
@ -83,6 +99,7 @@ func (p *readerPlayer) Play() {
func (p *readerPlayer) Pause() { func (p *readerPlayer) Pause() {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
p.player.Pause() p.player.Pause()
} }
@ -90,6 +107,7 @@ func (p *readerPlayer) Pause() {
func (p *readerPlayer) IsPlaying() bool { func (p *readerPlayer) IsPlaying() bool {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
return p.player.IsPlaying() return p.player.IsPlaying()
} }
@ -97,6 +115,7 @@ func (p *readerPlayer) IsPlaying() bool {
func (p *readerPlayer) Volume() float64 { func (p *readerPlayer) Volume() float64 {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
return p.player.Volume() return p.player.Volume()
} }
@ -104,6 +123,7 @@ func (p *readerPlayer) Volume() float64 {
func (p *readerPlayer) SetVolume(volume float64) { func (p *readerPlayer) SetVolume(volume float64) {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
p.player.SetVolume(volume) p.player.SetVolume(volume)
} }
@ -111,6 +131,7 @@ func (p *readerPlayer) SetVolume(volume float64) {
func (p *readerPlayer) Close() error { func (p *readerPlayer) Close() error {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
p.context.removePlayer(p) p.context.removePlayer(p)
return p.player.Close() return p.player.Close()
@ -119,9 +140,10 @@ func (p *readerPlayer) Close() error {
func (p *readerPlayer) Current() time.Duration { func (p *readerPlayer) Current() time.Duration {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
sample := (p.src.Current() - p.player.UnwrittenBufferSize()) / bytesPerSample sample := (p.src.Current() - p.player.UnwrittenBufferSize()) / bytesPerSample
return time.Duration(sample) * time.Second / time.Duration(p.sampleRate) return time.Duration(sample) * time.Second / time.Duration(p.factory.sampleRate)
} }
func (p *readerPlayer) Rewind() error { func (p *readerPlayer) Rewind() error {
@ -131,6 +153,7 @@ func (p *readerPlayer) Rewind() error {
func (p *readerPlayer) Seek(offset time.Duration) error { func (p *readerPlayer) Seek(offset time.Duration) error {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()
p.ensurePlayer()
if p.player.IsPlaying() { if p.player.IsPlaying() {
defer func() { defer func() {