1818import config
1919from logHandler import log
2020import 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,22 @@ 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 """
177+ import inputCore ; inputCore .logTimeSinceInput ()
166178 with self ._waveout_lock :
167179 if self ._waveout :
180+ if self ._closeTimer and self ._closeTimer .IsRunning ():
181+ self ._callOnMainThread (self ._closeTimer .Stop )
168182 return
169183 wfx = WAVEFORMATEX ()
170184 wfx .wFormatTag = WAVE_FORMAT_PCM
@@ -269,7 +283,8 @@ def pause(self, switch):
269283 def idle (self ):
270284 """Indicate that this player is now idle; i.e. the current continuous segment of audio is complete.
271285 This will first call L{sync} to synchronise with playback.
272- If L{closeWhenIdle} is C{True}, the output device will be closed.
286+ If L{closeWhenIdle} is C{True}, the output device will be closed if there
287+ is no further audio within L{IDLE_CLOSE_DELAY_MS}.
273288 A subsequent call to L{feed} will reopen it.
274289 """
275290 if not self ._minBufferSize :
@@ -286,7 +301,13 @@ def _idleUnbuffered(self):
286301 if not self ._waveout :
287302 return
288303 if self .closeWhenIdle :
289- self ._close ()
304+ if not self ._closeTimer :
305+ # We need a cancellable timer, so we can't use core.callLater.
306+ self ._closeTimer = wx .PyTimer (self ._close )
307+ self ._callOnMainThread (
308+ self ._closeTimer .Start , self .IDLE_CLOSE_DELAY_MS ,
309+ wx .TIMER_ONE_SHOT
310+ )
290311 if self ._audioDucker : self ._audioDucker .disable ()
291312
292313 def stop (self ):
0 commit comments