audio: Define playerImpl interface

This commit is contained in:
Hajime Hoshi 2021-01-07 00:59:13 +09:00
parent 7cf32efcd5
commit e77beac235
2 changed files with 44 additions and 20 deletions

View File

@ -66,7 +66,7 @@ type Context struct {
err error err error
ready bool ready bool
players map[*writerContextPlayerImpl]struct{} players map[playerImpl]struct{}
m sync.Mutex m sync.Mutex
semaphore chan struct{} semaphore chan struct{}
@ -97,7 +97,7 @@ func NewContext(sampleRate int) *Context {
c := &Context{ c := &Context{
sampleRate: sampleRate, sampleRate: sampleRate,
c: newWriterContext(sampleRate), c: newWriterContext(sampleRate),
players: map[*writerContextPlayerImpl]struct{}{}, players: map[playerImpl]struct{}{},
inited: make(chan struct{}), inited: make(chan struct{}),
semaphore: make(chan struct{}, 1), semaphore: make(chan struct{}, 1),
} }
@ -158,7 +158,7 @@ func (c *Context) setReady() {
c.m.Unlock() c.m.Unlock()
} }
func (c *Context) addPlayer(p *writerContextPlayerImpl) { func (c *Context) addPlayer(p playerImpl) {
c.m.Lock() c.m.Lock()
defer c.m.Unlock() defer c.m.Unlock()
c.players[p] = struct{}{} c.players[p] = struct{}{}
@ -174,7 +174,7 @@ func (c *Context) addPlayer(p *writerContextPlayerImpl) {
} }
} }
func (c *Context) removePlayer(p *writerContextPlayerImpl) { func (c *Context) removePlayer(p playerImpl) {
c.m.Lock() c.m.Lock()
delete(c.players, p) delete(c.players, p)
c.m.Unlock() c.m.Unlock()
@ -220,7 +220,22 @@ func (c *Context) SampleRate() int {
// This means that if a Player plays an infinite stream, // This means that if a Player plays an infinite stream,
// the object is never GCed unless Close is called. // the object is never GCed unless Close is called.
type Player struct { type Player struct {
p *writerContextPlayerImpl p playerImpl
}
type playerImpl interface {
io.Closer
Play()
IsPlaying() bool
Pause()
Volume() float64
SetVolume(volume float64)
Current() time.Duration
Rewind() error
Seek(offset time.Duration) error
source() io.Reader
} }
// NewPlayer creates a new player with the given stream. // NewPlayer creates a new player with the given stream.
@ -240,22 +255,13 @@ type Player struct {
// A Player doesn't close src even if src implements io.Closer. // A Player doesn't close src even if src implements io.Closer.
// Closing the source is src owner's responsibility. // Closing the source is src owner's responsibility.
func NewPlayer(context *Context, src io.Reader) (*Player, error) { func NewPlayer(context *Context, src io.Reader) (*Player, error) {
p := &Player{ pi, err := newWriterContextPlayerImpl(context, src)
&writerContextPlayerImpl{ if err != nil {
context: context, return nil, err
src: src,
sampleRate: context.sampleRate,
volume: 1,
},
}
if seeker, ok := p.p.src.(io.Seeker); ok {
// Get the current position of the source.
pos, err := seeker.Seek(0, io.SeekCurrent)
if err != nil {
return nil, err
}
p.p.pos = pos
} }
p := &Player{pi}
runtime.SetFinalizer(p, (*Player).finalize) runtime.SetFinalizer(p, (*Player).finalize)
return p, nil return p, nil

View File

@ -64,6 +64,24 @@ type writerContextPlayerImpl struct {
m sync.Mutex m sync.Mutex
} }
func newWriterContextPlayerImpl(context *Context, src io.Reader) (*writerContextPlayerImpl, error) {
p := &writerContextPlayerImpl{
context: context,
src: src,
sampleRate: context.sampleRate,
volume: 1,
}
if seeker, ok := p.src.(io.Seeker); ok {
// Get the current position of the source.
pos, err := seeker.Seek(0, io.SeekCurrent)
if err != nil {
return nil, err
}
p.pos = pos
}
return p, nil
}
func (p *writerContextPlayerImpl) Close() error { func (p *writerContextPlayerImpl) Close() error {
p.m.Lock() p.m.Lock()
defer p.m.Unlock() defer p.m.Unlock()