Skip to content

Commit

Permalink
windows: initialize drivers asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Jul 24, 2022
1 parent bba4f09 commit 489daa2
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 26 deletions.
11 changes: 4 additions & 7 deletions driver_wasapi_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ type wasapiContext struct {
m sync.Mutex
}

func newWASAPIContext(sampleRate, channelCount int, players *players) (*wasapiContext, chan struct{}, error) {
func newWASAPIContext(sampleRate, channelCount int, players *players) (*wasapiContext, error) {
t, err := newCOMThread()
if err != nil {
return nil, nil, err
return nil, err
}

c := &wasapiContext{
Expand All @@ -105,13 +105,10 @@ func newWASAPIContext(sampleRate, channelCount int, players *players) (*wasapiCo
}
})
if cerr != nil {
return nil, nil, cerr
return nil, cerr
}

ready := make(chan struct{})
close(ready)

return c, ready, nil
return c, nil
}

func (c *wasapiContext) initOnCOMThread() error {
Expand Down
47 changes: 36 additions & 11 deletions driver_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type context struct {

wasapiContext *wasapiContext
winmmContext *winmmContext

ready chan struct{}
err atomicError
}

func newContext(sampleRate, channelCount, bitDepthInBytes int) (*context, chan struct{}, error) {
Expand All @@ -36,22 +39,33 @@ func newContext(sampleRate, channelCount, bitDepthInBytes int) (*context, chan s
channelCount: channelCount,
bitDepthInBytes: bitDepthInBytes,
players: p,
ready: make(chan struct{}),
}

xc, ready, err0 := newWASAPIContext(sampleRate, channelCount, p)
if err0 == nil {
ctx.wasapiContext = xc
return ctx, ready, nil
}
wc, ready, err1 := newWinMMContext(sampleRate, channelCount, p)
if err1 == nil {
ctx.winmmContext = wc
return ctx, ready, nil
}
return nil, nil, fmt.Errorf("oto: initialization failed: WASAPI: %v, WinMM: %v", err0, err1)
// Initializing drivers might take some time. Do this asynchronously.
go func() {
defer close(ctx.ready)

xc, err0 := newWASAPIContext(sampleRate, channelCount, p)
if err0 == nil {
ctx.wasapiContext = xc
return
}

wc, err1 := newWinMMContext(sampleRate, channelCount, p)
if err1 == nil {
ctx.winmmContext = wc
return
}

ctx.err.TryStore(fmt.Errorf("oto: initialization failed: WASAPI: %v, WinMM: %v", err0, err1))
}()

return ctx, ctx.ready, nil
}

func (c *context) Suspend() error {
<-c.ready
if c.wasapiContext != nil {
return c.wasapiContext.Suspend()
}
Expand All @@ -62,6 +76,7 @@ func (c *context) Suspend() error {
}

func (c *context) Resume() error {
<-c.ready
if c.wasapiContext != nil {
return c.wasapiContext.Resume()
}
Expand All @@ -72,6 +87,16 @@ func (c *context) Resume() error {
}

func (c *context) Err() error {
if err := c.err.Load(); err != nil {
return err
}

select {
case <-c.ready:
default:
return nil
}

if c.wasapiContext != nil {
return c.wasapiContext.Err()
}
Expand Down
13 changes: 5 additions & 8 deletions driver_winmm_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@ type winmmContext struct {

var theWinMMContext *winmmContext

func newWinMMContext(sampleRate, channelCount int, players *players) (*winmmContext, chan struct{}, error) {
ready := make(chan struct{})
close(ready)

func newWinMMContext(sampleRate, channelCount int, players *players) (*winmmContext, error) {
c := &winmmContext{
players: players,
cond: sync.NewCond(&sync.Mutex{}),
Expand All @@ -105,26 +102,26 @@ func newWinMMContext(sampleRate, channelCount int, players *players) (*winmmCont
if errors.Is(err, windows.ERROR_NOT_FOUND) {
// TODO: No device was found. Return the dummy device (#77).
// TODO: Retry to open the device when possible.
return nil, nil, err
return nil, err
}
if err != nil {
return nil, nil, err
return nil, err
}

c.waveOut = w
c.headers = make([]*header, 0, 6)
for len(c.headers) < cap(c.headers) {
h, err := newHeader(c.waveOut, headerBufferSize)
if err != nil {
return nil, nil, err
return nil, err
}
c.headers = append(c.headers, h)
}

c.buf32 = make([]float32, headerBufferSize/4)
go c.loop()

return c, ready, nil
return c, nil
}

func (c *winmmContext) Suspend() error {
Expand Down

0 comments on commit 489daa2

Please sign in to comment.