Exemple #1
0
    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
Exemple #2
0
 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())
Exemple #3
0
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())
Exemple #4
0
    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()
Exemple #5
0
    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)
Exemple #6
0
 def version(self):
     """
     Returns the current version of libsoundio
     """
     return _ffi.string(_lib.soundio_version_string()).decode()