diff --git a/src/Makefile.am b/src/Makefile.am index 3bb2b4393..01488502d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/bluez-skeleton.c b/src/bluez-skeleton.c index ab2cd7834..2951e4718 100644 --- a/src/bluez-skeleton.c +++ b/src/bluez-skeleton.c @@ -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); +} diff --git a/src/bluez-skeleton.h b/src/bluez-skeleton.h index e5c71c80e..5a84bf275 100644 --- a/src/bluez-skeleton.h +++ b/src/bluez-skeleton.h @@ -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 diff --git a/src/bluez.c b/src/bluez.c index c504b62b4..342228f8c 100644 --- a/src/bluez.c +++ b/src/bluez.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -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; }; /** @@ -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); } @@ -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( @@ -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 = { @@ -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; } @@ -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( @@ -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 = { @@ -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; } @@ -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_; @@ -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); } @@ -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); } diff --git a/src/ofono-skeleton.c b/src/ofono-skeleton.c new file mode 100644 index 000000000..587cf1188 --- /dev/null +++ b/src/ofono-skeleton.c @@ -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 +#include +#include + +#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); +} diff --git a/src/ofono-skeleton.h b/src/ofono-skeleton.h new file mode 100644 index 000000000..2f488a036 --- /dev/null +++ b/src/ofono-skeleton.h @@ -0,0 +1,32 @@ +/* + * BlueALSA - ofono-skeleton.h + * 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. + * + */ + +#pragma once +#ifndef BLUEALSA_OFONOSKELETON_H_ +#define BLUEALSA_OFONOSKELETON_H_ + +#include +#include + +#include "dbus.h" + +typedef struct { + GDBusInterfaceSkeletonClass parent; +} ofono_HFAudioAgentIfaceSkeletonClass; + +typedef struct { + GDBusInterfaceSkeletonEx parent; +} ofono_HFAudioAgentIfaceSkeleton; + +ofono_HFAudioAgentIfaceSkeleton *ofono_hf_audio_agent_iface_skeleton_new( + const GDBusInterfaceSkeletonVTable *vtable, void *userdata, + GDestroyNotify userdata_free_func); + +#endif diff --git a/src/ofono.c b/src/ofono.c index dbb506216..48d2f67be 100644 --- a/src/ofono.c +++ b/src/ofono.c @@ -46,6 +46,7 @@ #include "hci.h" #include "hfp.h" #include "ofono-iface.h" +#include "ofono-skeleton.h" #include "shared/log.h" /** @@ -58,7 +59,7 @@ struct ofono_card_data { static GHashTable *ofono_card_data_map = NULL; static const char *dbus_agent_object_path = "/org/bluez/HFP/oFono"; -static unsigned int dbus_agent_object_id = 0; +static ofono_HFAudioAgentIfaceSkeleton *dbus_hf_agent = NULL; /** * Authorize oFono SCO connection. @@ -437,11 +438,11 @@ static void ofono_agent_release(GDBusMethodInvocation *inv, void *userdata) { g_object_unref(inv); } -static void ofono_hf_audio_agent_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; +/** + * Register to the oFono service. + * + * @return On success this function returns 0. Otherwise -1 is returned. */ +int ofono_register(void) { static const GDBusMethodCallDispatcher dispatchers[] = { { .method = "NewConnection", @@ -451,20 +452,8 @@ static void ofono_hf_audio_agent_method_call(GDBusConnection *conn, const char * { 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 to the oFono service. - * - * @return On success this function returns 0. Otherwise -1 is returned. */ -int ofono_register(void) { - - static const GDBusInterfaceVTable vtable = { - .method_call = ofono_hf_audio_agent_method_call, + static const GDBusInterfaceSkeletonVTable vtable = { + .dispatchers = dispatchers, }; GDBusMessage *msg = NULL, *rep = NULL; @@ -479,11 +468,17 @@ int ofono_register(void) { if (ofono_card_data_map == NULL) ofono_card_data_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - if (dbus_agent_object_id == 0) - if ((dbus_agent_object_id = g_dbus_connection_register_object(config.dbus, - dbus_agent_object_path, (GDBusInterfaceInfo *)&ofono_iface_hf_audio_agent, - &vtable, NULL, NULL, &err)) == 0) + if (dbus_hf_agent == NULL) { + ofono_HFAudioAgentIfaceSkeleton *ifs_hf_agent; + if ((ifs_hf_agent = ofono_hf_audio_agent_iface_skeleton_new(&vtable, NULL, NULL)) == NULL) + goto fail; + GDBusInterfaceSkeleton *ifs = G_DBUS_INTERFACE_SKELETON(ifs_hf_agent); + if (!g_dbus_interface_skeleton_export(ifs, config.dbus, dbus_agent_object_path, &err)) { + g_object_unref(ifs_hf_agent); goto fail; + } + dbus_hf_agent = ifs_hf_agent; + } msg = g_dbus_message_new_method_call(OFONO_SERVICE, "/", OFONO_IFACE_HF_AUDIO_MANAGER, "Register");