I would like to get the device path for bluez-based A2DP bluetooth player that I am creating. I am stuck implementing Play/Pause/Next/Previous commands efficiently, because the dbus availability and player path changes depending on the media player you choose. Furthermore, bluez sometimes decides to send a lot of useless information (for me) such as playlist details that makes the payload bigger for my application to handle. So the goal here is to obtain /org/bluez/dev_XX_XX_XX_XX_XX_XX/playerY
when a function is called.
def update_player():
manager = dbus.Interface(self.bus.get_object("org.bluez", "/"), "org.freedesktop.DBus.ObjectManager")
objects = manager.GetManagedObjects()
player_path = getFromDict(objects,[self.devicepath,"org.bluez.MediaControl1", "Player"])
When I try to change the media player, or bluez sends some logs (so 5% of the time in general), dbus org.freedesktop.DBus.ObjectManager
receives a lot of information which makes manager.GetManagedObjects()
get stuck for 10~20 seconds.
Is there a way of determining bluez object path without having to receive the entire org.freedesktop.DBus.ObjectManager
objects; or Is there a way to just limit the amount of message sent by bluez
. I really would like to get the object path efficiently. Any help is greately appreciated.
EDIT: Although I did not test it in the embedded system that had the problem with ObjectManager being populated, thanks to Partiban's great suggestion, I was able to use InterfacesAdded and some regex in order to match the path I needed.
self.bus.add_signal_receiver(self.objectPathHandler,
bus_name="org.bluez",
dbus_interface="org.freedesktop.DBus.ObjectManager",
signal_name="InterfacesAdded",
path_keyword="path")
def objectPathHandler(self, interface, changed, path):
iface = interface[interface.rfind(".") + 1:]
#print("InterfacesAdded: {}; changed: {}; path {}".format(iface, changed, path))
self.playerpath = re.findall('/org/bluez/hci[0-9]/dev_[\dA-F]{2}_[\dA-F]{2}_[\dA-F]{2}_[\dA-F]{2}_[\dA-F]{2}_[\dA-F]{2}/player[0-9]+', iface)[0]
print "Object path:"
print self.playerpath
def update_player(self):
print "Updating player"
if self.devicepath != "None" and self.playerpath != "None":
if self.playerpath:
self.connected = 1
self.getPlayer (self.playerpath)
player_properties = self.player.GetAll(PLAYER_IFACE, dbus_interface="org.freedesktop.DBus.Properties")
You should not be using
org.freedesktop.DBus.ObjectManager.GetManagedObjects
to get the object path every time. ThisGetManagedObjects
is meant to get existing or previously available interface and it's details when your application starts.For example, assuming Bluez is started and 1 end device is connected. Later your application starts, during init/start of your application you may need to get all the available/connected devices, so you can use
GetManagedObjects
to get it.For the purpose of runtime creation of interfaces, object path you should rely on signals
InterfacesAdded
andInterfacesRemoved
of the objectmanager.I don't have examples in python, but the below example in C typically does the
StartDiscovery
and monitor for new devices using signals. So you adapt to similar example in python using signals. The below example is just for clarity purpose (more details on this example is here in Linumiz).In this example of scanning of devices using
StartDiscovery
I have used both the signalsInterfaceRemoved
andInterfaceAdded
to demonstrate. So when new devices appeared on/org/hciX/
,bluez_device_appeared
is called and removal happens in the same way.If you have more then one bluetooth adapter connected, you can filter them under
g_dbus_connection_signal_subscribe
by specifying the adapters path e.g as/org/bluez/hciX
.All the DBUS based daemons use signals to notify the clients on the bus, so we see lots messaged on the bus. So we need to subscribe based on the exact need. This filter is applied at dbus daemon level and messages are forwarded.
To add
MediaControl1
interface of bluez is outdated and deprecated. All new applications should useMediaPlayer
as defined here.