@@ -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+
22922293if not hasattr (_ffi , 'I_AM_FAKE' ):
22932294 # This object shadows the 'default' class, except when building the docs.
22942295 default = default ()
22952296
22962297
22972298class 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
23012327class 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
27942828def _get_device_id (id_or_query_string , kind , raise_on_error = False ):
0 commit comments