Skip to content

Commit b6eb5da

Browse files
committed
add code and host error info to PortAudioError
+ Corrected two PortAudioError exception cases to ValueError exceptions + Added PaErrorCode and host error info to the `args` attribute of `PortAudioError` class when available.
1 parent 85729e8 commit b6eb5da

File tree

1 file changed

+49
-15
lines changed

1 file changed

+49
-15
lines changed

sounddevice.py

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ def playrec(data, samplerate=None, channels=None, dtype=None,
544544
input_frames = ctx.check_out(out, output_frames, channels, dtype,
545545
input_mapping)
546546
if input_frames != output_frames:
547-
raise PortAudioError('len(data) != len(out)')
547+
raise ValueError('len(data) != len(out)')
548548
ctx.frames = input_frames
549549

550550
def callback(indata, outdata, frames, time, status):
@@ -951,7 +951,7 @@ def __init__(self, kind, samplerate=None, blocksize=None, device=None,
951951
self._channels = iparameters.channelCount, oparameters.channelCount
952952
self._samplesize = isize, osize
953953
if isamplerate != osamplerate:
954-
raise PortAudioError(
954+
raise ValueError(
955955
'Input and output device must have the same samplerate')
956956
else:
957957
samplerate = isamplerate
@@ -2289,13 +2289,39 @@ def reset(self):
22892289
vars(self).clear()
22902290
self.__init__()
22912291

2292+
22922293
if not hasattr(_ffi, 'I_AM_FAKE'):
22932294
# This object shadows the 'default' class, except when building the docs.
22942295
default = default()
22952296

22962297

22972298
class PortAudioError(Exception):
2298-
"""This exception will be raised on PortAudio errors."""
2299+
"""This exception will be raised on PortAudio errors.
2300+
2301+
Attributes
2302+
----------
2303+
args
2304+
A variable length tuple containing the following elements when
2305+
available:
2306+
2307+
1) A string describing the error
2308+
2) The PortAudio ``PaErrorCode`` value
2309+
3) A 3-tuple containing the host API index, host error code, and the
2310+
host error message (which may be an empty string)
2311+
2312+
"""
2313+
2314+
def __str__(self):
2315+
errormsg = self.args[0] if self.args else ''
2316+
if len(self.args) > 1:
2317+
errormsg = "{0} [PaErrorCode {1}]".format(errormsg, self.args[1])
2318+
if len(self.args) > 2:
2319+
host_api, hosterror_code, hosterror_text = self.args[2]
2320+
hostname = query_hostapis(host_api)['name']
2321+
errormsg = "{0}: '{1}' [{2} error {3}]".format(
2322+
errormsg, hosterror_text, hostname, hosterror_code)
2323+
2324+
return errormsg
22992325

23002326

23012327
class CallbackStop(Exception):
@@ -2776,19 +2802,27 @@ def _split(value):
27762802
return invalue, outvalue
27772803

27782804

2779-
def _check(err, msg=""):
2805+
def _check(err, msg=''):
27802806
"""Raise error for non-zero error codes."""
2781-
if err < 0:
2782-
msg += ': ' if msg else ''
2783-
if err == _lib.paUnanticipatedHostError:
2784-
info = _lib.Pa_GetLastHostErrorInfo()
2785-
hostapi = _lib.Pa_HostApiTypeIdToHostApiIndex(info.hostApiType)
2786-
msg += 'Unanticipated host API {0} error {1}: {2!r}'.format(
2787-
hostapi, info.errorCode, _ffi.string(info.errorText).decode())
2788-
else:
2789-
msg += _ffi.string(_lib.Pa_GetErrorText(err)).decode()
2790-
raise PortAudioError(msg)
2791-
return err
2807+
if err >= 0:
2808+
return err
2809+
2810+
errormsg = _ffi.string(_lib.Pa_GetErrorText(err)).decode()
2811+
if msg:
2812+
errormsg = "{0}: {1}".format(msg, errormsg)
2813+
2814+
if err == _lib.paUnanticipatedHostError:
2815+
# (gh82) We grab the host error info here rather than inside
2816+
# PortAudioError since _check should only ever be called after a
2817+
# failing API function call. This way we can avoid any potential issues
2818+
# in scenarios where multiple APIs are being used simultaneously.
2819+
info = _lib.Pa_GetLastHostErrorInfo()
2820+
host_api = _lib.Pa_HostApiTypeIdToHostApiIndex(info.hostApiType)
2821+
hosterror_text = _ffi.string(info.errorText).decode()
2822+
hosterror_info = host_api, info.errorCode, hosterror_text
2823+
raise PortAudioError(errormsg, err, hosterror_info)
2824+
2825+
raise PortAudioError(errormsg, err)
27922826

27932827

27942828
def _get_device_id(id_or_query_string, kind, raise_on_error=False):

0 commit comments

Comments
 (0)