Как зарегистрировать обратные вызовы соединения с Bluez Profile1 DBus API

Я пытаюсь обновить наш код Bluetooth на компьютере, к которому наше приложение для Android подключается с помощью сокета rfcomm. До сих пор мы использовали параметр --compat для bluetoothd и некоторые функции SDP для регистрации нашей службы Bluetooth. Теперь я хочу использовать DBus API в Bluez 5, чтобы сделать его менее нестабильным и, возможно, заставить работать автоматическое подключение и автоматическое доверие после первого сопряжения.

Я могу зарегистрировать профиль с помощью метода RegisterProfile в org.bluez.ProfileManager1, затем я вижу свой собственный uuid в контроллере с помощью bluetoothctl, и приложение для Android тоже его видит. Затем мне нужен обратный вызов для запуска, когда устройство подключено к сокету, в который я могу писать. Я могу зарегистрироваться для получения сигнала PropertiesChanged на org.bluez.Device1, и он срабатывает как при подключении, так и при отключении, но не дает мне сокет. Я пытаюсь зарегистрировать объект с обратными вызовами в org.bluez.Profile1, но это просто не срабатывает. Я не совсем уверен, как следует обрабатывать UUID, поскольку мы будем использовать SPP, который имеет хорошо известный UUID, но я также хотел бы избежать шума и путаницы с другими устройствами, которые его используют, он должен общаться только с нашим приложением.

static const gchar btp_introspection_xml[] =
    "<node>"
    "  <interface name='org.bluez.Profile1'>"
    "    <method name='Release' />"
    "    <method name='NewConnection'>"
    "      <arg type='o' name='device' direction='in' />"
    "      <arg type='h' name='fd' direction='in' />"
    "      <arg type='a{sv}' name='fd_properties' direction='in' />"
    "    </method>"
    "    <method name='RequestDisconnection'>"
    "      <arg type='o' name='device' direction='in' />"
    "    </method>"
    "  </interface>"
    "</node>";


int register_profile(GDBusProxy *proxy)
{
    GVariant *profile;
    GVariantBuilder profile_builder;
    GError *error = NULL;

    printf("register_profile called!\n");

    g_variant_builder_init(&profile_builder, G_VARIANT_TYPE("(osa{sv})"));

    if (g_variant_is_object_path("/org/bluez/customprofile")) {
        printf("object path is good!\n");
    }

    g_variant_builder_add (&profile_builder, "o",
            "/org/bluez/customprofile");

    g_variant_builder_add (&profile_builder, "s", SERIAL_PORT_PROFILE_UUID);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("a{sv}"));


    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));   
    g_variant_builder_add (&profile_builder, "s", "Channel");
    g_variant_builder_add (&profile_builder, "v", g_variant_new_uint16(22));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Service");
    g_variant_builder_add (&profile_builder, "v",
            g_variant_new_string(CUSTOM_UUID));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Name");
    g_variant_builder_add (&profile_builder, "v",
            g_variant_new_string("Custom Serial Port"));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "Role");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_string("server"));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "RequireAuthentication");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_boolean(FALSE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "RequireAuthorization");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_boolean(FALSE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_open(&profile_builder, G_VARIANT_TYPE("{sv}"));
    g_variant_builder_add (&profile_builder, "s", "AutoConnect");
    g_variant_builder_add (&profile_builder, "v",
                g_variant_new_boolean(TRUE));
    g_variant_builder_close(&profile_builder);

    g_variant_builder_close(&profile_builder);
    profile = g_variant_builder_end(&profile_builder);

    GVariant * ret = g_dbus_proxy_call_sync (proxy,
                "RegisterProfile",
                profile,
                G_DBUS_CALL_FLAGS_NONE,
                -1,
                NULL,
                &error);
    g_assert_no_error(error);
    if(ret != NULL && error==NULL){
        return 0;
    } else {
        return 1;
    }
}


static void connection_callback(GDBusConnection *conn, const char *sender,
        const char *path, const char *interface, const char *method, GVariant *params,
        GDBusMethodInvocation *invocation, void *userdata) {

    g_print("Called: %s.%s()", interface, method);
    (void)conn;
    (void)sender;
    (void)path;
    (void)params;

    if (strcmp(method, "NewConnection") == 0)
        g_print("connected");
    else if (strcmp(method, "RequestDisconnection") == 0)
        g_print("disconnected");
    else if (strcmp(method, "Release") == 0)
        g_print("released?");

}

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

    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(strcmp(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)) {
    g_print("key: %s | value: %s\n",key,value);
        if(!g_strcmp0(key, "Connected")) {
            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;
            }
        gboolean status = g_variant_get_boolean(value);
            g_print("Device is \"%s\"\n", status ? "Connected" : "Disconnected");
        if (status) {
        //handle connection here instead?
        } else {
        g_print("stopping writer");
        stop_bt_writer();
        destroy_json_handler();
        }

        }
    }


done:
    if(properties != NULL)
        g_variant_iter_free(properties);
    if(value != NULL)
        g_variant_unref(value);
}


void init_server()
{
    GDBusProxy *proxy;
    GDBusConnection *conn;
    GError *error = NULL;
    OrgBluezProfile1 *interface;

    GMainLoop *loop = g_main_loop_new (NULL, FALSE);

    conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
    g_assert_no_error (error);

    proxy = g_dbus_proxy_new_sync (conn,
                G_DBUS_PROXY_FLAGS_NONE,
                NULL,/* GDBusInterfaceInfo */
                "org.bluez",/* name */
                "/org/bluez",/* object path */
                "org.bluez.ProfileManager1",/* interface */
                NULL,/* GCancellable */
                &error);
    g_assert_no_error (error);
    error=NULL;
    if (register_profile (proxy)) {
        printf("profile register failed\n");
        return;
    }
    printf("SPP profile registered");

    //register device property callback (connect/disconnect)
    guint sub_id = g_dbus_connection_signal_subscribe(conn,
                    "org.bluez",
                    "org.freedesktop.DBus.Properties",
                    "PropertiesChanged",
                    NULL,
                    "org.bluez.Device1",
                    G_DBUS_SIGNAL_FLAGS_NONE,
                    bluez_signal_device_changed,
                    NULL,
                    NULL);

    static GDBusInterfaceVTable vtable = {
        .method_call = connection_callback,
    };

    GDBusNodeInfo *introspection = g_dbus_node_info_new_for_xml(btp_introspection_xml, &error);
    GDBusInterfaceInfo *interface_info = g_dbus_node_info_lookup_interface(introspection, "org.bluez.Profile1");
    g_assert_no_error (error);
    error=NULL;
    guint regid = g_dbus_connection_register_object(conn,
                    "/org/bluez/customprofile",
                    interface_info,
                    &vtable,
                    NULL,
                    NULL,
                    &error);
    g_assert_no_error (error);
    printf("connection callback registered, id: %d;",regid);
    g_main_loop_run (loop);

    g_object_unref (proxy);
    g_object_unref (conn);

    return;
}

Регистрация обратного вызова завершается без ошибок, вывод из этого:

register_profile called!
object path is good!
SPP profile registered
connection callback registered, id: 1;

Поэтому я не понимаю, почему моя функция connection_callback никогда не срабатывает. Я ценю все отзывы, я не разбираюсь ни в DBus, ни в Bluetooth.


person karlsvan    schedule 15.08.2019    source источник


Ответы (1)


Моим решением было обновить bluez с 5.37 до 5.50. Я также следил за решением на Как мне зарегистрироваться профиль с bluez через dbus/gio? и не пробовал без этого после обновления. Только это не помогло без обновления, хотя

person karlsvan    schedule 22.08.2019