2

I need to register bluetooth service on Linux PC in C++ and so far, I am able to do it with such code: (taken and shorthened from here).

#include <cstdio>
#include <gio/gio.h>
#include <glib.h>

#define SERIAL_PORT_PROFILE_UUID "00001101-0000-1000-8000-00805F9B34FB"
#define CUSTOM_UUID              "22222222-2222-2222-2222-222222222222" //"E62C4DCA-9ABC-11E5-8994-FEFF819CDC9F"

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;
    }
}

void init_server()
{
    GDBusProxy *proxy;
    GDBusConnection *conn;
    GError *error = nullptr;

    GMainLoop *loop = g_main_loop_new (nullptr, false);

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

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

    g_object_unref (proxy);
    g_object_unref (conn);
}


int main(int argc, const char** argv) {
    init_server();
}

Everyting works great, and I can see the service in bluetoothctl or sdptool browse (from other PC).

The problem is: I want to continue the programm execution after the registration, but I do not understand how I can exit the loop after the execution of the g_main_loop_run (loop);. If i simply remove all calls to the main loop (GMainLoop *loop = g_main_loop_new (nullptr, false); and previous) then service ceases to appear in bluetoothctl/sdptool browse. And if I add line g_main_loop_quit(loop); right after the g_main_loop_run (loop);, it also will not be executed, because the loop is still running. So what shall I do?

I've read the GMainLoop and GDBusProxy descriptions (GMainLoop, GDBusProxy), but it did not helped a lot. I've also seen this question, but code listed there is not complete and I am not sure what I should take from there and what I shouldn't.

Alvov1
  • 157
  • 1
  • 2
  • 10
  • 1
    You are not supposed to exit the loop. You must develop your application around the loop. What I mean is, whatever other tasks you need to run, they must also utilize the event loop. For example, if you want to do something periodically you should use GLib's 'timers' which are handled by the event loop. Usually there is an alternative to run your own loop but then it becomes your responsibility to periodically trigger GLib's event loop so that it can process its own tasks. I wouldn't recommend going that way. – HeyYO Dec 24 '21 at 11:27
  • @HeyYO , You mean that there is no option to register service once, like it was shown [here](https://people.csail.mit.edu/albert/bluez-intro/x604.html), and continue the program execution? Bluetooth is only few part of my program, and I do not want to cover all other functionality in the loop. Actually, I want to: register service; receive one connection; get very few data; - and that's all for the bluetooth functionality. – Alvov1 Dec 27 '21 at 12:26

1 Answers1

0

If I understood correctly, You might want to continue doing something after "register_profile()". I would suggest to register callbacks on the proxy interface and complete everything then finally stay in event loop.

If there is a signal from the proxy interface then your program will get it and call the appropriate callback function that you would have registered with proxy signal callbacks.

If this is not your use case then please elaborate more.