# PyAudio : Python Bindings for PortAudio. # Copyright (c) 2006-2010 Hubert Pham # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ PyAudio : Python Bindings for PortAudio v19. **These bindings only support PortAudio blocking mode.** :var PaSampleFormat: A list of all PortAudio ``PaSampleFormat`` value constants. See: `paInt32`, `paInt24`, `paInt16`, `paInt8`, and `paUInt8`. :var PaHostApiTypeId: A list of all PortAudio ``PaHostApiTypeId`` constants. See: `paInDevelopment`, `paDirectSound`, `paMME`, `paASIO`, `paSoundManager`, `paCoreAudio`, `paOSS`, `paALSA`, `paAL`, *et al...* :var PaErrorCode: A list of all PortAudio ``PaErrorCode`` constants. Typically, error code constants are included in Python exception objects (as the second argument). See: `paNoError`, `paNotInitialized`, `paUnanticipatedHostError`, *et al...* :group PortAudio Constants: PaSampleFormat, PaHostApiTypeId, PaErrorCode :group PaSampleFormat Values: paFloat32, paInt32, paInt24, paInt16, paInt8, paUInt8, paCustomFormat :group PaHostApiTypeId Values: paInDevelopment, paDirectSound, paMME, paASIO, paSoundManager, paCoreAudio, paOSS, paALSA paAL, paBeOS, paWDMKS, paJACK, paWASAPI, paNoDevice :group PaErrorCode Values: paNoError, paNotInitialized, paUnanticipatedHostError, paInvalidChannelCount, paInvalidSampleRate, paInvalidDevice, paInvalidFlag, paSampleFormatNotSupported, paBadIODeviceCombination, paInsufficientMemory, paBufferTooBig, paBufferTooSmall, paNullCallback, paBadStreamPtr, paTimedOut, paInternalError, paDeviceUnavailable, paIncompatibleHostApiSpecificStreamInfo, paStreamIsStopped, paStreamIsNotStopped, paInputOverflowed, paOutputUnderflowed, paHostApiNotFound, paInvalidHostApi, paCanNotReadFromACallbackStream, paCanNotWriteToACallbackStream, paCanNotReadFromAnOutputOnlyStream, paCanNotWriteToAnInputOnlyStream, paIncompatibleStreamHostApi :group Stream Conversion Convenience Functions: get_sample_size, get_format_from_width :group PortAudio version: get_portaudio_version, get_portaudio_version_text :sort: PaSampleFormat, PaHostApiTypeId, PaErrorCode :sort: PortAudio Constants, PaSampleFormat Values, PaHostApiTypeId Values, PaErrorCode Values """ __author__ = "Hubert Pham" __version__ = "0.2.4" __docformat__ = "restructuredtext en" import _portaudio as pa # Try to use Python 2.4's built in `set' try: a = set() del a except NameError: from sets import Set as set ############################################################ # GLOBALS ############################################################ ##### PaSampleFormat Sample Formats ##### paFloat32 = pa.paFloat32 paInt32 = pa.paInt32 paInt24 = pa.paInt24 paInt16 = pa.paInt16 paInt8 = pa.paInt8 paUInt8 = pa.paUInt8 paCustomFormat = pa.paCustomFormat # group them together for epydoc PaSampleFormat = ['paFloat32', 'paInt32', 'paInt24', 'paInt16', 'paInt8', 'paUInt8', 'paCustomFormat'] ###### HostAPI TypeId ##### paInDevelopment = pa.paInDevelopment paDirectSound = pa.paDirectSound paMME = pa.paMME paASIO = pa.paASIO paSoundManager = pa.paSoundManager paCoreAudio = pa.paCoreAudio paOSS = pa.paOSS paALSA = pa.paALSA paAL = pa.paAL paBeOS = pa.paBeOS paWDMKS = pa.paWDMKS paJACK = pa.paJACK paWASAPI = pa.paWASAPI paNoDevice = pa.paNoDevice # group them together for epydoc PaHostApiTypeId = ['paInDevelopment', 'paDirectSound', 'paMME', 'paASIO', 'paSoundManager', 'paCoreAudio', 'paOSS', 'paALSA', 'paAL', 'paBeOS', 'paWDMKS', 'paJACK', 'paWASAPI', 'paNoDevice'] ###### portaudio error codes ##### paNoError = pa.paNoError paNotInitialized = pa.paNotInitialized paUnanticipatedHostError = pa.paUnanticipatedHostError paInvalidChannelCount = pa.paInvalidChannelCount paInvalidSampleRate = pa.paInvalidSampleRate paInvalidDevice = pa.paInvalidDevice paInvalidFlag = pa.paInvalidFlag paSampleFormatNotSupported = pa.paSampleFormatNotSupported paBadIODeviceCombination = pa.paBadIODeviceCombination paInsufficientMemory = pa.paInsufficientMemory paBufferTooBig = pa.paBufferTooBig paBufferTooSmall = pa.paBufferTooSmall paNullCallback = pa.paNullCallback paBadStreamPtr = pa.paBadStreamPtr paTimedOut = pa.paTimedOut paInternalError = pa.paInternalError paDeviceUnavailable = pa.paDeviceUnavailable paIncompatibleHostApiSpecificStreamInfo = pa.paIncompatibleHostApiSpecificStreamInfo paStreamIsStopped = pa.paStreamIsStopped paStreamIsNotStopped = pa.paStreamIsNotStopped paInputOverflowed = pa.paInputOverflowed paOutputUnderflowed = pa.paOutputUnderflowed paHostApiNotFound = pa.paHostApiNotFound paInvalidHostApi = pa.paInvalidHostApi paCanNotReadFromACallbackStream = pa.paCanNotReadFromACallbackStream paCanNotWriteToACallbackStream = pa.paCanNotWriteToACallbackStream paCanNotReadFromAnOutputOnlyStream = pa.paCanNotReadFromAnOutputOnlyStream paCanNotWriteToAnInputOnlyStream = pa.paCanNotWriteToAnInputOnlyStream paIncompatibleStreamHostApi = pa.paIncompatibleStreamHostApi # group them together for epydoc PaErrorCode = ['paNoError', 'paNotInitialized', 'paUnanticipatedHostError', 'paInvalidChannelCount', 'paInvalidSampleRate', 'paInvalidDevice', 'paInvalidFlag', 'paSampleFormatNotSupported', 'paBadIODeviceCombination', 'paInsufficientMemory', 'paBufferTooBig', 'paBufferTooSmall', 'paNullCallback', 'paBadStreamPtr', 'paTimedOut', 'paInternalError', 'paDeviceUnavailable', 'paIncompatibleHostApiSpecificStreamInfo', 'paStreamIsStopped', 'paStreamIsNotStopped', 'paInputOverflowed', 'paOutputUnderflowed', 'paHostApiNotFound', 'paInvalidHostApi', 'paCanNotReadFromACallbackStream', 'paCanNotWriteToACallbackStream', 'paCanNotReadFromAnOutputOnlyStream', 'paCanNotWriteToAnInputOnlyStream', 'paIncompatibleStreamHostApi'] ############################################################ # Convenience Functions ############################################################ def get_sample_size(format): """ Returns the size (in bytes) for the specified sample `format` (a `PaSampleFormat` constant). :param `format`: PortAudio sample format constant `PaSampleFormat`. :raises ValueError: Invalid specified `format`. :rtype: int """ return pa.get_sample_size(format) def get_format_from_width(width, unsigned = True): """ Returns a PortAudio format constant for the specified `width`. :param `width`: The desired sample width in bytes (1, 2, 3, or 4) :param `unsigned`: For 1 byte width, specifies signed or unsigned format. :raises ValueError: for invalid `width` :rtype: `PaSampleFormat` """ if width == 1: if unsigned: return paUInt8 else: return paInt8 elif width == 2: return paInt16 elif width == 3: return paInt24 elif width == 4: return paFloat32 else: raise ValueError, "Invalid width: %d" % width ############################################################ # Versioning ############################################################ def get_portaudio_version(): """ Returns portaudio version. :rtype: str """ return pa.get_version() def get_portaudio_version_text(): """ Returns PortAudio version as a text string. :rtype: str """ return pa.get_version_text() ############################################################ # Wrapper around _portaudio Stream (Internal) ############################################################ # Note: See PyAudio class below for main export. class Stream: """ PortAudio Stream Wrapper. Use `PyAudio.open` to make a new `Stream`. :group Opening and Closing: __init__, close :group Stream Info: get_input_latency, get_output_latency, get_time, get_cpu_load :group Stream Management: start_stream, stop_stream, is_active, is_stopped :group Input Output: write, read, get_read_available, get_write_available """ def __init__(self, PA_manager, rate, channels, format, input = False, output = False, input_device_index = None, output_device_index = None, frames_per_buffer = 1024, start = True, input_host_api_specific_stream_info = None, output_host_api_specific_stream_info = None): """ Initialize a stream; this should be called by `PyAudio.open`. A stream can either be input, output, or both. :param `PA_manager`: A reference to the managing `PyAudio` instance :param `rate`: Sampling rate :param `channels`: Number of channels :param `format`: Sampling size and format. See `PaSampleFormat`. :param `input`: Specifies whether this is an input stream. Defaults to False. :param `output`: Specifies whether this is an output stream. Defaults to False. :param `input_device_index`: Index of Input Device to use. Unspecified (or None) uses default device. Ignored if `input` is False. :param `output_device_index`: Index of Output Device to use. Unspecified (or None) uses the default device. Ignored if `output` is False. :param `frames_per_buffer`: Specifies the number of frames per buffer. :param `start`: Start the stream running immediately. Defaults to True. In general, there is no reason to set this to false. :param `input_host_api_specific_stream_info`: Specifies a host API specific stream information data structure for input. See `PaMacCoreStreamInfo`. :param `output_host_api_specific_stream_info`: Specifies a host API specific stream information data structure for output. See `PaMacCoreStreamInfo`. :raise ValueError: Neither input nor output are set True. """ # no stupidity allowed if not (input or output): raise ValueError, \ "Must specify an input or output " +\ "stream." # remember parent self._parent = PA_manager # remember if we are an: input, output (or both) self._is_input = input self._is_output = output # are we running? self._is_running = start # remember some parameters self._rate = rate self._channels = channels self._format = format self._frames_per_buffer = frames_per_buffer arguments = { 'rate' : rate, 'channels' : channels, 'format' : format, 'input' : input, 'output' : output, 'input_device_index' : input_device_index, 'output_device_index' : output_device_index, 'frames_per_buffer' : frames_per_buffer} if input_host_api_specific_stream_info: _l = input_host_api_specific_stream_info arguments[ 'input_host_api_specific_stream_info' ] = _l._get_host_api_stream_object() if output_host_api_specific_stream_info: _l = output_host_api_specific_stream_info arguments[ 'output_host_api_specific_stream_info' ] = _l._get_host_api_stream_object() # calling pa.open returns a stream object self._stream = pa.open(**arguments) self._input_latency = self._stream.inputLatency self._output_latency = self._stream.outputLatency if self._is_running: pa.start_stream(self._stream) def close(self): """ Close the stream """ pa.close(self._stream) self._is_running = False self._parent._remove_stream(self) ############################################################ # Stream Info ############################################################ def get_input_latency(self): """ Return the input latency. :rtype: float """ return self._stream.inputLatency def get_output_latency(self): """ Return the input latency. :rtype: float """ return self._stream.outputLatency def get_time(self): """ Return stream time. :rtype: float """ return pa.get_stream_time(self._stream) def get_cpu_load(self): """ Return the CPU load. (Note: this is always 0.0 for the blocking API.) :rtype: float """ return pa.get_stream_cpu_load(self._stream) ############################################################ # Stream Management ############################################################ def start_stream(self): """ Start the stream. """ if self._is_running: return pa.start_stream(self._stream) self._is_running = True def stop_stream(self): """ Stop the stream. Once the stream is stopped, one may not call write or read. However, one may call start_stream to resume the stream. """ if not self._is_running: return pa.stop_stream(self._stream) self._is_running = False def is_active(self): """ Returns whether the stream is active. :rtype: bool """ return pa.is_stream_active(self._stream) def is_stopped(self): """ Returns whether the stream is stopped. :rtype: bool """ return pa.is_stream_stopped(self._stream) ############################################################ # Reading/Writing ############################################################ def write(self, frames, num_frames = None, exception_on_underflow = False): """ Write samples to the stream. :param `frames`: The frames of data. :param `num_frames`: The number of frames to write. Defaults to None, in which this value will be automatically computed. :param `exception_on_underflow`: Specifies whether an exception should be thrown (or silently ignored) on buffer underflow. Defaults to False for improved performance, especially on slower platforms. :raises IOError: if the stream is not an output stream or if the write operation was unsuccessful. :rtype: `None` """ if not self._is_output: raise IOError("Not output stream", paCanNotWriteToAnInputOnlyStream) if num_frames == None: # determine how many frames to read width = get_sample_size(self._format) num_frames = len(frames) / (self._channels * width) #print len(frames), self._channels, self._width, num_frames pa.write_stream(self._stream, frames, num_frames, exception_on_underflow) def read(self, num_frames): """ Read samples from the stream. :param `num_frames`: The number of frames to read. :raises IOError: if stream is not an input stream or if the read operation was unsuccessful. :rtype: str """ if not self._is_input: raise IOError("Not input stream", paCanNotReadFromAnOutputOnlyStream) return pa.read_stream(self._stream, num_frames) def get_read_available(self): """ Return the number of frames that can be read without waiting. :rtype: int """ return pa.get_stream_read_available(self._stream) def get_write_available(self): """ Return the number of frames that can be written without waiting. :rtype: int """ return pa.get_stream_write_available(self._stream) ############################################################ # Main Export ############################################################ class PyAudio: """ Python interface to PortAudio. Provides methods to: - initialize and terminate PortAudio - open and close streams - query and inspect the available PortAudio Host APIs - query and inspect the available PortAudio audio devices Use this class to open and close streams. :group Stream Management: open, close :group Host API: get_host_api_count, get_default_host_api_info, get_host_api_info_by_type, get_host_api_info_by_index, get_device_info_by_host_api_device_index :group Device API: get_device_count, is_format_supported, get_default_input_device_info, get_default_output_device_info, get_device_info_by_index :group Stream Format Conversion: get_sample_size, get_format_from_width """ ############################################################ # Initialization and Termination ############################################################ def __init__(self): """ Initialize PortAudio. """ pa.initialize() self._streams = set() def terminate(self): """ Terminate PortAudio. :attention: Be sure to call this method for every instance of this object to release PortAudio resources. """ for stream in self._streams: stream.close() self._streams = set() pa.terminate() ############################################################ # Stream Format ############################################################ def get_sample_size(self, format): """ Returns the size (in bytes) for the specified sample `format` (a `PaSampleFormat` constant). :param `format`: Sample format constant (`PaSampleFormat`). :raises ValueError: Invalid specified `format`. :rtype: int """ return pa.get_sample_size(format) def get_format_from_width(self, width, unsigned = True): """ Returns a PortAudio format constant for the specified `width`. :param `width`: The desired sample width in bytes (1, 2, 3, or 4) :param `unsigned`: For 1 byte width, specifies signed or unsigned format. :raises ValueError: for invalid `width` :rtype: `PaSampleFormat` """ if width == 1: if unsigned: return paUInt8 else: return paInt8 elif width == 2: return paInt16 elif width == 3: return paInt24 elif width == 4: return paFloat32 else: raise ValueError, "Invalid width: %d" % width ############################################################ # Stream Factory ############################################################ def open(self, *args, **kwargs): """ Open a new stream. See constructor for `Stream.__init__` for parameter details. :returns: `Stream` """ stream = Stream(self, *args, **kwargs) self._streams.add(stream) return stream def close(self, stream): """ Close a stream. Typically use `Stream.close` instead. :param `stream`: An instance of the `Stream` object. :raises ValueError: if stream does not exist. """ if stream not in self._streams: raise ValueError, "Stream `%s' not found" % str(stream) stream.close() def _remove_stream(self, stream): """ Internal method. Removes a stream. :param `stream`: An instance of the `Stream` object. """ if stream in self._streams: self._streams.remove(stream) ############################################################ # Host API Inspection ############################################################ def get_host_api_count(self): """ Return the number of PortAudio Host APIs. :rtype: int """ return pa.get_host_api_count() def get_default_host_api_info(self): """ Return a dictionary containing the default Host API parameters. The keys of the dictionary mirror the data fields of PortAudio's ``PaHostApiInfo`` structure. :raises IOError: if no default input device available :rtype: dict """ defaultHostApiIndex = pa.get_default_host_api() return self.get_host_api_info_by_index(defaultHostApiIndex) def get_host_api_info_by_type(self, host_api_type): """ Return a dictionary containing the Host API parameters for the host API specified by the `host_api_type`. The keys of the dictionary mirror the data fields of PortAudio's ``PaHostApiInfo`` structure. :param `host_api_type`: The desired Host API (`PaHostApiTypeId` constant). :raises IOError: for invalid `host_api_type` :rtype: dict """ index = pa.host_api_type_id_to_host_api_index(host_api_type) return self.get_host_api_info_by_index(index) def get_host_api_info_by_index(self, host_api_index): """ Return a dictionary containing the Host API parameters for the host API specified by the `host_api_index`. The keys of the dictionary mirror the data fields of PortAudio's ``PaHostApiInfo`` structure. :param `host_api_index`: The host api index. :raises IOError: for invalid `host_api_index` :rtype: dict """ return self._make_host_api_dictionary( host_api_index, pa.get_host_api_info(host_api_index) ) def get_device_info_by_host_api_device_index(self, host_api_index, host_api_device_index): """ Return a dictionary containing the Device parameters for a given Host API's n'th device. The keys of the dictionary mirror the data fields of PortAudio's ``PaDeviceInfo`` structure. :param `host_api_index`: The Host API index number. :param `host_api_device_index`: The *n* 'th device of the host API. :raises IOError: for invalid indices :rtype: dict """ long_method_name = pa.host_api_device_index_to_device_index device_index = long_method_name(host_api_index, host_api_device_index) return self.get_device_info_by_index(device_index) def _make_host_api_dictionary(self, index, host_api_struct): """ Internal method to create Host API dictionary that mirrors PortAudio's ``PaHostApiInfo`` structure. :rtype: dict """ return {'index' : index, 'structVersion' : host_api_struct.structVersion, 'type' : host_api_struct.type, 'name' : host_api_struct.name, 'deviceCount' : host_api_struct.deviceCount, 'defaultInputDevice' : host_api_struct.defaultInputDevice, 'defaultOutputDevice' : host_api_struct.defaultOutputDevice} ############################################################ # Device Inspection ############################################################ def get_device_count(self): """ Return the number of PortAudio Host APIs. :rtype: int """ return pa.get_device_count() def is_format_supported(self, rate, input_device = None, input_channels = None, input_format = None, output_device = None, output_channels = None, output_format = None): """ Check to see if specified device configuration is supported. Returns True if the configuration is supported; throws a ValueError exception otherwise. :param `rate`: Specifies the desired rate (in Hz) :param `input_device`: The input device index. Specify `None` (default) for half-duplex output-only streams. :param `input_channels`: The desired number of input channels. Ignored if `input_device` is not specified (or `None`). :param `input_format`: PortAudio sample format constant defined in this module :param `output_device`: The output device index. Specify `None` (default) for half-duplex input-only streams. :param `output_channels`: The desired number of output channels. Ignored if `input_device` is not specified (or `None`). :param `output_format`: PortAudio sample format constant (`PaSampleFormat`). :rtype: bool :raises ValueError: tuple containing: (error string, PortAudio error code `PaErrorCode`). """ if input_device == None and output_device == None: raise ValueError("must specify stream format for input, " +\ "output, or both", paInvalidDevice); kwargs = {} if input_device != None: kwargs['input_device'] = input_device kwargs['input_channels'] = input_channels kwargs['input_format'] = input_format if output_device != None: kwargs['output_device'] = output_device kwargs['output_channels'] = output_channels kwargs['output_format'] = output_format return pa.is_format_supported(rate, **kwargs) def get_default_input_device_info(self): """ Return the default input Device parameters as a dictionary. The keys of the dictionary mirror the data fields of PortAudio's ``PaDeviceInfo`` structure. :raises IOError: No default input device available. :rtype: dict """ device_index = pa.get_default_input_device() return self.get_device_info_by_index(device_index) def get_default_output_device_info(self): """ Return the default output Device parameters as a dictionary. The keys of the dictionary mirror the data fields of PortAudio's ``PaDeviceInfo`` structure. :raises IOError: No default output device available. :rtype: dict """ device_index = pa.get_default_output_device() return self.get_device_info_by_index(device_index) def get_device_info_by_index(self, device_index): """ Return the Device parameters for device specified in `device_index` as a dictionary. The keys of the dictionary mirror the data fields of PortAudio's ``PaDeviceInfo`` structure. :param `device_index`: The device index. :raises IOError: Invalid `device_index`. :rtype: dict """ return self._make_device_info_dictionary( device_index, pa.get_device_info(device_index) ) def _make_device_info_dictionary(self, index, device_info): """ Internal method to create Device Info dictionary that mirrors PortAudio's ``PaDeviceInfo`` structure. :rtype: dict """ return {'index' : index, 'structVersion' : device_info.structVersion, 'name' : device_info.name, 'hostApi' : device_info.hostApi, 'maxInputChannels' : device_info.maxInputChannels, 'maxOutputChannels' : device_info.maxOutputChannels, 'defaultLowInputLatency' : device_info.defaultLowInputLatency, 'defaultLowOutputLatency' : device_info.defaultLowOutputLatency, 'defaultHighInputLatency' : device_info.defaultHighInputLatency, 'defaultHighOutputLatency' : device_info.defaultHighOutputLatency, 'defaultSampleRate' : device_info.defaultSampleRate } ###################################################################### # Host Specific Stream Info ###################################################################### try: paMacCoreStreamInfo = pa.paMacCoreStreamInfo except AttributeError: pass else: class PaMacCoreStreamInfo: """ Mac OS X-only: PaMacCoreStreamInfo is a PortAudio Host API Specific Stream Info data structure for specifying Mac OS X-only settings. Instantiate this class (if desired) and pass the instance as the argument in `PyAudio.open` to parameters ``input_host_api_specific_stream_info`` or ``output_host_api_specific_stream_info``. (See `Stream.__init__`.) :note: Mac OS X only. :group Flags (constants): paMacCoreChangeDeviceParameters, paMacCoreFailIfConversionRequired, paMacCoreConversionQualityMin, paMacCoreConversionQualityMedium, paMacCoreConversionQualityLow, paMacCoreConversionQualityHigh, paMacCoreConversionQualityMax, paMacCorePlayNice, paMacCorePro, paMacCoreMinimizeCPUButPlayNice, paMacCoreMinimizeCPU :group Settings: get_flags, get_channel_map """ paMacCoreChangeDeviceParameters = pa.paMacCoreChangeDeviceParameters paMacCoreFailIfConversionRequired = pa.paMacCoreFailIfConversionRequired paMacCoreConversionQualityMin = pa.paMacCoreConversionQualityMin paMacCoreConversionQualityMedium = pa.paMacCoreConversionQualityMedium paMacCoreConversionQualityLow = pa.paMacCoreConversionQualityLow paMacCoreConversionQualityHigh = pa.paMacCoreConversionQualityHigh paMacCoreConversionQualityMax = pa.paMacCoreConversionQualityMax paMacCorePlayNice = pa.paMacCorePlayNice paMacCorePro = pa.paMacCorePro paMacCoreMinimizeCPUButPlayNice = pa.paMacCoreMinimizeCPUButPlayNice paMacCoreMinimizeCPU = pa.paMacCoreMinimizeCPU def __init__(self, flags = None, channel_map = None): """ Initialize with flags and channel_map. See PortAudio documentation for more details on these parameters; they are passed almost verbatim to the PortAudio library. :param `flags`: paMacCore* flags OR'ed together. See `PaMacCoreStreamInfo`. :param `channel_map`: An array describing the channel mapping. See PortAudio documentation for usage. """ kwargs = {"flags" : flags, "channel_map" : channel_map} if flags == None: del kwargs["flags"] if channel_map == None: del kwargs["channel_map"] self._paMacCoreStreamInfo = paMacCoreStreamInfo(**kwargs) def get_flags(self): """ Return the flags set at instantiation. :rtype: int """ return self._paMacCoreStreamInfo.flags def get_channel_map(self): """ Return the channel map set at instantiation. :rtype: tuple or None """ return self._paMacCoreStreamInfo.channel_map def _get_host_api_stream_object(self): """ Private method. """ return self._paMacCoreStreamInfo