audio: Bug fix: Fill empty data even when audio is suspended

When writing is stopped on Oto's players, unexpected delaying
happens.

The ideal solution is to have APIs to suspend and resume Oto's
player, but this is not easy. For a temporary solution, write
zero values on the players when audio is suspended.

Fixes #975
This commit is contained in:
Hajime Hoshi 2019-11-07 01:09:40 +09:00
parent ddba7f0ee0
commit 529dddda53

View File

@ -63,11 +63,11 @@ type Context struct {
sampleRate int sampleRate int
err error err error
ready bool ready bool
suspended bool
players map[*playerImpl]struct{} players map[*playerImpl]struct{}
m sync.Mutex m sync.Mutex
semaphore chan struct{}
} }
var ( var (
@ -75,6 +75,8 @@ var (
theContextLock sync.Mutex theContextLock sync.Mutex
) )
var emptyBytes = make([]byte, 256)
// NewContext creates a new audio context with the given sample rate. // NewContext creates a new audio context with the given sample rate.
// //
// The sample rate is also used for decoding MP3 with audio/mp3 package // The sample rate is also used for decoding MP3 with audio/mp3 package
@ -99,16 +101,19 @@ func NewContext(sampleRate int) (*Context, error) {
c: newContext(sampleRate), c: newContext(sampleRate),
players: map[*playerImpl]struct{}{}, players: map[*playerImpl]struct{}{},
inited: make(chan struct{}), inited: make(chan struct{}),
semaphore: make(chan struct{}, 1),
} }
theContext = c theContext = c
h := getHook() h := getHook()
h.OnSuspendAudio(func() { h.OnSuspendAudio(func() {
c.semaphore <- struct{}{} c.m.Lock()
c.suspended = true
c.m.Unlock()
}) })
h.OnResumeAudio(func() { h.OnResumeAudio(func() {
<-c.semaphore c.m.Lock()
c.suspended = false
c.m.Unlock()
}) })
h.AppendHookOnBeforeUpdate(func() error { h.AppendHookOnBeforeUpdate(func() error {
@ -455,10 +460,14 @@ func (p *playerImpl) read() ([]byte, bool) {
const bufSize = 2048 const bufSize = 2048
p.context.semaphore <- struct{}{} // If audio is suspended, fill zero values not to cause delay (#975).
defer func() { // TODO: Oto's players should be able to be suspended and resumed.
<-p.context.semaphore p.context.m.Lock()
}() s := p.context.suspended
p.context.m.Unlock()
if s {
return emptyBytes, true
}
newBuf := make([]byte, bufSize-len(p.buf)) newBuf := make([]byte, bufSize-len(p.buf))
n, err := p.src.Read(newBuf) n, err := p.src.Read(newBuf)