Skip to content

Commit

Permalink
Export BlueZ D-Bus objects via interface skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
arkq committed Oct 30, 2021
1 parent 4c97d4b commit 5e781ba
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 88 deletions.
3 changes: 2 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ endif
if ENABLE_OFONO
bluealsa_SOURCES += \
ofono.c \
ofono-iface.c
ofono-iface.c \
ofono-skeleton.c
endif

if ENABLE_UPOWER
Expand Down
62 changes: 62 additions & 0 deletions src/bluez-skeleton.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,65 @@ bluez_BatteryProviderIfaceSkeleton *bluez_battery_provider_iface_skeleton_new(
(GDBusInterfaceInfo *)&bluez_iface_battery_provider,
vtable, userdata, userdata_free_func);
}

G_DEFINE_TYPE(bluez_MediaEndpointIfaceSkeleton, bluez_media_endpoint_iface_skeleton,
G_TYPE_DBUS_INTERFACE_SKELETON);

static void bluez_media_endpoint_iface_skeleton_class_init(
bluez_MediaEndpointIfaceSkeletonClass *ifc) {
GDBusInterfaceSkeletonClass *ifc_ = G_DBUS_INTERFACE_SKELETON_CLASS(ifc);
ifc_->get_info = g_dbus_interface_skeleton_ex_class_get_info;
ifc_->get_vtable = g_dbus_interface_skeleton_ex_class_get_vtable;
ifc_->get_properties = g_dbus_interface_skeleton_ex_class_get_properties;
}

static void bluez_media_endpoint_iface_skeleton_init(
bluez_MediaEndpointIfaceSkeleton *ifs) {
(void)ifs;
}

/**
* Create a skeleton for org.bluez.MediaEndpoint1 interface.
*
* @return On success, this function returns newly allocated GIO interface
* skeleton object, which shall be freed with g_object_unref(). If error
* occurs, NULL is returned. */
bluez_MediaEndpointIfaceSkeleton *bluez_media_endpoint_iface_skeleton_new(
const GDBusInterfaceSkeletonVTable *vtable, void *userdata,
GDestroyNotify userdata_free_func) {
const GType type = bluez_media_endpoint_iface_skeleton_get_type();
return g_dbus_interface_skeleton_ex_new(type,
(GDBusInterfaceInfo *)&bluez_iface_media_endpoint,
vtable, userdata, userdata_free_func);
}

G_DEFINE_TYPE(bluez_ProfileIfaceSkeleton, bluez_profile_iface_skeleton,
G_TYPE_DBUS_INTERFACE_SKELETON);

static void bluez_profile_iface_skeleton_class_init(
bluez_ProfileIfaceSkeletonClass *ifc) {
GDBusInterfaceSkeletonClass *ifc_ = G_DBUS_INTERFACE_SKELETON_CLASS(ifc);
ifc_->get_info = g_dbus_interface_skeleton_ex_class_get_info;
ifc_->get_vtable = g_dbus_interface_skeleton_ex_class_get_vtable;
ifc_->get_properties = g_dbus_interface_skeleton_ex_class_get_properties;
}

static void bluez_profile_iface_skeleton_init(
bluez_ProfileIfaceSkeleton *ifs) {
(void)ifs;
}

/**
* Create a skeleton for org.bluez.Profile1 interface.
*
* @return On success, this function returns newly allocated GIO interface
* skeleton object, which shall be freed with g_object_unref(). If error
* occurs, NULL is returned. */
bluez_ProfileIfaceSkeleton *bluez_profile_iface_skeleton_new(
const GDBusInterfaceSkeletonVTable *vtable, void *userdata,
GDestroyNotify userdata_free_func) {
const GType type = bluez_profile_iface_skeleton_get_type();
return g_dbus_interface_skeleton_ex_new(type,
(GDBusInterfaceInfo *)&bluez_iface_profile,
vtable, userdata, userdata_free_func);
}
24 changes: 24 additions & 0 deletions src/bluez-skeleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,28 @@ bluez_BatteryProviderIfaceSkeleton *bluez_battery_provider_iface_skeleton_new(
const GDBusInterfaceSkeletonVTable *vtable, void *userdata,
GDestroyNotify userdata_free_func);

typedef struct {
GDBusInterfaceSkeletonClass parent;
} bluez_MediaEndpointIfaceSkeletonClass;

typedef struct {
GDBusInterfaceSkeletonEx parent;
} bluez_MediaEndpointIfaceSkeleton;

bluez_MediaEndpointIfaceSkeleton *bluez_media_endpoint_iface_skeleton_new(
const GDBusInterfaceSkeletonVTable *vtable, void *userdata,
GDestroyNotify userdata_free_func);

typedef struct {
GDBusInterfaceSkeletonClass parent;
} bluez_ProfileIfaceSkeletonClass;

typedef struct {
GDBusInterfaceSkeletonEx parent;
} bluez_ProfileIfaceSkeleton;

bluez_ProfileIfaceSkeleton *bluez_profile_iface_skeleton_new(
const GDBusInterfaceSkeletonVTable *vtable, void *userdata,
GDestroyNotify userdata_free_func);

#endif
122 changes: 59 additions & 63 deletions src/bluez.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <errno.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
Expand Down Expand Up @@ -52,20 +53,22 @@
/**
* Data associated with registered D-Bus object. */
struct bluez_dbus_object_data {
/* D-Bus object registration ID */
unsigned int id;
/* D-Bus object registration path */
char path[64];
/* exported interface skeleton */
GDBusInterfaceSkeleton *ifs;
/* associated adapter */
int hci_dev_id;
const struct a2dp_codec *codec;
/* the type of the transport */
struct ba_transport_type ttype;
/* media endpoint codec */
const struct a2dp_codec *codec;
/* determine whether object is registered in BlueZ */
bool registered;
/* determine whether object is used */
bool connected;
/* memory self-management */
int ref_count;
atomic_int ref_count;
};

/**
Expand Down Expand Up @@ -101,7 +104,7 @@ static void bluez_adapter_free(struct bluez_adapter *adapter) {

static void bluez_dbus_object_data_unref(
struct bluez_dbus_object_data *obj) {
if (--obj->ref_count != 0)
if (atomic_fetch_sub_explicit(&obj->ref_count, 1, memory_order_relaxed) > 1)
return;
free(obj);
}
Expand Down Expand Up @@ -374,30 +377,6 @@ static void bluez_endpoint_release(GDBusMethodInvocation *inv, void *userdata) {
g_object_unref(inv);
}

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

static const GDBusMethodCallDispatcher dispatchers[] = {
{ .method = "SelectConfiguration",
.handler = bluez_endpoint_select_configuration },
{ .method = "SetConfiguration",
.handler = bluez_endpoint_set_configuration },
{ .method = "ClearConfiguration",
.handler = bluez_endpoint_clear_configuration },
{ .method = "Release",
.handler = bluez_endpoint_release },
{ 0 },
};

if (!g_dbus_dispatch_method_call(dispatchers,
sender, path, interface, method, invocation, userdata))
error("Couldn't dispatch D-Bus method call: %s.%s()", interface, method);

}

/**
* Register media endpoint in BlueZ. */
static int bluez_register_media_endpoint(
Expand Down Expand Up @@ -457,8 +436,20 @@ static void bluez_register_a2dp(
const struct a2dp_codec *codec,
const char *uuid) {

static const GDBusInterfaceVTable vtable = {
.method_call = bluez_endpoint_method_call,
static const GDBusMethodCallDispatcher dispatchers[] = {
{ .method = "SelectConfiguration",
.handler = bluez_endpoint_select_configuration },
{ .method = "SetConfiguration",
.handler = bluez_endpoint_set_configuration },
{ .method = "ClearConfiguration",
.handler = bluez_endpoint_clear_configuration },
{ .method = "Release",
.handler = bluez_endpoint_release },
{ 0 },
};

static const GDBusInterfaceSkeletonVTable vtable = {
.dispatchers = dispatchers,
};

struct ba_transport_type ttype = {
Expand Down Expand Up @@ -502,9 +493,16 @@ static void bluez_register_a2dp(
dbus_obj->ttype = ttype;
dbus_obj->ref_count = 2;

if ((dbus_obj->id = g_dbus_connection_register_object(config.dbus,
path, (GDBusInterfaceInfo *)&bluez_iface_media_endpoint, &vtable,
dbus_obj, (GDestroyNotify)bluez_dbus_object_data_unref, &err)) == 0) {
bluez_MediaEndpointIfaceSkeleton *ifs_endpoint;
if ((ifs_endpoint = bluez_media_endpoint_iface_skeleton_new(&vtable,
dbus_obj, (GDestroyNotify)bluez_dbus_object_data_unref)) == NULL) {
free(dbus_obj);
goto fail;
}

dbus_obj->ifs = G_DBUS_INTERFACE_SKELETON(ifs_endpoint);
if (!g_dbus_interface_skeleton_export(dbus_obj->ifs, config.dbus, path, &err)) {
g_object_unref(ifs_endpoint);
free(dbus_obj);
goto fail;
}
Expand Down Expand Up @@ -831,28 +829,6 @@ static void bluez_profile_release(GDBusMethodInvocation *inv, void *userdata) {
g_object_unref(inv);
}

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

static const GDBusMethodCallDispatcher dispatchers[] = {
{ .method = "NewConnection",
.handler = bluez_profile_new_connection },
{ .method = "RequestDisconnection",
.handler = bluez_profile_request_disconnection },
{ .method = "Release",
.handler = bluez_profile_release },
{ 0 },
};

if (!g_dbus_dispatch_method_call(dispatchers,
sender, path, interface, method, invocation, userdata))
error("Couldn't dispatch D-Bus method call: %s.%s()", interface, method);

}

/**
* Register hands-free profile in BlueZ. */
static int bluez_register_profile(
Expand Down Expand Up @@ -912,8 +888,18 @@ static void bluez_register_hfp(
uint16_t version,
uint16_t features) {

static const GDBusInterfaceVTable vtable = {
.method_call = bluez_profile_method_call,
static const GDBusMethodCallDispatcher dispatchers[] = {
{ .method = "NewConnection",
.handler = bluez_profile_new_connection },
{ .method = "RequestDisconnection",
.handler = bluez_profile_request_disconnection },
{ .method = "Release",
.handler = bluez_profile_release },
{ 0 },
};

static const GDBusInterfaceSkeletonVTable vtable = {
.dispatchers = dispatchers,
};

struct ba_transport_type ttype = {
Expand Down Expand Up @@ -943,9 +929,16 @@ static void bluez_register_hfp(
dbus_obj->ttype = ttype;
dbus_obj->ref_count = 2;

if ((dbus_obj->id = g_dbus_connection_register_object(config.dbus,
path, (GDBusInterfaceInfo *)&bluez_iface_profile, &vtable,
dbus_obj, (GDestroyNotify)bluez_dbus_object_data_unref, &err)) == 0) {
bluez_ProfileIfaceSkeleton *ifs_profile;
if ((ifs_profile = bluez_profile_iface_skeleton_new(&vtable,
dbus_obj, (GDestroyNotify)bluez_dbus_object_data_unref)) == NULL) {
free(dbus_obj);
goto fail;
}

dbus_obj->ifs = G_DBUS_INTERFACE_SKELETON(ifs_profile);
if (!g_dbus_interface_skeleton_export(dbus_obj->ifs, config.dbus, path, &err)) {
g_object_unref(ifs_profile);
free(dbus_obj);
goto fail;
}
Expand Down Expand Up @@ -1153,6 +1146,7 @@ static void bluez_signal_interfaces_removed(GDBusConnection *conn, const char *s
const char *path, const char *interface_, const char *signal, GVariant *params,
void *userdata) {
debug("Signal: %s.%s()", interface_, signal);
(void)conn;
(void)sender;
(void)path;
(void)interface_;
Expand All @@ -1177,7 +1171,8 @@ static void bluez_signal_interfaces_removed(GDBusConnection *conn, const char *s
g_hash_table_iter_init(&iter, dbus_object_data_map);
while (g_hash_table_iter_next(&iter, NULL, (gpointer)&dbus_obj))
if (dbus_obj->hci_dev_id == hci_dev_id) {
g_dbus_connection_unregister_object(conn, dbus_obj->id);
g_dbus_interface_skeleton_unexport(dbus_obj->ifs);
g_object_unref(dbus_obj->ifs);
g_hash_table_iter_remove(&iter);
}

Expand Down Expand Up @@ -1300,7 +1295,8 @@ static void bluez_disappeared(GDBusConnection *conn, const char *name,
struct bluez_dbus_object_data *dbus_obj;
g_hash_table_iter_init(&iter, dbus_object_data_map);
while (g_hash_table_iter_next(&iter, NULL, (gpointer)&dbus_obj)) {
g_dbus_connection_unregister_object(conn, dbus_obj->id);
g_dbus_interface_skeleton_unexport(dbus_obj->ifs);
g_object_unref(dbus_obj->ifs);
g_hash_table_iter_remove(&iter);
}

Expand Down
48 changes: 48 additions & 0 deletions src/ofono-skeleton.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* BlueALSA - ofono-skeleton.c
* Copyright (c) 2016-2021 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
* This project is licensed under the terms of the MIT license.
*
*/

#include "ofono-skeleton.h"

#include <gio/gio.h>
#include <glib-object.h>
#include <glib.h>

#include "ofono-iface.h"

G_DEFINE_TYPE(ofono_HFAudioAgentIfaceSkeleton, ofono_hf_audio_agent_iface_skeleton,
G_TYPE_DBUS_INTERFACE_SKELETON);

static void ofono_hf_audio_agent_iface_skeleton_class_init(
ofono_HFAudioAgentIfaceSkeletonClass *ifc) {
GDBusInterfaceSkeletonClass *ifc_ = G_DBUS_INTERFACE_SKELETON_CLASS(ifc);
ifc_->get_info = g_dbus_interface_skeleton_ex_class_get_info;
ifc_->get_vtable = g_dbus_interface_skeleton_ex_class_get_vtable;
ifc_->get_properties = g_dbus_interface_skeleton_ex_class_get_properties;
}

static void ofono_hf_audio_agent_iface_skeleton_init(
ofono_HFAudioAgentIfaceSkeleton *ifs) {
(void)ifs;
}

/**
* Create a skeleton for org.ofono.HandsfreeAudioAgent interface.
*
* @return On success, this function returns newly allocated GIO interface
* skeleton object, which shall be freed with g_object_unref(). If error
* occurs, NULL is returned. */
ofono_HFAudioAgentIfaceSkeleton *ofono_hf_audio_agent_iface_skeleton_new(
const GDBusInterfaceSkeletonVTable *vtable, void *userdata,
GDestroyNotify userdata_free_func) {
const GType type = ofono_hf_audio_agent_iface_skeleton_get_type();
return g_dbus_interface_skeleton_ex_new(type,
(GDBusInterfaceInfo *)&ofono_iface_hf_audio_agent,
vtable, userdata, userdata_free_func);
}
Loading

0 comments on commit 5e781ba

Please sign in to comment.