def delete(self): if _debug: print('delete') if not self.stream: return with context.lock: pa.pa_stream_disconnect(self.stream) # Wait for stream to terminate before continuing. Prevents cleaned up callbacks to be # called while pa.pa_stream_get_state(self.stream) != pa.PA_STREAM_TERMINATED: context.wait() pa.pa_stream_unref(self.stream) self.stream = None
def __init__(self, source_group, player): super(PulseAudioPlayer, self).__init__(source_group, player) self._events = [] self._timestamps = [] # List of (ref_time, timestamp) self._write_index = 0 # Current write index (tracked manually) self._read_index_valid = False # True only if buffer has non-stale data self._clear_write = False self._buffered_audio_data = None self._underflow_is_eos = False self._buffer_underflow = False self._playing = False audio_format = source_group.audio_format assert audio_format # Create sample_spec sample_spec = pa.pa_sample_spec() if audio_format.sample_size == 8: sample_spec.format = pa.PA_SAMPLE_U8 elif audio_format.sample_size == 16: if sys.byteorder == 'little': sample_spec.format = pa.PA_SAMPLE_S16LE else: sample_spec.format = pa.PA_SAMPLE_S16BE else: raise MediaException('Unsupported sample size') sample_spec.rate = audio_format.sample_rate sample_spec.channels = audio_format.channels channel_map = None self.sample_rate = audio_format.sample_rate with context.lock: # Create stream self.stream = pa.pa_stream_new(context._context, str(id(self)).encode('ASCII'), sample_spec, channel_map) check_not_null(self.stream) pa.pa_stream_ref(self.stream) # Callback trampoline for success operations self._success_cb_func = pa.pa_stream_success_cb_t(self._success_cb) self._context_success_cb_func = \ pa.pa_context_success_cb_t(self._context_success_cb) # Callback for underflow (to detect EOS when expected pa_timestamp # does not get reached). self._underflow_cb_func = \ pa.pa_stream_notify_cb_t(self._underflow_cb) pa.pa_stream_set_underflow_callback(self.stream, self._underflow_cb_func, None) # Callback for data write self._write_cb_func = pa.pa_stream_request_cb_t(self._write_cb) pa.pa_stream_set_write_callback(self.stream, self._write_cb_func, None) # Connect to sink device = None buffer_attr = None flags = (pa.PA_STREAM_START_CORKED | pa.PA_STREAM_INTERPOLATE_TIMING | pa.PA_STREAM_VARIABLE_RATE) sync_stream = None # TODO use this check( pa.pa_stream_connect_playback(self.stream, device, buffer_attr, flags, None, sync_stream) ) # Wait for stream readiness self._state_cb_func = pa.pa_stream_notify_cb_t(self._state_cb) pa.pa_stream_set_state_callback(self.stream, self._state_cb_func, None) while pa.pa_stream_get_state(self.stream) == pa.PA_STREAM_CREATING: context.wait() if pa.pa_stream_get_state(self.stream) != pa.PA_STREAM_READY: check(-1) if _debug: print('stream ready')