Skip to content

Commit aa38fb3

Browse files
authored
Merge af853ea into 56a6209
2 parents 56a6209 + af853ea commit aa38fb3

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

source/nvwave.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import config
1919
from logHandler import log
2020
import os.path
21+
import core
2122

2223
__all__ = (
2324
"WavePlayer", "getOutputDeviceNames", "outputDeviceIDToName", "outputDeviceNameToID",
@@ -100,6 +101,9 @@ class WavePlayer(object):
100101
"""
101102
#: Minimum length of buffer (in ms) before audio is played.
102103
MIN_BUFFER_MS = 300
104+
#: The time (in ms) to wait after L{idle} is called before closing the audio
105+
#: device. This is only applicable if L{closeWhenIdle} is C{True}.
106+
IDLE_CLOSE_DELAY_MS = 10000
103107
#: Flag used to signal that L{stop} has been called.
104108
STOPPING = "stopping"
105109
#: A lock to prevent WaveOut* functions from being called simultaneously, as this can cause problems even if they are for different HWAVEOUTs.
@@ -141,6 +145,7 @@ def __init__(self, channels, samplesPerSec, bitsPerSample,
141145
#: If C{True}, close the output device when no audio is being played.
142146
#: @type: bool
143147
self.closeWhenIdle = closeWhenIdle
148+
self._closeTimer = None
144149
if buffered:
145150
#: Minimum size of the buffer before audio is played.
146151
#: However, this is ignored if an C{onDone} callback is provided to L{feed}.
@@ -158,13 +163,21 @@ def __init__(self, channels, samplesPerSec, bitsPerSample,
158163
self._lock = threading.RLock()
159164
self.open()
160165

166+
def _callOnMainThread(self, func, *args):
167+
if threading.get_ident() == core.mainThreadId:
168+
func(*args)
169+
else:
170+
wx.CallAfter(func, *args)
171+
161172
def open(self):
162173
"""Open the output device.
163174
This will be called automatically when required.
164175
It is not an error if the output device is already open.
165176
"""
166177
with self._waveout_lock:
167178
if self._waveout:
179+
if self._closeTimer and self._closeTimer.IsRunning():
180+
self._callOnMainThread(self._closeTimer.Stop)
168181
return
169182
wfx = WAVEFORMATEX()
170183
wfx.wFormatTag = WAVE_FORMAT_PCM
@@ -269,7 +282,8 @@ def pause(self, switch):
269282
def idle(self):
270283
"""Indicate that this player is now idle; i.e. the current continuous segment of audio is complete.
271284
This will first call L{sync} to synchronise with playback.
272-
If L{closeWhenIdle} is C{True}, the output device will be closed.
285+
If L{closeWhenIdle} is C{True}, the output device will be closed if there
286+
is no further audio within L{IDLE_CLOSE_DELAY_MS}.
273287
A subsequent call to L{feed} will reopen it.
274288
"""
275289
if not self._minBufferSize:
@@ -286,7 +300,13 @@ def _idleUnbuffered(self):
286300
if not self._waveout:
287301
return
288302
if self.closeWhenIdle:
289-
self._close()
303+
if not self._closeTimer:
304+
# We need a cancellable timer, so we can't use core.callLater.
305+
self._closeTimer = wx.PyTimer(self._close)
306+
self._callOnMainThread(
307+
self._closeTimer.Start, self.IDLE_CLOSE_DELAY_MS,
308+
wx.TIMER_ONE_SHOT
309+
)
290310
if self._audioDucker: self._audioDucker.disable()
291311

292312
def stop(self):

0 commit comments

Comments
 (0)