audio: Refactoring

This commit is contained in:
Hajime Hoshi 2021-01-07 02:06:09 +09:00
parent e04e709a10
commit a6b3f32f3a
4 changed files with 44 additions and 30 deletions

View File

@ -48,6 +48,10 @@ const (
bytesPerSample = 2 * channelNum
)
type newPlayerImpler interface {
newPlayerImpl(context *Context, src io.Reader) (playerImpl, error)
}
// A Context represents a current state of audio.
//
// At most one Context object can exist in one process.
@ -55,7 +59,7 @@ const (
//
// For a typical usage example, see examples/wav/main.go.
type Context struct {
wc writerContext
np newPlayerImpler
// inited represents whether the audio device is initialized and available or not.
// On Android, audio loop cannot be started unless JVM is accessible. After updating one frame, JVM should exist.
@ -97,7 +101,7 @@ func NewContext(sampleRate int) *Context {
c := &Context{
sampleRate: sampleRate,
wc: newWriterContext(sampleRate),
np: newWriterContext(sampleRate),
players: map[playerImpl]struct{}{},
inited: make(chan struct{}),
semaphore: make(chan struct{}, 1),
@ -268,7 +272,7 @@ type playerImpl interface {
// A Player doesn't close src even if src implements io.Closer.
// Closing the source is src owner's responsibility.
func NewPlayer(context *Context, src io.Reader) (*Player, error) {
pi, err := newWriterContextPlayerImpl(context, context.wc, src)
pi, err := context.np.newPlayerImpl(context, src)
if err != nil {
return nil, err
}

View File

@ -19,15 +19,15 @@ import (
)
type (
dummyContext struct{}
dummyPlayer struct{}
dummyDriver struct{}
dummyPlayer struct{}
)
func (d *dummyContext) NewPlayer() io.WriteCloser {
func (d *dummyDriver) NewPlayer() io.WriteCloser {
return &dummyPlayer{}
}
func (d *dummyContext) Close() error {
func (d *dummyDriver) Close() error {
return nil
}
@ -40,7 +40,7 @@ func (p *dummyPlayer) Close() error {
}
func init() {
writerContextForTesting = &dummyContext{}
writerDriverForTesting = &dummyDriver{}
}
type dummyHook struct {

View File

@ -21,14 +21,14 @@ import (
"github.com/hajimehoshi/oto"
)
func newOtoContext(sampleRate int, initCh chan struct{}) *otoContext {
return &otoContext{
func newOtoDriver(sampleRate int, initCh chan struct{}) *otoDriver {
return &otoDriver{
sampleRate: sampleRate,
initCh: initCh,
}
}
type otoContext struct {
type otoDriver struct {
sampleRate int
initCh <-chan struct{}
@ -36,18 +36,18 @@ type otoContext struct {
once sync.Once
}
func (c *otoContext) NewPlayer() io.WriteCloser {
func (c *otoDriver) NewPlayer() io.WriteCloser {
return &otoPlayer{c: c}
}
func (c *otoContext) Close() error {
func (c *otoDriver) Close() error {
if c.c == nil {
return nil
}
return c.c.Close()
}
func (c *otoContext) ensureContext() error {
func (c *otoDriver) ensureContext() error {
var err error
c.once.Do(func() {
<-c.initCh
@ -57,7 +57,7 @@ func (c *otoContext) ensureContext() error {
}
type otoPlayer struct {
c *otoContext
c *otoDriver
p *oto.Player
once sync.Once
}

View File

@ -23,18 +23,18 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/hooks"
)
// writerContext represents a context represented as io.WriteClosers.
// The actual implementation is oto.Context.
type writerContext interface {
// writerDriver represents a driver using io.WriteClosers.
// The actual implementation is otoDriver.
type writerDriver interface {
NewPlayer() io.WriteCloser
io.Closer
}
var writerContextForTesting writerContext
var writerDriverForTesting writerDriver
func newWriterContext(sampleRate int) writerContext {
if writerContextForTesting != nil {
return writerContextForTesting
func newWriterDriver(sampleRate int) writerDriver {
if writerDriverForTesting != nil {
return writerDriverForTesting
}
ch := make(chan struct{})
@ -45,12 +45,22 @@ func newWriterContext(sampleRate int) writerContext {
})
return nil
})
return newOtoContext(sampleRate, ch)
return newOtoDriver(sampleRate, ch)
}
type writerContext struct {
driver writerDriver
}
func newWriterContext(sampleRate int) *writerContext {
return &writerContext{
driver: newWriterDriver(sampleRate),
}
}
type writerContextPlayerImpl struct {
context *Context
writerContext writerContext
driver writerDriver
src io.Reader
playing bool
closedExplicitly bool
@ -64,12 +74,12 @@ type writerContextPlayerImpl struct {
m sync.Mutex
}
func newWriterContextPlayerImpl(context *Context, writerContext writerContext, src io.Reader) (*writerContextPlayerImpl, error) {
func (c *writerContext) newPlayerImpl(context *Context, src io.Reader) (playerImpl, error) {
p := &writerContextPlayerImpl{
context: context,
writerContext: writerContext,
src: src,
volume: 1,
context: context,
driver: c.driver,
src: src,
volume: 1,
}
if seeker, ok := p.src.(io.Seeker); ok {
// Get the current position of the source.
@ -119,7 +129,7 @@ func (p *writerContextPlayerImpl) Play() {
func (p *writerContextPlayerImpl) loop() {
p.context.waitUntilInited()
w := p.writerContext.NewPlayer()
w := p.driver.NewPlayer()
wclosed := make(chan struct{})
defer func() {
<-wclosed