Python правильно и эффективно получает путь к объекту DBUS (например, / org / bluez / dev_XX_XX_XX_XX_XX_XX / playerY) - PullRequest
0 голосов
/ 28 сентября 2018

Я хотел бы получить путь к устройству для bluetooth-плеера A2DP на базе bluez, который я создаю.Я застрял в реализации команд Play / Pause / Next / Previous эффективно, потому что доступность 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 я смог использоватьИнтерфейсы добавлены и некоторые регулярные выражения для того, чтобы найти путь, который мне нужен.

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

1 Ответ

0 голосов
/ 28 сентября 2018

Не следует использовать org.freedesktop.DBus.ObjectManager.GetManagedObjects для получения пути к объекту каждый раз.Этот GetManagedObjects предназначен для получения существующего или ранее доступного интерфейса, а также подробностей при запуске приложения.

Например, если предположить, что Bluez запущен и подключено 1 конечное устройство.Позже ваше приложение запускается, во время инициализации / запуска приложения вам может потребоваться получить все доступные / подключенные устройства, чтобы вы могли использовать GetManagedObjects для его получения.

Для целей создания интерфейсов во время выполнения,путь к объекту, вы должны полагаться на сигналы InterfacesAdded и InterfacesRemoved менеджера объектов.

У меня нет примеров в 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 я использовал оба сигнала InterfaceRemoved и InterfaceAdded для демонстрации.Поэтому, когда новые устройства появились на /org/hciX/, вызывается bluez_device_appeared и удаление происходит аналогичным образом.

Если у вас подключено более одного адаптера Bluetooth, вы можете отфильтровать их в g_dbus_connection_signal_subscribe, указавпуть к адаптерам, например, /org/bluez/hciX.

Все демоны на основе DBUS используют сигналы для уведомления клиентов на шине, поэтому мы видим множество сообщений на шине.Таким образом, мы должны подписаться на основе точной необходимости.Этот фильтр применяется на уровне демона dbus, и сообщения пересылаются.

Для добавления MediaControl1 интерфейс bluez устарел и устарел.Все новые приложения должны использовать MediaPlayer как определено здесь .

...