Пример #1
0
 def unload(self):
     dprint(self.id)
     pa = PulseAudioUtils()
     id = self.id
     pa.UnloadModule(self.id, lambda x: dprint("Unload %s result %s" %
                                               (id, x)))
     self.id = None
     self.refcount = 0
Пример #2
0
    def on_load(self, user_data):
        self.devices = {}
        self.item = None

        self.deferred = []

        pa = PulseAudioUtils()
        pa.connect("event", self.on_pa_event)
        pa.connect("connected", self.on_pa_ready)
Пример #3
0
    def query_pa(self, device):
        def list_cb(cards):
            for c in cards.values():
                if c["proplist"]["device.string"] == device.Address:
                    self.devices[device.Address] = c
                    self.generate_menu(device)
                    return

        pa = PulseAudioUtils()
        pa.ListCards(list_cb)
Пример #4
0
    def query_pa(self, device):
        def list_cb(cards):
            for c in cards.values():
                if c["proplist"]["device.string"] == device['Address']:
                    self.devices[device['Address']] = c
                    self.generate_menu(device)
                    return

        pa = PulseAudioUtils()
        pa.list_cards(list_cb)
Пример #5
0
    def query_pa(self, device: Device, item: Gtk.MenuItem) -> None:
        def list_cb(cards: Mapping[str, "CardInfo"]) -> None:
            for c in cards.values():
                if c["proplist"]["device.string"] == device['Address']:
                    self.devices[device['Address']] = c
                    self.generate_menu(device, item)
                    return

        pa = PulseAudioUtils()
        pa.list_cards(list_cb)
Пример #6
0
    def on_activate_profile(self, device: "Device", profile: "CardProfileInfo") -> None:
        pa = PulseAudioUtils()

        c = self._devices[device['Address']]

        def on_result(res: int) -> None:
            if not res:
                logging.error("Failed to change profile to %s" % profile["name"])

        pa.set_card_profile(c["index"], profile["name"], on_result)
Пример #7
0
    def query_pa(self, device: "Device") -> None:
        def list_cb(cards: Mapping[str, "CardInfo"]) -> None:
            for c in cards.values():
                if c["proplist"]["device.string"] == device['Address']:
                    self._devices[device['Address']] = c
                    self.add_device_profile_menu(device)
                    return

        pa = PulseAudioUtils()
        pa.list_cards(list_cb)
Пример #8
0
    def on_selection_changed(self, item, device, profile):
        if item.get_active():
            pa = PulseAudioUtils()

            c = self.devices[device['Address']]

            def on_result(res):
                if not res:
                    MessageArea.show_message(_("Failed to change profile to %s" % profile))

            pa.SetCardProfile(c["index"], profile, on_result)
Пример #9
0
    def on_selection_changed(self, item, device, profile):
        if item.get_active():
            pa = PulseAudioUtils()

            c = self.devices[device['Address']]

            def on_result(res):
                if not res:
                    MessageArea.show_message(_("Failed to change profile to %s" % profile))

            pa.set_card_profile(c["index"], profile, on_result)
Пример #10
0
    def on_selection_changed(self, item: Gtk.CheckMenuItem, device: Device, profile: str) -> None:
        if item.get_active():
            pa = PulseAudioUtils()

            c = self.devices[device['Address']]

            def on_result(res: int) -> None:
                if not res:
                    MessageArea.show_message(_("Failed to change profile to %s" % profile))

            pa.set_card_profile(c["index"], profile, on_result)
Пример #11
0
    def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) -> List[DeviceMenuItem]:
        audio_source = False
        for uuid in device['UUIDs']:
            if ServiceUUID(uuid).short_uuid in (AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID):
                audio_source = True
                break

        if device['Connected'] and audio_source:

            pa = PulseAudioUtils()
            if not pa.connected:
                self.deferred.append(device)
                return []

            item = create_menuitem(_("Audio Profile"), "audio-card")
            item.props.tooltip_text = _("Select audio profile for PulseAudio")

            if not device['Address'] in self.devices:
                self.query_pa(device, item)
            else:
                self.generate_menu(device, item)

        else:
            return []

        return [DeviceMenuItem(item, DeviceMenuItem.Group.ACTIONS, 300)]
Пример #12
0
    def on_load(self, applet):
        self.signals = SignalTracker()
        if not self.get_option("checked"):
            self.set_option("checked", True)
            if not have("pactl"):
                applet.Plugins.SetConfig("PulseAudio", False)
                return

        self.bus = dbus.SystemBus()

        self.connected_sources = []
        self.connected_sinks = []
        self.connected_hs = []

        self.loaded_modules = {}

        self.pulse_utils = PulseAudioUtils()
        version = self.pulse_utils.GetVersion()
        dprint("PulseAudio version:", version)

        if version[0] == 0:
            if tuple(version) < (0, 9, 15):
                raise Exception(
                    "PulseAudio too old, required 0.9.15 or higher")

        self.signals.Handle("dbus",
                            self.bus,
                            self.on_sink_prop_change,
                            "PropertyChanged",
                            "org.bluez.AudioSink",
                            path_keyword="device")

        self.signals.Handle("dbus",
                            self.bus,
                            self.on_source_prop_change,
                            "PropertyChanged",
                            "org.bluez.AudioSource",
                            path_keyword="device")

        self.signals.Handle("dbus",
                            self.bus,
                            self.on_hsp_prop_change,
                            "PropertyChanged",
                            "org.bluez.Headset",
                            path_keyword="device")

        self.signals.Handle(self.pulse_utils, "event", self.on_pulse_event)
Пример #13
0
    def on_pa_event(self, utils: PulseAudioUtils, event: int, idx: int) -> None:
        logging.debug(f"{event} {idx}")

        def get_card_cb(card: "CardInfo") -> None:
            drivers = ("module-bluetooth-device.c",
                       "module-bluez4-device.c",
                       "module-bluez5-device.c")

            if card["driver"] in drivers:
                self.devices[card["proplist"]["device.string"]] = card
                self.regenerate_with_device(card["proplist"]["device.string"])

        if event & EventType.CARD:
            logging.info("card")
            if event & EventType.CHANGE:
                logging.info("change")
                utils.get_card(idx, get_card_cb)
            elif event & EventType.REMOVE:
                logging.info("remove")
            else:
                logging.info("add")
                utils.get_card(idx, get_card_cb)
Пример #14
0
    def on_load(self) -> None:
        self.devices: Dict[str, "CardInfo"] = {}

        self.deferred: List[Device] = []

        pa = PulseAudioUtils()
        pa.connect("event", self.on_pa_event)
        pa.connect("connected", self.on_pa_ready)
Пример #15
0
    def on_load(self, user_data):
        self.devices = {}
        self.item = None

        self.deferred = []

        pa = PulseAudioUtils()
        pa.connect("event", self.on_pa_event)
        pa.connect("connected", self.on_pa_ready)
Пример #16
0
    def on_load(self) -> None:
        self._devices: Dict[str, "CardInfo"] = {}
        self._device_menus: Dict[str, "MenuItem"] = {}

        self._menu = self.parent.Plugins.Menu

        pa = PulseAudioUtils()
        pa.connect("event", self.on_pa_event)
        pa.connect("connected", self.on_pa_ready)
Пример #17
0
    def load(self, args, cb):
        if self.id != None:
            self.unload()

        def load_cb(res):
            if res > 0:
                self.refcount = 1
                self.id = res
                if cb:
                    cb(res)
                self.emit("loaded")
            else:
                self.refcount = 0
                self.id = None

        PulseAudioUtils().LoadModule("module-bluetooth-device", args, load_cb)
Пример #18
0
    def request_device_profile_menu(self, device: "Device") -> None:
        audio_source = False
        for uuid in device['UUIDs']:
            if ServiceUUID(uuid).short_uuid in (AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID):
                audio_source = True
                break

        if device['Connected'] and audio_source:
            pa = PulseAudioUtils()
            if not pa.connected:
                return

            if not device['Address'] in self._devices:
                self.query_pa(device)
            else:
                self.add_device_profile_menu(device)
Пример #19
0
    def on_request_menu_items(self, manager_menu, device):

        if self.is_connected(device):
            pa = PulseAudioUtils()
            if not pa.connected:
                self.deferred.append(device)
                return

            self.item = create_menuitem(_("Audio Profile"), get_icon("audio-card", 16))
            self.item.props.tooltip_text = _("Select audio profile for PulseAudio")

            if not device.Address in self.devices:
                self.query_pa(device)
            else:
                self.generate_menu(device)

        else:
            return

        return [(self.item, 300)]
Пример #20
0
class PulseAudio(AppletPlugin):
    __author__ = "Walmis"
    __description__ = _(
        "Automatically manages Pulseaudio Bluetooth sinks/sources.\n"
        "<b>Note:</b> Requires pulseaudio 0.9.15 or higher")
    __icon__ = "audio-card"
    __options__ = {
        "checked": {
            "type": bool,
            "default": False
        },
        "make_default_sink": {
            "type": bool,
            "default": True,
            "name": _("Make default sink"),
            "desc": _("Make the a2dp audio sink the default after connection")
        },
        "move_streams": {
            "type": bool,
            "default": True,
            "name": _("Move streams"),
            "desc": _("Move existing audio streams to bluetooth device")
        }
    }

    def on_load(self, applet):
        self.signals = SignalTracker()
        if not self.get_option("checked"):
            self.set_option("checked", True)
            if not have("pactl"):
                applet.Plugins.SetConfig("PulseAudio", False)
                return

        self.bus = dbus.SystemBus()

        self.connected_sources = []
        self.connected_sinks = []
        self.connected_hs = []

        self.loaded_modules = {}

        self.pulse_utils = PulseAudioUtils()
        version = self.pulse_utils.GetVersion()
        dprint("PulseAudio version:", version)

        if version[0] == 0:
            if tuple(version) < (0, 9, 15):
                raise Exception(
                    "PulseAudio too old, required 0.9.15 or higher")

        self.signals.Handle("dbus",
                            self.bus,
                            self.on_sink_prop_change,
                            "PropertyChanged",
                            "org.bluez.AudioSink",
                            path_keyword="device")

        self.signals.Handle("dbus",
                            self.bus,
                            self.on_source_prop_change,
                            "PropertyChanged",
                            "org.bluez.AudioSource",
                            path_keyword="device")

        self.signals.Handle("dbus",
                            self.bus,
                            self.on_hsp_prop_change,
                            "PropertyChanged",
                            "org.bluez.Headset",
                            path_keyword="device")

        self.signals.Handle(self.pulse_utils, "event", self.on_pulse_event)

    def on_pulse_event(self, pa_utils, event, idx):
        if (EventType.CARD | EventType.CHANGE) == event:
            dprint(event)

            def card_cb(c):
                if "bluez.path" not in c["proplist"]:
                    # we're dealing with an event on a non-bluetooth device, we don't care
                    # about those.
                    return
                dprint(c)
                m = self.loaded_modules[c["proplist"]["bluez.path"]]
                if c["owner_module"] == m.id:
                    if c["active_profile"] == "a2dp_source":
                        SourceRedirector(m.id, c["proplist"]["bluez.path"],
                                         pa_utils)

            pa_utils.GetCard(idx, card_cb)

    def on_unload(self):
        self.signals.DisconnectAll()

    def load_module(self, dev_path, args, cb=None):
        if not dev_path in self.loaded_modules:
            m = Module()
            m.load(args, cb)
            self.loaded_modules[dev_path] = m
        else:
            self.loaded_modules[dev_path].ref()

    def try_unload_module(self, dev_path):
        try:
            m = self.loaded_modules[dev_path]
            m.unref()
            if m.refcount == 0:
                del self.loaded_modules[dev_path]
        except Exception, e:
            dprint(e)