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.GetManagedObjectsto get the object path every time. ThisGetManagedObjectsis 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
GetManagedObjectsto get it.For the purpose of runtime creation of interfaces, object path you should rely on signals
InterfacesAddedandInterfacesRemovedof the objectmanager.I don't have examples in python, but the below example in C typically does the
StartDiscoveryand 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
StartDiscoveryI have used both the signalsInterfaceRemovedandInterfaceAddedto demonstrate. So when new devices appeared on/org/hciX/,bluez_device_appearedis 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_subscribeby 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
MediaControl1interface of bluez is outdated and deprecated. All new applications should useMediaPlayeras defined here.