def get_layouts(self, device): """ Return a list of available layouts for a device Parameters ---------- device: (SoundIoDevice) device object Returns ------- (dict) Dictionary of available channel layouts for a device """ current = device.current_layout layouts = { 'current': { 'name': _ffi.string(current.name).decode() if current.name else 'None' }, 'available': [] } for idx in range(0, device.layout_count): layouts['available'].append({ 'name': (_ffi.string(device.layouts[idx].name).decode() if device.layouts[idx].name else 'None'), 'channel_count': device.layouts[idx].channel_count }) return layouts
def _check(self, code): """ Returns an error message associated with the return code """ if code != _lib.SoundIoErrorNone: raise PySoundIoError( _ffi.string(_lib.soundio_strerror(code)).decode())
def _input_error_callback(input_stream, error_code): """ Called internally when an error occurs in the input stream. """ logger = logging.getLogger(__name__) logger.error(_ffi.string(_lib.soundio_strerror(error_code)).decode())
def start_output_stream(self, device_id=None, sample_rate=None, dtype=None, block_size=None, channels=None, write_callback=None, underflow_callback=None): """ Creates output stream, and sets parameters. Then allocates a ring buffer and starts the stream. The write callback is called in an audio processing thread, when a block of data should be passed to the speakers. Data is added to the ring buffer to process. Parameters ---------- device_id: (int) output device id sample_rate: (int) desired sample rate (optional) dtype: (SoundIoFormat) desired format, see `Formats`_. (optional) block_size: (int) desired block size (optional) channels: (int) number of channels [1: mono, 2: stereo] (optional) write_callback: (fn) function to call with data, the function must have the arguments data and length. underflow_callback: (fn) function to call if data is not being written fast enough Raises ------ PySoundIoError if any invalid parameters are used Notes ----- An example write callback .. code-block:: python :linenos: # Note: `length` is the number of samples per channel def write_callback(data: bytearray, length: int): outdata = ar.array('f', [0] * length) for value in outdata: outdata = 1.0 data[:] = outdata.tostring() Underflow callback example .. code-block:: python :linenos: def underflow_callback(): print('buffer underflow') """ self.output['sample_rate'] = sample_rate self.output['format'] = dtype self.output['block_size'] = block_size self.output['channels'] = channels self.output['write_callback'] = write_callback self.output['underflow_callback'] = underflow_callback if device_id is not None: self.output['device'] = self.get_output_device(device_id) else: self.output['device'] = self.get_default_output_device() self.logger.info('Input Device: %s' % _ffi.string(self.output['device'].name).decode()) self.sort_channel_layouts(self.output['device']) if self.output['sample_rate']: if not self.supports_sample_rate(self.output['device'], self.output['sample_rate']): raise PySoundIoError('Invalid sample rate: %d' % self.output['sample_rate']) else: self.output['sample_rate'] = self.get_default_sample_rate( self.output['device']) if self.output['format']: if not self.supports_format(self.output['device'], self.output['format']): raise PySoundIoError('Invalid format: %s interleaved' % (_ffi.string( _lib.soundio_format_string( self.output['format'])).decode())) else: self.output['format'] = self.get_default_format( self.output['device']) self._create_output_stream() self._open_output_stream() self.output['bytes_per_frame'] = self.get_bytes_per_frame( self.output['format'], channels) capacity = int(constants.DEFAULT_RING_BUFFER_DURATION * self.output['stream'].sample_rate * self.output['bytes_per_frame']) self._create_output_ring_buffer(capacity) self._clear_output_buffer() if self.output['stream'].layout_error: raise RuntimeError('Layout error') layout_name = _ffi.string(self.output['stream'].layout.name).decode() self.logger.info('Created output stream with a %s layout', layout_name) self.output['thread'] = _OutputProcessingThread(parent=self) self._start_output_stream() self.flush()
def list_devices(self): """ Return a list of available devices Returns ------- (list)(dict) containing information on available input / output devices. """ output_count = _lib.soundio_output_device_count(self._soundio) input_count = _lib.soundio_input_device_count(self._soundio) default_output = _lib.soundio_default_output_device_index( self._soundio) default_input = _lib.soundio_default_input_device_index(self._soundio) input_devices = [] output_devices = [] for i in range(0, input_count): device = _lib.soundio_get_input_device(self._soundio, i) input_devices.append({ 'id': _ffi.string(device.id).decode(), 'name': _ffi.string(device.name).decode(), 'is_raw': device.is_raw, 'is_default': default_input == i, 'sample_rates': self.get_sample_rates(device), 'formats': self.get_formats(device), 'layouts': self.get_layouts(device), 'software_latency_min': device.software_latency_min, 'software_latency_max': device.software_latency_max, 'software_latency_current': device.software_latency_current, 'probe_error': PySoundIoError( _ffi.string(_lib.soundio_strerror(device.probe_error)). decode() if device.probe_error else None) }) _lib.soundio_device_unref(device) for i in range(0, output_count): device = _lib.soundio_get_output_device(self._soundio, i) output_devices.append({ 'id': _ffi.string(device.id).decode(), 'name': _ffi.string(device.name).decode(), 'is_raw': device.is_raw, 'is_default': default_output == i, 'sample_rates': self.get_sample_rates(device), 'formats': self.get_formats(device), 'layouts': self.get_layouts(device), 'software_latency_min': device.software_latency_min, 'software_latency_max': device.software_latency_max, 'software_latency_current': device.software_latency_current, 'probe_error': PySoundIoError( _ffi.string(_lib.soundio_strerror(device.probe_error)). decode() if device.probe_error else None) }) _lib.soundio_device_unref(device) self.logger.info('%d devices found' % (input_count + output_count)) return (input_devices, output_devices)
def version(self): """ Returns the current version of libsoundio """ return _ffi.string(_lib.soundio_version_string()).decode()