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
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)]
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_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)
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)
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)
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)
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)
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)]
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)