def load_sink(self): sink_name = 'PulseEffects' self.load_sink_info() if not self.sink_is_loaded: args = [] sink_properties = 'device.description=\'PulseEffects\'' sink_properties += 'device.class=\'sound\'' args.append('sink_name=' + sink_name) args.append('sink_properties=' + sink_properties) args.append('channels=2') args.append('rate=' + str(self.default_sink_rate)) argument = ' '.join(map(str, args)).encode('ascii') module = b'module-null-sink' def module_idx(context, idx, user_data): pass self.module_idx_cb = p.pa_context_index_cb_t(module_idx) o = p.pa_context_load_module(self.ctx, module, argument, self.module_idx_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o) self.load_sink_info()
def get_server_info(self): o = p.pa_context_get_server_info(self.ctx, self.server_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o)
def load_source_info(self, name): o = p.pa_context_get_source_info_by_name(self.ctx, name.encode(), self.source_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o)
def load_sink_info(self): sink_name = 'PulseEffects' o = p.pa_context_get_sink_info_by_name(self.ctx, sink_name.encode(), self.sink_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o)
def get_server_info(self): p.pa_threaded_mainloop_lock(self.main_loop) o = p.pa_context_get_server_info(self.ctx, self.server_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: p.pa_threaded_mainloop_wait(self.main_loop) p.pa_operation_unref(o) p.pa_threaded_mainloop_unlock(self.main_loop)
def find_sources(self): p.pa_threaded_mainloop_lock(self.main_loop) o = p.pa_context_get_source_info_list(self.ctx, self.source_info_cb, 1) # 1 for new while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: p.pa_threaded_mainloop_wait(self.main_loop) p.pa_operation_unref(o) p.pa_threaded_mainloop_unlock(self.main_loop)
def load_source_info(self, name): p.pa_threaded_mainloop_lock(self.main_loop) o = p.pa_context_get_source_info_by_name(self.ctx, name.encode(), self.source_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: p.pa_threaded_mainloop_wait(self.main_loop) p.pa_operation_unref(o) p.pa_threaded_mainloop_unlock(self.main_loop)
def unload_module(self, module): user_data = p.ctx_success_cb_data() user_data.operation = 'unload_module'.encode('utf-8') p.pa_threaded_mainloop_lock(self.main_loop) o = p.pa_context_unload_module(self.ctx, module, self.ctx_success_cb, p.get_ref(user_data)) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: p.pa_threaded_mainloop_wait(self.main_loop) p.pa_operation_unref(o) p.pa_threaded_mainloop_unlock(self.main_loop)
def drain_ctx(self): o = p.pa_context_drain(self.ctx, self.ctx_drain_notify_cb, None) if o: p.pa_threaded_mainloop_lock(self.main_loop) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: p.pa_threaded_mainloop_wait(self.main_loop) p.pa_threaded_mainloop_unlock(self.main_loop) self.log.debug(self.log_tag + 'drained pulseaudio context') p.pa_operation_unref(o) else: self.log.debug(self.log_tag + 'context is already drained')
def load_sink(self): sink_name = 'PulseEffects' self.load_sink_info() if not self.sink_is_loaded: self.log.info('loading Pulseeffects sink...') args = [] sink_properties = 'device.description=\'PulseEffects\'' sink_properties += 'device.class=\'sound\'' args.append('sink_name=' + sink_name) args.append('sink_properties=' + sink_properties) args.append('channels=2') args.append('rate=' + str(self.default_sink_rate)) argument = ' '.join(map(str, args)).encode('ascii') module = b'module-null-sink' def module_idx(context, idx, user_data): self.log.info('sink owner module index: ' + str(idx)) self.module_idx_cb = p.pa_context_index_cb_t(module_idx) o = p.pa_context_load_module(self.ctx, module, argument, self.module_idx_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o) self.load_sink_info() if self.sink_is_loaded: self.log.info('Pulseeffects sink was successfully loaded') self.log.info('Pulseeffects sink index:' + str(self.sink_idx)) self.log.info('Pulseeffects sink monitor name: ' + self.sink_monitor_name + '. We will process audio from this source.') else: self.log.critical('Could not load sink')
def load_sink(self, name, description, rate): self.sink_is_loaded = False self.load_sink_info(name) if not self.sink_is_loaded: args = [] sink_properties = description sink_properties += 'device.class=\'sound\'' args.append('sink_name=' + name) args.append('sink_properties=' + sink_properties) args.append('channels=2') args.append('rate=' + str(rate)) argument = ' '.join(map(str, args)).encode('ascii') module = b'module-null-sink' def module_idx(context, idx, user_data): self.log.info('sink owner module index: ' + str(idx)) self.module_idx_cb = p.pa_context_index_cb_t(module_idx) o = p.pa_context_load_module(self.ctx, module, argument, self.module_idx_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o) self.load_sink_info(name) if self.sink_is_loaded: return True else: return False else: return True
def load_sink(self, name, description, rate): self.sink_is_loaded = False self.load_sink_info(name) if not self.sink_is_loaded: args = [] sink_properties = description sink_properties += 'device.class=\'sound\'' args.append('sink_name=' + name) args.append('sink_properties=' + sink_properties) args.append('channels=2') args.append('rate=' + str(rate)) argument = ' '.join(map(str, args)).encode('ascii') module = b'module-null-sink' p.pa_threaded_mainloop_lock(self.main_loop) o = p.pa_context_load_module(self.ctx, module, argument, self.module_idx_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: p.pa_threaded_mainloop_wait(self.main_loop) p.pa_operation_unref(o) p.pa_threaded_mainloop_unlock(self.main_loop) self.load_sink_info(name) # checking if sink was loaded if self.sink_is_loaded: return True else: return False else: return True
def __init__(self): GObject.GObject.__init__(self) self.context_ok = False self.default_sink_name = '' self.sink_is_loaded = False self.sink_owner_module = -1 self.sink_idx = -1 self.sink_monitor_name = '' self.sink_inputs = [] self.max_volume = p.PA_VOLUME_NORM self.log = logging.getLogger('PulseEffects') self.app_blacklist = [ 'PulseEffects', 'pulseeffects', 'gsd-media-keys', 'GNOME Shell', 'libcanberra', 'gnome-pomodoro' ] self.media_blacklist = ['pulsesink probe'] # wrapping callbacks self.ctx_cb = p.pa_context_notify_cb_t(self.context_status) self.server_info_cb = p.pa_server_info_cb_t(self.server_info) self.default_sink_info_cb = p.pa_sink_info_cb_t(self.default_sink_info) self.sink_info_cb = p.pa_sink_info_cb_t(self.sink_info) self.sink_input_info_cb = p.pa_sink_input_info_cb_t( self.sink_input_info) self.ctx_success_cb = p.pa_context_success_cb_t(self.ctx_success) self.subscribe_cb = p.pa_context_subscribe_cb_t(self.subscribe) # creating main loop and context self.main_loop = p.pa_threaded_mainloop_new() self.main_loop_api = p.pa_threaded_mainloop_get_api(self.main_loop) self.ctx = p.pa_context_new(self.main_loop_api, b'PulseEffects') p.pa_context_set_state_callback(self.ctx, self.ctx_cb, None) p.pa_context_connect(self.ctx, None, 0, None) p.pa_threaded_mainloop_start(self.main_loop) # waiting context while self.context_ok is False: pass # getting default sink name through server info o = p.pa_context_get_server_info(self.ctx, self.server_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o) self.log.info('default pulseaudio sink: ' + self.default_sink_name) # getting default sink rate through sink info. We set # module-null-sink to the same rate to reduce clock drift o = p.pa_context_get_sink_info_by_name(self.ctx, self.default_sink_name.encode(), self.default_sink_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o) self.log.info('default pulseaudio sink audio format: ' + str(self.default_sink_format) + '. We will use the same format.') self.log.info('default pulseaudio sink sampling rate: ' + str(self.default_sink_rate) + ' Hz. We will use the same rate.') # load source sink self.load_sink() # search sink inputs o = p.pa_context_get_sink_input_info_list(self.ctx, self.sink_input_info_cb, None) while p.pa_operation_get_state(o) == p.PA_OPERATION_RUNNING: pass p.pa_operation_unref(o) # subscribing to pulseaudio events p.pa_context_set_subscribe_callback(self.ctx, self.subscribe_cb, None) p.pa_context_subscribe(self.ctx, p.PA_SUBSCRIPTION_MASK_SINK_INPUT, self.ctx_success_cb, None)