Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Timeout Feature for sounddevice.wait() Function #509

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions sounddevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,24 +375,41 @@ def callback(indata, outdata, frames, time, status):
return out


def wait(ignore_errors=True):
"""Wait for `play()`/`rec()`/`playrec()` to be finished.
def wait(ignore_errors=True, timeout=None):
"""Wait for `play()`/`rec()`/`playrec()` to be finished
with an optional timeout.

Playback/recording can be stopped with a `KeyboardInterrupt`.
Playback/recording can be stopped with a `KeyboardInterrupt`. If a timeout
is specified, the wait will return after the timeout period if
playback/recording hasn't finished.

Parameters
----------
timeout : float, optional
Maximum number of seconds to wait for `play()`/`rec()`/`playrec()`
to be finished.
If None (default), waits until finished or exceptions are raised.
ignore_errors : bool, optional
Whether to ignore errors when closing the stream.

Returns
-------
CallbackFlags or None
If at least one buffer over-/underrun happened during the last
playback/recording, a `CallbackFlags` object is returned.
bool or CallbackFlags or None
- CallbackFlags if at least one buffer over-/underrun happened during
the last playback/recording and no timeout was specified.
- None if the operation completes without buffer over-/underrun issues
and no timeout is specified.
- True if timeout is specified and playback/recording finished and no
exception raised.
- False if timeout is specified and timeout elapses before
playback/recording finished and no exception raised.

See Also
--------
get_status

"""
if _last_callback:
return _last_callback.wait(ignore_errors)
return _last_callback.wait(ignore_errors, timeout=timeout)


def stop(ignore_errors=True):
Expand Down Expand Up @@ -2612,16 +2629,34 @@ def start_stream(self, StreamClass, samplerate, channels, dtype, callback,
if blocking:
self.wait()

def wait(self, ignore_errors=True):
"""Wait for finished_callback.
def wait(self, ignore_errors=True, timeout=None):
"""
Wait for a finished_callback with an optional timeout.

This method waits for the event to be set or for the optional timeout
to elapse. If a timeout is specified, and it is reached without the
event being set, the method returns False. Otherwise, it returns the
stream status or None. The stream is closed if it finishes normally or
an exception occurs.

Can be interrupted with a KeyboardInterrupt.
Args:
ignore_errors (bool): Whether to ignore errors when closing stream.
timeout (float, optional): Time in seconds to wait before time out.

Returns:
True if the wait completes before timeout, False if it times out,
or the stream's status (or None) if no timeout is specified.
"""
exception_raised = True
finished = False
try:
self.event.wait()
finished = self.event.wait(timeout=timeout)
exception_raised = False
finally:
self.stream.close(ignore_errors)
if finished or exception_raised:
self.stream.close(ignore_errors)
if timeout and not exception_raised:
return finished
return self.status if self.status else None


Expand Down
Loading