Skip to content

Commit

Permalink
Rework exception raising to handle GIL acquisition more efficiently
Browse files Browse the repository at this point in the history
  • Loading branch information
nocarryr committed Apr 14, 2020
1 parent 6e6eff1 commit f5f6abc
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 27 deletions.
4 changes: 2 additions & 2 deletions cysounddevice/conversion.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ from cysounddevice.pawrapper cimport *
from cysounddevice.types cimport *
from cysounddevice.buffer cimport BufferItem

cdef void pack_buffer_item(BufferItem* item, float[:,:] src) nogil
cdef int pack_buffer_item(BufferItem* item, float[:,:] src) nogil except -1
cdef void pack_float32(BufferItem* item, float[:,:] src) nogil
cdef void pack_sint32(BufferItem* item, float[:,:] src) nogil
cdef void pack_sint24(BufferItem* item, float[:,:] src) nogil
cdef void pack_sint16(BufferItem* item, float[:,:] src) nogil
cdef void pack_sint8(BufferItem* item, float[:,:] src) nogil
cdef void pack_uint8(BufferItem* item, float[:,:] src) nogil

cdef void unpack_buffer_item(BufferItem* item, float[:,:] dest) nogil
cdef int unpack_buffer_item(BufferItem* item, float[:,:] dest) nogil except -1
cdef void unpack_float32(BufferItem* item, float[:,:] dest) nogil
cdef void unpack_sint32(BufferItem* item, float[:,:] dest) nogil
cdef void unpack_sint24(BufferItem* item, float[:,:] dest) nogil
Expand Down
14 changes: 8 additions & 6 deletions cysounddevice/conversion.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
# TODO: Endian-ness should be checked at compilation time
DEF LITTLE_ENDIAN = True

from cysounddevice.utils cimport raise_withgil, PyExc_ValueError

# -----------------------------------------------------------------------------
# Convert from 2-dimensional float32 array/memoryview into flattened values
# scaled for the SampleBuffer's sample_format, then pack them
# into the BufferItem's char buffer.
# -----------------------------------------------------------------------------

cdef void pack_buffer_item(BufferItem* item, float[:,:] src) nogil:
cdef int pack_buffer_item(BufferItem* item, float[:,:] src) nogil except -1:
cdef SampleFormat* fmt = item.parent_buffer.sample_format
if fmt.pa_ident == paFloat32:
pack_float32(item, src)
Expand All @@ -24,8 +26,8 @@ cdef void pack_buffer_item(BufferItem* item, float[:,:] src) nogil:
elif fmt.pa_ident == paUInt8:
pack_uint8(item, src)
else:
with gil:
raise Exception('Unsupported format')
raise_withgil(PyExc_ValueError, 'Unsupported format')
return 0

cdef void pack_float32(BufferItem* item, float[:,:] src) nogil:
cdef Py_ssize_t i, chan_ix, chan_num
Expand Down Expand Up @@ -149,7 +151,7 @@ cdef void pack_uint8(BufferItem* item, float[:,:] src) nogil:
# placing the results into a 2-dimensional array/memoryview.
# -----------------------------------------------------------------------------

cdef void unpack_buffer_item(BufferItem* item, float[:,:] dest) nogil:
cdef int unpack_buffer_item(BufferItem* item, float[:,:] dest) nogil except -1:
cdef SampleFormat* fmt = item.parent_buffer.sample_format
if fmt.pa_ident == paFloat32:
unpack_float32(item, dest)
Expand All @@ -164,8 +166,8 @@ cdef void unpack_buffer_item(BufferItem* item, float[:,:] dest) nogil:
elif fmt.pa_ident == paUInt8:
unpack_uint8(item, dest)
else:
with gil:
raise Exception('Unsupported format')
raise_withgil(PyExc_ValueError, 'Unsupported format')
return 0

cdef void unpack_float32(BufferItem* item, float[:,:] dest) nogil:
cdef Py_ssize_t i, chan_ix, chan_num
Expand Down
8 changes: 4 additions & 4 deletions cysounddevice/devices.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ cimport cython
import atexit

from cysounddevice.pawrapper cimport *
from cysounddevice.utils cimport handle_error
from cysounddevice.utils cimport handle_pa_error

cdef class DeviceInfo:
"""Container for information about particular device
Expand Down Expand Up @@ -186,8 +186,8 @@ cdef class PortAudio:
if self._initialized:
return
self._initialized = True
handle_error(PaJack_SetClientName(self.jack_client_name_ptr))
handle_error(Pa_Initialize())
handle_pa_error(PaJack_SetClientName(self.jack_client_name_ptr))
handle_pa_error(Pa_Initialize())
self._get_info()
cpdef close(self):
"""Close all streams and terminates the PortAudio library
Expand All @@ -209,7 +209,7 @@ cdef class PortAudio:
self.host_apis_by_name.clear()
self.devices_by_name.clear()
self.devices_by_paindex.clear()
handle_error(Pa_Terminate())
handle_pa_error(Pa_Terminate())
def __enter__(self):
self.open()
return self
Expand Down
10 changes: 5 additions & 5 deletions cysounddevice/stream_callback.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ cdef class StreamCallback:
if self.user_data:
user_data = self.user_data
if user_data.error_status != CallbackError_none:
with gil:
raise_stream_callback_error(user_data)
raise_stream_callback_error(user_data)
return 0

@cython.boundscheck(False)
Expand Down Expand Up @@ -198,7 +197,7 @@ cdef int _stream_callback(const void* in_bfr,
samp_bfr.current_block += 1
return paContinue

cdef raise_stream_callback_error(CallbackUserData* user_data):
cdef int raise_stream_callback_error(CallbackUserData* user_data) except -1 with gil:
cdef PaStreamCallbackFlags cb_flags = user_data.last_callback_flags
cdef object msg = None
if user_data.error_status == CallbackError_flags:
Expand All @@ -212,15 +211,16 @@ cdef raise_stream_callback_error(CallbackUserData* user_data):
if cb_flags & 8:
msgs.append('Output Overflow')
if not len(msgs):
return
return 0
msg = ', '.join(msgs)
elif user_data.error_status == CallbackError_input_aborted:
msg = 'Input Aborted'
elif user_data.error_status == CallbackError_output_aborted:
msg = 'Output Aborted'
else:
return
return 0
warnings.warn(StreamCallbackError(msg))
return 0

cdef void callback_user_data_destroy(CallbackUserData* user_data) except *:
if user_data.in_buffer != NULL:
Expand Down
12 changes: 6 additions & 6 deletions cysounddevice/streams.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
cimport cython

from cysounddevice.pawrapper cimport *
from cysounddevice.utils cimport handle_error
from cysounddevice.utils cimport handle_pa_error
from cysounddevice.devices cimport DeviceInfo
from cysounddevice.types cimport *
from cysounddevice.stream_callback cimport StreamCallback, CallbackUserData
Expand Down Expand Up @@ -115,7 +115,7 @@ cdef class Stream:
self.sample_rate,
)
if err != 0:
handle_error(err)
handle_pa_error(err)
return err
cpdef check_active(self):
cdef PaError err
Expand All @@ -131,7 +131,7 @@ cdef class Stream:
active = False
self._pa_stream_ptr = NULL
else:
handle_error(err)
handle_pa_error(err)
return active
cpdef open(self):
"""Open the stream and begin audio processing
Expand All @@ -151,7 +151,7 @@ cdef class Stream:
))
self.callback_handler._build_user_data()
cdef CallbackUserData* user_data = self.callback_handler.user_data
handle_error(Pa_OpenStream(
handle_pa_error(Pa_OpenStream(
&ptr,
pa_input_params,
pa_output_params,
Expand All @@ -174,7 +174,7 @@ cdef class Stream:
self._pa_stream_ptr = ptr
cdef PaError err = Pa_StartStream(ptr)
if err != paStreamIsNotStopped:
handle_error(err)
handle_pa_error(err)
self.starting = False
# print('waiting...')
# Pa_Sleep(5000)
Expand All @@ -194,7 +194,7 @@ cdef class Stream:
Pa_AbortStream(ptr)

self._pa_stream_ptr = NULL
# handle_error(Pa_StopStream(self._pa_stream_ptr))
# handle_pa_error(Pa_StopStream(self._pa_stream_ptr))
# print('stopped')
self.callback_handler._free_user_data()
print('closed')
Expand Down
10 changes: 9 additions & 1 deletion cysounddevice/utils.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# cython: language_level=3

# from . cimport pawrapper as pa

cdef extern from 'Python.h':
ctypedef struct PyObject
PyObject *PyExc_Exception
PyObject *PyExc_ValueError

from cysounddevice.pawrapper cimport *

cpdef handle_error(PaError err)
cdef int raise_withgil(PyObject *error, char *msg) except -1 with gil

cdef int handle_pa_error(PaError err) nogil except -1
11 changes: 8 additions & 3 deletions cysounddevice/utils.pyx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

from cysounddevice cimport pawrapper

cdef int raise_withgil(PyObject *error, char *msg) except -1 with gil:
raise (<object>error)(msg.decode('ascii'))

class PortAudioError(Exception):
def __init__(self, error_msg, err_code, host_info=None):
Expand All @@ -10,9 +12,12 @@ class PortAudioError(Exception):
def __str__(self):
return repr(self.error_msg)

cpdef handle_error(PaError err):
if err == paNoError:
return
cdef int handle_pa_error(PaError err) nogil except -1:
if err != paNoError:
raise_pa_error(err)
return 0

cdef int raise_pa_error(PaError err) except -1 with gil:
cdef bytes msg_bytes = Pa_GetErrorText(err)
cdef str msg_str = msg_bytes.decode('UTF-8')
raise PortAudioError(msg_str, err)

0 comments on commit f5f6abc

Please sign in to comment.