Skip to content

Commit

Permalink
windows: bug fix: crash when suspending/resuming when there are no de…
Browse files Browse the repository at this point in the history
…vices

Updates hajimehoshi/ebiten#2318
  • Loading branch information
hajimehoshi committed Jan 27, 2023
1 parent a3a27d0 commit 774596e
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 101 deletions.
36 changes: 0 additions & 36 deletions api_winmm_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ var (
var (
procWaveOutOpen = winmm.NewProc("waveOutOpen")
procWaveOutClose = winmm.NewProc("waveOutClose")
procWaveOutPause = winmm.NewProc("waveOutPause")
procWaveOutPrepareHeader = winmm.NewProc("waveOutPrepareHeader")
procWaveOutReset = winmm.NewProc("waveOutReset")
procWaveOutRestart = winmm.NewProc("waveOutRestart")
procWaveOutUnprepareHeader = winmm.NewProc("waveOutUnprepareHeader")
procWaveOutWrite = winmm.NewProc("waveOutWrite")
)
Expand Down Expand Up @@ -140,17 +137,6 @@ func waveOutClose(hwo uintptr) error {
return nil
}

func waveOutPause(hwo uintptr) error {
r, _, e := procWaveOutPause.Call(hwo)
if _MMRESULT(r) != _MMSYSERR_NOERROR {
if e != nil && e != windows.ERROR_SUCCESS {
return fmt.Errorf("oto: waveOutPause failed: %w", e)
}
return fmt.Errorf("oto: waveOutPause failed: %w", _MMRESULT(r))
}
return nil
}

func waveOutPrepareHeader(hwo uintptr, pwh *_WAVEHDR) error {
r, _, e := procWaveOutPrepareHeader.Call(hwo, uintptr(unsafe.Pointer(pwh)), unsafe.Sizeof(_WAVEHDR{}))
runtime.KeepAlive(pwh)
Expand All @@ -163,28 +149,6 @@ func waveOutPrepareHeader(hwo uintptr, pwh *_WAVEHDR) error {
return nil
}

func waveOutReset(hwo uintptr) error {
r, _, e := procWaveOutReset.Call(hwo)
if _MMRESULT(r) != _MMSYSERR_NOERROR {
if e != nil && e != windows.ERROR_SUCCESS {
return fmt.Errorf("oto: waveOutReset failed: %w", e)
}
return fmt.Errorf("oto: waveOutReset failed: %w", _MMRESULT(r))
}
return nil
}

func waveOutRestart(hwo uintptr) error {
r, _, e := procWaveOutRestart.Call(hwo)
if _MMRESULT(r) != _MMSYSERR_NOERROR {
if e != nil && e != windows.ERROR_SUCCESS {
return fmt.Errorf("oto: waveOutRestart failed: %w", e)
}
return fmt.Errorf("oto: waveOutRestart failed: %w", _MMRESULT(r))
}
return nil
}

func waveOutUnprepareHeader(hwo uintptr, pwh *_WAVEHDR) error {
r, _, e := procWaveOutUnprepareHeader.Call(hwo, uintptr(unsafe.Pointer(pwh)), unsafe.Sizeof(_WAVEHDR{}))
runtime.KeepAlive(pwh)
Expand Down
83 changes: 18 additions & 65 deletions driver_winmm_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ type winmmContext struct {
loopEndCh chan error

cond *sync.Cond

suspended bool
suspendedCond *sync.Cond
}

var theWinMMContext *winmmContext
Expand All @@ -94,6 +97,7 @@ func newWinMMContext(sampleRate, channelCount int, mux *mux.Mux, bufferSizeInByt
bufferSizeInBytes: bufferSizeInBytes,
mux: mux,
cond: sync.NewCond(&sync.Mutex{}),
suspendedCond: sync.NewCond(&sync.Mutex{}),
}
theWinMMContext = c

Expand Down Expand Up @@ -151,54 +155,20 @@ func (c *winmmContext) start() error {
}

func (c *winmmContext) Suspend() error {
c.cond.L.Lock()
defer c.cond.L.Unlock()
c.suspendedCond.L.Lock()
c.suspended = true
c.suspendedCond.L.Unlock()
c.suspendedCond.Signal()

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

if err := waveOutPause(c.waveOut); err != nil {
return err
}
return nil
}

func (c *winmmContext) Resume() (ferr error) {
var restart bool
defer func() {
if ferr != nil {
return
}
if !restart {
return
}
if err := c.stopLoopIfNeeded(); err != nil {
ferr = err
return
}
if err := c.start(); err != nil {
ferr = err
return
}
}()

c.cond.L.Lock()
defer c.cond.L.Unlock()

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

// TODO: Ensure at least one header is queued?
c.suspendedCond.L.Lock()
c.suspended = false
c.suspendedCond.L.Unlock()
c.suspendedCond.Signal()

if err := waveOutRestart(c.waveOut); err != nil {
if errors.Is(err, _MMSYSERR_NODRIVER) {
restart = true
return nil
}
return err
}
return nil
}

Expand Down Expand Up @@ -239,36 +209,19 @@ func (c *winmmContext) waitUntilHeaderAvailable() bool {
return c.err.Load() == nil && c.loopEndCh == nil
}

func (c *winmmContext) stopLoopIfNeeded() error {
ch := c.stopLoop()
if ch == nil {
return nil
}
return <-ch
}

func (c *winmmContext) stopLoop() chan error {
c.cond.L.Lock()
defer c.cond.L.Unlock()

// If the loop is already stopping, do nothing.
if c.loopEndCh != nil {
return nil
}

ch := make(chan error)
c.loopEndCh = ch
c.cond.Signal()
return ch
}

func (c *winmmContext) loop() {
defer func() {
if err := c.closeLoop(); err != nil {
c.err.TryStore(err)
}
}()
for {
c.suspendedCond.L.Lock()
for c.suspended {
c.suspendedCond.Wait()
}
c.suspendedCond.L.Unlock()

if !c.waitUntilHeaderAvailable() {
return
}
Expand Down

0 comments on commit 774596e

Please sign in to comment.