gpt4 book ai didi

Python正确有效地获取DBUS对象路径(例如/org/bluez/dev_XX_XX_XX_XX_XX_XX/playerY)

转载 作者:行者123 更新时间:2023-12-01 08:59:35 24 4
gpt4 key购买 nike

我想获取我正在创建的基于 bluez 的 A2DP 蓝牙播放器的设备路径。我无法有效地执行“播放/暂停/下一个/上一个”命令,因为 dbus 可用性和播放器路径会根据您选择的媒体播放器而变化。此外,bluez 有时会决定发送大量无用信息(对我来说),例如播放列表详细信息,这使得我的应用程序需要处理的负载更大。所以这里的目标是在调用函数时获取 /org/bluez/dev_XX_XX_XX_XX_XX_XX/playerY

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

当我尝试更改媒体播放器或 bluez 发送一些日志(一般情况下是 5% 的时间)时,dbus org.freedesktop.DBus.ObjectManager 会收到大量信息,这使得manager.GetManagedObjects() 卡住 10~20 秒。

是否有一种方法可以确定 bluez 对象路径,而无需接收整个 org.freedesktop.DBus.ObjectManager 对象;或者有没有办法限制 bluez 发送的消息量。我真的很想有效地获取对象路径。非常感谢任何帮助。

编辑:尽管我没有在存在填充 ObjectManager 问题的嵌入式系统中对其进行测试,但由于 Partiban 的出色建议,我能够使用 InterfacesAdded 和一些正则表达式来匹配我需要的路径。

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")

最佳答案

您不应该每次都使用 org.freedesktop.DBus.ObjectManager.GetManagedObjects 来获取对象路径。此 GetManagedObjects 旨在在应用程序启动时获取现有或以前可用的接口(interface)及其详细信息。

例如,假设 Bluez 已启动并连接了 1 个终端设备。稍后您的应用程序启动,在应用程序的初始化/启动期间,您可能需要获取所有可用/连接的设备,因此您可以使用 GetManagedObjects 来获取它。

为了运行时创建接口(interface),对象路径应依赖对象管理器的信号 InterfacesAddedInterfacesRemoved

我没有 Python 示例,但下面的 C 示例通常会执行 StartDiscovery 并使用信号监视新设备。因此,您可以使用信号来适应 python 中的类似示例。下面的示例只是为了清楚起见(有关此示例的更多详细信息请参阅 Linumiz )。

/*
* bluez_adapter_scan.c - Scan for bluetooth devices
* - This example scans for new devices after powering the adapter, if any devices
* appeared in /org/hciX/dev_XX_YY_ZZ_AA_BB_CC, it is monitered using "InterfaceAdded"
* signal and all the properties of the device is printed
* - Scanning continues to run until any device is disappered, this happens after 180 seconds
* automatically if the device is not used.
* gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/bluez_adapter_scan ./bluez_adapter_scan.c `pkg-config --libs glib-2.0 gio-2.0`
*/
#include <glib.h>
#include <gio/gio.h>

GDBusConnection *con;
static void bluez_property_value(const gchar *key, GVariant *value)
{
const gchar *type = g_variant_get_type_string(value);

g_print("\t%s : ", key);
switch(*type) {
case 'o':
case 's':
g_print("%s\n", g_variant_get_string(value, NULL));
break;
case 'b':
g_print("%d\n", g_variant_get_boolean(value));
break;
case 'u':
g_print("%d\n", g_variant_get_uint32(value));
break;
case 'a':
/* TODO Handling only 'as', but not array of dicts */
if(g_strcmp0(type, "as"))
break;
g_print("\n");
const gchar *uuid;
GVariantIter i;
g_variant_iter_init(&i, value);
while(g_variant_iter_next(&i, "s", &uuid))
g_print("\t\t%s\n", uuid);
break;
default:
g_print("Other\n");
break;
}
}

static void bluez_device_appeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
(void)user_data;

GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
GVariant *properties;

g_variant_get(parameters, "(&oa{sa{sv}})", &object, &interfaces);
while(g_variant_iter_next(interfaces, "{&s@a{sv}}", &interface_name, &properties)) {
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device")) {
g_print("[ %s ]\n", object);
const gchar *property_name;
GVariantIter i;
GVariant *prop_val;
g_variant_iter_init(&i, properties);
while(g_variant_iter_next(&i, "{&sv}", &property_name, &prop_val))
bluez_property_value(property_name, prop_val);
g_variant_unref(prop_val);
}
g_variant_unref(properties);
}
return;
}

#define BT_ADDRESS_STRING_SIZE 18
static void bluez_device_disappeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;

GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
char address[BT_ADDRESS_STRING_SIZE] = {'\0'};

g_variant_get(parameters, "(&oas)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "s", &interface_name)) {
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device")) {
int i;
char *tmp = g_strstr_len(object, -1, "dev_") + 4;

for(i = 0; *tmp != '\0'; i++, tmp++) {
if(*tmp == '_') {
address[i] = ':';
continue;
}
address[i] = *tmp;
}
g_print("\nDevice %s removed\n", address);
g_main_loop_quit((GMainLoop *)user_data);
}
}
return;
}

static void bluez_signal_adapter_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
{
(void)conn;
(void)sender;
(void)path;
(void)interface;
(void)userdata;

GVariantIter *properties = NULL;
GVariantIter *unknown = NULL;
const char *iface;
const char *key;
GVariant *value = NULL;
const gchar *signature = g_variant_get_type_string(params);

if(g_strcmp0(signature, "(sa{sv}as)") != 0) {
g_print("Invalid signature for %s: %s != %s", signal, signature, "(sa{sv}as)");
goto done;
}

g_variant_get(params, "(&sa{sv}as)", &iface, &properties, &unknown);
while(g_variant_iter_next(properties, "{&sv}", &key, &value)) {
if(!g_strcmp0(key, "Powered")) {
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
}
g_print("Adapter is Powered \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
}
if(!g_strcmp0(key, "Discovering")) {
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
}
g_print("Adapter scan \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
}
}
done:
if(properties != NULL)
g_variant_iter_free(properties);
if(value != NULL)
g_variant_unref(value);
}

static int bluez_adapter_call_method(const char *method)
{
GVariant *result;
GError *error = NULL;

result = g_dbus_connection_call_sync(con,
"org.bluez",
/* TODO Find the adapter path runtime */
"/org/bluez/hci0",
"org.bluez.Adapter1",
method,
NULL,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;

g_variant_unref(result);
return 0;
}

static int bluez_adapter_set_property(const char *prop, GVariant *value)
{
GVariant *result;
GError *error = NULL;

result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez/hci0",
"org.freedesktop.DBus.Properties",
"Set",
g_variant_new("(ssv)", "org.bluez.Adapter1", prop, value),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;

g_variant_unref(result);
return 0;
}

int main(void)
{
GMainLoop *loop;
int rc;
guint prop_changed;
guint iface_added;
guint iface_removed;

con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
if(con == NULL) {
g_print("Not able to get connection to system bus\n");
return 1;
}

loop = g_main_loop_new(NULL, FALSE);

prop_changed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Adapter1",
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_signal_adapter_changed,
NULL,
NULL);

iface_added = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_appeared,
loop,
NULL);

iface_removed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_disappeared,
loop,
NULL);

rc = bluez_adapter_set_property("Powered", g_variant_new("b", TRUE));
if(rc) {
g_print("Not able to enable the adapter\n");
goto fail;
}

rc = bluez_adapter_call_method("StartDiscovery");
if(rc) {
g_print("Not able to scan for new devices\n");
goto fail;
}

g_main_loop_run(loop);
rc = bluez_adapter_call_method("StopDiscovery");
if(rc)
g_print("Not able to stop scanning\n");
g_usleep(100);

rc = bluez_adapter_set_property("Powered", g_variant_new("b", FALSE));
if(rc)
g_print("Not able to disable the adapter\n");
fail:
g_dbus_connection_signal_unsubscribe(con, prop_changed);
g_dbus_connection_signal_unsubscribe(con, iface_added);
g_dbus_connection_signal_unsubscribe(con, iface_removed);
g_object_unref(con);
return 0;
}

在使用 StartDiscovery 扫描设备的示例中,我使用了 InterfaceRemovedInterfaceAdded 信号进行演示。因此,当新设备出现在 /org/hciX/ 上时,会调用 bluez_device_appeared 并以相同的方式进行删除。

如果您连接了多个蓝牙适配器,您可以通过指定适配器路径(例如 /org/bluez/hciX)在 g_dbus_connection_signal_subscribe 下过滤它们。

所有基于 DBUS 的守护进程都使用信号来通知总线上的客户端,因此我们看到总线上有很多消息。所以我们需要根据具体需求进行订阅。此过滤器应用于 dbus 守护进程级别并转发消息。

添加 bluez 的 MediaControl1 接口(interface)已过时且已弃用。所有新应用程序都应使用定义的 MediaPlayer here .

关于Python正确有效地获取DBUS对象路径(例如/org/bluez/dev_XX_XX_XX_XX_XX_XX/playerY),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52555385/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com