audio: Split locks

This commit is contained in:
Hajime Hoshi 2017-06-04 03:14:48 +09:00
parent e7478b794a
commit 873b3905df

View File

@ -313,7 +313,8 @@ type Player struct {
pos int64 pos int64
volume float64 volume float64
sync.RWMutex srcM sync.Mutex
m sync.RWMutex
} }
// NewPlayer creates a new player with the given stream. // NewPlayer creates a new player with the given stream.
@ -375,45 +376,47 @@ func NewPlayerFromBytes(context *Context, src []byte) (*Player, error) {
func (p *Player) Close() error { func (p *Player) Close() error {
p.players.removePlayer(p) p.players.removePlayer(p)
runtime.SetFinalizer(p, nil) runtime.SetFinalizer(p, nil)
p.Lock() p.srcM.Lock()
err := p.src.Close() err := p.src.Close()
p.Unlock() p.srcM.Unlock()
return err return err
} }
func (p *Player) readToBuffer(length int) error { func (p *Player) readToBuffer(length int) error {
p.Lock() p.srcM.Lock()
p.m.Lock()
bb := make([]byte, length) bb := make([]byte, length)
n, err := p.src.Read(bb) n, err := p.src.Read(bb)
if 0 < n { if 0 < n {
p.buf = append(p.buf, bb[:n]...) p.buf = append(p.buf, bb[:n]...)
} }
p.Unlock() p.m.Unlock()
p.srcM.Unlock()
return err return err
} }
func (p *Player) bufferToInt16(lengthInBytes int) []int16 { func (p *Player) bufferToInt16(lengthInBytes int) []int16 {
p.RLock() p.m.RLock()
r := make([]int16, lengthInBytes/2) r := make([]int16, lengthInBytes/2)
for i := 0; i < lengthInBytes/2; i++ { for i := 0; i < lengthInBytes/2; i++ {
r[i] = int16(p.buf[2*i]) | (int16(p.buf[2*i+1]) << 8) r[i] = int16(p.buf[2*i]) | (int16(p.buf[2*i+1]) << 8)
r[i] = int16(float64(r[i]) * p.volume) r[i] = int16(float64(r[i]) * p.volume)
} }
p.RUnlock() p.m.RUnlock()
return r return r
} }
func (p *Player) proceed(length int) { func (p *Player) proceed(length int) {
p.Lock() p.m.Lock()
p.buf = p.buf[length:] p.buf = p.buf[length:]
p.pos += int64(length) p.pos += int64(length)
p.Unlock() p.m.Unlock()
} }
func (p *Player) bufferLength() int { func (p *Player) bufferLength() int {
p.RLock() p.m.RLock()
l := len(p.buf) l := len(p.buf)
p.RUnlock() p.m.RUnlock()
return l return l
} }
@ -453,14 +456,16 @@ func (p *Player) Seek(offset time.Duration) error {
defer p.players.removeSeeking(p) defer p.players.removeSeeking(p)
o := int64(offset) * bytesPerSample * channelNum * int64(p.sampleRate) / int64(time.Second) o := int64(offset) * bytesPerSample * channelNum * int64(p.sampleRate) / int64(time.Second)
o &= mask o &= mask
p.Lock() p.srcM.Lock()
defer p.Unlock()
p.buf = []byte{}
pos, err := p.src.Seek(o, io.SeekStart) pos, err := p.src.Seek(o, io.SeekStart)
p.srcM.Unlock()
if err != nil { if err != nil {
return err return err
} }
p.m.Lock()
p.buf = []byte{}
p.pos = pos p.pos = pos
p.m.Unlock()
return nil return nil
} }
@ -478,19 +483,21 @@ func (p *Player) Pause() error {
// //
// Current is concurrent safe. // Current is concurrent safe.
func (p *Player) Current() time.Duration { func (p *Player) Current() time.Duration {
p.RLock() p.m.RLock()
defer p.RUnlock()
sample := p.pos / bytesPerSample / channelNum sample := p.pos / bytesPerSample / channelNum
return time.Duration(sample) * time.Second / time.Duration(p.sampleRate) t := time.Duration(sample) * time.Second / time.Duration(p.sampleRate)
p.m.RUnlock()
return t
} }
// Volume returns the current volume of this player [0-1]. // Volume returns the current volume of this player [0-1].
// //
// Volume is concurrent safe. // Volume is concurrent safe.
func (p *Player) Volume() float64 { func (p *Player) Volume() float64 {
p.RLock() p.m.RLock()
defer p.RUnlock() v := p.volume
return p.volume p.m.RUnlock()
return v
} }
// SetVolume sets the volume of this player. // SetVolume sets the volume of this player.
@ -498,8 +505,8 @@ func (p *Player) Volume() float64 {
// //
// SetVolume is concurrent safe. // SetVolume is concurrent safe.
func (p *Player) SetVolume(volume float64) { func (p *Player) SetVolume(volume float64) {
p.Lock() p.m.Lock()
defer p.Unlock() defer p.m.Unlock()
// The condition must be true when volume is NaN. // The condition must be true when volume is NaN.
if !(0 <= volume && volume <= 1) { if !(0 <= volume && volume <= 1) {
panic("audio: volume must be in between 0 and 1") panic("audio: volume must be in between 0 and 1")