Skip to content

Commit 781cf15

Browse files
committed
Support for CData function pointers as callbacks
1 parent 92453c4 commit 781cf15

1 file changed

Lines changed: 26 additions & 15 deletions

File tree

sounddevice.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -843,10 +843,12 @@ def get_portaudio_version():
843843
class _StreamBase(object):
844844
"""Base class for Raw{Input,Output}Stream."""
845845

846-
def __init__(self, kind, samplerate, blocksize, device, channels, dtype,
847-
latency, extra_settings, callback_wrapper, finished_callback,
848-
clip_off, dither_off, never_drop_input,
849-
prime_output_buffers_using_stream_callback):
846+
def __init__(self, kind, samplerate=None, blocksize=None, device=None,
847+
channels=None, dtype=None, latency=None, extra_settings=None,
848+
callback=None, finished_callback=None, clip_off=None,
849+
dither_off=None, never_drop_input=None,
850+
prime_output_buffers_using_stream_callback=None,
851+
userdata=None):
850852
if blocksize is None:
851853
blocksize = default.blocksize
852854
if clip_off is None:
@@ -904,16 +906,22 @@ def __init__(self, kind, samplerate, blocksize, device, channels, dtype,
904906
iparameters = _ffi.NULL
905907
oparameters = parameters
906908

907-
if callback_wrapper:
908-
self._callback = _ffi.callback(
909-
'PaStreamCallback', callback_wrapper, error=_lib.paAbort)
909+
if callback is None:
910+
callback = _ffi.NULL
911+
elif isinstance(callback, _ffi.CData):
912+
# Use cast() to allow CData from different FFI instance:
913+
callback = _ffi.cast('PaStreamCallback*', callback)
910914
else:
911-
self._callback = _ffi.NULL
912-
915+
callback = _ffi.callback(
916+
'PaStreamCallback', callback, error=_lib.paAbort)
917+
# CFFI callback object is kept alive during stream lifetime:
918+
self._callback = callback
919+
if userdata is None:
920+
userdata = _ffi.NULL
913921
self._ptr = _ffi.new('PaStream**')
914922
_check(_lib.Pa_OpenStream(self._ptr, iparameters, oparameters,
915923
samplerate, blocksize, stream_flags,
916-
self._callback, _ffi.NULL),
924+
callback, userdata),
917925
'Error opening {0}'.format(self.__class__.__name__))
918926

919927
# dereference PaStream** --> PaStream*
@@ -933,14 +941,17 @@ def __init__(self, kind, samplerate, blocksize, device, channels, dtype,
933941
self._latency = info.inputLatency, info.outputLatency
934942

935943
if finished_callback:
944+
if not isinstance(finished_callback, _ffi.CData):
936945

937-
def finished_callback_wrapper(_):
938-
return finished_callback()
946+
def finished_callback_wrapper(_):
947+
return finished_callback()
939948

940-
self._finished_callback = _ffi.callback(
941-
'PaStreamFinishedCallback', finished_callback_wrapper)
949+
finished_callback = _ffi.callback(
950+
'PaStreamFinishedCallback', finished_callback_wrapper)
951+
# CFFI callback object is kept alive during stream lifetime:
952+
self._finished_callback = finished_callback
942953
_check(_lib.Pa_SetStreamFinishedCallback(self._ptr,
943-
self._finished_callback))
954+
finished_callback))
944955

945956
# Avoid confusion if something goes wrong before assigning self._ptr:
946957
_ptr = _ffi.NULL

0 commit comments

Comments
 (0)