Last active
August 15, 2024 06:46
-
-
Save borancar/52dbc52cebe80fda439e41434221fa1c to your computer and use it in GitHub Desktop.
Bluetooth speaker agent (A2DP, AVRCP, HFP, HSP), all your bluetooth devices streaming to Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# SPDX-License-Identifier: LGPL-2.1-or-later | |
import dbus | |
import dbus.service | |
import dbus.mainloop.glib | |
from gi.repository import GLib | |
BUS_NAME = 'org.bluez' | |
AGENT_INTERFACE = 'org.bluez.Agent1' | |
AGENT_PATH = "/speaker/agent" | |
A2DP = '0000110d-0000-1000-8000-00805f9b34fb' | |
AVRCP = '0000110e-0000-1000-8000-00805f9b34fb' | |
HFP = '0000111e-0000-1000-8000-00805f9b34fb' | |
HSP = '00001108-0000-1000-8000-00805f9b34fb' | |
bus = None | |
class Rejected(dbus.DBusException): | |
_dbus_error_name = "org.bluez.Error.Rejected" | |
class Agent(dbus.service.Object): | |
exit_on_release = True | |
def set_exit_on_release(self, exit_on_release): | |
self.exit_on_release = exit_on_release | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="", out_signature="") | |
def Release(self): | |
print("Release") | |
if self.exit_on_release: | |
mainloop.quit() | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="os", out_signature="") | |
def AuthorizeService(self, device, uuid): | |
# Always authorize A2DP, AVRCP, HFP and HSP connection | |
if uuid in [A2DP, AVRCP, HFP, HSP]: | |
print("AuthorizeService (%s, %s)" % (device, uuid)) | |
return | |
else: | |
print("Service rejected (%s, %s)" % (device, uuid)) | |
raise Rejected("Connection rejected by user") | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="", out_signature="") | |
def Cancel(self): | |
print("Cancel") | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="o", out_signature="s") | |
def RequestPinCode(self, device): | |
print("Requesting pincode (%s)" % (device)) | |
return "0000" | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="os", out_signature="") | |
def DisplayPinCode(self, device, pincode): | |
print("Pincode: %s (%s)" % (pincode, device)) | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="o", out_signature="u") | |
def RequestPasskey(self, device): | |
print("Requesting passkey (%s)" % (device)) | |
return 0 | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="ouq", out_signature="") | |
def DisplayPasskey(self, device, passkey, entered): | |
print("Passkey: %06d (%s, %d)" % (passkey, device, entered)) | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="ou", out_signature="") | |
def RequestConfirmation(self, device, passkey): | |
print("Requesting confirmation (%s, %d)" % (device, passkey)) | |
@dbus.service.method(AGENT_INTERFACE, | |
in_signature="o", out_signature="") | |
def RequestAuthorization(self, device): | |
print("Request authorization (%s)" % (device)) | |
if __name__ == '__main__': | |
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) | |
bus = dbus.SystemBus() | |
agent = Agent(bus, AGENT_PATH) | |
mainloop = GLib.MainLoop() | |
# By default Bluetooth adapter is not discoverable and there's | |
# a 3 min timeout | |
# Set it as always discoverable | |
adapter = dbus.Interface(bus.get_object(BUS_NAME, "/org/bluez/hci0"), | |
"org.freedesktop.DBus.Properties") | |
adapter.Set("org.bluez.Adapter1", "DiscoverableTimeout", dbus.UInt32(0)) | |
adapter.Set("org.bluez.Adapter1", "Discoverable", True) | |
print("Bluetooth speaker discoverable") | |
obj = bus.get_object(BUS_NAME, "/org/bluez") | |
manager = dbus.Interface(obj, "org.bluez.AgentManager1") | |
manager.RegisterAgent(AGENT_PATH, "KeyboardDisplay") | |
print("Agent registered") | |
manager.RequestDefaultAgent(AGENT_PATH) | |
mainloop.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment