Example #1
0
    def ctx_notify_cb(self, ctx, user_data):
        state = p.pa_context_get_state(ctx)

        if state == p.PA_CONTEXT_UNCONNECTED:
            self.log.debug(self.log_tag + 'pulseaudio context is unconnected')
        elif state == p.PA_CONTEXT_CONNECTING:
            self.log.debug(self.log_tag + 'pulseaudio context is connecting')
        elif state == p.PA_CONTEXT_AUTHORIZING:
            self.log.debug(self.log_tag + 'pulseaudio context is authorizing')
        elif state == p.PA_CONTEXT_SETTING_NAME:
            self.log.debug(self.log_tag + 'pulseaudio context is setting name')
        elif state == p.PA_CONTEXT_READY:
            self.log.debug(self.log_tag + 'pulseaudio context is ready')
            self.log.debug(self.log_tag + 'connected to server: ' +
                           p.pa_context_get_server(ctx).decode())
            self.log.debug(self.log_tag + 'server protocol version: ' +
                           str(p.pa_context_get_server_protocol_version(ctx)))

            p.pa_context_set_subscribe_callback(ctx, self.subscribe_cb, None)

            # subscribing to pulseaudio events

            subscription_mask = p.PA_SUBSCRIPTION_MASK_SINK_INPUT + \
                p.PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT + \
                p.PA_SUBSCRIPTION_MASK_SOURCE + \
                p.PA_SUBSCRIPTION_MASK_SINK + \
                p.PA_SUBSCRIPTION_MASK_SERVER

            udata = p.ctx_success_cb_data()

            udata.operation = 'subscribe'.encode('utf-8')

            p.pa_context_subscribe(ctx, subscription_mask, self.ctx_success_cb,
                                   p.get_ref(udata))

            self.event_ctx_ready.set()

        elif state == p.PA_CONTEXT_FAILED:
            self.log.critical(self.log_tag +
                              'failed to start pulseaudio context')
            self.log.critical(self.log_tag +
                              'unferencing pulseaudio context object')

            p.pa_context_unref(ctx)

        elif state == p.PA_CONTEXT_TERMINATED:
            self.log.debug(self.log_tag + 'pulseaudio context terminated')

            self.event_ctx_terminated.set()
Example #2
0
    def context_notify(self, ctx, user_data):
        state = p.pa_context_get_state(ctx)

        if state == p.PA_CONTEXT_READY:
            self.log.info('pulseaudio context started')
            self.log.info('connected to server: ' +
                          p.pa_context_get_server(ctx).decode())
            self.log.info('server protocol version: ' +
                          str(p.pa_context_get_server_protocol_version(ctx)))

            p.pa_context_set_subscribe_callback(self.ctx, self.subscribe_cb,
                                                None)

            # subscribing to pulseaudio events

            subscription_mask = p.PA_SUBSCRIPTION_MASK_SINK_INPUT + \
                p.PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT + \
                p.PA_SUBSCRIPTION_MASK_SOURCE + \
                p.PA_SUBSCRIPTION_MASK_SERVER

            p.pa_context_subscribe(self.ctx, subscription_mask,
                                   self.ctx_success_cb, None)

            self.context_ok = True

        elif state == p.PA_CONTEXT_FAILED:
            self.log.critical('failed to start pulseaudio context')
            self.log.info('unferencing pulseaudio context object')
            p.pa_context_unref(self.ctx)

        elif state == p.PA_CONTEXT_TERMINATED:
            self.log.info('pulseaudio context terminated')

            self.log.info('unferencing pulseaudio context object')
            p.pa_context_unref(self.ctx)

            self.context_ok = False
    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)
    def __init__(self):
        GObject.GObject.__init__(self)

        self.context_ok = False

        self.default_sink_idx = -1
        self.default_sink_name = ''
        self.default_sink_rate = -1
        self.default_sink_format = ''

        self.default_source_idx = -1
        self.default_source_name = ''
        self.default_source_rate = -1
        self.default_source_format = ''

        # these variables are used to get values inside pulseaudio's callbacks
        self.sink_is_loaded = False
        self.sink_owner_module = -1
        self.sink_idx = -1
        self.sink_rate = -1
        self.sink_format = ''
        self.sink_monitor_name = ''
        self.sink_monitor_idx = -1

        # these variables are used to get values inside pulseaudio's callbacks
        self.source_idx = -1
        self.source_rate = -1
        self.source_format = ''

        # we redirect sink inputs to this sink
        self.apps_sink_idx = -1
        self.apps_sink_owner_module = -1
        self.apps_sink_rate = -1
        self.apps_sink_format = ''
        self.apps_sink_monitor_name = ''
        self.apps_sink_monitor_idx = -1
        self.apps_sink_description = '\'PulseEffects(apps)\''

        # microphone processed output will be sent to this sink
        # we redirect source outputs to this sink monitor
        self.mic_sink_idx = -1
        self.mic_sink_owner_module = -1
        self.mic_sink_rate = -1
        self.mic_sink_format = ''
        self.mic_sink_monitor_name = ''
        self.mic_sink_monitor_idx = -1
        self.mic_sink_description = '\'PulseEffects(mic)\''

        self.max_volume = p.PA_VOLUME_NORM

        self.log = logging.getLogger('PulseEffects')

        # it makes no sense to show some kind of apps. So we blacklist them
        self.app_blacklist = [
            'PulseEffects', 'pulseeffects', 'gsd-media-keys', 'GNOME Shell',
            'libcanberra', 'gnome-pomodoro', 'PulseAudio Volume Control',
            'Screenshot'
        ]

        self.media_blacklist = [
            'pulsesink probe', 'bell-window-system', 'audio-volume-change',
            'Peak detect', 'screen-capture'
        ]

        # wrapping callbacks
        self.ctx_notify_cb = p.pa_context_notify_cb_t(self.context_notify)
        self.server_info_cb = p.pa_server_info_cb_t(self.server_info)
        self.sink_info_cb = p.pa_sink_info_cb_t(self.sink_info)
        self.source_info_cb = p.pa_source_info_cb_t(self.source_info)
        self.sink_input_info_cb = p.pa_sink_input_info_cb_t(
            self.sink_input_info)
        self.source_output_info_cb = p.pa_source_output_info_cb_t(
            self.source_output_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)
        self.stream_state_cb = p.pa_stream_notify_cb_t(
            self.stream_state_callback)
        self.stream_read_cb = p.pa_stream_request_cb_t(
            self.stream_read_callback)

        # 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_notify_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

        self.get_server_info()
        self.get_default_sink_info()
        self.get_default_source_info()

        # subscribing to pulseaudio events
        p.pa_context_set_subscribe_callback(self.ctx, self.subscribe_cb, None)

        subscription_mask = p.PA_SUBSCRIPTION_MASK_SINK_INPUT + \
            p.PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT + \
            p.PA_SUBSCRIPTION_MASK_SOURCE

        p.pa_context_subscribe(self.ctx, subscription_mask,
                               self.ctx_success_cb, None)