audio: pair locks with defer and move the disposal of a context to audio.go
This commit is contained in:
1 parent
8198c5c4b3
commit
4300b92d4b
3 files changed
+35
-24
No files matched your search
@@ -233,6 +233,19 @@ func (c *Context) waitForPlayingPlayers() bool {
|
|||||||
return !c.disposed
|
return !c.disposed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dispose makes the goroutine updating the players exit, and waits for it to exit.
|
||||||
|
func (c *Context) dispose() {
|
||||||
|
c.markDisposed()
|
||||||
|
c.updater.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) markDisposed() {
|
||||||
|
c.m.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
c.disposed = true
|
||||||
|
c.cond.Broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) addPlayingPlayer(p *playerImpl) {
|
func (c *Context) addPlayingPlayer(p *playerImpl) {
|
||||||
c.m.Lock()
|
c.m.Lock()
|
||||||
defer c.m.Unlock()
|
defer c.m.Unlock()
|
||||||
|
|||||||
+2
-5
@@ -71,8 +71,7 @@ func TestGC(t *testing.T) {
|
|||||||
if err := audio.UpdateForTesting(); err != nil {
|
if err := audio.UpdateForTesting(); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
// 200[ms] should be enough for all the bytes to be consumed. The test runs on the fake
|
// 200[ms] should be enough for all the bytes to be consumed.
|
||||||
// clock of synctest, so this does not take real time.
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
}
|
}
|
||||||
t.Errorf("time out")
|
t.Errorf("time out")
|
||||||
@@ -658,8 +657,7 @@ func TestPositionNotGrowingAfterFinished(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.Play()
|
p.Play()
|
||||||
// Wait until the player finishes its source. The test runs on the fake clock of synctest, so
|
// Wait until the player finishes its source.
|
||||||
// the deadline does not take real time.
|
|
||||||
var finished bool
|
var finished bool
|
||||||
deadline := time.Now().Add(10 * time.Second)
|
deadline := time.Now().Add(10 * time.Second)
|
||||||
for time.Now().Before(deadline) {
|
for time.Now().Before(deadline) {
|
||||||
@@ -889,7 +887,6 @@ func TestPlayOnIdleContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// waitUntil polls cond until it holds or the deadline passes, and reports whether it held.
|
// waitUntil polls cond until it holds or the deadline passes, and reports whether it held.
|
||||||
// The test runs on the fake clock of synctest, so the deadline does not take real time.
|
|
||||||
waitUntil := func(cond func() bool) bool {
|
waitUntil := func(cond func() bool) bool {
|
||||||
deadline := time.Now().Add(10 * time.Second)
|
deadline := time.Now().Add(10 * time.Second)
|
||||||
for time.Now().Before(deadline) {
|
for time.Now().Before(deadline) {
|
||||||
|
|||||||
+20
-19
@@ -73,17 +73,20 @@ func (c *dummyContext) NewPlayer(r io.Reader) player {
|
|||||||
|
|
||||||
// stopPlayers stops the players' goroutines reading their sources, and waits for them to exit.
|
// stopPlayers stops the players' goroutines reading their sources, and waits for them to exit.
|
||||||
func (c *dummyContext) stopPlayers() {
|
func (c *dummyContext) stopPlayers() {
|
||||||
c.mu.Lock()
|
for _, p := range c.takePlayers() {
|
||||||
players := c.players
|
|
||||||
c.players = nil
|
|
||||||
c.mu.Unlock()
|
|
||||||
|
|
||||||
for _, p := range players {
|
|
||||||
p.PauseAndStopReading()
|
p.PauseAndStopReading()
|
||||||
p.readers.Wait()
|
p.readers.Wait()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *dummyContext) takePlayers() []*dummyPlayer {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
players := c.players
|
||||||
|
c.players = nil
|
||||||
|
return players
|
||||||
|
}
|
||||||
|
|
||||||
func (c *dummyContext) MaxBufferSize() int {
|
func (c *dummyContext) MaxBufferSize() int {
|
||||||
return 48000 * channelCount * bitDepthInBytesInt16 / 4
|
return 48000 * channelCount * bitDepthInBytesInt16 / 4
|
||||||
}
|
}
|
||||||
@@ -349,23 +352,21 @@ func ContextCreatedForTesting() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ResetContextForTesting discards the current context, so that a test can create a new one.
|
// ResetContextForTesting discards the current context, so that a test can create a new one.
|
||||||
// ResetContextForTesting waits for the goroutines the context and its players started to exit, so
|
// ResetContextForTesting stops the goroutine updating the players and the goroutines reading the
|
||||||
// that they do not outlive the test.
|
// players' sources, and waits for them to exit.
|
||||||
func ResetContextForTesting() {
|
func ResetContextForTesting() {
|
||||||
|
if c := takeContextForTesting(); c != nil {
|
||||||
|
c.dispose()
|
||||||
|
}
|
||||||
|
dummyContextForTesting.stopPlayers()
|
||||||
|
}
|
||||||
|
|
||||||
|
func takeContextForTesting() *Context {
|
||||||
theContextLock.Lock()
|
theContextLock.Lock()
|
||||||
|
defer theContextLock.Unlock()
|
||||||
c := theContext
|
c := theContext
|
||||||
theContext = nil
|
theContext = nil
|
||||||
theContextLock.Unlock()
|
return c
|
||||||
|
|
||||||
if c != nil {
|
|
||||||
c.m.Lock()
|
|
||||||
c.disposed = true
|
|
||||||
c.cond.Broadcast()
|
|
||||||
c.m.Unlock()
|
|
||||||
c.updater.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
dummyContextForTesting.stopPlayers()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InfiniteLoop) SetNoBlendForTesting(value bool) {
|
func (i *InfiniteLoop) SetNoBlendForTesting(value bool) {
|
||||||
|
|||||||
Reference in new issue
Block a user